xref: /dragonfly/sys/vfs/hpfs/hpfs_vnops.c (revision af79c6e5)
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.11 2003/10/09 22:27:23 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 <vm/vm.h>
45 #include <vm/vm_param.h>
46 #if !defined(__FreeBSD__)
47 #include <vm/vm_prot.h>
48 #endif
49 #include <vm/vm_page.h>
50 #include <vm/vm_object.h>
51 #include <vm/vm_pager.h>
52 #include <vm/vm_zone.h>
53 #if defined(__FreeBSD__)
54 #include <vm/vnode_pager.h>
55 #endif
56 #include <vm/vm_extern.h>
57 #include <sys/buf2.h>
58 
59 #if !defined(__FreeBSD__)
60 #include <miscfs/specfs/specdev.h>
61 #include <miscfs/genfs/genfs.h>
62 #endif
63 
64 #include <sys/unistd.h> /* for pathconf(2) constants */
65 
66 #include "hpfs.h"
67 #include "hpfsmount.h"
68 #include "hpfs_subr.h"
69 #include "hpfs_ioctl.h"
70 
71 static int	hpfs_de_uiomove (struct hpfsmount *, struct hpfsdirent *,
72 				     struct uio *);
73 static int	hpfs_ioctl (struct vop_ioctl_args *ap);
74 static int	hpfs_read (struct vop_read_args *);
75 static int	hpfs_write (struct vop_write_args *ap);
76 static int	hpfs_getattr (struct vop_getattr_args *ap);
77 static int	hpfs_setattr (struct vop_setattr_args *ap);
78 static int	hpfs_inactive (struct vop_inactive_args *ap);
79 static int	hpfs_print (struct vop_print_args *ap);
80 static int	hpfs_reclaim (struct vop_reclaim_args *ap);
81 static int	hpfs_strategy (struct vop_strategy_args *ap);
82 static int	hpfs_access (struct vop_access_args *ap);
83 static int	hpfs_open (struct vop_open_args *ap);
84 static int	hpfs_close (struct vop_close_args *ap);
85 static int	hpfs_readdir (struct vop_readdir_args *ap);
86 static int	hpfs_lookup (struct vop_lookup_args *ap);
87 static int	hpfs_create (struct vop_create_args *);
88 static int	hpfs_remove (struct vop_remove_args *);
89 static int	hpfs_bmap (struct vop_bmap_args *ap);
90 #if defined(__FreeBSD__)
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(__FreeBSD__)
98 int
99 hpfs_getpages(ap)
100 	struct vop_getpages_args *ap;
101 {
102 	return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
103 		ap->a_reqpage);
104 }
105 
106 int
107 hpfs_putpages(ap)
108 	struct vop_putpages_args *ap;
109 {
110 	return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
111 		ap->a_sync, ap->a_rtvals);
112 }
113 
114 static int
115 hpfs_fsync(ap)
116 	struct vop_fsync_args /* {
117 		struct vnode *a_vp;
118 		struct ucred *a_cred;
119 		int a_waitfor;
120 		struct proc *a_td;
121 	} */ *ap;
122 {
123 	struct vnode *vp = ap->a_vp;
124 	int s;
125 	struct buf *bp, *nbp;
126 
127 	/*
128 	 * Flush all dirty buffers associated with a vnode.
129 	 */
130 loop:
131 	s = splbio();
132 	for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
133 		nbp = TAILQ_NEXT(bp, b_vnbufs);
134 		if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
135 			continue;
136 		if ((bp->b_flags & B_DELWRI) == 0)
137 			panic("hpfs_fsync: not dirty");
138 		bremfree(bp);
139 		splx(s);
140 		(void) bwrite(bp);
141 		goto loop;
142 	}
143 	while (vp->v_numoutput) {
144 		vp->v_flag |= VBWAIT;
145 		(void) tsleep((caddr_t)&vp->v_numoutput, 0, "hpfsn", 0);
146 	}
147 #ifdef DIAGNOSTIC
148 	if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
149 		vprint("hpfs_fsync: dirty", vp);
150 		goto loop;
151 	}
152 #endif
153 	splx(s);
154 
155 	/*
156 	 * Write out the on-disc version of the vnode.
157 	 */
158 	return hpfs_update(VTOHP(vp));
159 }
160 
161 #endif
162 
163 static int
164 hpfs_ioctl (
165 	struct vop_ioctl_args /* {
166 		struct vnode *a_vp;
167 		u_long a_command;
168 		caddr_t a_data;
169 		int a_fflag;
170 		struct ucred *a_cred;
171 		struct proc *a_td;
172 	} */ *ap)
173 {
174 	struct vnode *vp = ap->a_vp;
175 	struct hpfsnode *hp = VTOHP(vp);
176 	int error;
177 
178 	printf("hpfs_ioctl(0x%x, 0x%lx, 0x%p, 0x%x): ",
179 		hp->h_no, ap->a_command, ap->a_data, ap->a_fflag);
180 
181 	switch (ap->a_command) {
182 	case HPFSIOCGEANUM: {
183 		u_long eanum;
184 		u_long passed;
185 		struct ea *eap;
186 
187 		eanum = 0;
188 
189 		if (hp->h_fn.fn_ealen > 0) {
190 			eap = (struct ea *)&(hp->h_fn.fn_int);
191 			passed = 0;
192 
193 			while (passed < hp->h_fn.fn_ealen) {
194 
195 				printf("EAname: %s\n", EA_NAME(eap));
196 
197 				eanum++;
198 				passed += sizeof(struct ea) +
199 					  eap->ea_namelen + 1 + eap->ea_vallen;
200 				eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
201 						passed);
202 			}
203 			error = 0;
204 		} else {
205 			error = ENOENT;
206 		}
207 
208 		printf("%lu eas\n", eanum);
209 
210 		*(u_long *)ap->a_data = eanum;
211 
212 		break;
213 	}
214 	case HPFSIOCGEASZ: {
215 		u_long eanum;
216 		u_long passed;
217 		struct ea *eap;
218 
219 		printf("EA%ld\n", *(u_long *)ap->a_data);
220 
221 		eanum = 0;
222 		if (hp->h_fn.fn_ealen > 0) {
223 			eap = (struct ea *)&(hp->h_fn.fn_int);
224 			passed = 0;
225 
226 			error = ENOENT;
227 			while (passed < hp->h_fn.fn_ealen) {
228 				printf("EAname: %s\n", EA_NAME(eap));
229 
230 				if (eanum == *(u_long *)ap->a_data) {
231 					*(u_long *)ap->a_data =
232 					  	eap->ea_namelen + 1 +
233 						eap->ea_vallen;
234 
235 					error = 0;
236 					break;
237 				}
238 
239 				eanum++;
240 				passed += sizeof(struct ea) +
241 					  eap->ea_namelen + 1 + eap->ea_vallen;
242 				eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
243 						passed);
244 			}
245 		} else {
246 			error = ENOENT;
247 		}
248 
249 		break;
250 	}
251 	case HPFSIOCRDEA: {
252 		u_long eanum;
253 		u_long passed;
254 		struct hpfs_rdea *rdeap;
255 		struct ea *eap;
256 
257 		rdeap = (struct hpfs_rdea *)ap->a_data;
258 		printf("EA%ld\n", rdeap->ea_no);
259 
260 		eanum = 0;
261 		if (hp->h_fn.fn_ealen > 0) {
262 			eap = (struct ea *)&(hp->h_fn.fn_int);
263 			passed = 0;
264 
265 			error = ENOENT;
266 			while (passed < hp->h_fn.fn_ealen) {
267 				printf("EAname: %s\n", EA_NAME(eap));
268 
269 				if (eanum == rdeap->ea_no) {
270 					rdeap->ea_sz = eap->ea_namelen + 1 +
271 							eap->ea_vallen;
272 					copyout(EA_NAME(eap),rdeap->ea_data,
273 						rdeap->ea_sz);
274 					error = 0;
275 					break;
276 				}
277 
278 				eanum++;
279 				passed += sizeof(struct ea) +
280 					  eap->ea_namelen + 1 + eap->ea_vallen;
281 				eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
282 						passed);
283 			}
284 		} else {
285 			error = ENOENT;
286 		}
287 
288 		break;
289 	}
290 	default:
291 		error = EOPNOTSUPP;
292 		break;
293 	}
294 	return (error);
295 }
296 
297 /*
298  * Map file offset to disk offset.
299  */
300 int
301 hpfs_bmap(ap)
302 	struct vop_bmap_args /* {
303 		struct vnode *a_vp;
304 		daddr_t  a_bn;
305 		struct vnode **a_vpp;
306 		daddr_t *a_bnp;
307 		int *a_runp;
308 		int *a_runb;
309 	} */ *ap;
310 {
311 	struct hpfsnode *hp = VTOHP(ap->a_vp);
312 	int error;
313 
314 	if (ap->a_vpp != NULL)
315 		*ap->a_vpp = hp->h_devvp;
316 #if defined(__FreeBSD__)
317 	if (ap->a_runb != NULL)
318 		*ap->a_runb = 0;
319 #endif
320 	if (ap->a_bnp == NULL)
321 		return (0);
322 
323 	dprintf(("hpfs_bmap(0x%x, 0x%x): ",hp->h_no, ap->a_bn));
324 
325 	error = hpfs_hpbmap (hp, ap->a_bn, ap->a_bnp, ap->a_runp);
326 
327 	return (error);
328 }
329 
330 static int
331 hpfs_read(ap)
332 	struct vop_read_args /* {
333 		struct vnode *a_vp;
334 		struct uio *a_uio;
335 		int a_ioflag;
336 		struct ucred *a_cred;
337 	} */ *ap;
338 {
339 	struct vnode *vp = ap->a_vp;
340 	struct hpfsnode *hp = VTOHP(vp);
341 	struct uio *uio = ap->a_uio;
342 	struct buf *bp;
343 	u_int xfersz, toread;
344 	u_int off;
345 	daddr_t lbn, bn;
346 	int resid;
347 	int runl;
348 	int error = 0;
349 
350 	resid = min (uio->uio_resid, hp->h_fn.fn_size - uio->uio_offset);
351 
352 	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));
353 
354 	while (resid) {
355 		lbn = uio->uio_offset >> DEV_BSHIFT;
356 		off = uio->uio_offset & (DEV_BSIZE - 1);
357 		dprintf(("hpfs_read: resid: 0x%x lbn: 0x%x off: 0x%x\n",
358 			uio->uio_resid, lbn, off));
359 		error = hpfs_hpbmap(hp, lbn, &bn, &runl);
360 		if (error)
361 			return (error);
362 
363 		toread = min(off + resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE));
364 		xfersz = (toread + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
365 		dprintf(("hpfs_read: bn: 0x%x (0x%x) toread: 0x%x (0x%x)\n",
366 			bn, runl, toread, xfersz));
367 
368 		if (toread == 0)
369 			break;
370 
371 		error = bread(hp->h_devvp, bn, xfersz, &bp);
372 		if (error) {
373 			brelse(bp);
374 			break;
375 		}
376 
377 		error = uiomove(bp->b_data + off, toread - off, uio);
378 		if(error) {
379 			brelse(bp);
380 			break;
381 		}
382 		brelse(bp);
383 		resid -= toread;
384 	}
385 	dprintf(("hpfs_read: successful\n"));
386 	return (error);
387 }
388 
389 static int
390 hpfs_write(ap)
391 	struct vop_write_args /* {
392 		struct vnode *a_vp;
393 		struct uio *a_uio;
394 		int  a_ioflag;
395 		struct ucred *a_cred;
396 	} */ *ap;
397 {
398 	struct vnode *vp = ap->a_vp;
399 	struct hpfsnode *hp = VTOHP(vp);
400 	struct uio *uio = ap->a_uio;
401 	struct buf *bp;
402 	u_int xfersz, towrite;
403 	u_int off;
404 	daddr_t lbn, bn;
405 	int runl;
406 	int error = 0;
407 
408 	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));
409 
410 	if (ap->a_ioflag & IO_APPEND) {
411 		dprintf(("hpfs_write: APPEND mode\n"));
412 		uio->uio_offset = hp->h_fn.fn_size;
413 	}
414 	if (uio->uio_offset + uio->uio_resid > hp->h_fn.fn_size) {
415 		error = hpfs_extend (hp, uio->uio_offset + uio->uio_resid);
416 		if (error) {
417 			printf("hpfs_write: hpfs_extend FAILED %d\n", error);
418 			return (error);
419 		}
420 	}
421 
422 	while (uio->uio_resid) {
423 		lbn = uio->uio_offset >> DEV_BSHIFT;
424 		off = uio->uio_offset & (DEV_BSIZE - 1);
425 		dprintf(("hpfs_write: resid: 0x%x lbn: 0x%x off: 0x%x\n",
426 			uio->uio_resid, lbn, off));
427 		error = hpfs_hpbmap(hp, lbn, &bn, &runl);
428 		if (error)
429 			return (error);
430 
431 		towrite = min(off + uio->uio_resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE));
432 		xfersz = (towrite + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
433 		dprintf(("hpfs_write: bn: 0x%x (0x%x) towrite: 0x%x (0x%x)\n",
434 			bn, runl, towrite, xfersz));
435 
436 		if ((off == 0) && (towrite == xfersz)) {
437 			bp = getblk(hp->h_devvp, bn, xfersz, 0, 0);
438 			clrbuf(bp);
439 		} else {
440 			error = bread(hp->h_devvp, bn, xfersz, &bp);
441 			if (error) {
442 				brelse(bp);
443 				return (error);
444 			}
445 		}
446 
447 		error = uiomove(bp->b_data + off, towrite - off, uio);
448 		if(error) {
449 			brelse(bp);
450 			return (error);
451 		}
452 
453 		if (ap->a_ioflag & IO_SYNC)
454 			bwrite(bp);
455 		else
456 			bawrite(bp);
457 	}
458 
459 	dprintf(("hpfs_write: successful\n"));
460 	return (0);
461 }
462 
463 /*
464  * XXXXX do we need hpfsnode locking inside?
465  */
466 static int
467 hpfs_getattr(ap)
468 	struct vop_getattr_args /* {
469 		struct vnode *a_vp;
470 		struct vattr *a_vap;
471 		struct ucred *a_cred;
472 		struct proc *a_td;
473 	} */ *ap;
474 {
475 	struct vnode *vp = ap->a_vp;
476 	struct hpfsnode *hp = VTOHP(vp);
477 	struct vattr *vap = ap->a_vap;
478 	int error;
479 
480 	dprintf(("hpfs_getattr(0x%x):\n", hp->h_no));
481 
482 #if defined(__FreeBSD__)
483 	vap->va_fsid = dev2udev(hp->h_dev);
484 #else /* defined(__NetBSD__) */
485 	vap->va_fsid = ip->i_dev;
486 #endif
487 	vap->va_fileid = hp->h_no;
488 	vap->va_mode = hp->h_mode;
489 	vap->va_nlink = 1;
490 	vap->va_uid = hp->h_uid;
491 	vap->va_gid = hp->h_gid;
492 	vap->va_rdev = 0;				/* XXX UNODEV ? */
493 	vap->va_size = hp->h_fn.fn_size;
494 	vap->va_bytes = ((hp->h_fn.fn_size + DEV_BSIZE-1) & ~(DEV_BSIZE-1)) +
495 			DEV_BSIZE;
496 
497 	if (!(hp->h_flag & H_PARVALID)) {
498 		error = hpfs_validateparent(hp);
499 		if (error)
500 			return (error);
501 	}
502 	vap->va_atime = hpfstimetounix(hp->h_atime);
503 	vap->va_mtime = hpfstimetounix(hp->h_mtime);
504 	vap->va_ctime = hpfstimetounix(hp->h_ctime);
505 
506 	vap->va_flags = 0;
507 	vap->va_gen = 0;
508 	vap->va_blocksize = DEV_BSIZE;
509 	vap->va_type = vp->v_type;
510 	vap->va_filerev = 0;
511 
512 	return (0);
513 }
514 
515 /*
516  * XXXXX do we need hpfsnode locking inside?
517  */
518 static int
519 hpfs_setattr(ap)
520 	struct vop_setattr_args /* {
521 		struct vnode *a_vp;
522 		struct vattr *a_vap;
523 		struct ucred *a_cred;
524 		struct thread *a_td;
525 	} */ *ap;
526 {
527 	struct vnode *vp = ap->a_vp;
528 	struct hpfsnode *hp = VTOHP(vp);
529 	struct vattr *vap = ap->a_vap;
530 	struct ucred *cred = ap->a_cred;
531 	struct thread *td = ap->a_td;
532 	int error;
533 
534 	dprintf(("hpfs_setattr(0x%x):\n", hp->h_no));
535 
536 	/*
537 	 * Check for unsettable attributes.
538 	 */
539 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
540 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
541 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
542 	    (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
543 		dprintf(("hpfs_setattr: changing nonsettable attr\n"));
544 		return (EINVAL);
545 	}
546 
547 	/* Can't change flags XXX Could be implemented */
548 	if (vap->va_flags != VNOVAL) {
549 		printf("hpfs_setattr: FLAGS CANNOT BE SET\n");
550 		return (EINVAL);
551 	}
552 
553 	/* Can't change uid/gid XXX Could be implemented */
554 	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
555 		printf("hpfs_setattr: UID/GID CANNOT BE SET\n");
556 		return (EINVAL);
557 	}
558 
559 	/* Can't change mode XXX Could be implemented */
560 	if (vap->va_mode != (mode_t)VNOVAL) {
561 		printf("hpfs_setattr: MODE CANNOT BE SET\n");
562 		return (EINVAL);
563 	}
564 
565 	/* Update times */
566 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
567 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
568 			return (EROFS);
569 		if (cred->cr_uid != hp->h_uid &&
570 		    (error = suser_cred(cred, PRISON_ROOT)) &&
571 		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
572 		    (error = VOP_ACCESS(vp, VWRITE, cred, td))))
573 			return (error);
574 		if (vap->va_atime.tv_sec != VNOVAL)
575 			hp->h_atime = vap->va_atime.tv_sec;
576 		if (vap->va_mtime.tv_sec != VNOVAL)
577 			hp->h_mtime = vap->va_mtime.tv_sec;
578 
579 		hp->h_flag |= H_PARCHANGE;
580 	}
581 
582 	if (vap->va_size != VNOVAL) {
583 		switch (vp->v_type) {
584 		case VDIR:
585 			return (EISDIR);
586 		case VREG:
587 			if (vp->v_mount->mnt_flag & MNT_RDONLY)
588 				return (EROFS);
589 			break;
590 		default:
591 			printf("hpfs_setattr: WRONG v_type\n");
592 			return (EINVAL);
593 		}
594 
595 		if (vap->va_size < hp->h_fn.fn_size) {
596 #if defined(__FreeBSD__)
597 			error = vtruncbuf(vp, td, vap->va_size, DEV_BSIZE);
598 			if (error)
599 				return (error);
600 #else /* defined(__NetBSD__) */
601 #error Need alternation for vtruncbuf()
602 #endif
603 			error = hpfs_truncate(hp, vap->va_size);
604 			if (error)
605 				return (error);
606 
607 		} else if (vap->va_size > hp->h_fn.fn_size) {
608 #if defined(__FreeBSD__)
609 			vnode_pager_setsize(vp, vap->va_size);
610 #endif
611 			error = hpfs_extend(hp, vap->va_size);
612 			if (error)
613 				return (error);
614 		}
615 	}
616 
617 	return (0);
618 }
619 
620 /*
621  * Last reference to an node.  If necessary, write or delete it.
622  */
623 int
624 hpfs_inactive(ap)
625 	struct vop_inactive_args /* {
626 		struct vnode *a_vp;
627 	} */ *ap;
628 {
629 	struct vnode *vp = ap->a_vp;
630 	struct hpfsnode *hp = VTOHP(vp);
631 	int error;
632 
633 	dprintf(("hpfs_inactive(0x%x): \n", hp->h_no));
634 
635 	if (hp->h_flag & H_CHANGE) {
636 		dprintf(("hpfs_inactive: node changed, update\n"));
637 		error = hpfs_update (hp);
638 		if (error)
639 			return (error);
640 	}
641 
642 	if (hp->h_flag & H_PARCHANGE) {
643 		dprintf(("hpfs_inactive: parent node changed, update\n"));
644 		error = hpfs_updateparent (hp);
645 		if (error)
646 			return (error);
647 	}
648 
649 	if (prtactive && vp->v_usecount != 0)
650 		vprint("hpfs_inactive: pushing active", vp);
651 
652 	if (hp->h_flag & H_INVAL) {
653 		VOP__UNLOCK(vp,0,ap->a_td);
654 #if defined(__FreeBSD__)
655 		vrecycle(vp, NULL, ap->a_td);
656 #else /* defined(__NetBSD__) */
657 		vgone(vp);
658 #endif
659 		return (0);
660 	}
661 
662 	VOP__UNLOCK(vp,0,ap->a_td);
663 	return (0);
664 }
665 
666 /*
667  * Reclaim an inode so that it can be used for other purposes.
668  */
669 int
670 hpfs_reclaim(ap)
671 	struct vop_reclaim_args /* {
672 		struct vnode *a_vp;
673 	} */ *ap;
674 {
675 	struct vnode *vp = ap->a_vp;
676 	struct hpfsnode *hp = VTOHP(vp);
677 
678 	dprintf(("hpfs_reclaim(0x%x0): \n", hp->h_no));
679 
680 	hpfs_hphashrem(hp);
681 
682 	/* Purge old data structures associated with the inode. */
683 	cache_purge(vp);
684 	if (hp->h_devvp) {
685 		vrele(hp->h_devvp);
686 		hp->h_devvp = NULL;
687 	}
688 
689 	vp->v_data = NULL;
690 
691 	FREE(hp, M_HPFSNO);
692 
693 	return (0);
694 }
695 
696 static int
697 hpfs_print(ap)
698 	struct vop_print_args /* {
699 		struct vnode *a_vp;
700 	} */ *ap;
701 {
702 	struct vnode *vp = ap->a_vp;
703 	struct hpfsnode *hp = VTOHP(vp);
704 
705 	printf("tag VT_HPFS, ino 0x%x",hp->h_no);
706 	lockmgr_printinfo(&hp->h_lock);
707 	printf("\n");
708 	return (0);
709 }
710 
711 /*
712  * Calculate the logical to physical mapping if not done already,
713  * then call the device strategy routine.
714  *
715  * In order to be able to swap to a file, the VOP_BMAP operation may not
716  * deadlock on memory.  See hpfs_bmap() for details. XXXXXXX (not impl)
717  */
718 int
719 hpfs_strategy(ap)
720 	struct vop_strategy_args /* {
721 		struct buf *a_bp;
722 	} */ *ap;
723 {
724 	struct buf *bp = ap->a_bp;
725 	struct vnode *vp = ap->a_vp;
726 	struct vnode *nvp;
727 	int error;
728 
729 	dprintf(("hpfs_strategy(): \n"));
730 
731 	if (vp->v_type == VBLK || vp->v_type == VCHR)
732 		panic("hpfs_strategy: spec");
733 	if (bp->b_blkno == bp->b_lblkno) {
734 		error = VOP_BMAP(vp, bp->b_lblkno, &nvp, &bp->b_blkno, NULL, NULL);
735 		if (error) {
736 			printf("hpfs_strategy: VOP_BMAP FAILED %d\n", error);
737 			bp->b_error = error;
738 			bp->b_flags |= B_ERROR;
739 			biodone(bp);
740 			return (error);
741 		}
742 		if ((long)bp->b_blkno == -1)
743 			vfs_bio_clrbuf(bp);
744 	}
745 	if ((long)bp->b_blkno == -1) {
746 		biodone(bp);
747 		return (0);
748 	}
749 	bp->b_dev = nvp->v_rdev;
750 	VOP_STRATEGY(nvp, bp);
751 	return (0);
752 }
753 
754 /*
755  * XXXXX do we need hpfsnode locking inside?
756  */
757 int
758 hpfs_access(ap)
759 	struct vop_access_args /* {
760 		struct vnode *a_vp;
761 		int  a_mode;
762 		struct ucred *a_cred;
763 		struct proc *a_td;
764 	} */ *ap;
765 {
766 	struct vnode *vp = ap->a_vp;
767 	struct hpfsnode *hp = VTOHP(vp);
768 	struct ucred *cred = ap->a_cred;
769 	mode_t mask, mode = ap->a_mode;
770 	gid_t *gp;
771 	int i;
772 
773 	dprintf(("hpfs_access(0x%x):\n", hp->h_no));
774 
775 	/*
776 	 * Disallow write attempts on read-only file systems;
777 	 * unless the file is a socket, fifo, or a block or
778 	 * character device resident on the file system.
779 	 */
780 	if (mode & VWRITE) {
781 		switch ((int)vp->v_type) {
782 		case VDIR:
783 		case VLNK:
784 		case VREG:
785 			if (vp->v_mount->mnt_flag & MNT_RDONLY)
786 				return (EROFS);
787 			break;
788 		}
789 	}
790 
791 	/* Otherwise, user id 0 always gets access. */
792 	if (cred->cr_uid == 0)
793 		return (0);
794 
795 	mask = 0;
796 
797 	/* Otherwise, check the owner. */
798 	if (cred->cr_uid == hp->h_uid) {
799 		if (mode & VEXEC)
800 			mask |= S_IXUSR;
801 		if (mode & VREAD)
802 			mask |= S_IRUSR;
803 		if (mode & VWRITE)
804 			mask |= S_IWUSR;
805 		return ((hp->h_mode & mask) == mask ? 0 : EACCES);
806 	}
807 
808 	/* Otherwise, check the groups. */
809 	for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
810 		if (hp->h_gid == *gp) {
811 			if (mode & VEXEC)
812 				mask |= S_IXGRP;
813 			if (mode & VREAD)
814 				mask |= S_IRGRP;
815 			if (mode & VWRITE)
816 				mask |= S_IWGRP;
817 			return ((hp->h_mode & mask) == mask ? 0 : EACCES);
818 		}
819 
820 	/* Otherwise, check everyone else. */
821 	if (mode & VEXEC)
822 		mask |= S_IXOTH;
823 	if (mode & VREAD)
824 		mask |= S_IROTH;
825 	if (mode & VWRITE)
826 		mask |= S_IWOTH;
827 	return ((hp->h_mode & mask) == mask ? 0 : EACCES);
828 }
829 
830 /*
831  * Open called.
832  *
833  * Nothing to do.
834  */
835 /* ARGSUSED */
836 static int
837 hpfs_open(ap)
838 	struct vop_open_args /* {
839 		struct vnode *a_vp;
840 		int  a_mode;
841 		struct ucred *a_cred;
842 		struct proc *a_td;
843 	} */ *ap;
844 {
845 #if HPFS_DEBUG
846 	struct vnode *vp = ap->a_vp;
847 	struct hpfsnode *hp = VTOHP(vp);
848 
849 	printf("hpfs_open(0x%x):\n",hp->h_no);
850 #endif
851 
852 	/*
853 	 * Files marked append-only must be opened for appending.
854 	 */
855 
856 	return (0);
857 }
858 
859 /*
860  * Close called.
861  *
862  * Update the times on the inode.
863  */
864 /* ARGSUSED */
865 static int
866 hpfs_close(ap)
867 	struct vop_close_args /* {
868 		struct vnode *a_vp;
869 		int  a_fflag;
870 		struct ucred *a_cred;
871 		struct proc *a_td;
872 	} */ *ap;
873 {
874 #if HPFS_DEBUG
875 	struct vnode *vp = ap->a_vp;
876 	struct hpfsnode *hp = VTOHP(vp);
877 
878 	printf("hpfs_close: %d\n",hp->h_no);
879 #endif
880 
881 	return (0);
882 }
883 
884 static int
885 hpfs_de_uiomove (
886 	struct hpfsmount *hpmp,
887 	struct hpfsdirent *dep,
888 	struct uio *uio)
889 {
890 	struct dirent cde;
891 	int i, error;
892 
893 	dprintf(("[no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x] ",
894 		dep->de_fnode, dep->de_size, dep->de_namelen,
895 		dep->de_namelen, dep->de_name, dep->de_flag));
896 
897 	/*strncpy(cde.d_name, dep->de_name, dep->de_namelen);*/
898 	for (i=0; i<dep->de_namelen; i++)
899 		cde.d_name[i] = hpfs_d2u(hpmp, dep->de_name[i]);
900 
901 	cde.d_name[dep->de_namelen] = '\0';
902 	cde.d_namlen = dep->de_namelen;
903 	cde.d_fileno = dep->de_fnode;
904 	cde.d_type = (dep->de_flag & DE_DIR) ? DT_DIR : DT_REG;
905 	cde.d_reclen = sizeof(struct dirent);
906 
907 	error = uiomove((char *)&cde, sizeof(struct dirent), uio);
908 	if (error)
909 		return (error);
910 
911 	dprintf(("[0x%x] ", uio->uio_resid));
912 	return (error);
913 }
914 
915 
916 static struct dirent hpfs_de_dot =
917 	{ 0, sizeof(struct dirent), DT_DIR, 1, "." };
918 static struct dirent hpfs_de_dotdot =
919 	{ 0, sizeof(struct dirent), DT_DIR, 2, ".." };
920 int
921 hpfs_readdir(ap)
922 	struct vop_readdir_args /* {
923 		struct vnode *a_vp;
924 		struct uio *a_uio;
925 		struct ucred *a_cred;
926 		int *a_ncookies;
927 		u_int **cookies;
928 	} */ *ap;
929 {
930 	struct vnode *vp = ap->a_vp;
931 	struct hpfsnode *hp = VTOHP(vp);
932 	struct hpfsmount *hpmp = hp->h_hpmp;
933 	struct uio *uio = ap->a_uio;
934 	int ncookies = 0, i, num, cnum;
935 	int error = 0;
936 	off_t off;
937 	struct buf *bp;
938 	struct dirblk *dp;
939 	struct hpfsdirent *dep;
940 	lsn_t olsn;
941 	lsn_t lsn;
942 	int level;
943 
944 	dprintf(("hpfs_readdir(0x%x, 0x%x, 0x%x): ",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid));
945 
946 	off = uio->uio_offset;
947 
948 	if( uio->uio_offset < sizeof(struct dirent) ) {
949 		dprintf((". faked, "));
950 		hpfs_de_dot.d_fileno = hp->h_no;
951 		error = uiomove((char *)&hpfs_de_dot,sizeof(struct dirent),uio);
952 		if(error) {
953 			return (error);
954 		}
955 
956 		ncookies ++;
957 	}
958 
959 	if( uio->uio_offset < 2 * sizeof(struct dirent) ) {
960 		dprintf((".. faked, "));
961 		hpfs_de_dotdot.d_fileno = hp->h_fn.fn_parent;
962 
963 		error = uiomove((char *)&hpfs_de_dotdot, sizeof(struct dirent),
964 				uio);
965 		if(error) {
966 			return (error);
967 		}
968 
969 		ncookies ++;
970 	}
971 
972 	num = uio->uio_offset / sizeof(struct dirent) - 2;
973 	cnum = 0;
974 
975 	lsn = ((alleaf_t *)hp->h_fn.fn_abd)->al_lsn;
976 
977 	olsn = 0;
978 	level = 1;
979 
980 dive:
981 	dprintf(("[dive 0x%x] ", lsn));
982 	error = bread(hp->h_devvp, lsn, D_BSIZE, &bp);
983 	if (error) {
984 		brelse(bp);
985 		return (error);
986 	}
987 
988 	dp = (struct dirblk *) bp->b_data;
989 	if (dp->d_magic != D_MAGIC) {
990 		printf("hpfs_readdir: MAGIC DOESN'T MATCH\n");
991 		brelse(bp);
992 		return (EINVAL);
993 	}
994 
995 	dep = D_DIRENT(dp);
996 
997 	if (olsn) {
998 		dprintf(("[restore 0x%x] ", olsn));
999 
1000 		while(!(dep->de_flag & DE_END) ) {
1001 			if((dep->de_flag & DE_DOWN) &&
1002 			   (olsn == DE_DOWNLSN(dep)))
1003 					 break;
1004 			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
1005 		}
1006 
1007 		if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
1008 			if (dep->de_flag & DE_END)
1009 				goto blockdone;
1010 
1011 			if (!(dep->de_flag & DE_SPECIAL)) {
1012 				if (num <= cnum) {
1013 					if (uio->uio_resid < sizeof(struct dirent)) {
1014 						brelse(bp);
1015 						dprintf(("[resid] "));
1016 						goto readdone;
1017 					}
1018 
1019 					error = hpfs_de_uiomove(hpmp, dep, uio);
1020 					if (error) {
1021 						brelse (bp);
1022 						return (error);
1023 					}
1024 					ncookies++;
1025 
1026 					if (uio->uio_resid < sizeof(struct dirent)) {
1027 						brelse(bp);
1028 						dprintf(("[resid] "));
1029 						goto readdone;
1030 					}
1031 				}
1032 				cnum++;
1033 			}
1034 
1035 			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
1036 		} else {
1037 			printf("hpfs_readdir: ERROR! oLSN not found\n");
1038 			brelse(bp);
1039 			return (EINVAL);
1040 		}
1041 	}
1042 
1043 	olsn = 0;
1044 
1045 	while(!(dep->de_flag & DE_END)) {
1046 		if(dep->de_flag & DE_DOWN) {
1047 			lsn = DE_DOWNLSN(dep);
1048 			brelse(bp);
1049 			level++;
1050 			goto dive;
1051 		}
1052 
1053 		if (!(dep->de_flag & DE_SPECIAL)) {
1054 			if (num <= cnum) {
1055 				if (uio->uio_resid < sizeof(struct dirent)) {
1056 					brelse(bp);
1057 					dprintf(("[resid] "));
1058 					goto readdone;
1059 				}
1060 
1061 				error = hpfs_de_uiomove(hpmp, dep, uio);
1062 				if (error) {
1063 					brelse (bp);
1064 					return (error);
1065 				}
1066 				ncookies++;
1067 
1068 				if (uio->uio_resid < sizeof(struct dirent)) {
1069 					brelse(bp);
1070 					dprintf(("[resid] "));
1071 					goto readdone;
1072 				}
1073 			}
1074 			cnum++;
1075 		}
1076 
1077 		dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
1078 	}
1079 
1080 	if(dep->de_flag & DE_DOWN) {
1081 		dprintf(("[enddive] "));
1082 		lsn = DE_DOWNLSN(dep);
1083 		brelse(bp);
1084 		level++;
1085 		goto dive;
1086 	}
1087 
1088 blockdone:
1089 	dprintf(("[EOB] "));
1090 	olsn = lsn;
1091 	lsn = dp->d_parent;
1092 	brelse(bp);
1093 	level--;
1094 
1095 	dprintf(("[level %d] ", level));
1096 
1097 	if (level > 0)
1098 		goto dive;	/* undive really */
1099 
1100 	if (ap->a_eofflag) {
1101 	    dprintf(("[EOF] "));
1102 	    *ap->a_eofflag = 1;
1103 	}
1104 
1105 readdone:
1106 	dprintf(("[readdone]\n"));
1107 	if (!error && ap->a_ncookies != NULL) {
1108 		struct dirent* dpStart;
1109 		struct dirent* dp;
1110 #if defined(__FreeBSD__)
1111 		u_long *cookies;
1112 		u_long *cookiep;
1113 #else /* defined(__NetBSD__) */
1114 		off_t *cookies;
1115 		off_t *cookiep;
1116 #endif
1117 
1118 		dprintf(("%d cookies, ",ncookies));
1119 		if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1120 			panic("hpfs_readdir: unexpected uio from NFS server");
1121 		dpStart = (struct dirent *)
1122 		     ((caddr_t)uio->uio_iov->iov_base -
1123 			 (uio->uio_offset - off));
1124 #if defined(__FreeBSD__)
1125 		MALLOC(cookies, u_long *, ncookies * sizeof(u_long),
1126 		       M_TEMP, M_WAITOK);
1127 #else /* defined(__NetBSD__) */
1128 		MALLOC(cookies, off_t *, ncookies * sizeof(off_t),
1129 		       M_TEMP, M_WAITOK);
1130 #endif
1131 		for (dp = dpStart, cookiep = cookies, i=0;
1132 		     i < ncookies;
1133 		     dp = (struct dirent *)((caddr_t) dp + dp->d_reclen), i++) {
1134 			off += dp->d_reclen;
1135 			*cookiep++ = (u_int) off;
1136 		}
1137 		*ap->a_ncookies = ncookies;
1138 		*ap->a_cookies = cookies;
1139 	}
1140 
1141 	return (0);
1142 }
1143 
1144 int
1145 hpfs_lookup(ap)
1146 	struct vop_lookup_args /* {
1147 		struct vnode *a_dvp;
1148 		struct vnode **a_vpp;
1149 		struct componentname *a_cnp;
1150 	} */ *ap;
1151 {
1152 	struct vnode *dvp = ap->a_dvp;
1153 	struct hpfsnode *dhp = VTOHP(dvp);
1154 	struct hpfsmount *hpmp = dhp->h_hpmp;
1155 	struct componentname *cnp = ap->a_cnp;
1156 	struct ucred *cred = cnp->cn_cred;
1157 	int error;
1158 	int nameiop = cnp->cn_nameiop;
1159 	int flags = cnp->cn_flags;
1160 	int lockparent = flags & CNP_LOCKPARENT;
1161 #if HPFS_DEBUG
1162 	int wantparent = flags & (CNP_LOCKPARENT | CNP_WANTPARENT);
1163 #endif
1164 	dprintf(("hpfs_lookup(0x%x, %s, %ld, %d, %d): \n",
1165 		dhp->h_no, cnp->cn_nameptr, cnp->cn_namelen,
1166 		lockparent, wantparent));
1167 
1168 	if (nameiop != NAMEI_CREATE && nameiop != NAMEI_DELETE && nameiop != NAMEI_LOOKUP) {
1169 		printf("hpfs_lookup: LOOKUP, DELETE and CREATE are only supported\n");
1170 		return (EOPNOTSUPP);
1171 	}
1172 
1173 	error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_td);
1174 	if(error)
1175 		return (error);
1176 
1177 	if( (cnp->cn_namelen == 1) &&
1178 	    !strncmp(cnp->cn_nameptr,".",1) ) {
1179 		dprintf(("hpfs_lookup(0x%x,...): . faked\n",dhp->h_no));
1180 
1181 		VREF(dvp);
1182 		*ap->a_vpp = dvp;
1183 
1184 		return (0);
1185 	} else if( (cnp->cn_namelen == 2) &&
1186 	    !strncmp(cnp->cn_nameptr,"..",2) && (flags & CNP_ISDOTDOT) ) {
1187 		dprintf(("hpfs_lookup(0x%x,...): .. faked (0x%x)\n",
1188 			dhp->h_no, dhp->h_fn.fn_parent));
1189 
1190 		VOP__UNLOCK(dvp,0,cnp->cn_td);
1191 
1192 		error = VFS_VGET(hpmp->hpm_mp,
1193 				 dhp->h_fn.fn_parent, ap->a_vpp);
1194 		if(error) {
1195 			VOP__LOCK(dvp, 0, cnp->cn_td);
1196 			return(error);
1197 		}
1198 
1199 		if( lockparent && (flags & CNP_ISLASTCN) &&
1200 		    (error = VOP__LOCK(dvp, 0, cnp->cn_td)) ) {
1201 			vput( *(ap->a_vpp) );
1202 			return (error);
1203 		}
1204 		return (error);
1205 	} else {
1206 		struct buf *bp;
1207 		struct hpfsdirent *dep;
1208 		struct hpfsnode *hp;
1209 
1210 		error = hpfs_genlookupbyname(dhp,
1211 				cnp->cn_nameptr, cnp->cn_namelen, &bp, &dep);
1212 		if (error) {
1213 			if ((error == ENOENT) && (flags & CNP_ISLASTCN) &&
1214 			    (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME)) {
1215 				if(!lockparent)
1216 					VOP__UNLOCK(dvp, 0, cnp->cn_td);
1217 				cnp->cn_flags |= CNP_SAVENAME;
1218 				return (EJUSTRETURN);
1219 			}
1220 
1221 			return (error);
1222 		}
1223 
1224 		dprintf(("hpfs_lookup: fnode: 0x%x, CPID: 0x%x\n",
1225 			 dep->de_fnode, dep->de_cpid));
1226 
1227 		if (nameiop == NAMEI_DELETE && (flags & CNP_ISLASTCN)) {
1228 			error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_td);
1229 			if (error) {
1230 				brelse(bp);
1231 				return (error);
1232 			}
1233 		}
1234 
1235 		if (dhp->h_no == dep->de_fnode) {
1236 			brelse(bp);
1237 			VREF(dvp);
1238 			*ap->a_vpp = dvp;
1239 			return (0);
1240 		}
1241 
1242 		error = VFS_VGET(hpmp->hpm_mp, dep->de_fnode, ap->a_vpp);
1243 		if (error) {
1244 			printf("hpfs_lookup: VFS_VGET FAILED %d\n", error);
1245 			brelse(bp);
1246 			return(error);
1247 		}
1248 
1249 		hp = VTOHP(*ap->a_vpp);
1250 
1251 		hp->h_mtime = dep->de_mtime;
1252 		hp->h_ctime = dep->de_ctime;
1253 		hp->h_atime = dep->de_atime;
1254 		bcopy(dep->de_name, hp->h_name, dep->de_namelen);
1255 		hp->h_name[dep->de_namelen] = '\0';
1256 		hp->h_namelen = dep->de_namelen;
1257 		hp->h_flag |= H_PARVALID;
1258 
1259 		brelse(bp);
1260 
1261 		if(!lockparent || !(flags & CNP_ISLASTCN))
1262 			VOP__UNLOCK(dvp, 0, cnp->cn_td);
1263 		if ((flags & CNP_MAKEENTRY) &&
1264 		    (!(flags & CNP_ISLASTCN) ||
1265 		     (nameiop != NAMEI_DELETE && nameiop != NAMEI_CREATE)))
1266 			cache_enter(dvp, NCPNULL, *ap->a_vpp, cnp);
1267 	}
1268 	return (error);
1269 }
1270 
1271 int
1272 hpfs_remove(ap)
1273 	struct vop_remove_args /* {
1274 		struct vnode *a_dvp;
1275 		struct vnode *a_vp;
1276 		struct componentname *a_cnp;
1277 	} */ *ap;
1278 {
1279 	int error;
1280 
1281 	dprintf(("hpfs_remove(0x%x, %s, %ld): \n", VTOHP(ap->a_vp)->h_no,
1282 		ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
1283 
1284 	if (ap->a_vp->v_type == VDIR)
1285 		return (EPERM);
1286 
1287 	error = hpfs_removefnode (ap->a_dvp, ap->a_vp, ap->a_cnp);
1288 	return (error);
1289 }
1290 
1291 int
1292 hpfs_create(ap)
1293 	struct vop_create_args /* {
1294 		struct vnode *a_dvp;
1295 		struct vnode **a_vpp;
1296 		struct componentname *a_cnp;
1297 		struct vattr *a_vap;
1298 	} */ *ap;
1299 {
1300 	int error;
1301 
1302 	dprintf(("hpfs_create(0x%x, %s, %ld): \n", VTOHP(ap->a_dvp)->h_no,
1303 		ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
1304 
1305 	if (!(ap->a_cnp->cn_flags & CNP_HASBUF))
1306 		panic ("hpfs_create: no name\n");
1307 
1308 	error = hpfs_makefnode (ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
1309 
1310 	return (error);
1311 }
1312 
1313 /*
1314  * Return POSIX pathconf information applicable to NTFS filesystem
1315  */
1316 int
1317 hpfs_pathconf(ap)
1318 	struct vop_pathconf_args /* {
1319 		struct vnode *a_vp;
1320 		int a_name;
1321 		t *a_retval;
1322 	} */ *ap;
1323 {
1324 	switch (ap->a_name) {
1325 	case _PC_LINK_MAX:
1326 		*ap->a_retval = 1;
1327 		return (0);
1328 	case _PC_NAME_MAX:
1329 		*ap->a_retval = HPFS_MAXFILENAME;
1330 		return (0);
1331 	case _PC_PATH_MAX:
1332 		*ap->a_retval = PATH_MAX;
1333 		return (0);
1334 	case _PC_CHOWN_RESTRICTED:
1335 		*ap->a_retval = 1;
1336 		return (0);
1337 	case _PC_NO_TRUNC:
1338 		*ap->a_retval = 0;
1339 		return (0);
1340 #if defined(__NetBSD__)
1341 	case _PC_SYNC_IO:
1342 		*ap->a_retval = 1;
1343 		return (0);
1344 	case _PC_FILESIZEBITS:
1345 		*ap->a_retval = 32;
1346 		return (0);
1347 #endif
1348 	default:
1349 		return (EINVAL);
1350 	}
1351 	/* NOTREACHED */
1352 }
1353 
1354 
1355 /*
1356  * Global vfs data structures
1357  */
1358 vop_t **hpfs_vnodeop_p;
1359 #if defined(__FreeBSD__)
1360 struct vnodeopv_entry_desc hpfs_vnodeop_entries[] = {
1361 	{ &vop_default_desc, (vop_t *)vop_defaultop },
1362 
1363 	{ &vop_getattr_desc, (vop_t *)hpfs_getattr },
1364 	{ &vop_setattr_desc, (vop_t *)hpfs_setattr },
1365 	{ &vop_inactive_desc, (vop_t *)hpfs_inactive },
1366 	{ &vop_reclaim_desc, (vop_t *)hpfs_reclaim },
1367 	{ &vop_print_desc, (vop_t *)hpfs_print },
1368 	{ &vop_create_desc, (vop_t *)hpfs_create },
1369 	{ &vop_remove_desc, (vop_t *)hpfs_remove },
1370 	{ &vop_islocked_desc, (vop_t *)vop_stdislocked },
1371 	{ &vop_unlock_desc, (vop_t *)vop_stdunlock },
1372 	{ &vop_lock_desc, (vop_t *)vop_stdlock },
1373 	{ &vop_cachedlookup_desc, (vop_t *)hpfs_lookup },
1374 	{ &vop_lookup_desc, (vop_t *)vfs_cache_lookup },
1375 	{ &vop_access_desc, (vop_t *)hpfs_access },
1376 	{ &vop_close_desc, (vop_t *)hpfs_close },
1377 	{ &vop_open_desc, (vop_t *)hpfs_open },
1378 	{ &vop_readdir_desc, (vop_t *)hpfs_readdir },
1379 	{ &vop_fsync_desc, (vop_t *)hpfs_fsync },
1380 	{ &vop_bmap_desc, (vop_t *)hpfs_bmap },
1381 	{ &vop_getpages_desc, (vop_t *) hpfs_getpages },
1382 	{ &vop_putpages_desc, (vop_t *) hpfs_putpages },
1383 	{ &vop_strategy_desc, (vop_t *)hpfs_strategy },
1384 	{ &vop_bwrite_desc, (vop_t *)vop_stdbwrite },
1385 	{ &vop_read_desc, (vop_t *)hpfs_read },
1386 	{ &vop_write_desc, (vop_t *)hpfs_write },
1387 	{ &vop_ioctl_desc, (vop_t *)hpfs_ioctl },
1388 	{ &vop_pathconf_desc, (vop_t *)hpfs_pathconf },
1389 	{ NULL, NULL }
1390 };
1391 
1392 static
1393 struct vnodeopv_desc hpfs_vnodeop_opv_desc =
1394 	{ &hpfs_vnodeop_p, hpfs_vnodeop_entries };
1395 
1396 VNODEOP_SET(hpfs_vnodeop_opv_desc);
1397 #else /* defined(__NetBSD__) */
1398 struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = {
1399 	{ &vop_default_desc, (vop_t *) genfs_badop },	/* XXX */
1400 	{ &vop_lookup_desc, (vop_t *) hpfs_lookup },	/* lookup */
1401 	{ &vop_create_desc, genfs_eopnotsupp },		/* create */
1402 	{ &vop_mknod_desc, genfs_eopnotsupp },		/* mknod */
1403 	{ &vop_open_desc, (vop_t *) hpfs_open },	/* open */
1404 	{ &vop_close_desc,(vop_t *) hpfs_close },	/* close */
1405 	{ &vop_access_desc, (vop_t *) hpfs_access },	/* access */
1406 	{ &vop_getattr_desc, (vop_t *) hpfs_getattr },	/* getattr */
1407 	{ &vop_setattr_desc, genfs_eopnotsupp },	/* setattr */
1408 	{ &vop_read_desc, (vop_t *) hpfs_read },	/* read */
1409 	{ &vop_write_desc, (vop_t *) hpfs_write },	/* write */
1410 	{ &vop_lease_desc, genfs_lease_check },		/* lease */
1411 	{ &vop_fcntl_desc, genfs_fcntl },		/* fcntl */
1412 	{ &vop_ioctl_desc, genfs_enoioctl },		/* ioctl */
1413 	{ &vop_poll_desc, genfs_poll },			/* poll */
1414 	{ &vop_revoke_desc, genfs_revoke },		/* revoke */
1415 	{ &vop_mmap_desc, genfs_eopnotsupp },		/* mmap */
1416 	{ &vop_fsync_desc, genfs_fsync },		/* fsync */
1417 	{ &vop_seek_desc, genfs_seek },			/* seek */
1418 	{ &vop_remove_desc, genfs_eopnotsupp },		/* remove */
1419 	{ &vop_link_desc, genfs_eopnotsupp },		/* link */
1420 	{ &vop_rename_desc, genfs_eopnotsupp },		/* rename */
1421 	{ &vop_mkdir_desc, genfs_eopnotsupp },		/* mkdir */
1422 	{ &vop_rmdir_desc, genfs_eopnotsupp },		/* rmdir */
1423 	{ &vop_symlink_desc, genfs_eopnotsupp },	/* symlink */
1424 	{ &vop_readdir_desc, (vop_t *) hpfs_readdir },	/* readdir */
1425 	{ &vop_readlink_desc, genfs_eopnotsupp },	/* readlink */
1426 	{ &vop_abortop_desc, genfs_abortop },		/* abortop */
1427 	{ &vop_inactive_desc, (vop_t *) hpfs_inactive },	/* inactive */
1428 	{ &vop_reclaim_desc, (vop_t *) hpfs_reclaim },	/* reclaim */
1429 	{ &vop_lock_desc, genfs_lock },			/* lock */
1430 	{ &vop_unlock_desc, genfs_unlock },		/* unlock */
1431 	{ &vop_bmap_desc, (vop_t *) hpfs_bmap },	/* bmap */
1432 	{ &vop_strategy_desc, (vop_t *) hpfs_strategy },	/* strategy */
1433 	{ &vop_print_desc, (vop_t *) hpfs_print },	/* print */
1434 	{ &vop_islocked_desc, genfs_islocked },		/* islocked */
1435 	{ &vop_pathconf_desc, hpfs_pathconf },		/* pathconf */
1436 	{ &vop_advlock_desc, genfs_nullop },		/* advlock */
1437 	{ &vop_blkatoff_desc, genfs_eopnotsupp },	/* blkatoff */
1438 	{ &vop_valloc_desc, genfs_eopnotsupp },		/* valloc */
1439 	{ &vop_reallocblks_desc, genfs_eopnotsupp },	/* reallocblks */
1440 	{ &vop_vfree_desc, genfs_eopnotsupp },		/* vfree */
1441 	{ &vop_truncate_desc, genfs_eopnotsupp },	/* truncate */
1442 	{ &vop_update_desc, genfs_eopnotsupp },		/* update */
1443 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
1444 	{ (struct vnodeop_desc *)NULL, (int (*) (void *))NULL }
1445 };
1446 struct vnodeopv_desc ntfs_vnodeop_opv_desc =
1447 	{ &ntfs_vnodeop_p, ntfs_vnodeop_entries };
1448 
1449 #endif
1450