Introduce cratom(), remove crcopy().
[dragonfly.git] / sys / vfs / ntfs / ntfs_vnops.c
1 /*      $NetBSD: ntfs_vnops.c,v 1.23 1999/10/31 19:45:27 jdolecek Exp $ */
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.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * $FreeBSD: src/sys/ntfs/ntfs_vnops.c,v 1.9.2.4 2002/08/06 19:35:18 semenu Exp $
39  * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.3 2003/06/25 03:56:07 dillon Exp $
40  *
41  */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/time.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/vnode.h>
50 #include <sys/mount.h>
51 #include <sys/proc.h>
52 #include <sys/namei.h>
53 #include <sys/malloc.h>
54 #include <sys/buf.h>
55 #include <sys/dirent.h>
56
57 #include <vm/vm.h>
58 #include <vm/vm_param.h>
59 #if defined(__NetBSD__)
60 #include <vm/vm_prot.h>
61 #endif
62 #include <vm/vm_page.h>
63 #include <vm/vm_object.h>
64 #include <vm/vm_pager.h>
65 #if defined(__FreeBSD__)
66 #include <vm/vnode_pager.h>
67 #endif
68 #include <vm/vm_extern.h>
69
70 #include <sys/sysctl.h>
71
72 /*#define NTFS_DEBUG 1*/
73 #include <ntfs/ntfs.h>
74 #include <ntfs/ntfs_inode.h>
75 #include <ntfs/ntfs_subr.h>
76 #if defined(__NetBSD__)
77 #include <miscfs/specfs/specdev.h>
78 #include <miscfs/genfs/genfs.h>
79 #endif
80
81 #include <sys/unistd.h> /* for pathconf(2) constants */
82
83 static int      ntfs_read __P((struct vop_read_args *));
84 static int      ntfs_write __P((struct vop_write_args *ap));
85 static int      ntfs_getattr __P((struct vop_getattr_args *ap));
86 static int      ntfs_inactive __P((struct vop_inactive_args *ap));
87 static int      ntfs_print __P((struct vop_print_args *ap));
88 static int      ntfs_reclaim __P((struct vop_reclaim_args *ap));
89 static int      ntfs_strategy __P((struct vop_strategy_args *ap));
90 static int      ntfs_access __P((struct vop_access_args *ap));
91 static int      ntfs_open __P((struct vop_open_args *ap));
92 static int      ntfs_close __P((struct vop_close_args *ap));
93 static int      ntfs_readdir __P((struct vop_readdir_args *ap));
94 static int      ntfs_lookup __P((struct vop_lookup_args *ap));
95 static int      ntfs_bmap __P((struct vop_bmap_args *ap));
96 #if defined(__FreeBSD__)
97 static int      ntfs_getpages __P((struct vop_getpages_args *ap));
98 static int      ntfs_putpages __P((struct vop_putpages_args *));
99 static int      ntfs_fsync __P((struct vop_fsync_args *ap));
100 #else
101 static int      ntfs_bypass __P((struct vop_generic_args *ap));
102 #endif
103 static int      ntfs_pathconf __P((void *));
104
105 int     ntfs_prtactive = 1;     /* 1 => print out reclaim of active vnodes */
106
107 #if defined(__FreeBSD__)
108 int
109 ntfs_getpages(ap)
110         struct vop_getpages_args *ap;
111 {
112         return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
113                 ap->a_reqpage);
114 }
115
116 int
117 ntfs_putpages(ap)
118         struct vop_putpages_args *ap;
119 {
120         return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
121                 ap->a_sync, ap->a_rtvals);
122 }
123 #endif
124
125 /*
126  * This is a noop, simply returning what one has been given.
127  */
128 int
129 ntfs_bmap(ap)
130         struct vop_bmap_args /* {
131                 struct vnode *a_vp;
132                 daddr_t  a_bn;
133                 struct vnode **a_vpp;
134                 daddr_t *a_bnp;
135                 int *a_runp;
136                 int *a_runb;
137         } */ *ap;
138 {
139         dprintf(("ntfs_bmap: vn: %p, blk: %d\n", ap->a_vp,(u_int32_t)ap->a_bn));
140         if (ap->a_vpp != NULL)
141                 *ap->a_vpp = ap->a_vp;
142         if (ap->a_bnp != NULL)
143                 *ap->a_bnp = ap->a_bn;
144         if (ap->a_runp != NULL)
145                 *ap->a_runp = 0;
146 #if !defined(__NetBSD__)
147         if (ap->a_runb != NULL)
148                 *ap->a_runb = 0;
149 #endif
150         return (0);
151 }
152
153 static int
154 ntfs_read(ap)
155         struct vop_read_args /* {
156                 struct vnode *a_vp;
157                 struct uio *a_uio;
158                 int a_ioflag;
159                 struct ucred *a_cred;
160         } */ *ap;
161 {
162         register struct vnode *vp = ap->a_vp;
163         register struct fnode *fp = VTOF(vp);
164         register struct ntnode *ip = FTONT(fp);
165         struct uio *uio = ap->a_uio;
166         struct ntfsmount *ntmp = ip->i_mp;
167         struct buf *bp;
168         daddr_t cn;
169         int resid, off, toread;
170         int error;
171
172         dprintf(("ntfs_read: ino: %d, off: %d resid: %d, segflg: %d\n",ip->i_number,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg));
173
174         dprintf(("ntfs_read: filesize: %d",(u_int32_t)fp->f_size));
175
176         /* don't allow reading after end of file */
177         if (uio->uio_offset > fp->f_size)
178                 return (0);
179
180         resid = min(uio->uio_resid, fp->f_size - uio->uio_offset);
181
182         dprintf((", resid: %d\n", resid));
183
184         error = 0;
185         while (resid) {
186                 cn = ntfs_btocn(uio->uio_offset);
187                 off = ntfs_btocnoff(uio->uio_offset);
188
189                 toread = min(off + resid, ntfs_cntob(1));
190
191                 error = bread(vp, cn, ntfs_cntob(1), NOCRED, &bp);
192                 if (error) {
193                         brelse(bp);
194                         break;
195                 }
196
197                 error = uiomove(bp->b_data + off, toread - off, uio);
198                 if(error) {
199                         brelse(bp);
200                         break;
201                 }
202                 brelse(bp);
203
204                 resid -= toread - off;
205         }
206
207         return (error);
208 }
209
210 #if !defined(__FreeBSD__)
211
212 static int
213 ntfs_bypass(ap)
214         struct vop_generic_args /* {
215                 struct vnodeop_desc *a_desc;
216                 <other random data follows, presumably>
217         } */ *ap;
218 {
219         int error = ENOTTY;
220         dprintf(("ntfs_bypass: %s\n", ap->a_desc->vdesc_name));
221         return (error);
222 }
223
224 #endif
225
226 static int
227 ntfs_getattr(ap)
228         struct vop_getattr_args /* {
229                 struct vnode *a_vp;
230                 struct vattr *a_vap;
231                 struct ucred *a_cred;
232                 struct thread *a_td;
233         } */ *ap;
234 {
235         register struct vnode *vp = ap->a_vp;
236         register struct fnode *fp = VTOF(vp);
237         register struct ntnode *ip = FTONT(fp);
238         register struct vattr *vap = ap->a_vap;
239
240         dprintf(("ntfs_getattr: %d, flags: %d\n",ip->i_number,ip->i_flag));
241
242 #if defined(__FreeBSD__)
243         vap->va_fsid = dev2udev(ip->i_dev);
244 #else /* NetBSD */
245         vap->va_fsid = ip->i_dev;
246 #endif
247         vap->va_fileid = ip->i_number;
248         vap->va_mode = ip->i_mp->ntm_mode;
249         vap->va_nlink = ip->i_nlink;
250         vap->va_uid = ip->i_mp->ntm_uid;
251         vap->va_gid = ip->i_mp->ntm_gid;
252         vap->va_rdev = 0;                               /* XXX UNODEV ? */
253         vap->va_size = fp->f_size;
254         vap->va_bytes = fp->f_allocated;
255         vap->va_atime = ntfs_nttimetounix(fp->f_times.t_access);
256         vap->va_mtime = ntfs_nttimetounix(fp->f_times.t_write);
257         vap->va_ctime = ntfs_nttimetounix(fp->f_times.t_create);
258         vap->va_flags = ip->i_flag;
259         vap->va_gen = 0;
260         vap->va_blocksize = ip->i_mp->ntm_spc * ip->i_mp->ntm_bps;
261         vap->va_type = vp->v_type;
262         vap->va_filerev = 0;
263         return (0);
264 }
265
266
267 /*
268  * Last reference to an ntnode.  If necessary, write or delete it.
269  */
270 int
271 ntfs_inactive(ap)
272         struct vop_inactive_args /* {
273                 struct vnode *a_vp;
274         } */ *ap;
275 {
276         register struct vnode *vp = ap->a_vp;
277 #ifdef NTFS_DEBUG
278         register struct ntnode *ip = VTONT(vp);
279 #endif
280
281         dprintf(("ntfs_inactive: vnode: %p, ntnode: %d\n", vp, ip->i_number));
282
283         if (ntfs_prtactive && vp->v_usecount != 0)
284                 vprint("ntfs_inactive: pushing active", vp);
285
286         VOP__UNLOCK(vp, 0, ap->a_td);
287
288         /* XXX since we don't support any filesystem changes
289          * right now, nothing more needs to be done
290          */
291         return (0);
292 }
293
294 /*
295  * Reclaim an fnode/ntnode so that it can be used for other purposes.
296  */
297 int
298 ntfs_reclaim(ap)
299         struct vop_reclaim_args /* {
300                 struct vnode *a_vp;
301         } */ *ap;
302 {
303         register struct vnode *vp = ap->a_vp;
304         register struct fnode *fp = VTOF(vp);
305         register struct ntnode *ip = FTONT(fp);
306         int error;
307
308         dprintf(("ntfs_reclaim: vnode: %p, ntnode: %d\n", vp, ip->i_number));
309
310         if (ntfs_prtactive && vp->v_usecount != 0)
311                 vprint("ntfs_reclaim: pushing active", vp);
312
313         if ((error = ntfs_ntget(ip)) != 0)
314                 return (error);
315         
316         /* Purge old data structures associated with the inode. */
317         cache_purge(vp);
318
319         ntfs_frele(fp);
320         ntfs_ntput(ip);
321         vp->v_data = NULL;
322
323         return (0);
324 }
325
326 static int
327 ntfs_print(ap)
328         struct vop_print_args /* {
329                 struct vnode *a_vp;
330         } */ *ap;
331 {
332         return (0);
333 }
334
335 /*
336  * Calculate the logical to physical mapping if not done already,
337  * then call the device strategy routine.
338  */
339 int
340 ntfs_strategy(ap)
341         struct vop_strategy_args /* {
342                 struct buf *a_bp;
343         } */ *ap;
344 {
345         register struct buf *bp = ap->a_bp;
346         register struct vnode *vp = bp->b_vp;
347         register struct fnode *fp = VTOF(vp);
348         register struct ntnode *ip = FTONT(fp);
349         struct ntfsmount *ntmp = ip->i_mp;
350         int error;
351
352 #ifdef __FreeBSD__
353         dprintf(("ntfs_strategy: offset: %d, blkno: %d, lblkno: %d\n",
354                 (u_int32_t)bp->b_offset,(u_int32_t)bp->b_blkno,
355                 (u_int32_t)bp->b_lblkno));
356 #else
357         dprintf(("ntfs_strategy: blkno: %d, lblkno: %d\n",
358                 (u_int32_t)bp->b_blkno,
359                 (u_int32_t)bp->b_lblkno));
360 #endif
361
362         dprintf(("strategy: bcount: %d flags: 0x%lx\n", 
363                 (u_int32_t)bp->b_bcount,bp->b_flags));
364
365         if (bp->b_flags & B_READ) {
366                 u_int32_t toread;
367
368                 if (ntfs_cntob(bp->b_blkno) >= fp->f_size) {
369                         clrbuf(bp);
370                         error = 0;
371                 } else {
372                         toread = min(bp->b_bcount,
373                                  fp->f_size-ntfs_cntob(bp->b_blkno));
374                         dprintf(("ntfs_strategy: toread: %d, fsize: %d\n",
375                                 toread,(u_int32_t)fp->f_size));
376
377                         error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
378                                 fp->f_attrname, ntfs_cntob(bp->b_blkno),
379                                 toread, bp->b_data, NULL);
380
381                         if (error) {
382                                 printf("ntfs_strategy: ntfs_readattr failed\n");
383                                 bp->b_error = error;
384                                 bp->b_flags |= B_ERROR;
385                         }
386
387                         bzero(bp->b_data + toread, bp->b_bcount - toread);
388                 }
389         } else {
390                 size_t tmp;
391                 u_int32_t towrite;
392
393                 if (ntfs_cntob(bp->b_blkno) + bp->b_bcount >= fp->f_size) {
394                         printf("ntfs_strategy: CAN'T EXTEND FILE\n");
395                         bp->b_error = error = EFBIG;
396                         bp->b_flags |= B_ERROR;
397                 } else {
398                         towrite = min(bp->b_bcount,
399                                 fp->f_size-ntfs_cntob(bp->b_blkno));
400                         dprintf(("ntfs_strategy: towrite: %d, fsize: %d\n",
401                                 towrite,(u_int32_t)fp->f_size));
402
403                         error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,  
404                                 fp->f_attrname, ntfs_cntob(bp->b_blkno),towrite,
405                                 bp->b_data, &tmp, NULL);
406
407                         if (error) {
408                                 printf("ntfs_strategy: ntfs_writeattr fail\n");
409                                 bp->b_error = error;
410                                 bp->b_flags |= B_ERROR;
411                         }
412                 }
413         }
414         biodone(bp);
415         return (error);
416 }
417
418 static int
419 ntfs_write(ap)
420         struct vop_write_args /* {
421                 struct vnode *a_vp;
422                 struct uio *a_uio;
423                 int  a_ioflag;
424                 struct ucred *a_cred;
425         } */ *ap;
426 {
427         register struct vnode *vp = ap->a_vp;
428         register struct fnode *fp = VTOF(vp);
429         register struct ntnode *ip = FTONT(fp);
430         struct uio *uio = ap->a_uio;
431         struct ntfsmount *ntmp = ip->i_mp;
432         u_int64_t towrite;
433         size_t written;
434         int error;
435
436         dprintf(("ntfs_write: ino: %d, off: %d resid: %d, segflg: %d\n",ip->i_number,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg));
437         dprintf(("ntfs_write: filesize: %d",(u_int32_t)fp->f_size));
438
439         if (uio->uio_resid + uio->uio_offset > fp->f_size) {
440                 printf("ntfs_write: CAN'T WRITE BEYOND END OF FILE\n");
441                 return (EFBIG);
442         }
443
444         towrite = min(uio->uio_resid, fp->f_size - uio->uio_offset);
445
446         dprintf((", towrite: %d\n",(u_int32_t)towrite));
447
448         error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
449                 fp->f_attrname, uio->uio_offset, towrite, NULL, &written, uio);
450 #ifdef NTFS_DEBUG
451         if (error)
452                 printf("ntfs_write: ntfs_writeattr failed: %d\n", error);
453 #endif
454
455         return (error);
456 }
457
458 int
459 ntfs_access(ap)
460         struct vop_access_args /* {
461                 struct vnode *a_vp;
462                 int  a_mode;
463                 struct ucred *a_cred;
464                 struct thread *a_td;
465         } */ *ap;
466 {
467         struct vnode *vp = ap->a_vp;
468         struct ntnode *ip = VTONT(vp);
469         struct ucred *cred = ap->a_cred;
470         mode_t mask, mode = ap->a_mode;
471         register gid_t *gp;
472         int i;
473 #ifdef QUOTA
474         int error;
475 #endif
476
477         dprintf(("ntfs_access: %d\n",ip->i_number));
478
479         /*
480          * Disallow write attempts on read-only file systems;
481          * unless the file is a socket, fifo, or a block or
482          * character device resident on the file system.
483          */
484         if (mode & VWRITE) {
485                 switch ((int)vp->v_type) {
486                 case VDIR:
487                 case VLNK:
488                 case VREG:
489                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
490                                 return (EROFS);
491 #ifdef QUOTA
492                         if (error = getinoquota(ip))
493                                 return (error);
494 #endif
495                         break;
496                 }
497         }
498
499         /* Otherwise, user id 0 always gets access. */
500         if (cred->cr_uid == 0)
501                 return (0);
502
503         mask = 0;
504
505         /* Otherwise, check the owner. */
506         if (cred->cr_uid == ip->i_mp->ntm_uid) {
507                 if (mode & VEXEC)
508                         mask |= S_IXUSR;
509                 if (mode & VREAD)
510                         mask |= S_IRUSR;
511                 if (mode & VWRITE)
512                         mask |= S_IWUSR;
513                 return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES);
514         }
515
516         /* Otherwise, check the groups. */
517         for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
518                 if (ip->i_mp->ntm_gid == *gp) {
519                         if (mode & VEXEC)
520                                 mask |= S_IXGRP;
521                         if (mode & VREAD)
522                                 mask |= S_IRGRP;
523                         if (mode & VWRITE)
524                                 mask |= S_IWGRP;
525                         return ((ip->i_mp->ntm_mode&mask) == mask ? 0 : EACCES);
526                 }
527
528         /* Otherwise, check everyone else. */
529         if (mode & VEXEC)
530                 mask |= S_IXOTH;
531         if (mode & VREAD)
532                 mask |= S_IROTH;
533         if (mode & VWRITE)
534                 mask |= S_IWOTH;
535         return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES);
536 }
537
538 /*
539  * Open called.
540  *
541  * Nothing to do.
542  */
543 /* ARGSUSED */
544 static int
545 ntfs_open(ap)
546         struct vop_open_args /* {
547                 struct vnode *a_vp;
548                 int  a_mode;
549                 struct ucred *a_cred;
550                 struct thread *a_td;
551         } */ *ap;
552 {
553 #if NTFS_DEBUG
554         register struct vnode *vp = ap->a_vp;
555         register struct ntnode *ip = VTONT(vp);
556
557         printf("ntfs_open: %d\n",ip->i_number);
558 #endif
559
560         /*
561          * Files marked append-only must be opened for appending.
562          */
563
564         return (0);
565 }
566
567 /*
568  * Close called.
569  *
570  * Update the times on the inode.
571  */
572 /* ARGSUSED */
573 static int
574 ntfs_close(ap)
575         struct vop_close_args /* {
576                 struct vnode *a_vp;
577                 int  a_fflag;
578                 struct ucred *a_cred;
579                 struct thread *a_td;
580         } */ *ap;
581 {
582 #if NTFS_DEBUG
583         register struct vnode *vp = ap->a_vp;
584         register struct ntnode *ip = VTONT(vp);
585
586         printf("ntfs_close: %d\n",ip->i_number);
587 #endif
588
589         return (0);
590 }
591
592 int
593 ntfs_readdir(ap)
594         struct vop_readdir_args /* {
595                 struct vnode *a_vp;
596                 struct uio *a_uio;
597                 struct ucred *a_cred;
598                 int *a_ncookies;
599                 u_int **cookies;
600         } */ *ap;
601 {
602         register struct vnode *vp = ap->a_vp;
603         register struct fnode *fp = VTOF(vp);
604         register struct ntnode *ip = FTONT(fp);
605         struct uio *uio = ap->a_uio;
606         struct ntfsmount *ntmp = ip->i_mp;
607         int i, error = 0;
608         u_int32_t faked = 0, num;
609         int ncookies = 0;
610         struct dirent cde;
611         off_t off;
612
613         dprintf(("ntfs_readdir %d off: %d resid: %d\n",ip->i_number,(u_int32_t)uio->uio_offset,uio->uio_resid));
614
615         off = uio->uio_offset;
616
617         /* Simulate . in every dir except ROOT */
618         if( ip->i_number != NTFS_ROOTINO ) {
619                 struct dirent dot = { NTFS_ROOTINO,
620                                 sizeof(struct dirent), DT_DIR, 1, "." };
621
622                 if( uio->uio_offset < sizeof(struct dirent) ) {
623                         dot.d_fileno = ip->i_number;
624                         error = uiomove((char *)&dot,sizeof(struct dirent),uio);
625                         if(error)
626                                 return (error);
627
628                         ncookies ++;
629                 }
630         }
631
632         /* Simulate .. in every dir including ROOT */
633         if( uio->uio_offset < 2 * sizeof(struct dirent) ) {
634                 struct dirent dotdot = { NTFS_ROOTINO,
635                                 sizeof(struct dirent), DT_DIR, 2, ".." };
636
637                 error = uiomove((char *)&dotdot,sizeof(struct dirent),uio);
638                 if(error)
639                         return (error);
640
641                 ncookies ++;
642         }
643
644         faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2;
645         num = uio->uio_offset / sizeof(struct dirent) - faked;
646
647         while( uio->uio_resid >= sizeof(struct dirent) ) {
648                 struct attr_indexentry *iep;
649
650                 error = ntfs_ntreaddir(ntmp, fp, num, &iep);
651
652                 if(error)
653                         return (error);
654
655                 if( NULL == iep )
656                         break;
657
658                 for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent));
659                         iep = NTFS_NEXTREC(iep, struct attr_indexentry *))
660                 {
661                         if(!ntfs_isnamepermitted(ntmp,iep))
662                                 continue;
663
664                         for(i=0; i<iep->ie_fnamelen; i++) {
665                                 cde.d_name[i] = NTFS_U28(iep->ie_fname[i]);
666                         }
667                         cde.d_name[i] = '\0';
668                         dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ",
669                                 num, cde.d_name, iep->ie_fnametype,
670                                 iep->ie_flag));
671                         cde.d_namlen = iep->ie_fnamelen;
672                         cde.d_fileno = iep->ie_number;
673                         cde.d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
674                         cde.d_reclen = sizeof(struct dirent);
675                         dprintf(("%s\n", (cde.d_type == DT_DIR) ? "dir":"reg"));
676
677                         error = uiomove((char *)&cde, sizeof(struct dirent), uio);
678                         if(error)
679                                 return (error);
680
681                         ncookies++;
682                         num++;
683                 }
684         }
685
686         dprintf(("ntfs_readdir: %d entries (%d bytes) read\n",
687                 ncookies,(u_int)(uio->uio_offset - off)));
688         dprintf(("ntfs_readdir: off: %d resid: %d\n",
689                 (u_int32_t)uio->uio_offset,uio->uio_resid));
690
691         if (!error && ap->a_ncookies != NULL) {
692                 struct dirent* dpStart;
693                 struct dirent* dp;
694 #if defined(__FreeBSD__)
695                 u_long *cookies;
696                 u_long *cookiep;
697 #else /* defined(__NetBSD__) */
698                 off_t *cookies;
699                 off_t *cookiep;
700 #endif
701
702                 ddprintf(("ntfs_readdir: %d cookies\n",ncookies));
703                 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
704                         panic("ntfs_readdir: unexpected uio from NFS server");
705                 dpStart = (struct dirent *)
706                      ((caddr_t)uio->uio_iov->iov_base -
707                          (uio->uio_offset - off));
708 #if defined(__FreeBSD__)
709                 MALLOC(cookies, u_long *, ncookies * sizeof(u_long),
710                        M_TEMP, M_WAITOK);
711 #else /* defined(__NetBSD__) */
712                 MALLOC(cookies, off_t *, ncookies * sizeof(off_t),
713                        M_TEMP, M_WAITOK);
714 #endif
715                 for (dp = dpStart, cookiep = cookies, i=0;
716                      i < ncookies;
717                      dp = (struct dirent *)((caddr_t) dp + dp->d_reclen), i++) {
718                         off += dp->d_reclen;
719                         *cookiep++ = (u_int) off;
720                 }
721                 *ap->a_ncookies = ncookies;
722                 *ap->a_cookies = cookies;
723         }
724 /*
725         if (ap->a_eofflag)
726             *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset;
727 */
728         return (error);
729 }
730
731 int
732 ntfs_lookup(ap)
733         struct vop_lookup_args /* {
734                 struct vnode *a_dvp;
735                 struct vnode **a_vpp;
736                 struct componentname *a_cnp;
737         } */ *ap;
738 {
739         register struct vnode *dvp = ap->a_dvp;
740         register struct ntnode *dip = VTONT(dvp);
741         struct ntfsmount *ntmp = dip->i_mp;
742         struct componentname *cnp = ap->a_cnp;
743         struct ucred *cred = cnp->cn_cred;
744         int error;
745         int lockparent = cnp->cn_flags & LOCKPARENT;
746 #if NTFS_DEBUG
747         int wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
748 #endif
749         dprintf(("ntfs_lookup: \"%.*s\" (%ld bytes) in %d, lp: %d, wp: %d \n",
750                 (int)cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_namelen,
751                 dip->i_number, lockparent, wantparent));
752
753         error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_td);
754         if(error)
755                 return (error);
756
757         if ((cnp->cn_flags & ISLASTCN) &&
758             (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
759             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
760                 return (EROFS);
761
762 #ifdef __NetBSD__
763         /*
764          * We now have a segment name to search for, and a directory
765          * to search.
766          *
767          * Before tediously performing a linear scan of the directory,
768          * check the name cache to see if the directory/name pair
769          * we are looking for is known already.
770          */
771         if ((error = cache_lookup(ap->a_dvp, ap->a_vpp, cnp)) >= 0)
772                 return (error);
773 #endif
774
775         if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
776                 dprintf(("ntfs_lookup: faking . directory in %d\n",
777                         dip->i_number));
778
779                 VREF(dvp);
780                 *ap->a_vpp = dvp;
781                 error = 0;
782         } else if (cnp->cn_flags & ISDOTDOT) {
783                 struct ntvattr *vap;
784
785                 dprintf(("ntfs_lookup: faking .. directory in %d\n",
786                          dip->i_number));
787
788                 error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap);
789                 if(error)
790                         return (error);
791
792                 VOP__UNLOCK(dvp,0,cnp->cn_td);
793                 cnp->cn_flags |= PDIRUNLOCK;
794
795                 dprintf(("ntfs_lookup: parentdir: %d\n",
796                          vap->va_a_name->n_pnumber));
797                 error = VFS_VGET(ntmp->ntm_mountp,
798                                  vap->va_a_name->n_pnumber,ap->a_vpp); 
799                 ntfs_ntvattrrele(vap);
800                 if (error) {
801                         if (VN_LOCK(dvp,LK_EXCLUSIVE|LK_RETRY,cnp->cn_td)==0)
802                                 cnp->cn_flags &= ~PDIRUNLOCK;
803                         return (error);
804                 }
805
806                 if (lockparent && (cnp->cn_flags & ISLASTCN)) {
807                         error = VN_LOCK(dvp, LK_EXCLUSIVE, cnp->cn_td);
808                         if (error) {
809                                 vput( *(ap->a_vpp) );
810                                 return (error);
811                         }
812                         cnp->cn_flags &= ~PDIRUNLOCK;
813                 }
814         } else {
815                 error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp);
816                 if (error) {
817                         dprintf(("ntfs_ntlookupfile: returned %d\n", error));
818                         return (error);
819                 }
820
821                 dprintf(("ntfs_lookup: found ino: %d\n", 
822                         VTONT(*ap->a_vpp)->i_number));
823
824                 if(!lockparent || !(cnp->cn_flags & ISLASTCN))
825                         VOP__UNLOCK(dvp, 0, cnp->cn_td);
826         }
827
828         if (cnp->cn_flags & MAKEENTRY)
829                 cache_enter(dvp, *ap->a_vpp, cnp);
830
831         return (error);
832 }
833
834 #if defined(__FreeBSD__)
835 /*
836  * Flush the blocks of a file to disk.
837  *
838  * This function is worthless for vnodes that represent directories. Maybe we
839  * could just do a sync if they try an fsync on a directory file.
840  */
841 static int
842 ntfs_fsync(ap)
843         struct vop_fsync_args /* {
844                 struct vnode *a_vp;
845                 struct ucred *a_cred;
846                 int a_waitfor;
847                 struct thread *a_td;
848         } */ *ap;
849 {
850         return (0);
851 }
852 #endif
853
854 /*
855  * Return POSIX pathconf information applicable to NTFS filesystem
856  */
857 int
858 ntfs_pathconf(v)
859         void *v;
860 {
861         struct vop_pathconf_args /* {
862                 struct vnode *a_vp;
863                 int a_name;
864                 register_t *a_retval;
865         } */ *ap = v;
866
867         switch (ap->a_name) {
868         case _PC_LINK_MAX:
869                 *ap->a_retval = 1;
870                 return (0);
871         case _PC_NAME_MAX:
872                 *ap->a_retval = NTFS_MAXFILENAME;
873                 return (0);
874         case _PC_PATH_MAX:
875                 *ap->a_retval = PATH_MAX;
876                 return (0);
877         case _PC_CHOWN_RESTRICTED:
878                 *ap->a_retval = 1;
879                 return (0);
880         case _PC_NO_TRUNC:
881                 *ap->a_retval = 0;
882                 return (0);
883 #if defined(__NetBSD__)
884         case _PC_SYNC_IO:
885                 *ap->a_retval = 1;
886                 return (0);
887         case _PC_FILESIZEBITS:
888                 *ap->a_retval = 64;
889                 return (0);
890 #endif
891         default:
892                 return (EINVAL);
893         }
894         /* NOTREACHED */
895 }
896
897 /*
898  * Global vfs data structures
899  */
900 vop_t **ntfs_vnodeop_p;
901 #if defined(__FreeBSD__)
902 static
903 struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = {
904         { &vop_default_desc, (vop_t *)vop_defaultop },
905
906         { &vop_getattr_desc, (vop_t *)ntfs_getattr },
907         { &vop_inactive_desc, (vop_t *)ntfs_inactive },
908         { &vop_reclaim_desc, (vop_t *)ntfs_reclaim },
909         { &vop_print_desc, (vop_t *)ntfs_print },
910         { &vop_pathconf_desc, ntfs_pathconf },
911
912         { &vop_islocked_desc, (vop_t *)vop_stdislocked },
913         { &vop_unlock_desc, (vop_t *)vop_stdunlock },
914         { &vop_lock_desc, (vop_t *)vop_stdlock },
915         { &vop_cachedlookup_desc, (vop_t *)ntfs_lookup },
916         { &vop_lookup_desc, (vop_t *)vfs_cache_lookup },
917
918         { &vop_access_desc, (vop_t *)ntfs_access },
919         { &vop_close_desc, (vop_t *)ntfs_close },
920         { &vop_open_desc, (vop_t *)ntfs_open },
921         { &vop_readdir_desc, (vop_t *)ntfs_readdir },
922         { &vop_fsync_desc, (vop_t *)ntfs_fsync },
923
924         { &vop_bmap_desc, (vop_t *)ntfs_bmap },
925         { &vop_getpages_desc, (vop_t *) ntfs_getpages },
926         { &vop_putpages_desc, (vop_t *) ntfs_putpages },
927         { &vop_strategy_desc, (vop_t *)ntfs_strategy },
928         { &vop_bwrite_desc, (vop_t *)vop_stdbwrite },
929         { &vop_read_desc, (vop_t *)ntfs_read },
930         { &vop_write_desc, (vop_t *)ntfs_write },
931
932         { NULL, NULL }
933 };
934
935 static
936 struct vnodeopv_desc ntfs_vnodeop_opv_desc =
937         { &ntfs_vnodeop_p, ntfs_vnodeop_entries };
938
939 VNODEOP_SET(ntfs_vnodeop_opv_desc);
940
941 #else /* !FreeBSD */
942
943 struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = {
944         { &vop_default_desc, (vop_t *) ntfs_bypass },
945         { &vop_lookup_desc, (vop_t *) ntfs_lookup },    /* lookup */
946         { &vop_create_desc, genfs_eopnotsupp },         /* create */
947         { &vop_mknod_desc, genfs_eopnotsupp },          /* mknod */
948         { &vop_open_desc, (vop_t *) ntfs_open },        /* open */
949         { &vop_close_desc,(vop_t *)  ntfs_close },      /* close */
950         { &vop_access_desc, (vop_t *) ntfs_access },    /* access */
951         { &vop_getattr_desc, (vop_t *) ntfs_getattr },  /* getattr */
952         { &vop_setattr_desc, genfs_eopnotsupp },        /* setattr */
953         { &vop_read_desc, (vop_t *) ntfs_read },        /* read */
954         { &vop_write_desc, (vop_t *) ntfs_write },      /* write */
955         { &vop_lease_desc, genfs_lease_check },         /* lease */
956         { &vop_fcntl_desc, genfs_fcntl },               /* fcntl */
957         { &vop_ioctl_desc, genfs_enoioctl },            /* ioctl */
958         { &vop_poll_desc, genfs_poll },                 /* poll */
959         { &vop_revoke_desc, genfs_revoke },             /* revoke */
960         { &vop_mmap_desc, genfs_eopnotsupp },           /* mmap */
961         { &vop_fsync_desc, genfs_fsync },               /* fsync */
962         { &vop_seek_desc, genfs_seek },                 /* seek */
963         { &vop_remove_desc, genfs_eopnotsupp },         /* remove */
964         { &vop_link_desc, genfs_eopnotsupp },           /* link */
965         { &vop_rename_desc, genfs_eopnotsupp },         /* rename */
966         { &vop_mkdir_desc, genfs_eopnotsupp },          /* mkdir */
967         { &vop_rmdir_desc, genfs_eopnotsupp },          /* rmdir */
968         { &vop_symlink_desc, genfs_eopnotsupp },        /* symlink */
969         { &vop_readdir_desc, (vop_t *) ntfs_readdir },  /* readdir */
970         { &vop_readlink_desc, genfs_eopnotsupp },       /* readlink */
971         { &vop_abortop_desc, genfs_abortop },           /* abortop */
972         { &vop_inactive_desc, (vop_t *) ntfs_inactive },        /* inactive */
973         { &vop_reclaim_desc, (vop_t *) ntfs_reclaim },  /* reclaim */
974         { &vop_lock_desc, genfs_lock },                 /* lock */
975         { &vop_unlock_desc, genfs_unlock },             /* unlock */
976         { &vop_bmap_desc, (vop_t *) ntfs_bmap },        /* bmap */
977         { &vop_strategy_desc, (vop_t *) ntfs_strategy },        /* strategy */
978         { &vop_print_desc, (vop_t *) ntfs_print },      /* print */
979         { &vop_islocked_desc, genfs_islocked },         /* islocked */
980         { &vop_pathconf_desc, ntfs_pathconf },          /* pathconf */
981         { &vop_advlock_desc, genfs_nullop },            /* advlock */
982         { &vop_blkatoff_desc, genfs_eopnotsupp },       /* blkatoff */
983         { &vop_valloc_desc, genfs_eopnotsupp },         /* valloc */
984         { &vop_reallocblks_desc, genfs_eopnotsupp },    /* reallocblks */
985         { &vop_vfree_desc, genfs_eopnotsupp },          /* vfree */
986         { &vop_truncate_desc, genfs_eopnotsupp },       /* truncate */
987         { &vop_update_desc, genfs_eopnotsupp },         /* update */
988         { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
989         { (struct vnodeop_desc *)NULL, (int (*) __P((void *)))NULL }
990 };
991 struct vnodeopv_desc ntfs_vnodeop_opv_desc =
992         { &ntfs_vnodeop_p, ntfs_vnodeop_entries };
993
994 #endif