Annotation of src/sys/fs/ntfs/ntfs_vnops.c, Revision 1.52.2.4
1.52.2.2 tls 1: /* $NetBSD$ */
1.1 jdolecek 2:
3: /*
4: * Copyright (c) 1992, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * This code is derived from software contributed to Berkeley by
8: * John Heidemann of the UCLA Ficus project.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.14 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 jdolecek 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: *
34: * Id: ntfs_vnops.c,v 1.5 1999/05/12 09:43:06 semenu Exp
35: *
36: */
37:
38: #include <sys/cdefs.h>
1.52.2.2 tls 39: __KERNEL_RCSID(0, "$NetBSD$");
1.1 jdolecek 40:
41: #include <sys/param.h>
42: #include <sys/systm.h>
43: #include <sys/kernel.h>
44: #include <sys/time.h>
45: #include <sys/stat.h>
46: #include <sys/vnode.h>
47: #include <sys/mount.h>
48: #include <sys/namei.h>
49: #include <sys/malloc.h>
50: #include <sys/buf.h>
51: #include <sys/dirent.h>
1.29 elad 52: #include <sys/kauth.h>
1.1 jdolecek 53: #include <sys/sysctl.h>
54:
55:
56: #include <fs/ntfs/ntfs.h>
57: #include <fs/ntfs/ntfs_inode.h>
58: #include <fs/ntfs/ntfs_subr.h>
1.52.2.4! jdolecek 59: #include <fs/ntfs/ntfs_vfsops.h>
1.1 jdolecek 60: #include <miscfs/specfs/specdev.h>
61: #include <miscfs/genfs/genfs.h>
62:
63: #include <sys/unistd.h> /* for pathconf(2) constants */
64:
1.30 christos 65: static int ntfs_bypass(void *);
66: static int ntfs_read(void *);
67: static int ntfs_write(void *);
68: static int ntfs_getattr(void *);
69: static int ntfs_inactive(void *);
70: static int ntfs_print(void *);
71: static int ntfs_reclaim(void *);
72: static int ntfs_strategy(void *);
73: static int ntfs_access(void *);
74: static int ntfs_open(void *);
75: static int ntfs_close(void *);
76: static int ntfs_readdir(void *);
77: static int ntfs_lookup(void *);
78: static int ntfs_bmap(void *);
79: static int ntfs_fsync(void *);
1.24 xtraeme 80: static int ntfs_pathconf(void *);
1.1 jdolecek 81:
82: /*
83: * This is a noop, simply returning what one has been given.
84: */
85: int
1.30 christos 86: ntfs_bmap(void *v)
87: {
1.1 jdolecek 88: struct vop_bmap_args /* {
89: struct vnode *a_vp;
90: daddr_t a_bn;
91: struct vnode **a_vpp;
92: daddr_t *a_bnp;
93: int *a_runp;
94: int *a_runb;
1.30 christos 95: } */ *ap = v;
1.1 jdolecek 96: dprintf(("ntfs_bmap: vn: %p, blk: %d\n", ap->a_vp,(u_int32_t)ap->a_bn));
97: if (ap->a_vpp != NULL)
98: *ap->a_vpp = ap->a_vp;
99: if (ap->a_bnp != NULL)
100: *ap->a_bnp = ap->a_bn;
101: if (ap->a_runp != NULL)
102: *ap->a_runp = 0;
103: return (0);
104: }
105:
106: static int
1.30 christos 107: ntfs_read(void *v)
108: {
1.1 jdolecek 109: struct vop_read_args /* {
110: struct vnode *a_vp;
111: struct uio *a_uio;
112: int a_ioflag;
1.29 elad 113: kauth_cred_t a_cred;
1.30 christos 114: } */ *ap = v;
1.1 jdolecek 115: struct vnode *vp = ap->a_vp;
116: struct fnode *fp = VTOF(vp);
117: struct ntnode *ip = FTONT(fp);
118: struct uio *uio = ap->a_uio;
119: struct ntfsmount *ntmp = ip->i_mp;
120: u_int64_t toread;
121: int error;
122:
1.28 yamt 123: dprintf(("ntfs_read: ino: %llu, off: %qd resid: %qd\n",
1.25 christos 124: (unsigned long long)ip->i_number, (long long)uio->uio_offset,
1.28 yamt 125: (long long)uio->uio_resid));
1.1 jdolecek 126:
1.22 christos 127: dprintf(("ntfs_read: filesize: %qu",(long long)fp->f_size));
1.1 jdolecek 128:
129: /* don't allow reading after end of file */
130: if (uio->uio_offset > fp->f_size)
131: toread = 0;
132: else
1.20 jdolecek 133: toread = MIN(uio->uio_resid, fp->f_size - uio->uio_offset );
1.1 jdolecek 134:
1.22 christos 135: dprintf((", toread: %qu\n",(long long)toread));
1.1 jdolecek 136:
137: if (toread == 0)
138: return (0);
139:
140: error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
141: fp->f_attrname, uio->uio_offset, toread, NULL, uio);
142: if (error) {
143: printf("ntfs_read: ntfs_readattr failed: %d\n",error);
144: return (error);
145: }
146:
147: return (0);
148: }
149:
150: static int
1.30 christos 151: ntfs_bypass(void *v)
152: {
1.1 jdolecek 153: struct vop_generic_args /* {
154: struct vnodeop_desc *a_desc;
155: <other random data follows, presumably>
1.30 christos 156: } */ *ap __unused = v;
1.1 jdolecek 157: int error = ENOTTY;
158: dprintf(("ntfs_bypass: %s\n", ap->a_desc->vdesc_name));
159: return (error);
160: }
161:
162:
163: static int
1.30 christos 164: ntfs_getattr(void *v)
165: {
1.1 jdolecek 166: struct vop_getattr_args /* {
167: struct vnode *a_vp;
168: struct vattr *a_vap;
1.29 elad 169: kauth_cred_t a_cred;
1.30 christos 170: } */ *ap = v;
1.1 jdolecek 171: struct vnode *vp = ap->a_vp;
172: struct fnode *fp = VTOF(vp);
173: struct ntnode *ip = FTONT(fp);
174: struct vattr *vap = ap->a_vap;
175:
1.25 christos 176: dprintf(("ntfs_getattr: %llu, flags: %d\n",
177: (unsigned long long)ip->i_number, ip->i_flag));
1.1 jdolecek 178:
179: vap->va_fsid = ip->i_dev;
180: vap->va_fileid = ip->i_number;
181: vap->va_mode = ip->i_mp->ntm_mode;
182: vap->va_nlink = ip->i_nlink;
183: vap->va_uid = ip->i_mp->ntm_uid;
184: vap->va_gid = ip->i_mp->ntm_gid;
185: vap->va_rdev = 0; /* XXX UNODEV ? */
186: vap->va_size = fp->f_size;
187: vap->va_bytes = fp->f_allocated;
188: vap->va_atime = ntfs_nttimetounix(fp->f_times.t_access);
189: vap->va_mtime = ntfs_nttimetounix(fp->f_times.t_write);
190: vap->va_ctime = ntfs_nttimetounix(fp->f_times.t_create);
191: vap->va_flags = ip->i_flag;
192: vap->va_gen = 0;
193: vap->va_blocksize = ip->i_mp->ntm_spc * ip->i_mp->ntm_bps;
194: vap->va_type = vp->v_type;
195: vap->va_filerev = 0;
196: return (0);
197: }
198:
199:
200: /*
201: * Last reference to an ntnode. If necessary, write or delete it.
202: */
203: int
1.30 christos 204: ntfs_inactive(void *v)
205: {
1.52.2.4! jdolecek 206: struct vop_inactive_v2_args /* {
1.1 jdolecek 207: struct vnode *a_vp;
1.52.2.4! jdolecek 208: bool *a_recycle;
1.30 christos 209: } */ *ap = v;
1.52.2.4! jdolecek 210: struct vnode *vp __unused = ap->a_vp;
1.1 jdolecek 211: #ifdef NTFS_DEBUG
212: struct ntnode *ip = VTONT(vp);
213: #endif
214:
1.25 christos 215: dprintf(("ntfs_inactive: vnode: %p, ntnode: %llu\n", vp,
216: (unsigned long long)ip->i_number));
1.1 jdolecek 217:
218: /* XXX since we don't support any filesystem changes
219: * right now, nothing more needs to be done
220: */
221: return (0);
222: }
223:
224: /*
225: * Reclaim an fnode/ntnode so that it can be used for other purposes.
226: */
227: int
1.30 christos 228: ntfs_reclaim(void *v)
229: {
1.52.2.4! jdolecek 230: struct vop_reclaim_v2_args /* {
1.1 jdolecek 231: struct vnode *a_vp;
1.30 christos 232: } */ *ap = v;
1.1 jdolecek 233: struct vnode *vp = ap->a_vp;
234: struct fnode *fp = VTOF(vp);
235: struct ntnode *ip = FTONT(fp);
1.52.2.4! jdolecek 236: const int attrlen = strlen(fp->f_attrname);
1.1 jdolecek 237: int error;
238:
1.52.2.4! jdolecek 239: VOP_UNLOCK(vp);
! 240:
1.25 christos 241: dprintf(("ntfs_reclaim: vnode: %p, ntnode: %llu\n", vp,
242: (unsigned long long)ip->i_number));
1.1 jdolecek 243:
244: if ((error = ntfs_ntget(ip)) != 0)
245: return (error);
1.21 perry 246:
1.1 jdolecek 247: if (ip->i_devvp) {
248: vrele(ip->i_devvp);
249: ip->i_devvp = NULL;
250: }
1.32 ad 251: genfs_node_destroy(vp);
1.1 jdolecek 252: vp->v_data = NULL;
253:
1.52.2.4! jdolecek 254: /* Destroy fnode. */
! 255: if (fp->f_key != &fp->f_smallkey)
! 256: kmem_free(fp->f_key, NTKEY_SIZE(attrlen));
! 257: if (fp->f_dirblbuf)
! 258: free(fp->f_dirblbuf, M_NTFSDIR);
! 259: kmem_free(fp, sizeof(*fp));
! 260: ntfs_ntrele(ip);
! 261:
! 262: ntfs_ntput(ip);
! 263:
1.1 jdolecek 264: return (0);
265: }
266:
267: static int
1.30 christos 268: ntfs_print(void *v)
269: {
1.1 jdolecek 270: struct vop_print_args /* {
271: struct vnode *a_vp;
1.30 christos 272: } */ *ap = v;
1.3 jdolecek 273: struct ntnode *ip = VTONT(ap->a_vp);
274:
1.23 christos 275: printf("tag VT_NTFS, ino %llu, flag %#x, usecount %d, nlink %ld\n",
276: (unsigned long long)ip->i_number, ip->i_flag, ip->i_usecount,
277: ip->i_nlink);
1.3 jdolecek 278: printf(" ");
279: printf("\n");
1.1 jdolecek 280: return (0);
281: }
282:
283: /*
284: * Calculate the logical to physical mapping if not done already,
285: * then call the device strategy routine.
286: */
287: int
1.30 christos 288: ntfs_strategy(void *v)
289: {
1.1 jdolecek 290: struct vop_strategy_args /* {
1.16 hannken 291: struct vnode *a_vp;
1.1 jdolecek 292: struct buf *a_bp;
1.30 christos 293: } */ *ap = v;
1.1 jdolecek 294: struct buf *bp = ap->a_bp;
1.16 hannken 295: struct vnode *vp = ap->a_vp;
1.1 jdolecek 296: struct fnode *fp = VTOF(vp);
297: struct ntnode *ip = FTONT(fp);
298: struct ntfsmount *ntmp = ip->i_mp;
299: int error;
300:
301: dprintf(("ntfs_strategy: blkno: %d, lblkno: %d\n",
302: (u_int32_t)bp->b_blkno,
303: (u_int32_t)bp->b_lblkno));
304:
1.21 perry 305: dprintf(("strategy: bcount: %u flags: 0x%x\n",
1.1 jdolecek 306: (u_int32_t)bp->b_bcount,bp->b_flags));
307:
308: if (bp->b_flags & B_READ) {
309: u_int32_t toread;
310:
311: if (ntfs_cntob(bp->b_blkno) >= fp->f_size) {
312: clrbuf(bp);
313: error = 0;
314: } else {
1.20 jdolecek 315: toread = MIN(bp->b_bcount,
316: fp->f_size - ntfs_cntob(bp->b_blkno));
1.1 jdolecek 317: dprintf(("ntfs_strategy: toread: %d, fsize: %d\n",
318: toread,(u_int32_t)fp->f_size));
319:
320: error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
321: fp->f_attrname, ntfs_cntob(bp->b_blkno),
322: toread, bp->b_data, NULL);
323:
324: if (error) {
325: printf("ntfs_strategy: ntfs_readattr failed\n");
326: bp->b_error = error;
327: }
328:
1.33 christos 329: memset((char *)bp->b_data + toread, 0,
330: bp->b_bcount - toread);
1.1 jdolecek 331: }
332: } else {
333: size_t tmp;
334: u_int32_t towrite;
335:
336: if (ntfs_cntob(bp->b_blkno) + bp->b_bcount >= fp->f_size) {
337: printf("ntfs_strategy: CAN'T EXTEND FILE\n");
338: bp->b_error = error = EFBIG;
339: } else {
1.20 jdolecek 340: towrite = MIN(bp->b_bcount,
341: fp->f_size - ntfs_cntob(bp->b_blkno));
1.1 jdolecek 342: dprintf(("ntfs_strategy: towrite: %d, fsize: %d\n",
343: towrite,(u_int32_t)fp->f_size));
344:
1.21 perry 345: error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
1.1 jdolecek 346: fp->f_attrname, ntfs_cntob(bp->b_blkno),towrite,
347: bp->b_data, &tmp, NULL);
348:
349: if (error) {
350: printf("ntfs_strategy: ntfs_writeattr fail\n");
351: bp->b_error = error;
352: }
353: }
354: }
355: biodone(bp);
356: return (error);
357: }
358:
359: static int
1.30 christos 360: ntfs_write(void *v)
361: {
1.1 jdolecek 362: struct vop_write_args /* {
363: struct vnode *a_vp;
364: struct uio *a_uio;
365: int a_ioflag;
1.29 elad 366: kauth_cred_t a_cred;
1.30 christos 367: } */ *ap = v;
1.1 jdolecek 368: struct vnode *vp = ap->a_vp;
369: struct fnode *fp = VTOF(vp);
370: struct ntnode *ip = FTONT(fp);
371: struct uio *uio = ap->a_uio;
372: struct ntfsmount *ntmp = ip->i_mp;
373: u_int64_t towrite;
374: size_t written;
375: int error;
376:
1.28 yamt 377: dprintf(("ntfs_write: ino: %llu, off: %qd resid: %qd\n",
1.25 christos 378: (unsigned long long)ip->i_number, (long long)uio->uio_offset,
1.28 yamt 379: (long long)uio->uio_resid));
1.22 christos 380: dprintf(("ntfs_write: filesize: %qu",(long long)fp->f_size));
1.1 jdolecek 381:
382: if (uio->uio_resid + uio->uio_offset > fp->f_size) {
383: printf("ntfs_write: CAN'T WRITE BEYOND END OF FILE\n");
384: return (EFBIG);
385: }
386:
1.20 jdolecek 387: towrite = MIN(uio->uio_resid, fp->f_size - uio->uio_offset);
1.1 jdolecek 388:
1.22 christos 389: dprintf((", towrite: %qu\n",(long long)towrite));
1.1 jdolecek 390:
391: error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
392: fp->f_attrname, uio->uio_offset, towrite, NULL, &written, uio);
393: #ifdef NTFS_DEBUG
394: if (error)
395: printf("ntfs_write: ntfs_writeattr failed: %d\n", error);
396: #endif
397:
398: return (error);
399: }
400:
1.45 elad 401: static int
402: ntfs_check_possible(struct vnode *vp, struct ntnode *ip, mode_t mode)
1.30 christos 403: {
1.1 jdolecek 404:
405: /*
406: * Disallow write attempts on read-only file systems;
407: * unless the file is a socket, fifo, or a block or
408: * character device resident on the file system.
409: */
410: if (mode & VWRITE) {
411: switch ((int)vp->v_type) {
412: case VDIR:
413: case VLNK:
414: case VREG:
415: if (vp->v_mount->mnt_flag & MNT_RDONLY)
416: return (EROFS);
417: break;
418: }
419: }
420:
1.45 elad 421: return 0;
422: }
423:
424: static int
425: ntfs_check_permitted(struct vnode *vp, struct ntnode *ip, mode_t mode,
426: kauth_cred_t cred)
427: {
428: mode_t file_mode;
429:
1.43 elad 430: file_mode = ip->i_mp->ntm_mode | (S_IXUSR|S_IXGRP|S_IXOTH);
1.1 jdolecek 431:
1.52.2.2 tls 432: return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
1.50 elad 433: file_mode), vp, NULL, genfs_can_access(vp->v_type, file_mode,
434: ip->i_mp->ntm_uid, ip->i_mp->ntm_gid, mode, cred));
1.45 elad 435: }
436:
437: int
438: ntfs_access(void *v)
439: {
440: struct vop_access_args /* {
441: struct vnode *a_vp;
442: int a_mode;
443: kauth_cred_t a_cred;
444: } */ *ap = v;
445: struct vnode *vp = ap->a_vp;
446: struct ntnode *ip = VTONT(vp);
447: int error;
448:
449: dprintf(("ntfs_access: %llu\n", (unsigned long long)ip->i_number));
450:
451: error = ntfs_check_possible(vp, ip, ap->a_mode);
452: if (error)
453: return error;
454:
455: error = ntfs_check_permitted(vp, ip, ap->a_mode, ap->a_cred);
456:
457: return error;
1.1 jdolecek 458: }
459:
460: /*
461: * Open called.
462: *
463: * Nothing to do.
464: */
465: /* ARGSUSED */
466: static int
1.30 christos 467: ntfs_open(void *v)
468: {
1.1 jdolecek 469: struct vop_open_args /* {
470: struct vnode *a_vp;
471: int a_mode;
1.29 elad 472: kauth_cred_t a_cred;
1.30 christos 473: } */ *ap __unused = v;
1.25 christos 474: #ifdef NTFS_DEBUG
1.1 jdolecek 475: struct vnode *vp = ap->a_vp;
476: struct ntnode *ip = VTONT(vp);
477:
1.52.2.4! jdolecek 478: dprintf(("ntfs_open: %llu\n", (unsigned long long)ip->i_number));
1.1 jdolecek 479: #endif
480:
481: /*
482: * Files marked append-only must be opened for appending.
483: */
484:
485: return (0);
486: }
487:
488: /*
489: * Close called.
490: *
491: * Update the times on the inode.
492: */
493: /* ARGSUSED */
494: static int
1.30 christos 495: ntfs_close(void *v)
496: {
1.1 jdolecek 497: struct vop_close_args /* {
498: struct vnode *a_vp;
499: int a_fflag;
1.29 elad 500: kauth_cred_t a_cred;
1.30 christos 501: } */ *ap __unused = v;
1.25 christos 502: #ifdef NTFS_DEBUG
1.1 jdolecek 503: struct vnode *vp = ap->a_vp;
504: struct ntnode *ip = VTONT(vp);
505:
1.52.2.4! jdolecek 506: dprintf(("ntfs_close: %llu\n", (unsigned long long)ip->i_number));
1.1 jdolecek 507: #endif
508:
509: return (0);
510: }
511:
512: int
1.30 christos 513: ntfs_readdir(void *v)
514: {
1.1 jdolecek 515: struct vop_readdir_args /* {
516: struct vnode *a_vp;
517: struct uio *a_uio;
1.29 elad 518: kauth_cred_t a_cred;
1.1 jdolecek 519: int *a_ncookies;
520: u_int **cookies;
1.30 christos 521: } */ *ap = v;
1.1 jdolecek 522: struct vnode *vp = ap->a_vp;
523: struct fnode *fp = VTOF(vp);
524: struct ntnode *ip = FTONT(fp);
525: struct uio *uio = ap->a_uio;
526: struct ntfsmount *ntmp = ip->i_mp;
527: int i, error = 0;
528: u_int32_t faked = 0, num;
529: int ncookies = 0;
530: struct dirent *cde;
531: off_t off;
532:
1.25 christos 533: dprintf(("ntfs_readdir %llu off: %qd resid: %qd\n",
534: (unsigned long long)ip->i_number, (long long)uio->uio_offset,
535: (long long)uio->uio_resid));
1.1 jdolecek 536:
537: off = uio->uio_offset;
538:
1.42 cegger 539: cde = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
1.1 jdolecek 540:
541: /* Simulate . in every dir except ROOT */
542: if (ip->i_number != NTFS_ROOTINO
543: && uio->uio_offset < sizeof(struct dirent)) {
544: cde->d_fileno = ip->i_number;
545: cde->d_reclen = sizeof(struct dirent);
546: cde->d_type = DT_DIR;
547: cde->d_namlen = 1;
548: strncpy(cde->d_name, ".", 2);
549: error = uiomove((void *)cde, sizeof(struct dirent), uio);
550: if (error)
551: goto out;
552:
553: ncookies++;
554: }
555:
556: /* Simulate .. in every dir including ROOT */
557: if (uio->uio_offset < 2 * sizeof(struct dirent)) {
558: cde->d_fileno = NTFS_ROOTINO; /* XXX */
559: cde->d_reclen = sizeof(struct dirent);
560: cde->d_type = DT_DIR;
561: cde->d_namlen = 2;
562: strncpy(cde->d_name, "..", 3);
563:
564: error = uiomove((void *) cde, sizeof(struct dirent), uio);
565: if (error)
566: goto out;
567:
568: ncookies++;
569: }
570:
571: faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2;
572: num = uio->uio_offset / sizeof(struct dirent) - faked;
573:
574: while (uio->uio_resid >= sizeof(struct dirent)) {
575: struct attr_indexentry *iep;
576: char *fname;
577: size_t remains;
578: int sz;
579:
580: error = ntfs_ntreaddir(ntmp, fp, num, &iep);
581: if (error)
582: goto out;
583:
584: if (NULL == iep)
585: break;
586:
587: for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent));
588: iep = NTFS_NEXTREC(iep, struct attr_indexentry *))
589: {
590: if(!ntfs_isnamepermitted(ntmp,iep))
591: continue;
592:
593: remains = sizeof(cde->d_name) - 1;
594: fname = cde->d_name;
595: for(i=0; i<iep->ie_fnamelen; i++) {
596: sz = (*ntmp->ntm_wput)(fname, remains,
597: iep->ie_fname[i]);
598: fname += sz;
599: remains -= sz;
600: }
601: *fname = '\0';
602: dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ",
603: num, cde->d_name, iep->ie_fnametype,
604: iep->ie_flag));
605: cde->d_namlen = fname - (char *) cde->d_name;
606: cde->d_fileno = iep->ie_number;
607: cde->d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
608: cde->d_reclen = sizeof(struct dirent);
609: dprintf(("%s\n", (cde->d_type == DT_DIR) ? "dir":"reg"));
610:
611: error = uiomove((void *)cde, sizeof(struct dirent), uio);
612: if (error)
613: goto out;
614:
615: ncookies++;
616: num++;
617: }
618: }
619:
620: dprintf(("ntfs_readdir: %d entries (%d bytes) read\n",
621: ncookies,(u_int)(uio->uio_offset - off)));
1.22 christos 622: dprintf(("ntfs_readdir: off: %qd resid: %qu\n",
623: (long long)uio->uio_offset,(long long)uio->uio_resid));
1.1 jdolecek 624:
625: if (!error && ap->a_ncookies != NULL) {
626: struct dirent* dpStart;
627: struct dirent* dp;
628: off_t *cookies;
629: off_t *cookiep;
630:
1.15 jdolecek 631: dprintf(("ntfs_readdir: %d cookies\n",ncookies));
1.1 jdolecek 632: dpStart = (struct dirent *)
1.33 christos 633: ((char *)uio->uio_iov->iov_base -
1.1 jdolecek 634: (uio->uio_offset - off));
635: cookies = malloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
636: for (dp = dpStart, cookiep = cookies, i=0;
637: i < ncookies;
1.33 christos 638: dp = (struct dirent *)((char *) dp + dp->d_reclen), i++) {
1.1 jdolecek 639: off += dp->d_reclen;
640: *cookiep++ = (u_int) off;
641: }
642: *ap->a_ncookies = ncookies;
643: *ap->a_cookies = cookies;
644: }
645: /*
646: if (ap->a_eofflag)
647: *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset;
648: */
649: out:
1.42 cegger 650: free(cde, M_TEMP);
1.1 jdolecek 651: return (error);
652: }
653:
654: int
1.30 christos 655: ntfs_lookup(void *v)
656: {
1.52.2.3 tls 657: struct vop_lookup_v2_args /* {
1.1 jdolecek 658: struct vnode *a_dvp;
659: struct vnode **a_vpp;
660: struct componentname *a_cnp;
1.30 christos 661: } */ *ap = v;
1.1 jdolecek 662: struct vnode *dvp = ap->a_dvp;
663: struct ntnode *dip = VTONT(dvp);
664: struct ntfsmount *ntmp = dip->i_mp;
665: struct componentname *cnp = ap->a_cnp;
1.29 elad 666: kauth_cred_t cred = cnp->cn_cred;
1.1 jdolecek 667: int error;
1.31 chs 668:
1.41 ad 669: dprintf(("ntfs_lookup: \"%.*s\" (%lld bytes) in %llu\n",
670: (int)cnp->cn_namelen, cnp->cn_nameptr, (long long)cnp->cn_namelen,
1.31 chs 671: (unsigned long long)dip->i_number));
1.1 jdolecek 672:
1.36 pooka 673: error = VOP_ACCESS(dvp, VEXEC, cred);
1.1 jdolecek 674: if(error)
675: return (error);
676:
677: if ((cnp->cn_flags & ISLASTCN) &&
678: (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
679: (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
680: return (EROFS);
681:
682: /*
683: * We now have a segment name to search for, and a directory
684: * to search.
685: *
686: * Before tediously performing a linear scan of the directory,
687: * check the name cache to see if the directory/name pair
688: * we are looking for is known already.
689: */
1.52.2.1 tls 690: if (cache_lookup(ap->a_dvp, cnp->cn_nameptr, cnp->cn_namelen,
691: cnp->cn_nameiop, cnp->cn_flags, NULL, ap->a_vpp)) {
692: return *ap->a_vpp == NULLVP ? ENOENT : 0;
693: }
1.1 jdolecek 694:
695: if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
1.25 christos 696: dprintf(("ntfs_lookup: faking . directory in %llu\n",
697: (unsigned long long)dip->i_number));
1.1 jdolecek 698:
1.46 pooka 699: vref(dvp);
1.1 jdolecek 700: *ap->a_vpp = dvp;
701: error = 0;
702: } else if (cnp->cn_flags & ISDOTDOT) {
703: struct ntvattr *vap;
704:
1.25 christos 705: dprintf(("ntfs_lookup: faking .. directory in %llu\n",
706: (unsigned long long)dip->i_number));
1.1 jdolecek 707:
708: error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap);
1.31 chs 709: if (error) {
1.1 jdolecek 710: return (error);
1.31 chs 711: }
1.1 jdolecek 712:
713: dprintf(("ntfs_lookup: parentdir: %d\n",
714: vap->va_a_name->n_pnumber));
1.52.2.4! jdolecek 715: error = ntfs_vgetex(ntmp->ntm_mountp,
! 716: vap->va_a_name->n_pnumber,
! 717: NTFS_A_DATA, "", 0, ap->a_vpp);
1.1 jdolecek 718: ntfs_ntvattrrele(vap);
719: if (error) {
720: return (error);
721: }
722: } else {
723: error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp);
724: if (error) {
725: dprintf(("ntfs_ntlookupfile: returned %d\n", error));
726: return (error);
727: }
728:
1.25 christos 729: dprintf(("ntfs_lookup: found ino: %llu\n",
730: (unsigned long long)VTONT(*ap->a_vpp)->i_number));
1.1 jdolecek 731: }
732:
1.52.2.1 tls 733: cache_enter(dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen,
734: cnp->cn_flags);
1.1 jdolecek 735:
1.52 rmind 736: return error;
1.1 jdolecek 737: }
738:
739: /*
740: * Flush the blocks of a file to disk.
741: *
742: * This function is worthless for vnodes that represent directories. Maybe we
743: * could just do a sync if they try an fsync on a directory file.
744: */
745: static int
1.30 christos 746: ntfs_fsync(void *v)
747: {
1.1 jdolecek 748: struct vop_fsync_args /* {
749: struct vnode *a_vp;
1.29 elad 750: kauth_cred_t a_cred;
1.26 yamt 751: int a_flags;
1.1 jdolecek 752: off_t offlo;
753: off_t offhi;
1.30 christos 754: } */ *ap = v;
1.26 yamt 755: struct vnode *vp = ap->a_vp;
756:
757: if (ap->a_flags & FSYNC_CACHE) {
758: return EOPNOTSUPP;
759: }
760:
1.51 chs 761: return vflushbuf(vp, ap->a_flags);
1.1 jdolecek 762: }
763:
764: /*
765: * Return POSIX pathconf information applicable to NTFS filesystem
766: */
1.4 jdolecek 767: static int
1.30 christos 768: ntfs_pathconf(void *v)
1.1 jdolecek 769: {
770: struct vop_pathconf_args /* {
771: struct vnode *a_vp;
772: int a_name;
773: register_t *a_retval;
774: } */ *ap = v;
775:
776: switch (ap->a_name) {
777: case _PC_LINK_MAX:
778: *ap->a_retval = 1;
779: return (0);
780: case _PC_NAME_MAX:
1.19 jdolecek 781: *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_namemax;
1.1 jdolecek 782: return (0);
783: case _PC_PATH_MAX:
784: *ap->a_retval = PATH_MAX;
785: return (0);
786: case _PC_CHOWN_RESTRICTED:
787: *ap->a_retval = 1;
788: return (0);
789: case _PC_NO_TRUNC:
790: *ap->a_retval = 0;
791: return (0);
792: case _PC_SYNC_IO:
793: *ap->a_retval = 1;
794: return (0);
795: case _PC_FILESIZEBITS:
796: *ap->a_retval = 64;
797: return (0);
798: default:
799: return (EINVAL);
800: }
801: /* NOTREACHED */
1.5 jdolecek 802: }
803:
1.1 jdolecek 804: /*
805: * Global vfs data structures
806: */
807: vop_t **ntfs_vnodeop_p;
808:
809: const struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = {
810: { &vop_default_desc, (vop_t *) ntfs_bypass },
811: { &vop_lookup_desc, (vop_t *) ntfs_lookup }, /* lookup */
812: { &vop_create_desc, genfs_eopnotsupp }, /* create */
813: { &vop_mknod_desc, genfs_eopnotsupp }, /* mknod */
814: { &vop_open_desc, (vop_t *) ntfs_open }, /* open */
815: { &vop_close_desc,(vop_t *) ntfs_close }, /* close */
816: { &vop_access_desc, (vop_t *) ntfs_access }, /* access */
817: { &vop_getattr_desc, (vop_t *) ntfs_getattr }, /* getattr */
818: { &vop_setattr_desc, genfs_eopnotsupp }, /* setattr */
819: { &vop_read_desc, (vop_t *) ntfs_read }, /* read */
820: { &vop_write_desc, (vop_t *) ntfs_write }, /* write */
1.52.2.3 tls 821: { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */
822: { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */
1.1 jdolecek 823: { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */
824: { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */
825: { &vop_poll_desc, genfs_poll }, /* poll */
826: { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */
827: { &vop_revoke_desc, genfs_revoke }, /* revoke */
828: { &vop_mmap_desc, genfs_mmap }, /* mmap */
1.26 yamt 829: { &vop_fsync_desc, (vop_t *) ntfs_fsync }, /* fsync */
1.1 jdolecek 830: { &vop_seek_desc, genfs_seek }, /* seek */
1.6 jdolecek 831: { &vop_remove_desc, genfs_eopnotsupp }, /* remove */
832: { &vop_link_desc, genfs_eopnotsupp }, /* link */
833: { &vop_rename_desc, genfs_eopnotsupp }, /* rename */
834: { &vop_mkdir_desc, genfs_eopnotsupp }, /* mkdir */
835: { &vop_rmdir_desc, genfs_eopnotsupp }, /* rmdir */
1.1 jdolecek 836: { &vop_symlink_desc, genfs_eopnotsupp }, /* symlink */
837: { &vop_readdir_desc, (vop_t *) ntfs_readdir }, /* readdir */
838: { &vop_readlink_desc, genfs_eopnotsupp }, /* readlink */
839: { &vop_abortop_desc, genfs_abortop }, /* abortop */
840: { &vop_inactive_desc, (vop_t *) ntfs_inactive }, /* inactive */
841: { &vop_reclaim_desc, (vop_t *) ntfs_reclaim }, /* reclaim */
842: { &vop_lock_desc, genfs_lock }, /* lock */
843: { &vop_unlock_desc, genfs_unlock }, /* unlock */
844: { &vop_bmap_desc, (vop_t *) ntfs_bmap }, /* bmap */
845: { &vop_strategy_desc, (vop_t *) ntfs_strategy }, /* strategy */
846: { &vop_print_desc, (vop_t *) ntfs_print }, /* print */
847: { &vop_islocked_desc, genfs_islocked }, /* islocked */
848: { &vop_pathconf_desc, ntfs_pathconf }, /* pathconf */
849: { &vop_advlock_desc, genfs_nullop }, /* advlock */
850: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
851: { &vop_getpages_desc, genfs_compat_getpages }, /* getpages */
852: { &vop_putpages_desc, genfs_putpages }, /* putpages */
853: { NULL, NULL }
854: };
855: const struct vnodeopv_desc ntfs_vnodeop_opv_desc =
856: { &ntfs_vnodeop_p, ntfs_vnodeop_entries };
CVSweb <webmaster@jp.NetBSD.org>