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