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