Annotation of src/sys/fs/ntfs/ntfs_vnops.c, Revision 1.49.4.5
1.49.4.5! yamt 1: /* $NetBSD: ntfs_vnops.c,v 1.49.4.4 2013/01/16 05:33:40 yamt Exp $ */
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.49.4.5! yamt 39: __KERNEL_RCSID(0, "$NetBSD: ntfs_vnops.c,v 1.49.4.4 2013/01/16 05:33:40 yamt Exp $");
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>
59: #include <miscfs/specfs/specdev.h>
60: #include <miscfs/genfs/genfs.h>
61:
62: #include <sys/unistd.h> /* for pathconf(2) constants */
63:
1.30 christos 64: static int ntfs_bypass(void *);
65: static int ntfs_read(void *);
66: static int ntfs_write(void *);
67: static int ntfs_getattr(void *);
68: static int ntfs_inactive(void *);
69: static int ntfs_print(void *);
70: static int ntfs_reclaim(void *);
71: static int ntfs_strategy(void *);
72: static int ntfs_access(void *);
73: static int ntfs_open(void *);
74: static int ntfs_close(void *);
75: static int ntfs_readdir(void *);
76: static int ntfs_lookup(void *);
77: static int ntfs_bmap(void *);
78: static int ntfs_fsync(void *);
1.24 xtraeme 79: static int ntfs_pathconf(void *);
1.1 jdolecek 80:
1.18 jdolecek 81: extern int prtactive;
1.1 jdolecek 82:
83: /*
84: * This is a noop, simply returning what one has been given.
85: */
86: int
1.30 christos 87: ntfs_bmap(void *v)
88: {
1.1 jdolecek 89: struct vop_bmap_args /* {
90: struct vnode *a_vp;
91: daddr_t a_bn;
92: struct vnode **a_vpp;
93: daddr_t *a_bnp;
94: int *a_runp;
95: int *a_runb;
1.30 christos 96: } */ *ap = v;
1.1 jdolecek 97: dprintf(("ntfs_bmap: vn: %p, blk: %d\n", ap->a_vp,(u_int32_t)ap->a_bn));
98: if (ap->a_vpp != NULL)
99: *ap->a_vpp = ap->a_vp;
100: if (ap->a_bnp != NULL)
101: *ap->a_bnp = ap->a_bn;
102: if (ap->a_runp != NULL)
103: *ap->a_runp = 0;
104: return (0);
105: }
106:
107: static int
1.30 christos 108: ntfs_read(void *v)
109: {
1.1 jdolecek 110: struct vop_read_args /* {
111: struct vnode *a_vp;
112: struct uio *a_uio;
113: int a_ioflag;
1.29 elad 114: kauth_cred_t a_cred;
1.30 christos 115: } */ *ap = v;
1.1 jdolecek 116: struct vnode *vp = ap->a_vp;
117: struct fnode *fp = VTOF(vp);
118: struct ntnode *ip = FTONT(fp);
119: struct uio *uio = ap->a_uio;
120: struct ntfsmount *ntmp = ip->i_mp;
121: u_int64_t toread;
122: int error;
123:
1.28 yamt 124: dprintf(("ntfs_read: ino: %llu, off: %qd resid: %qd\n",
1.25 christos 125: (unsigned long long)ip->i_number, (long long)uio->uio_offset,
1.28 yamt 126: (long long)uio->uio_resid));
1.1 jdolecek 127:
1.22 christos 128: dprintf(("ntfs_read: filesize: %qu",(long long)fp->f_size));
1.1 jdolecek 129:
130: /* don't allow reading after end of file */
131: if (uio->uio_offset > fp->f_size)
132: toread = 0;
133: else
1.20 jdolecek 134: toread = MIN(uio->uio_resid, fp->f_size - uio->uio_offset );
1.1 jdolecek 135:
1.22 christos 136: dprintf((", toread: %qu\n",(long long)toread));
1.1 jdolecek 137:
138: if (toread == 0)
139: return (0);
140:
141: error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
142: fp->f_attrname, uio->uio_offset, toread, NULL, uio);
143: if (error) {
144: printf("ntfs_read: ntfs_readattr failed: %d\n",error);
145: return (error);
146: }
147:
148: return (0);
149: }
150:
151: static int
1.30 christos 152: ntfs_bypass(void *v)
153: {
1.1 jdolecek 154: struct vop_generic_args /* {
155: struct vnodeop_desc *a_desc;
156: <other random data follows, presumably>
1.30 christos 157: } */ *ap __unused = v;
1.1 jdolecek 158: int error = ENOTTY;
159: dprintf(("ntfs_bypass: %s\n", ap->a_desc->vdesc_name));
160: return (error);
161: }
162:
163:
164: static int
1.30 christos 165: ntfs_getattr(void *v)
166: {
1.1 jdolecek 167: struct vop_getattr_args /* {
168: struct vnode *a_vp;
169: struct vattr *a_vap;
1.29 elad 170: kauth_cred_t a_cred;
1.30 christos 171: } */ *ap = v;
1.1 jdolecek 172: struct vnode *vp = ap->a_vp;
173: struct fnode *fp = VTOF(vp);
174: struct ntnode *ip = FTONT(fp);
175: struct vattr *vap = ap->a_vap;
176:
1.25 christos 177: dprintf(("ntfs_getattr: %llu, flags: %d\n",
178: (unsigned long long)ip->i_number, ip->i_flag));
1.1 jdolecek 179:
180: vap->va_fsid = ip->i_dev;
181: vap->va_fileid = ip->i_number;
182: vap->va_mode = ip->i_mp->ntm_mode;
183: vap->va_nlink = ip->i_nlink;
184: vap->va_uid = ip->i_mp->ntm_uid;
185: vap->va_gid = ip->i_mp->ntm_gid;
186: vap->va_rdev = 0; /* XXX UNODEV ? */
187: vap->va_size = fp->f_size;
188: vap->va_bytes = fp->f_allocated;
189: vap->va_atime = ntfs_nttimetounix(fp->f_times.t_access);
190: vap->va_mtime = ntfs_nttimetounix(fp->f_times.t_write);
191: vap->va_ctime = ntfs_nttimetounix(fp->f_times.t_create);
192: vap->va_flags = ip->i_flag;
193: vap->va_gen = 0;
194: vap->va_blocksize = ip->i_mp->ntm_spc * ip->i_mp->ntm_bps;
195: vap->va_type = vp->v_type;
196: vap->va_filerev = 0;
197: return (0);
198: }
199:
200:
201: /*
202: * Last reference to an ntnode. If necessary, write or delete it.
203: */
204: int
1.30 christos 205: ntfs_inactive(void *v)
206: {
1.1 jdolecek 207: struct vop_inactive_args /* {
208: struct vnode *a_vp;
1.30 christos 209: } */ *ap = v;
1.1 jdolecek 210: struct vnode *vp = ap->a_vp;
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:
1.47 hannken 218: VOP_UNLOCK(vp);
1.1 jdolecek 219:
220: /* XXX since we don't support any filesystem changes
221: * right now, nothing more needs to be done
222: */
223: return (0);
224: }
225:
226: /*
227: * Reclaim an fnode/ntnode so that it can be used for other purposes.
228: */
229: int
1.30 christos 230: ntfs_reclaim(void *v)
231: {
1.1 jdolecek 232: struct vop_reclaim_args /* {
233: struct vnode *a_vp;
1.30 christos 234: } */ *ap = v;
1.1 jdolecek 235: struct vnode *vp = ap->a_vp;
236: struct fnode *fp = VTOF(vp);
237: struct ntnode *ip = FTONT(fp);
238: int error;
239:
1.25 christos 240: dprintf(("ntfs_reclaim: vnode: %p, ntnode: %llu\n", vp,
241: (unsigned long long)ip->i_number));
1.1 jdolecek 242:
1.37 ad 243: if (prtactive && vp->v_usecount > 1)
1.1 jdolecek 244: vprint("ntfs_reclaim: pushing active", vp);
245:
246: if ((error = ntfs_ntget(ip)) != 0)
247: return (error);
1.21 perry 248:
1.1 jdolecek 249: if (ip->i_devvp) {
250: vrele(ip->i_devvp);
251: ip->i_devvp = NULL;
252: }
253:
1.32 ad 254: genfs_node_destroy(vp);
1.1 jdolecek 255: ntfs_frele(fp);
256: ntfs_ntput(ip);
257: vp->v_data = NULL;
258:
259: return (0);
260: }
261:
262: static int
1.30 christos 263: ntfs_print(void *v)
264: {
1.1 jdolecek 265: struct vop_print_args /* {
266: struct vnode *a_vp;
1.30 christos 267: } */ *ap = v;
1.3 jdolecek 268: struct ntnode *ip = VTONT(ap->a_vp);
269:
1.23 christos 270: printf("tag VT_NTFS, ino %llu, flag %#x, usecount %d, nlink %ld\n",
271: (unsigned long long)ip->i_number, ip->i_flag, ip->i_usecount,
272: ip->i_nlink);
1.3 jdolecek 273: printf(" ");
274: printf("\n");
1.1 jdolecek 275: return (0);
276: }
277:
278: /*
279: * Calculate the logical to physical mapping if not done already,
280: * then call the device strategy routine.
281: */
282: int
1.30 christos 283: ntfs_strategy(void *v)
284: {
1.1 jdolecek 285: struct vop_strategy_args /* {
1.16 hannken 286: struct vnode *a_vp;
1.1 jdolecek 287: struct buf *a_bp;
1.30 christos 288: } */ *ap = v;
1.1 jdolecek 289: struct buf *bp = ap->a_bp;
1.16 hannken 290: struct vnode *vp = ap->a_vp;
1.1 jdolecek 291: struct fnode *fp = VTOF(vp);
292: struct ntnode *ip = FTONT(fp);
293: struct ntfsmount *ntmp = ip->i_mp;
294: int error;
295:
296: dprintf(("ntfs_strategy: blkno: %d, lblkno: %d\n",
297: (u_int32_t)bp->b_blkno,
298: (u_int32_t)bp->b_lblkno));
299:
1.21 perry 300: dprintf(("strategy: bcount: %u flags: 0x%x\n",
1.1 jdolecek 301: (u_int32_t)bp->b_bcount,bp->b_flags));
302:
303: if (bp->b_flags & B_READ) {
304: u_int32_t toread;
305:
306: if (ntfs_cntob(bp->b_blkno) >= fp->f_size) {
307: clrbuf(bp);
308: error = 0;
309: } else {
1.20 jdolecek 310: toread = MIN(bp->b_bcount,
311: fp->f_size - ntfs_cntob(bp->b_blkno));
1.1 jdolecek 312: dprintf(("ntfs_strategy: toread: %d, fsize: %d\n",
313: toread,(u_int32_t)fp->f_size));
314:
315: error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
316: fp->f_attrname, ntfs_cntob(bp->b_blkno),
317: toread, bp->b_data, NULL);
318:
319: if (error) {
320: printf("ntfs_strategy: ntfs_readattr failed\n");
321: bp->b_error = error;
322: }
323:
1.33 christos 324: memset((char *)bp->b_data + toread, 0,
325: bp->b_bcount - toread);
1.1 jdolecek 326: }
327: } else {
328: size_t tmp;
329: u_int32_t towrite;
330:
331: if (ntfs_cntob(bp->b_blkno) + bp->b_bcount >= fp->f_size) {
332: printf("ntfs_strategy: CAN'T EXTEND FILE\n");
333: bp->b_error = error = EFBIG;
334: } else {
1.20 jdolecek 335: towrite = MIN(bp->b_bcount,
336: fp->f_size - ntfs_cntob(bp->b_blkno));
1.1 jdolecek 337: dprintf(("ntfs_strategy: towrite: %d, fsize: %d\n",
338: towrite,(u_int32_t)fp->f_size));
339:
1.21 perry 340: error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
1.1 jdolecek 341: fp->f_attrname, ntfs_cntob(bp->b_blkno),towrite,
342: bp->b_data, &tmp, NULL);
343:
344: if (error) {
345: printf("ntfs_strategy: ntfs_writeattr fail\n");
346: bp->b_error = error;
347: }
348: }
349: }
350: biodone(bp);
351: return (error);
352: }
353:
354: static int
1.30 christos 355: ntfs_write(void *v)
356: {
1.1 jdolecek 357: struct vop_write_args /* {
358: struct vnode *a_vp;
359: struct uio *a_uio;
360: int a_ioflag;
1.29 elad 361: kauth_cred_t a_cred;
1.30 christos 362: } */ *ap = v;
1.1 jdolecek 363: struct vnode *vp = ap->a_vp;
364: struct fnode *fp = VTOF(vp);
365: struct ntnode *ip = FTONT(fp);
366: struct uio *uio = ap->a_uio;
367: struct ntfsmount *ntmp = ip->i_mp;
368: u_int64_t towrite;
369: size_t written;
370: int error;
371:
1.28 yamt 372: dprintf(("ntfs_write: ino: %llu, off: %qd resid: %qd\n",
1.25 christos 373: (unsigned long long)ip->i_number, (long long)uio->uio_offset,
1.28 yamt 374: (long long)uio->uio_resid));
1.22 christos 375: dprintf(("ntfs_write: filesize: %qu",(long long)fp->f_size));
1.1 jdolecek 376:
377: if (uio->uio_resid + uio->uio_offset > fp->f_size) {
378: printf("ntfs_write: CAN'T WRITE BEYOND END OF FILE\n");
379: return (EFBIG);
380: }
381:
1.20 jdolecek 382: towrite = MIN(uio->uio_resid, fp->f_size - uio->uio_offset);
1.1 jdolecek 383:
1.22 christos 384: dprintf((", towrite: %qu\n",(long long)towrite));
1.1 jdolecek 385:
386: error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
387: fp->f_attrname, uio->uio_offset, towrite, NULL, &written, uio);
388: #ifdef NTFS_DEBUG
389: if (error)
390: printf("ntfs_write: ntfs_writeattr failed: %d\n", error);
391: #endif
392:
393: return (error);
394: }
395:
1.45 elad 396: static int
397: ntfs_check_possible(struct vnode *vp, struct ntnode *ip, mode_t mode)
1.30 christos 398: {
1.1 jdolecek 399:
400: /*
401: * Disallow write attempts on read-only file systems;
402: * unless the file is a socket, fifo, or a block or
403: * character device resident on the file system.
404: */
405: if (mode & VWRITE) {
406: switch ((int)vp->v_type) {
407: case VDIR:
408: case VLNK:
409: case VREG:
410: if (vp->v_mount->mnt_flag & MNT_RDONLY)
411: return (EROFS);
412: break;
413: }
414: }
415:
1.45 elad 416: return 0;
417: }
418:
419: static int
420: ntfs_check_permitted(struct vnode *vp, struct ntnode *ip, mode_t mode,
421: kauth_cred_t cred)
422: {
423: mode_t file_mode;
424:
1.43 elad 425: file_mode = ip->i_mp->ntm_mode | (S_IXUSR|S_IXGRP|S_IXOTH);
1.1 jdolecek 426:
1.49.4.5! yamt 427: return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
1.49.4.1 yamt 428: file_mode), vp, NULL, genfs_can_access(vp->v_type, file_mode,
429: ip->i_mp->ntm_uid, ip->i_mp->ntm_gid, mode, cred));
1.45 elad 430: }
431:
432: int
433: ntfs_access(void *v)
434: {
435: struct vop_access_args /* {
436: struct vnode *a_vp;
437: int a_mode;
438: kauth_cred_t a_cred;
439: } */ *ap = v;
440: struct vnode *vp = ap->a_vp;
441: struct ntnode *ip = VTONT(vp);
442: int error;
443:
444: dprintf(("ntfs_access: %llu\n", (unsigned long long)ip->i_number));
445:
446: error = ntfs_check_possible(vp, ip, ap->a_mode);
447: if (error)
448: return error;
449:
450: error = ntfs_check_permitted(vp, ip, ap->a_mode, ap->a_cred);
451:
452: return error;
1.1 jdolecek 453: }
454:
455: /*
456: * Open called.
457: *
458: * Nothing to do.
459: */
460: /* ARGSUSED */
461: static int
1.30 christos 462: ntfs_open(void *v)
463: {
1.1 jdolecek 464: struct vop_open_args /* {
465: struct vnode *a_vp;
466: int a_mode;
1.29 elad 467: kauth_cred_t a_cred;
1.30 christos 468: } */ *ap __unused = v;
1.25 christos 469: #ifdef NTFS_DEBUG
1.1 jdolecek 470: struct vnode *vp = ap->a_vp;
471: struct ntnode *ip = VTONT(vp);
472:
1.25 christos 473: printf("ntfs_open: %llu\n", (unsigned long long)ip->i_number);
1.1 jdolecek 474: #endif
475:
476: /*
477: * Files marked append-only must be opened for appending.
478: */
479:
480: return (0);
481: }
482:
483: /*
484: * Close called.
485: *
486: * Update the times on the inode.
487: */
488: /* ARGSUSED */
489: static int
1.30 christos 490: ntfs_close(void *v)
491: {
1.1 jdolecek 492: struct vop_close_args /* {
493: struct vnode *a_vp;
494: int a_fflag;
1.29 elad 495: kauth_cred_t a_cred;
1.30 christos 496: } */ *ap __unused = v;
1.25 christos 497: #ifdef NTFS_DEBUG
1.1 jdolecek 498: struct vnode *vp = ap->a_vp;
499: struct ntnode *ip = VTONT(vp);
500:
1.25 christos 501: printf("ntfs_close: %llu\n", (unsigned long long)ip->i_number);
1.1 jdolecek 502: #endif
503:
504: return (0);
505: }
506:
507: int
1.30 christos 508: ntfs_readdir(void *v)
509: {
1.1 jdolecek 510: struct vop_readdir_args /* {
511: struct vnode *a_vp;
512: struct uio *a_uio;
1.29 elad 513: kauth_cred_t a_cred;
1.1 jdolecek 514: int *a_ncookies;
515: u_int **cookies;
1.30 christos 516: } */ *ap = v;
1.1 jdolecek 517: struct vnode *vp = ap->a_vp;
518: struct fnode *fp = VTOF(vp);
519: struct ntnode *ip = FTONT(fp);
520: struct uio *uio = ap->a_uio;
521: struct ntfsmount *ntmp = ip->i_mp;
522: int i, error = 0;
523: u_int32_t faked = 0, num;
524: int ncookies = 0;
525: struct dirent *cde;
526: off_t off;
527:
1.25 christos 528: dprintf(("ntfs_readdir %llu off: %qd resid: %qd\n",
529: (unsigned long long)ip->i_number, (long long)uio->uio_offset,
530: (long long)uio->uio_resid));
1.1 jdolecek 531:
532: off = uio->uio_offset;
533:
1.42 cegger 534: cde = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
1.1 jdolecek 535:
536: /* Simulate . in every dir except ROOT */
537: if (ip->i_number != NTFS_ROOTINO
538: && uio->uio_offset < sizeof(struct dirent)) {
539: cde->d_fileno = ip->i_number;
540: cde->d_reclen = sizeof(struct dirent);
541: cde->d_type = DT_DIR;
542: cde->d_namlen = 1;
543: strncpy(cde->d_name, ".", 2);
544: error = uiomove((void *)cde, sizeof(struct dirent), uio);
545: if (error)
546: goto out;
547:
548: ncookies++;
549: }
550:
551: /* Simulate .. in every dir including ROOT */
552: if (uio->uio_offset < 2 * sizeof(struct dirent)) {
553: cde->d_fileno = NTFS_ROOTINO; /* XXX */
554: cde->d_reclen = sizeof(struct dirent);
555: cde->d_type = DT_DIR;
556: cde->d_namlen = 2;
557: strncpy(cde->d_name, "..", 3);
558:
559: error = uiomove((void *) cde, sizeof(struct dirent), uio);
560: if (error)
561: goto out;
562:
563: ncookies++;
564: }
565:
566: faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2;
567: num = uio->uio_offset / sizeof(struct dirent) - faked;
568:
569: while (uio->uio_resid >= sizeof(struct dirent)) {
570: struct attr_indexentry *iep;
571: char *fname;
572: size_t remains;
573: int sz;
574:
575: error = ntfs_ntreaddir(ntmp, fp, num, &iep);
576: if (error)
577: goto out;
578:
579: if (NULL == iep)
580: break;
581:
582: for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent));
583: iep = NTFS_NEXTREC(iep, struct attr_indexentry *))
584: {
585: if(!ntfs_isnamepermitted(ntmp,iep))
586: continue;
587:
588: remains = sizeof(cde->d_name) - 1;
589: fname = cde->d_name;
590: for(i=0; i<iep->ie_fnamelen; i++) {
591: sz = (*ntmp->ntm_wput)(fname, remains,
592: iep->ie_fname[i]);
593: fname += sz;
594: remains -= sz;
595: }
596: *fname = '\0';
597: dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ",
598: num, cde->d_name, iep->ie_fnametype,
599: iep->ie_flag));
600: cde->d_namlen = fname - (char *) cde->d_name;
601: cde->d_fileno = iep->ie_number;
602: cde->d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
603: cde->d_reclen = sizeof(struct dirent);
604: dprintf(("%s\n", (cde->d_type == DT_DIR) ? "dir":"reg"));
605:
606: error = uiomove((void *)cde, sizeof(struct dirent), uio);
607: if (error)
608: goto out;
609:
610: ncookies++;
611: num++;
612: }
613: }
614:
615: dprintf(("ntfs_readdir: %d entries (%d bytes) read\n",
616: ncookies,(u_int)(uio->uio_offset - off)));
1.22 christos 617: dprintf(("ntfs_readdir: off: %qd resid: %qu\n",
618: (long long)uio->uio_offset,(long long)uio->uio_resid));
1.1 jdolecek 619:
620: if (!error && ap->a_ncookies != NULL) {
621: struct dirent* dpStart;
622: struct dirent* dp;
623: off_t *cookies;
624: off_t *cookiep;
625:
1.15 jdolecek 626: dprintf(("ntfs_readdir: %d cookies\n",ncookies));
1.1 jdolecek 627: dpStart = (struct dirent *)
1.33 christos 628: ((char *)uio->uio_iov->iov_base -
1.1 jdolecek 629: (uio->uio_offset - off));
630: cookies = malloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
631: for (dp = dpStart, cookiep = cookies, i=0;
632: i < ncookies;
1.33 christos 633: dp = (struct dirent *)((char *) dp + dp->d_reclen), i++) {
1.1 jdolecek 634: off += dp->d_reclen;
635: *cookiep++ = (u_int) off;
636: }
637: *ap->a_ncookies = ncookies;
638: *ap->a_cookies = cookies;
639: }
640: /*
641: if (ap->a_eofflag)
642: *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset;
643: */
644: out:
1.42 cegger 645: free(cde, M_TEMP);
1.1 jdolecek 646: return (error);
647: }
648:
649: int
1.30 christos 650: ntfs_lookup(void *v)
651: {
1.49.4.5! yamt 652: struct vop_lookup_v2_args /* {
1.1 jdolecek 653: struct vnode *a_dvp;
654: struct vnode **a_vpp;
655: struct componentname *a_cnp;
1.30 christos 656: } */ *ap = v;
1.1 jdolecek 657: struct vnode *dvp = ap->a_dvp;
658: struct ntnode *dip = VTONT(dvp);
659: struct ntfsmount *ntmp = dip->i_mp;
660: struct componentname *cnp = ap->a_cnp;
1.29 elad 661: kauth_cred_t cred = cnp->cn_cred;
1.1 jdolecek 662: int error;
1.31 chs 663:
1.41 ad 664: dprintf(("ntfs_lookup: \"%.*s\" (%lld bytes) in %llu\n",
665: (int)cnp->cn_namelen, cnp->cn_nameptr, (long long)cnp->cn_namelen,
1.31 chs 666: (unsigned long long)dip->i_number));
1.1 jdolecek 667:
1.36 pooka 668: error = VOP_ACCESS(dvp, VEXEC, cred);
1.1 jdolecek 669: if(error)
670: return (error);
671:
672: if ((cnp->cn_flags & ISLASTCN) &&
673: (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
674: (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
675: return (EROFS);
676:
677: /*
678: * We now have a segment name to search for, and a directory
679: * to search.
680: *
681: * Before tediously performing a linear scan of the directory,
682: * check the name cache to see if the directory/name pair
683: * we are looking for is known already.
684: */
1.49.4.4 yamt 685: if (cache_lookup(ap->a_dvp, cnp->cn_nameptr, cnp->cn_namelen,
686: cnp->cn_nameiop, cnp->cn_flags, NULL, ap->a_vpp)) {
687: return *ap->a_vpp == NULLVP ? ENOENT : 0;
688: }
1.1 jdolecek 689:
690: if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
1.25 christos 691: dprintf(("ntfs_lookup: faking . directory in %llu\n",
692: (unsigned long long)dip->i_number));
1.1 jdolecek 693:
1.46 pooka 694: vref(dvp);
1.1 jdolecek 695: *ap->a_vpp = dvp;
696: error = 0;
697: } else if (cnp->cn_flags & ISDOTDOT) {
698: struct ntvattr *vap;
699:
1.25 christos 700: dprintf(("ntfs_lookup: faking .. directory in %llu\n",
701: (unsigned long long)dip->i_number));
1.1 jdolecek 702:
1.47 hannken 703: VOP_UNLOCK(dvp);
1.1 jdolecek 704: error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap);
1.31 chs 705: if (error) {
706: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.1 jdolecek 707: return (error);
1.31 chs 708: }
1.1 jdolecek 709:
710: dprintf(("ntfs_lookup: parentdir: %d\n",
711: vap->va_a_name->n_pnumber));
712: error = VFS_VGET(ntmp->ntm_mountp,
1.21 perry 713: vap->va_a_name->n_pnumber,ap->a_vpp);
1.1 jdolecek 714: ntfs_ntvattrrele(vap);
1.31 chs 715: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.1 jdolecek 716: if (error) {
717: return (error);
718: }
719: } else {
720: error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp);
721: if (error) {
722: dprintf(("ntfs_ntlookupfile: returned %d\n", error));
723: return (error);
724: }
725:
1.25 christos 726: dprintf(("ntfs_lookup: found ino: %llu\n",
727: (unsigned long long)VTONT(*ap->a_vpp)->i_number));
1.1 jdolecek 728: }
729:
1.49.4.4 yamt 730: cache_enter(dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen,
731: cnp->cn_flags);
1.1 jdolecek 732:
1.49.4.5! yamt 733: if (*ap->a_vpp != dvp)
! 734: VOP_UNLOCK(*ap->a_vpp);
! 735:
1.49.4.3 yamt 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.49.4.2 yamt 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 */
821: { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */
822: { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */
823: { &vop_poll_desc, genfs_poll }, /* poll */
824: { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */
825: { &vop_revoke_desc, genfs_revoke }, /* revoke */
826: { &vop_mmap_desc, genfs_mmap }, /* mmap */
1.26 yamt 827: { &vop_fsync_desc, (vop_t *) ntfs_fsync }, /* fsync */
1.1 jdolecek 828: { &vop_seek_desc, genfs_seek }, /* seek */
1.6 jdolecek 829: { &vop_remove_desc, genfs_eopnotsupp }, /* remove */
830: { &vop_link_desc, genfs_eopnotsupp }, /* link */
831: { &vop_rename_desc, genfs_eopnotsupp }, /* rename */
832: { &vop_mkdir_desc, genfs_eopnotsupp }, /* mkdir */
833: { &vop_rmdir_desc, genfs_eopnotsupp }, /* rmdir */
1.1 jdolecek 834: { &vop_symlink_desc, genfs_eopnotsupp }, /* symlink */
835: { &vop_readdir_desc, (vop_t *) ntfs_readdir }, /* readdir */
836: { &vop_readlink_desc, genfs_eopnotsupp }, /* readlink */
837: { &vop_abortop_desc, genfs_abortop }, /* abortop */
838: { &vop_inactive_desc, (vop_t *) ntfs_inactive }, /* inactive */
839: { &vop_reclaim_desc, (vop_t *) ntfs_reclaim }, /* reclaim */
840: { &vop_lock_desc, genfs_lock }, /* lock */
841: { &vop_unlock_desc, genfs_unlock }, /* unlock */
842: { &vop_bmap_desc, (vop_t *) ntfs_bmap }, /* bmap */
843: { &vop_strategy_desc, (vop_t *) ntfs_strategy }, /* strategy */
844: { &vop_print_desc, (vop_t *) ntfs_print }, /* print */
845: { &vop_islocked_desc, genfs_islocked }, /* islocked */
846: { &vop_pathconf_desc, ntfs_pathconf }, /* pathconf */
847: { &vop_advlock_desc, genfs_nullop }, /* advlock */
848: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
849: { &vop_getpages_desc, genfs_compat_getpages }, /* getpages */
850: { &vop_putpages_desc, genfs_putpages }, /* putpages */
851: { NULL, NULL }
852: };
853: const struct vnodeopv_desc ntfs_vnodeop_opv_desc =
854: { &ntfs_vnodeop_p, ntfs_vnodeop_entries };
CVSweb <webmaster@jp.NetBSD.org>