Merge from vendor branch TCPDUMP:
[dragonfly.git] / sys / vfs / hpfs / hpfs_vnops.c
1 /*-
2  * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/fs/hpfs/hpfs_vnops.c,v 1.2.2.2 2002/01/15 18:35:09 semenu Exp $
27  * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.45 2007/08/28 01:04:33 dillon Exp $
28  */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/proc.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/vnode.h>
38 #include <sys/mount.h>
39 #include <sys/namei.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/dirent.h>
43
44 #include <machine/limits.h>
45
46 #include <vm/vm.h>
47 #include <vm/vm_param.h>
48 #if !defined(__DragonFly__)
49 #include <vm/vm_prot.h>
50 #endif
51 #include <vm/vm_page.h>
52 #include <vm/vm_object.h>
53 #include <vm/vm_pager.h>
54 #include <vm/vm_zone.h>
55 #if defined(__DragonFly__)
56 #include <vm/vnode_pager.h>
57 #endif
58 #include <vm/vm_extern.h>
59 #include <sys/buf2.h>
60
61 #if !defined(__DragonFly__)
62 #include <miscfs/specfs/specdev.h>
63 #include <miscfs/genfs/genfs.h>
64 #endif
65
66 #include <sys/unistd.h> /* for pathconf(2) constants */
67
68 #include "hpfs.h"
69 #include "hpfsmount.h"
70 #include "hpfs_subr.h"
71 #include "hpfs_ioctl.h"
72
73 static int      hpfs_de_uiomove (int *, struct hpfsmount *,
74                                  struct hpfsdirent *, struct uio *);
75 static int      hpfs_ioctl (struct vop_ioctl_args *ap);
76 static int      hpfs_read (struct vop_read_args *);
77 static int      hpfs_write (struct vop_write_args *ap);
78 static int      hpfs_getattr (struct vop_getattr_args *ap);
79 static int      hpfs_setattr (struct vop_setattr_args *ap);
80 static int      hpfs_inactive (struct vop_inactive_args *ap);
81 static int      hpfs_print (struct vop_print_args *ap);
82 static int      hpfs_reclaim (struct vop_reclaim_args *ap);
83 static int      hpfs_strategy (struct vop_strategy_args *ap);
84 static int      hpfs_access (struct vop_access_args *ap);
85 static int      hpfs_readdir (struct vop_readdir_args *ap);
86 static int      hpfs_lookup (struct vop_old_lookup_args *ap);
87 static int      hpfs_create (struct vop_old_create_args *);
88 static int      hpfs_remove (struct vop_old_remove_args *);
89 static int      hpfs_bmap (struct vop_bmap_args *ap);
90 #if defined(__DragonFly__)
91 static int      hpfs_fsync (struct vop_fsync_args *ap);
92 #endif
93 static int      hpfs_pathconf (struct vop_pathconf_args *ap);
94
95 #if defined(__DragonFly__)
96
97 /*
98  * hpfs_fsync(struct vnode *a_vp, int a_waitfor)
99  */
100 static int
101 hpfs_fsync(struct vop_fsync_args *ap)
102 {
103         struct vnode *vp = ap->a_vp;
104
105         /*
106          * Flush all dirty buffers associated with a vnode.
107          */
108 #ifdef DIAGNOSTIC
109 loop:
110 #endif
111         vfsync(vp, ap->a_waitfor, 0, NULL, NULL);
112 #ifdef DIAGNOSTIC
113         if (ap->a_waitfor == MNT_WAIT && !RB_EMPTY(&vp->v_rbdirty_tree)) {
114                 vprint("hpfs_fsync: dirty", vp);
115                 goto loop;
116         }
117 #endif
118
119         /*
120          * Write out the on-disc version of the vnode.
121          */
122         return hpfs_update(VTOHP(vp));
123 }
124
125 #endif
126
127 /*
128  * hpfs_ioctl(struct vnode *a_vp, u_long a_command, caddr_t a_data,
129  *            int a_fflag, struct ucred *a_cred)
130  */
131 static int
132 hpfs_ioctl(struct vop_ioctl_args *ap)
133 {
134         struct vnode *vp = ap->a_vp;
135         struct hpfsnode *hp = VTOHP(vp);
136         int error;
137
138         kprintf("hpfs_ioctl(0x%x, 0x%lx, 0x%p, 0x%x): ",
139                 hp->h_no, ap->a_command, ap->a_data, ap->a_fflag);
140
141         switch (ap->a_command) {
142         case HPFSIOCGEANUM: {
143                 u_long eanum;
144                 u_long passed;
145                 struct ea *eap;
146
147                 eanum = 0;
148
149                 if (hp->h_fn.fn_ealen > 0) {
150                         eap = (struct ea *)&(hp->h_fn.fn_int);
151                         passed = 0;
152
153                         while (passed < hp->h_fn.fn_ealen) {
154
155                                 kprintf("EAname: %s\n", EA_NAME(eap));
156
157                                 eanum++;
158                                 passed += sizeof(struct ea) +
159                                           eap->ea_namelen + 1 + eap->ea_vallen;
160                                 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
161                                                 passed);
162                         }
163                         error = 0;
164                 } else {
165                         error = ENOENT;
166                 }
167
168                 kprintf("%lu eas\n", eanum);
169
170                 *(u_long *)ap->a_data = eanum;
171
172                 break;
173         }
174         case HPFSIOCGEASZ: {
175                 u_long eanum;
176                 u_long passed;
177                 struct ea *eap;
178
179                 kprintf("EA%ld\n", *(u_long *)ap->a_data);
180
181                 eanum = 0;
182                 if (hp->h_fn.fn_ealen > 0) {
183                         eap = (struct ea *)&(hp->h_fn.fn_int);
184                         passed = 0;
185
186                         error = ENOENT;
187                         while (passed < hp->h_fn.fn_ealen) {
188                                 kprintf("EAname: %s\n", EA_NAME(eap));
189
190                                 if (eanum == *(u_long *)ap->a_data) {
191                                         *(u_long *)ap->a_data =
192                                                 eap->ea_namelen + 1 +
193                                                 eap->ea_vallen;
194
195                                         error = 0;
196                                         break;
197                                 }
198
199                                 eanum++;
200                                 passed += sizeof(struct ea) +
201                                           eap->ea_namelen + 1 + eap->ea_vallen;
202                                 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
203                                                 passed);
204                         }
205                 } else {
206                         error = ENOENT;
207                 }
208
209                 break;
210         }
211         case HPFSIOCRDEA: {
212                 u_long eanum;
213                 u_long passed;
214                 struct hpfs_rdea *rdeap;
215                 struct ea *eap;
216
217                 rdeap = (struct hpfs_rdea *)ap->a_data;
218                 kprintf("EA%ld\n", rdeap->ea_no);
219
220                 eanum = 0;
221                 if (hp->h_fn.fn_ealen > 0) {
222                         eap = (struct ea *)&(hp->h_fn.fn_int);
223                         passed = 0;
224
225                         error = ENOENT;
226                         while (passed < hp->h_fn.fn_ealen) {
227                                 kprintf("EAname: %s\n", EA_NAME(eap));
228
229                                 if (eanum == rdeap->ea_no) {
230                                         rdeap->ea_sz = eap->ea_namelen + 1 +
231                                                         eap->ea_vallen;
232                                         copyout(EA_NAME(eap),rdeap->ea_data,
233                                                 rdeap->ea_sz);
234                                         error = 0;
235                                         break;
236                                 }
237
238                                 eanum++;
239                                 passed += sizeof(struct ea) +
240                                           eap->ea_namelen + 1 + eap->ea_vallen;
241                                 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
242                                                 passed);
243                         }
244                 } else {
245                         error = ENOENT;
246                 }
247
248                 break;
249         }
250         default:
251                 error = EOPNOTSUPP;
252                 break;
253         }
254         return (error);
255 }
256
257 /*
258  * Map file offset to disk offset.
259  *
260  * hpfs_bmap(struct vnode *a_vp, off_t a_loffset,
261  *           off_t *a_doffsetp, int *a_runp, int *a_runb)
262  */
263 int
264 hpfs_bmap(struct vop_bmap_args *ap)
265 {
266         struct hpfsnode *hp = VTOHP(ap->a_vp);
267         int error;
268         daddr_t lbn;
269         daddr_t dbn;
270
271         if (ap->a_runb != NULL)
272                 *ap->a_runb = 0;
273         if (ap->a_doffsetp == NULL)
274                 return (0);
275
276         dprintf(("hpfs_bmap(0x%x, 0x%x): ",hp->h_no, ap->a_bn));
277
278         lbn = ap->a_loffset >> DEV_BSHIFT;
279         KKASSERT(((int)ap->a_loffset & DEV_BMASK) == 0);
280
281         error = hpfs_hpbmap (hp, lbn, &dbn, ap->a_runp);
282         if (error || dbn == (daddr_t)-1) {
283                 *ap->a_doffsetp = NOOFFSET;
284         } else {
285                 *ap->a_doffsetp = (off_t)dbn << DEV_BSHIFT;
286         }
287         return (error);
288 }
289
290 /*
291  * hpfs_read(struct vnode *a_vp, struct uio *a_uio, int a_ioflag,
292  *           struct ucred *a_cred)
293  */
294 static int
295 hpfs_read(struct vop_read_args *ap)
296 {
297         struct vnode *vp = ap->a_vp;
298         struct hpfsnode *hp = VTOHP(vp);
299         struct uio *uio = ap->a_uio;
300         struct buf *bp;
301         u_int xfersz, toread;
302         u_int off;
303         daddr_t lbn, bn;
304         int resid;
305         int runl;
306         int error = 0;
307
308         resid = min (uio->uio_resid, hp->h_fn.fn_size - uio->uio_offset);
309
310         dprintf(("hpfs_read(0x%x, off: %d resid: %d, segflg: %d): [resid: 0x%x]\n",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg, resid));
311
312         while (resid) {
313                 lbn = uio->uio_offset >> DEV_BSHIFT;
314                 off = uio->uio_offset & (DEV_BSIZE - 1);
315                 dprintf(("hpfs_read: resid: 0x%x lbn: 0x%x off: 0x%x\n",
316                         uio->uio_resid, lbn, off));
317                 error = hpfs_hpbmap(hp, lbn, &bn, &runl);
318                 if (error)
319                         return (error);
320
321                 toread = min(off + resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE));
322                 xfersz = (toread + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
323                 dprintf(("hpfs_read: bn: 0x%x (0x%x) toread: 0x%x (0x%x)\n",
324                         bn, runl, toread, xfersz));
325
326                 if (toread == 0) 
327                         break;
328
329                 error = bread(hp->h_devvp, dbtodoff(bn), xfersz, &bp);
330                 if (error) {
331                         brelse(bp);
332                         break;
333                 }
334
335                 error = uiomove(bp->b_data + off, toread - off, uio);
336                 if(error) {
337                         brelse(bp);
338                         break;
339                 }
340                 brelse(bp);
341                 resid -= toread;
342         }
343         dprintf(("hpfs_read: successful\n"));
344         return (error);
345 }
346
347 /*
348  * hpfs_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag,
349  *            struct ucred *a_cred)
350  */
351 static int
352 hpfs_write(struct vop_write_args *ap)
353 {
354         struct vnode *vp = ap->a_vp;
355         struct hpfsnode *hp = VTOHP(vp);
356         struct uio *uio = ap->a_uio;
357         struct buf *bp;
358         u_int xfersz, towrite;
359         u_int off;
360         daddr_t lbn, bn;
361         int runl;
362         int error = 0;
363
364         dprintf(("hpfs_write(0x%x, off: %d resid: %d, segflg: %d):\n",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg));
365
366         if (ap->a_ioflag & IO_APPEND) {
367                 dprintf(("hpfs_write: APPEND mode\n"));
368                 uio->uio_offset = hp->h_fn.fn_size;
369         }
370         if (uio->uio_offset + uio->uio_resid > hp->h_fn.fn_size) {
371                 error = hpfs_extend (hp, uio->uio_offset + uio->uio_resid);
372                 if (error) {
373                         kprintf("hpfs_write: hpfs_extend FAILED %d\n", error);
374                         return (error);
375                 }
376         }
377
378         while (uio->uio_resid) {
379                 lbn = uio->uio_offset >> DEV_BSHIFT;
380                 off = uio->uio_offset & (DEV_BSIZE - 1);
381                 dprintf(("hpfs_write: resid: 0x%x lbn: 0x%x off: 0x%x\n",
382                         uio->uio_resid, lbn, off));
383                 error = hpfs_hpbmap(hp, lbn, &bn, &runl);
384                 if (error)
385                         return (error);
386
387                 towrite = min(off + uio->uio_resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE));
388                 xfersz = (towrite + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
389                 dprintf(("hpfs_write: bn: 0x%x (0x%x) towrite: 0x%x (0x%x)\n",
390                         bn, runl, towrite, xfersz));
391
392                 /*
393                  * We do not have to issue a read-before-write if the xfer
394                  * size does not cover the whole block.
395                  *
396                  * In the UIO_NOCOPY case, however, we are not overwriting
397                  * anything and must do a read-before-write to fill in
398                  * any missing pieces.
399                  */
400                 if (off == 0 && towrite == xfersz &&
401                     uio->uio_segflg != UIO_NOCOPY) {
402                         bp = getblk(hp->h_devvp, dbtodoff(bn), xfersz, 0, 0);
403                         clrbuf(bp);
404                 } else {
405                         error = bread(hp->h_devvp, dbtodoff(bn), xfersz, &bp);
406                         if (error) {
407                                 brelse(bp);
408                                 return (error);
409                         }
410                 }
411
412                 error = uiomove(bp->b_data + off, towrite - off, uio);
413                 if(error) {
414                         brelse(bp);
415                         return (error);
416                 }
417
418                 if (ap->a_ioflag & IO_SYNC)
419                         bwrite(bp);
420                 else
421                         bawrite(bp);
422         }
423
424         dprintf(("hpfs_write: successful\n"));
425         return (0);
426 }
427
428 /*
429  * XXXXX do we need hpfsnode locking inside?
430  *
431  * hpfs_getattr(struct vnode *a_vp, struct vattr *a_vap)
432  */
433 static int
434 hpfs_getattr(struct vop_getattr_args *ap)
435 {
436         struct vnode *vp = ap->a_vp;
437         struct hpfsnode *hp = VTOHP(vp);
438         struct vattr *vap = ap->a_vap;
439         int error;
440
441         dprintf(("hpfs_getattr(0x%x):\n", hp->h_no));
442
443 #if defined(__DragonFly__)
444         vap->va_fsid = dev2udev(hp->h_dev);
445 #else /* defined(__NetBSD__) */
446         vap->va_fsid = ip->i_dev;
447 #endif
448         vap->va_fileid = hp->h_no;
449         vap->va_mode = hp->h_mode;
450         vap->va_nlink = 1;
451         vap->va_uid = hp->h_uid;
452         vap->va_gid = hp->h_gid;
453         vap->va_rmajor = VNOVAL;
454         vap->va_rminor = VNOVAL;
455         vap->va_size = hp->h_fn.fn_size;
456         vap->va_bytes = ((hp->h_fn.fn_size + DEV_BSIZE-1) & ~(DEV_BSIZE-1)) +
457                         DEV_BSIZE;
458
459         if (!(hp->h_flag & H_PARVALID)) {
460                 error = hpfs_validateparent(hp);
461                 if (error) 
462                         return (error);
463         }
464         vap->va_atime = hpfstimetounix(hp->h_atime);
465         vap->va_mtime = hpfstimetounix(hp->h_mtime);
466         vap->va_ctime = hpfstimetounix(hp->h_ctime);
467
468         vap->va_flags = 0;
469         vap->va_gen = 0;
470         vap->va_blocksize = DEV_BSIZE;
471         vap->va_type = vp->v_type;
472         vap->va_filerev = 0;
473
474         return (0);
475 }
476
477 /*
478  * XXXXX do we need hpfsnode locking inside?
479  *
480  * hpfs_setattr(struct vnode *a_vp, struct vattr *a_vap, struct ucred *a_cred)
481  */
482 static int
483 hpfs_setattr(struct vop_setattr_args *ap)
484 {
485         struct vnode *vp = ap->a_vp;
486         struct hpfsnode *hp = VTOHP(vp);
487         struct vattr *vap = ap->a_vap;
488         struct ucred *cred = ap->a_cred;
489         int error;
490
491         dprintf(("hpfs_setattr(0x%x):\n", hp->h_no));
492
493         /*
494          * Check for unsettable attributes.
495          */
496         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
497             (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
498             (vap->va_blocksize != VNOVAL) || (vap->va_rmajor != VNOVAL) ||
499             (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
500                 dprintf(("hpfs_setattr: changing nonsettable attr\n"));
501                 return (EINVAL);
502         }
503
504         /* Can't change flags XXX Could be implemented */
505         if (vap->va_flags != VNOVAL) {
506                 kprintf("hpfs_setattr: FLAGS CANNOT BE SET\n");
507                 return (EINVAL);
508         }
509
510         /* Can't change uid/gid XXX Could be implemented */
511         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
512                 kprintf("hpfs_setattr: UID/GID CANNOT BE SET\n");
513                 return (EINVAL);
514         }
515
516         /* Can't change mode XXX Could be implemented */
517         if (vap->va_mode != (mode_t)VNOVAL) {
518                 kprintf("hpfs_setattr: MODE CANNOT BE SET\n");
519                 return (EINVAL);
520         }
521
522         /* Update times */
523         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
524                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
525                         return (EROFS);
526                 if (cred->cr_uid != hp->h_uid &&
527                     (error = suser_cred(cred, PRISON_ROOT)) &&
528                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
529                     (error = VOP_ACCESS(vp, VWRITE, cred))))
530                         return (error);
531                 if (vap->va_atime.tv_sec != VNOVAL)
532                         hp->h_atime = vap->va_atime.tv_sec;
533                 if (vap->va_mtime.tv_sec != VNOVAL)
534                         hp->h_mtime = vap->va_mtime.tv_sec;
535
536                 hp->h_flag |= H_PARCHANGE;
537         }
538
539         if (vap->va_size != VNOVAL) {
540                 switch (vp->v_type) {
541                 case VDIR:
542                         return (EISDIR);
543                 case VREG:
544                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
545                                 return (EROFS);
546                         break;
547                 default:
548                         kprintf("hpfs_setattr: WRONG v_type\n");
549                         return (EINVAL);
550                 }
551
552                 if (vap->va_size < hp->h_fn.fn_size) {
553 #if defined(__DragonFly__)
554                         error = vtruncbuf(vp, vap->va_size, DEV_BSIZE);
555                         if (error)
556                                 return (error);
557 #else /* defined(__NetBSD__) */
558 #error Need alternation for vtruncbuf()
559 #endif
560                         error = hpfs_truncate(hp, vap->va_size);
561                         if (error)
562                                 return (error);
563
564                 } else if (vap->va_size > hp->h_fn.fn_size) {
565 #if defined(__DragonFly__)
566                         vnode_pager_setsize(vp, vap->va_size);
567 #endif
568                         error = hpfs_extend(hp, vap->va_size);
569                         if (error)
570                                 return (error);
571                 }
572         }
573
574         return (0);
575 }
576
577 /*
578  * Last reference to an node.  If necessary, write or delete it.
579  *
580  * hpfs_inactive(struct vnode *a_vp)
581  */
582 int
583 hpfs_inactive(struct vop_inactive_args *ap)
584 {
585         struct vnode *vp = ap->a_vp;
586         struct hpfsnode *hp = VTOHP(vp);
587         int error;
588
589         dprintf(("hpfs_inactive(0x%x): \n", hp->h_no));
590
591         if (hp->h_flag & H_CHANGE) {
592                 dprintf(("hpfs_inactive: node changed, update\n"));
593                 error = hpfs_update (hp);
594                 if (error)
595                         return (error);
596         }
597
598         if (hp->h_flag & H_PARCHANGE) {
599                 dprintf(("hpfs_inactive: parent node changed, update\n"));
600                 error = hpfs_updateparent (hp);
601                 if (error)
602                         return (error);
603         }
604
605         if (prtactive && vp->v_sysref.refcnt > 1)
606                 vprint("hpfs_inactive: pushing active", vp);
607
608         if (hp->h_flag & H_INVAL) {
609 #if defined(__DragonFly__)
610                 vrecycle(vp);
611 #else /* defined(__NetBSD__) */
612                 vgone(vp);
613 #endif
614                 return (0);
615         }
616         return (0);
617 }
618
619 /*
620  * Reclaim an inode so that it can be used for other purposes.
621  *
622  * hpfs_reclaim(struct vnode *a_vp)
623  */
624 int
625 hpfs_reclaim(struct vop_reclaim_args *ap)
626 {
627         struct vnode *vp = ap->a_vp;
628         struct hpfsnode *hp = VTOHP(vp);
629
630         dprintf(("hpfs_reclaim(0x%x0): \n", hp->h_no));
631
632         hpfs_hphashrem(hp);
633
634         /* Purge old data structures associated with the inode. */
635         if (hp->h_devvp) {
636                 vrele(hp->h_devvp);
637                 hp->h_devvp = NULL;
638         }
639
640         vp->v_data = NULL;
641
642         FREE(hp, M_HPFSNO);
643
644         return (0);
645 }
646
647 /*
648  * hpfs_print(struct vnode *a_vp)
649  */
650 static int
651 hpfs_print(struct vop_print_args *ap)
652 {
653         struct vnode *vp = ap->a_vp;
654         struct hpfsnode *hp = VTOHP(vp);
655
656         kprintf("tag VT_HPFS, ino 0x%x",hp->h_no);
657         lockmgr_printinfo(&vp->v_lock);
658         kprintf("\n");
659         return (0);
660 }
661
662 /*
663  * Calculate the logical to physical mapping if not done already,
664  * then call the device strategy routine.
665  *
666  * In order to be able to swap to a file, the VOP_BMAP operation may not
667  * deadlock on memory.  See hpfs_bmap() for details. XXXXXXX (not impl)
668  *
669  * hpfs_strategy(struct vnode *a_vp, struct bio *a_bio)
670  */
671 int
672 hpfs_strategy(struct vop_strategy_args *ap)
673 {
674         struct bio *bio = ap->a_bio;
675         struct bio *nbio;
676         struct buf *bp = bio->bio_buf;
677         struct vnode *vp = ap->a_vp;
678         struct hpfsnode *hp;
679         int error;
680
681         dprintf(("hpfs_strategy(): \n"));
682
683         if (vp->v_type == VBLK || vp->v_type == VCHR)
684                 panic("hpfs_strategy: spec");
685
686         nbio = push_bio(bio);
687         if (nbio->bio_offset == NOOFFSET) {
688                 error = VOP_BMAP(vp, bio->bio_offset, &nbio->bio_offset,
689                                  NULL, NULL);
690                 if (error) {
691                         kprintf("hpfs_strategy: VOP_BMAP FAILED %d\n", error);
692                         bp->b_error = error;
693                         bp->b_flags |= B_ERROR;
694                         /* I/O was never started on nbio, must biodone(bio) */
695                         biodone(bio);
696                         return (error);
697                 }
698                 if (nbio->bio_offset == NOOFFSET)
699                         vfs_bio_clrbuf(bp);
700         }
701         if (nbio->bio_offset == NOOFFSET) {
702                 /* I/O was never started on nbio, must biodone(bio) */
703                 biodone(bio);
704                 return (0);
705         }
706         hp = VTOHP(ap->a_vp);
707         vn_strategy(hp->h_devvp, nbio);
708         return (0);
709 }
710
711 /*
712  * XXXXX do we need hpfsnode locking inside?
713  *
714  * hpfs_access(struct vnode *a_vp, int a_mode, struct ucred *a_cred)
715  */
716 int
717 hpfs_access(struct vop_access_args *ap)
718 {
719         struct vnode *vp = ap->a_vp;
720         struct hpfsnode *hp = VTOHP(vp);
721         struct ucred *cred = ap->a_cred;
722         mode_t mask, mode = ap->a_mode;
723         gid_t *gp;
724         int i;
725
726         dprintf(("hpfs_access(0x%x):\n", hp->h_no));
727
728         /*
729          * Disallow write attempts on read-only file systems;
730          * unless the file is a socket, fifo, or a block or
731          * character device resident on the file system.
732          */
733         if (mode & VWRITE) {
734                 switch ((int)vp->v_type) {
735                 case VDIR:
736                 case VLNK:
737                 case VREG:
738                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
739                                 return (EROFS);
740                         break;
741                 }
742         }
743
744         /* Otherwise, user id 0 always gets access. */
745         if (cred->cr_uid == 0)
746                 return (0);
747
748         mask = 0;
749
750         /* Otherwise, check the owner. */
751         if (cred->cr_uid == hp->h_uid) {
752                 if (mode & VEXEC)
753                         mask |= S_IXUSR;
754                 if (mode & VREAD)
755                         mask |= S_IRUSR;
756                 if (mode & VWRITE)
757                         mask |= S_IWUSR;
758                 return ((hp->h_mode & mask) == mask ? 0 : EACCES);
759         }
760
761         /* Otherwise, check the groups. */
762         for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
763                 if (hp->h_gid == *gp) {
764                         if (mode & VEXEC)
765                                 mask |= S_IXGRP;
766                         if (mode & VREAD)
767                                 mask |= S_IRGRP;
768                         if (mode & VWRITE)
769                                 mask |= S_IWGRP;
770                         return ((hp->h_mode & mask) == mask ? 0 : EACCES);
771                 }
772
773         /* Otherwise, check everyone else. */
774         if (mode & VEXEC)
775                 mask |= S_IXOTH;
776         if (mode & VREAD)
777                 mask |= S_IROTH;
778         if (mode & VWRITE)
779                 mask |= S_IWOTH;
780         return ((hp->h_mode & mask) == mask ? 0 : EACCES);
781 }
782
783 static int
784 hpfs_de_uiomove(int *error, struct hpfsmount *hpmp, struct hpfsdirent *dep,
785                 struct uio *uio)
786 {
787         char convname[HPFS_MAXFILENAME + 1];
788         int i, success;
789
790         dprintf(("[no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x] ",
791                 dep->de_fnode, dep->de_size, dep->de_namelen,
792                 dep->de_namelen, dep->de_name, dep->de_flag));
793
794         /*strncpy(cde.d_name, dep->de_name, dep->de_namelen);*/
795         for (i=0; i<dep->de_namelen; i++) 
796                 convname[i] = hpfs_d2u(hpmp, dep->de_name[i]);
797         convname[dep->de_namelen] = '\0';
798
799         success = vop_write_dirent(error, uio, dep->de_fnode,
800                         (dep->de_flag & DE_DIR) ? DT_DIR : DT_REG,
801                         dep->de_namelen, convname);
802
803         dprintf(("[0x%x] ", uio->uio_resid));
804         return (success);
805 }
806
807
808 /*
809  * hpfs_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred,
810  *              int *a_ncookies, u_int **cookies)
811  */
812 int
813 hpfs_readdir(struct vop_readdir_args *ap)
814 {
815         struct vnode *vp = ap->a_vp;
816         struct hpfsnode *hp = VTOHP(vp);
817         struct hpfsmount *hpmp = hp->h_hpmp;
818         struct uio *uio = ap->a_uio;
819         int ncookies = 0, i, num, cnum;
820         int error = 0;
821         struct buf *bp;
822         struct dirblk *dp;
823         struct hpfsdirent *dep;
824         lsn_t olsn;
825         lsn_t lsn;
826         int level;
827
828         dprintf(("hpfs_readdir(0x%x, 0x%x, 0x%x): ",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid));
829
830         /*
831          * As we need to fake up . and .., and the remaining directory structure
832          * can't be expressed in one off_t as well, we just increment uio_offset
833          * by 1 for each entry.
834          *
835          * num is the entry we need to start reporting
836          * cnum is the current entry
837          */
838         if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX)
839                 return(EINVAL);
840         if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
841                 return (error);
842
843         num = uio->uio_offset;
844         cnum = 0;
845
846         if( num <= cnum ) {
847                 dprintf((". faked, "));
848                 if (vop_write_dirent(&error, uio, hp->h_no, DT_DIR, 1, "."))
849                         goto done;
850                 if (error)
851                         goto done;
852                 ncookies ++;
853         }
854         cnum++;
855
856         if( num <= cnum ) {
857                 dprintf((".. faked, "));
858                 if (vop_write_dirent(&error, uio, hp->h_fn.fn_parent, DT_DIR, 2, ".."))
859                         goto readdone;
860                 if (error)
861                         goto done;
862                 ncookies ++;
863         }
864         cnum++;
865
866         lsn = ((alleaf_t *)hp->h_fn.fn_abd)->al_lsn;
867
868         olsn = 0;
869         level = 1;
870
871 dive:
872         dprintf(("[dive 0x%x] ", lsn));
873         error = bread(hp->h_devvp, dbtodoff(lsn), D_BSIZE, &bp);
874         if (error) {
875                 brelse(bp);
876                 goto done;
877         }
878
879         dp = (struct dirblk *) bp->b_data;
880         if (dp->d_magic != D_MAGIC) {
881                 kprintf("hpfs_readdir: MAGIC DOESN'T MATCH\n");
882                 brelse(bp);
883                 error = EINVAL;
884                 goto done;
885         }
886
887         dep = D_DIRENT(dp);
888
889         if (olsn) {
890                 dprintf(("[restore 0x%x] ", olsn));
891
892                 while(!(dep->de_flag & DE_END) ) {
893                         if((dep->de_flag & DE_DOWN) &&
894                            (olsn == DE_DOWNLSN(dep)))
895                                          break;
896                         dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
897                 }
898
899                 if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
900                         if (dep->de_flag & DE_END)
901                                 goto blockdone;
902
903                         if (!(dep->de_flag & DE_SPECIAL)) {
904                                 if (num <= cnum) {
905                                         if (hpfs_de_uiomove(&error, hpmp, dep, uio)) {
906                                                 brelse(bp);
907                                                 dprintf(("[resid] "));
908                                                 goto readdone;
909                                         }
910                                         if (error) {
911                                                 brelse (bp);
912                                                 goto done;
913                                         }
914                                         ncookies++;
915                                 }
916                                 cnum++;
917                         }
918
919                         dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
920                 } else {
921                         kprintf("hpfs_readdir: ERROR! oLSN not found\n");
922                         brelse(bp);
923                         error = EINVAL;
924                         goto done;
925                 }
926         }
927
928         olsn = 0;
929
930         while(!(dep->de_flag & DE_END)) {
931                 if(dep->de_flag & DE_DOWN) {
932                         lsn = DE_DOWNLSN(dep);
933                         brelse(bp);
934                         level++;
935                         goto dive;
936                 }
937
938                 if (!(dep->de_flag & DE_SPECIAL)) {
939                         if (num <= cnum) {
940                                 if (hpfs_de_uiomove(&error, hpmp, dep, uio)) {
941                                         brelse(bp);
942                                         dprintf(("[resid] "));
943                                         goto readdone;
944                                 }
945                                 if (error) {
946                                         brelse (bp);
947                                         goto done;
948                                 }
949                                 ncookies++;
950                         }
951                         cnum++;
952                 }
953
954                 dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
955         }
956
957         if(dep->de_flag & DE_DOWN) {
958                 dprintf(("[enddive] "));
959                 lsn = DE_DOWNLSN(dep);
960                 brelse(bp);
961                 level++;
962                 goto dive;
963         }
964
965 blockdone:
966         dprintf(("[EOB] "));
967         olsn = lsn;
968         lsn = dp->d_parent;
969         brelse(bp);
970         level--;
971
972         dprintf(("[level %d] ", level));
973
974         if (level > 0)
975                 goto dive;      /* undive really */
976
977         if (ap->a_eofflag) {
978             dprintf(("[EOF] "));
979             *ap->a_eofflag = 1;
980         }
981
982 readdone:
983         uio->uio_offset = cnum;
984         dprintf(("[readdone]\n"));
985         if (!error && ap->a_ncookies != NULL) {
986 #if defined(__DragonFly__)
987                 u_long *cookies;
988                 u_long *cookiep;
989 #else /* defined(__NetBSD__) */
990                 off_t *cookies;
991                 off_t *cookiep;
992 #endif
993
994                 dprintf(("%d cookies, ",ncookies));
995                 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
996                         panic("hpfs_readdir: unexpected uio from NFS server");
997 #if defined(__DragonFly__)
998                 MALLOC(cookies, u_long *, ncookies * sizeof(u_long),
999                        M_TEMP, M_WAITOK);
1000 #else /* defined(__NetBSD__) */
1001                 MALLOC(cookies, off_t *, ncookies * sizeof(off_t),
1002                        M_TEMP, M_WAITOK);
1003 #endif
1004                 for (cookiep = cookies, i=0; i < ncookies; i++)
1005                         *cookiep++ = (u_int)++num;
1006
1007                 *ap->a_ncookies = ncookies;
1008                 *ap->a_cookies = cookies;
1009         }
1010
1011 done:
1012         vn_unlock(ap->a_vp);
1013         return (error);
1014 }
1015
1016 /*
1017  * hpfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
1018  *              struct componentname *a_cnp)
1019  */
1020 int
1021 hpfs_lookup(struct vop_old_lookup_args *ap)
1022 {
1023         struct vnode *dvp = ap->a_dvp;
1024         struct hpfsnode *dhp = VTOHP(dvp);
1025         struct hpfsmount *hpmp = dhp->h_hpmp;
1026         struct componentname *cnp = ap->a_cnp;
1027         struct ucred *cred = cnp->cn_cred;
1028         int error;
1029         int nameiop = cnp->cn_nameiop;
1030         int flags = cnp->cn_flags;
1031         int lockparent = flags & CNP_LOCKPARENT;
1032 #if HPFS_DEBUG
1033         int wantparent = flags & (CNP_LOCKPARENT | CNP_WANTPARENT);
1034 #endif
1035         dprintf(("hpfs_lookup(0x%x, %s, %ld, %d, %d): \n",
1036                 dhp->h_no, cnp->cn_nameptr, cnp->cn_namelen,
1037                 lockparent, wantparent));
1038
1039         if (nameiop != NAMEI_CREATE && nameiop != NAMEI_DELETE && nameiop != NAMEI_LOOKUP) {
1040                 kprintf("hpfs_lookup: LOOKUP, DELETE and CREATE are only supported\n");
1041                 return (EOPNOTSUPP);
1042         }
1043
1044         error = VOP_ACCESS(dvp, VEXEC, cred);
1045         if(error)
1046                 return (error);
1047
1048         if( (cnp->cn_namelen == 1) &&
1049             !strncmp(cnp->cn_nameptr,".",1) ) {
1050                 dprintf(("hpfs_lookup(0x%x,...): . faked\n",dhp->h_no));
1051
1052                 vref(dvp);
1053                 *ap->a_vpp = dvp;
1054
1055                 return (0);
1056         } else if( (cnp->cn_namelen == 2) &&
1057             !strncmp(cnp->cn_nameptr,"..",2) && (flags & CNP_ISDOTDOT) ) {
1058                 dprintf(("hpfs_lookup(0x%x,...): .. faked (0x%x)\n",
1059                         dhp->h_no, dhp->h_fn.fn_parent));
1060
1061                 VOP__UNLOCK(dvp, 0);
1062
1063                 error = VFS_VGET(hpmp->hpm_mp,
1064                                  dhp->h_fn.fn_parent, ap->a_vpp); 
1065                 if (error) {
1066                         VOP__LOCK(dvp, 0);
1067                         return(error);
1068                 }
1069
1070                 if (lockparent && (error = VOP__LOCK(dvp, 0))) {
1071                         vput( *(ap->a_vpp) );
1072                         return (error);
1073                 }
1074                 return (error);
1075         } else {
1076                 struct buf *bp;
1077                 struct hpfsdirent *dep;
1078                 struct hpfsnode *hp;
1079
1080                 error = hpfs_genlookupbyname(dhp,
1081                                 cnp->cn_nameptr, cnp->cn_namelen, &bp, &dep);
1082                 if (error) {
1083                         if (error == ENOENT && 
1084                             (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME)) {
1085                                 if(!lockparent)
1086                                         VOP__UNLOCK(dvp, 0);
1087                                 return (EJUSTRETURN);
1088                         }
1089
1090                         return (error);
1091                 }
1092
1093                 dprintf(("hpfs_lookup: fnode: 0x%x, CPID: 0x%x\n",
1094                          dep->de_fnode, dep->de_cpid));
1095
1096                 if (nameiop == NAMEI_DELETE) {
1097                         error = VOP_ACCESS(dvp, VWRITE, cred);
1098                         if (error) {
1099                                 brelse(bp);
1100                                 return (error);
1101                         }
1102                 }
1103
1104                 if (dhp->h_no == dep->de_fnode) {
1105                         brelse(bp);
1106                         vref(dvp);
1107                         *ap->a_vpp = dvp;
1108                         return (0);
1109                 }
1110
1111                 error = VFS_VGET(hpmp->hpm_mp, dep->de_fnode, ap->a_vpp);
1112                 if (error) {
1113                         kprintf("hpfs_lookup: VFS_VGET FAILED %d\n", error);
1114                         brelse(bp);
1115                         return(error);
1116                 }
1117
1118                 hp = VTOHP(*ap->a_vpp);
1119
1120                 hp->h_mtime = dep->de_mtime;
1121                 hp->h_ctime = dep->de_ctime;
1122                 hp->h_atime = dep->de_atime;
1123                 bcopy(dep->de_name, hp->h_name, dep->de_namelen);
1124                 hp->h_name[dep->de_namelen] = '\0';
1125                 hp->h_namelen = dep->de_namelen;
1126                 hp->h_flag |= H_PARVALID;
1127
1128                 brelse(bp);
1129
1130                 if(!lockparent)
1131                         VOP__UNLOCK(dvp, 0);
1132         }
1133         return (error);
1134 }
1135
1136 /*
1137  * hpfs_remove(struct vnode *a_dvp, struct vnode *a_vp,
1138  *              struct componentname *a_cnp)
1139  */
1140 int
1141 hpfs_remove(struct vop_old_remove_args *ap)
1142 {
1143         int error;
1144
1145         dprintf(("hpfs_remove(0x%x, %s, %ld): \n", VTOHP(ap->a_vp)->h_no,
1146                 ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
1147
1148         if (ap->a_vp->v_type == VDIR)
1149                 return (EPERM);
1150
1151         error = hpfs_removefnode (ap->a_dvp, ap->a_vp, ap->a_cnp);
1152         return (error);
1153 }
1154
1155 /*
1156  * hpfs_create(struct vnode *a_dvp, struct vnode **a_vpp,
1157  *              struct componentname *a_cnp, struct vattr *a_vap)
1158  */
1159 int
1160 hpfs_create(struct vop_old_create_args *ap)
1161 {
1162         int error;
1163
1164         dprintf(("hpfs_create(0x%x, %s, %ld): \n", VTOHP(ap->a_dvp)->h_no,
1165                 ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
1166
1167         error = hpfs_makefnode (ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
1168
1169         return (error);
1170 }
1171
1172 /*
1173  * Return POSIX pathconf information applicable to NTFS filesystem
1174  *
1175  * hpfs_pathconf(struct vnode *a_vp, int a_name, t *a_retval)
1176  */
1177 int
1178 hpfs_pathconf(struct vop_pathconf_args *ap)
1179 {
1180         switch (ap->a_name) {
1181         case _PC_LINK_MAX:
1182                 *ap->a_retval = 1;
1183                 return (0);
1184         case _PC_NAME_MAX:
1185                 *ap->a_retval = HPFS_MAXFILENAME;
1186                 return (0);
1187         case _PC_PATH_MAX:
1188                 *ap->a_retval = PATH_MAX;
1189                 return (0);
1190         case _PC_CHOWN_RESTRICTED:
1191                 *ap->a_retval = 1;
1192                 return (0);
1193         case _PC_NO_TRUNC:
1194                 *ap->a_retval = 0;
1195                 return (0);
1196 #if defined(__NetBSD__)
1197         case _PC_SYNC_IO:
1198                 *ap->a_retval = 1;
1199                 return (0);
1200         case _PC_FILESIZEBITS:
1201                 *ap->a_retval = 32;
1202                 return (0);
1203 #endif
1204         default:
1205                 return (EINVAL);
1206         }
1207         /* NOTREACHED */
1208 }
1209
1210
1211 /*
1212  * Global vfs data structures
1213  */
1214
1215 struct vop_ops hpfs_vnode_vops = {
1216         .vop_default =          vop_defaultop,
1217         .vop_getattr =          hpfs_getattr,
1218         .vop_setattr =          hpfs_setattr,
1219         .vop_inactive =         hpfs_inactive,
1220         .vop_reclaim =          hpfs_reclaim,
1221         .vop_print =            hpfs_print,
1222         .vop_old_create =       hpfs_create,
1223         .vop_old_remove =       hpfs_remove,
1224         .vop_old_lookup =       hpfs_lookup,
1225         .vop_access =           hpfs_access,
1226         .vop_readdir =          hpfs_readdir,
1227         .vop_fsync =            hpfs_fsync,
1228         .vop_bmap =             hpfs_bmap,
1229         .vop_getpages =         vop_stdgetpages,
1230         .vop_putpages =         vop_stdputpages,
1231         .vop_strategy =         hpfs_strategy,
1232         .vop_read =             hpfs_read,
1233         .vop_write =            hpfs_write,
1234         .vop_ioctl =            hpfs_ioctl,
1235         .vop_pathconf =         hpfs_pathconf
1236 };
1237