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