154371Ssemenu/*-
254371Ssemenu * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
354371Ssemenu * All rights reserved.
454371Ssemenu *
554371Ssemenu * Redistribution and use in source and binary forms, with or without
654371Ssemenu * modification, are permitted provided that the following conditions
754371Ssemenu * are met:
854371Ssemenu * 1. Redistributions of source code must retain the above copyright
954371Ssemenu *    notice, this list of conditions and the following disclaimer.
1054371Ssemenu * 2. Redistributions in binary form must reproduce the above copyright
1154371Ssemenu *    notice, this list of conditions and the following disclaimer in the
1254371Ssemenu *    documentation and/or other materials provided with the distribution.
1354371Ssemenu *
1454371Ssemenu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1554371Ssemenu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1654371Ssemenu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1754371Ssemenu * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1854371Ssemenu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1954371Ssemenu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2054371Ssemenu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2154371Ssemenu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2254371Ssemenu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2354371Ssemenu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2454371Ssemenu * SUCH DAMAGE.
2554371Ssemenu *
2654371Ssemenu * $FreeBSD$
2754371Ssemenu */
2854371Ssemenu
2954371Ssemenu#include <sys/param.h>
3054371Ssemenu#include <sys/systm.h>
3154371Ssemenu#include <sys/kernel.h>
3254371Ssemenu#include <sys/proc.h>
33143588Sphk#include <sys/conf.h>
3454371Ssemenu#include <sys/time.h>
3554371Ssemenu#include <sys/types.h>
3654371Ssemenu#include <sys/stat.h>
3754371Ssemenu#include <sys/vnode.h>
3854371Ssemenu#include <sys/mount.h>
3954371Ssemenu#include <sys/namei.h>
4054371Ssemenu#include <sys/malloc.h>
4160041Sphk#include <sys/bio.h>
4254371Ssemenu#include <sys/buf.h>
4354371Ssemenu#include <sys/dirent.h>
4454371Ssemenu
4554371Ssemenu#include <vm/vm.h>
4654371Ssemenu#include <vm/vm_param.h>
4754371Ssemenu#include <vm/vm_page.h>
4854371Ssemenu#include <vm/vm_object.h>
4954371Ssemenu#include <vm/vm_pager.h>
5054371Ssemenu#include <vm/vnode_pager.h>
5154371Ssemenu#include <vm/vm_extern.h>
5254371Ssemenu
5354371Ssemenu#include <sys/unistd.h> /* for pathconf(2) constants */
5454371Ssemenu
5554371Ssemenu#include <fs/hpfs/hpfs.h>
5654371Ssemenu#include <fs/hpfs/hpfsmount.h>
5754371Ssemenu#include <fs/hpfs/hpfs_subr.h>
5854371Ssemenu#include <fs/hpfs/hpfs_ioctl.h>
5954371Ssemenu
6092727Salfredstatic int	hpfs_de_uiomove(struct hpfsmount *, struct hpfsdirent *,
6192727Salfred				     struct uio *);
62138270Sphkstatic vop_ioctl_t	hpfs_ioctl;
63138270Sphkstatic vop_read_t	hpfs_read;
64138270Sphkstatic vop_write_t	hpfs_write;
65138270Sphkstatic vop_getattr_t	hpfs_getattr;
66138270Sphkstatic vop_setattr_t	hpfs_setattr;
67138270Sphkstatic vop_inactive_t	hpfs_inactive;
68138270Sphkstatic vop_print_t	hpfs_print;
69138270Sphkstatic vop_reclaim_t	hpfs_reclaim;
70138270Sphkstatic vop_strategy_t	hpfs_strategy;
71138270Sphkstatic vop_access_t	hpfs_access;
72138270Sphkstatic vop_open_t	hpfs_open;
73138270Sphkstatic vop_close_t	hpfs_close;
74138270Sphkstatic vop_readdir_t	hpfs_readdir;
75138279Sphkstatic vop_cachedlookup_t	hpfs_lookup;
76138270Sphkstatic vop_create_t	hpfs_create;
77138270Sphkstatic vop_remove_t	hpfs_remove;
78138270Sphkstatic vop_bmap_t	hpfs_bmap;
79138270Sphkstatic vop_fsync_t	hpfs_fsync;
80138270Sphkstatic vop_pathconf_t	hpfs_pathconf;
81166774Spjdstatic vop_vptofh_t	hpfs_vptofh;
8254371Ssemenu
8354371Ssemenustatic int
8454371Ssemenuhpfs_fsync(ap)
8554371Ssemenu	struct vop_fsync_args /* {
8654371Ssemenu		struct vnode *a_vp;
8754371Ssemenu		struct ucred *a_cred;
8854371Ssemenu		int a_waitfor;
8983366Sjulian		struct thread *a_td;
9054371Ssemenu	} */ *ap;
9154371Ssemenu{
9254371Ssemenu	/*
93110584Sjeff	 * Flush our dirty buffers.
9454371Ssemenu	 */
95110584Sjeff	vop_stdfsync(ap);
9654371Ssemenu
9754371Ssemenu	/*
9854371Ssemenu	 * Write out the on-disc version of the vnode.
9954371Ssemenu	 */
100110584Sjeff	return hpfs_update(VTOHP(ap->a_vp));
10154371Ssemenu}
10254371Ssemenu
10354371Ssemenustatic int
10454371Ssemenuhpfs_ioctl (
10554371Ssemenu	struct vop_ioctl_args /* {
10654371Ssemenu		struct vnode *a_vp;
10754371Ssemenu		u_long a_command;
10854371Ssemenu		caddr_t a_data;
10954371Ssemenu		int a_fflag;
11054371Ssemenu		struct ucred *a_cred;
11186928Sjhb		struct thread *a_td;
11254371Ssemenu	} */ *ap)
11354371Ssemenu{
11454371Ssemenu	register struct vnode *vp = ap->a_vp;
11554371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
11654371Ssemenu	int error;
11754371Ssemenu
11854371Ssemenu	printf("hpfs_ioctl(0x%x, 0x%lx, 0x%p, 0x%x): ",
11954371Ssemenu		hp->h_no, ap->a_command, ap->a_data, ap->a_fflag);
12054371Ssemenu
12154371Ssemenu	switch (ap->a_command) {
12254371Ssemenu	case HPFSIOCGEANUM: {
12354371Ssemenu		u_long eanum;
12454371Ssemenu		u_long passed;
12554371Ssemenu		struct ea *eap;
12654371Ssemenu
12754371Ssemenu		eanum = 0;
12854371Ssemenu
12954371Ssemenu		if (hp->h_fn.fn_ealen > 0) {
13054371Ssemenu			eap = (struct ea *)&(hp->h_fn.fn_int);
13154371Ssemenu			passed = 0;
13254371Ssemenu
13354371Ssemenu			while (passed < hp->h_fn.fn_ealen) {
13454371Ssemenu
13554371Ssemenu				printf("EAname: %s\n", EA_NAME(eap));
13654371Ssemenu
13754371Ssemenu				eanum++;
13854371Ssemenu				passed += sizeof(struct ea) +
13954371Ssemenu					  eap->ea_namelen + 1 + eap->ea_vallen;
14054371Ssemenu				eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
14154371Ssemenu						passed);
14254371Ssemenu			}
14354371Ssemenu			error = 0;
14454371Ssemenu		} else {
14554371Ssemenu			error = ENOENT;
14654371Ssemenu		}
14754371Ssemenu
14854371Ssemenu		printf("%lu eas\n", eanum);
14954371Ssemenu
15054371Ssemenu		*(u_long *)ap->a_data = eanum;
15154371Ssemenu
15254371Ssemenu		break;
15354371Ssemenu	}
15454371Ssemenu	case HPFSIOCGEASZ: {
15554371Ssemenu		u_long eanum;
15654371Ssemenu		u_long passed;
15754371Ssemenu		struct ea *eap;
15854371Ssemenu
15954371Ssemenu		printf("EA%ld\n", *(u_long *)ap->a_data);
16054371Ssemenu
16154371Ssemenu		eanum = 0;
16254371Ssemenu		if (hp->h_fn.fn_ealen > 0) {
16354371Ssemenu			eap = (struct ea *)&(hp->h_fn.fn_int);
16454371Ssemenu			passed = 0;
16554371Ssemenu
16654371Ssemenu			error = ENOENT;
16754371Ssemenu			while (passed < hp->h_fn.fn_ealen) {
16854371Ssemenu				printf("EAname: %s\n", EA_NAME(eap));
16954371Ssemenu
17054371Ssemenu				if (eanum == *(u_long *)ap->a_data) {
17154371Ssemenu					*(u_long *)ap->a_data =
17254371Ssemenu					  	eap->ea_namelen + 1 +
17354371Ssemenu						eap->ea_vallen;
17454371Ssemenu
17554371Ssemenu					error = 0;
17654371Ssemenu					break;
17754371Ssemenu				}
17854371Ssemenu
17954371Ssemenu				eanum++;
18054371Ssemenu				passed += sizeof(struct ea) +
18154371Ssemenu					  eap->ea_namelen + 1 + eap->ea_vallen;
18254371Ssemenu				eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
18354371Ssemenu						passed);
18454371Ssemenu			}
18554371Ssemenu		} else {
18654371Ssemenu			error = ENOENT;
18754371Ssemenu		}
18854371Ssemenu
18954371Ssemenu		break;
19054371Ssemenu	}
19154371Ssemenu	case HPFSIOCRDEA: {
19254371Ssemenu		u_long eanum;
19354371Ssemenu		u_long passed;
19454371Ssemenu		struct hpfs_rdea *rdeap;
19554371Ssemenu		struct ea *eap;
19654371Ssemenu
19754371Ssemenu		rdeap = (struct hpfs_rdea *)ap->a_data;
19854371Ssemenu		printf("EA%ld\n", rdeap->ea_no);
19954371Ssemenu
20054371Ssemenu		eanum = 0;
20154371Ssemenu		if (hp->h_fn.fn_ealen > 0) {
20254371Ssemenu			eap = (struct ea *)&(hp->h_fn.fn_int);
20354371Ssemenu			passed = 0;
20454371Ssemenu
20554371Ssemenu			error = ENOENT;
20654371Ssemenu			while (passed < hp->h_fn.fn_ealen) {
20754371Ssemenu				printf("EAname: %s\n", EA_NAME(eap));
20854371Ssemenu
20954371Ssemenu				if (eanum == rdeap->ea_no) {
21054371Ssemenu					rdeap->ea_sz = eap->ea_namelen + 1 +
21154371Ssemenu							eap->ea_vallen;
21254371Ssemenu					copyout(EA_NAME(eap),rdeap->ea_data,
21354371Ssemenu						rdeap->ea_sz);
21454371Ssemenu					error = 0;
21554371Ssemenu					break;
21654371Ssemenu				}
21754371Ssemenu
21854371Ssemenu				eanum++;
21954371Ssemenu				passed += sizeof(struct ea) +
22054371Ssemenu					  eap->ea_namelen + 1 + eap->ea_vallen;
22154371Ssemenu				eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
22254371Ssemenu						passed);
22354371Ssemenu			}
22454371Ssemenu		} else {
22554371Ssemenu			error = ENOENT;
22654371Ssemenu		}
22754371Ssemenu
22854371Ssemenu		break;
22954371Ssemenu	}
23054371Ssemenu	default:
231104003Sphk		error = ENOTTY;
23254371Ssemenu		break;
23354371Ssemenu	}
23454371Ssemenu	return (error);
23554371Ssemenu}
23654371Ssemenu
23754371Ssemenu/*
23854371Ssemenu * Map file offset to disk offset.
23954371Ssemenu */
24054371Ssemenuint
24154371Ssemenuhpfs_bmap(ap)
24254371Ssemenu	struct vop_bmap_args /* {
24354371Ssemenu		struct vnode *a_vp;
24454371Ssemenu		daddr_t  a_bn;
245137726Sphk		struct bufobj **a_bop;
24654371Ssemenu		daddr_t *a_bnp;
24754371Ssemenu		int *a_runp;
24854371Ssemenu		int *a_runb;
24954371Ssemenu	} */ *ap;
25054371Ssemenu{
25154371Ssemenu	register struct hpfsnode *hp = VTOHP(ap->a_vp);
25292363Smckusick	daddr_t blkno;
25354371Ssemenu	int error;
25454371Ssemenu
255137726Sphk	if (ap->a_bop != NULL)
256137726Sphk		*ap->a_bop = &hp->h_devvp->v_bufobj;
25754371Ssemenu	if (ap->a_runb != NULL)
25854371Ssemenu		*ap->a_runb = 0;
25954371Ssemenu	if (ap->a_bnp == NULL)
26054371Ssemenu		return (0);
26154371Ssemenu
26254371Ssemenu	dprintf(("hpfs_bmap(0x%x, 0x%x): ",hp->h_no, ap->a_bn));
26354371Ssemenu
26492363Smckusick	error = hpfs_hpbmap (hp, ap->a_bn, &blkno, ap->a_runp);
26592363Smckusick	*ap->a_bnp = blkno;
26654371Ssemenu
26754371Ssemenu	return (error);
26854371Ssemenu}
26954371Ssemenu
27054371Ssemenustatic int
27154371Ssemenuhpfs_read(ap)
27254371Ssemenu	struct vop_read_args /* {
27354371Ssemenu		struct vnode *a_vp;
27454371Ssemenu		struct uio *a_uio;
27554371Ssemenu		int a_ioflag;
27654371Ssemenu		struct ucred *a_cred;
27754371Ssemenu	} */ *ap;
27854371Ssemenu{
27954371Ssemenu	register struct vnode *vp = ap->a_vp;
28054371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
28154371Ssemenu	struct uio *uio = ap->a_uio;
28254371Ssemenu	struct buf *bp;
28354371Ssemenu	u_int xfersz, toread;
28454371Ssemenu	u_int off;
28554371Ssemenu	daddr_t lbn, bn;
28654371Ssemenu	int resid;
28754371Ssemenu	int runl;
28854371Ssemenu	int error = 0;
28954371Ssemenu
29054371Ssemenu	resid = min (uio->uio_resid, hp->h_fn.fn_size - uio->uio_offset);
29154371Ssemenu
29254371Ssemenu	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));
29354371Ssemenu
29454371Ssemenu	while (resid) {
29554371Ssemenu		lbn = uio->uio_offset >> DEV_BSHIFT;
29654371Ssemenu		off = uio->uio_offset & (DEV_BSIZE - 1);
29754371Ssemenu		dprintf(("hpfs_read: resid: 0x%x lbn: 0x%x off: 0x%x\n",
29854371Ssemenu			uio->uio_resid, lbn, off));
29954371Ssemenu		error = hpfs_hpbmap(hp, lbn, &bn, &runl);
30054371Ssemenu		if (error)
30154371Ssemenu			return (error);
30254371Ssemenu
30354371Ssemenu		toread = min(off + resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE));
30454371Ssemenu		xfersz = (toread + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
30554371Ssemenu		dprintf(("hpfs_read: bn: 0x%x (0x%x) toread: 0x%x (0x%x)\n",
30654371Ssemenu			bn, runl, toread, xfersz));
30754371Ssemenu
30854371Ssemenu		if (toread == 0)
30954371Ssemenu			break;
31054371Ssemenu
31154371Ssemenu		error = bread(hp->h_devvp, bn, xfersz, NOCRED, &bp);
31254371Ssemenu		if (error) {
31354371Ssemenu			brelse(bp);
31454371Ssemenu			break;
31554371Ssemenu		}
31654371Ssemenu
31754371Ssemenu		error = uiomove(bp->b_data + off, toread - off, uio);
31854371Ssemenu		if(error) {
31954371Ssemenu			brelse(bp);
32054371Ssemenu			break;
32154371Ssemenu		}
32254371Ssemenu		brelse(bp);
32354371Ssemenu		resid -= toread;
32454371Ssemenu	}
32554371Ssemenu	dprintf(("hpfs_read: successful\n"));
32654371Ssemenu	return (error);
32754371Ssemenu}
32854371Ssemenu
32954371Ssemenustatic int
33054371Ssemenuhpfs_write(ap)
33154371Ssemenu	struct vop_write_args /* {
33254371Ssemenu		struct vnode *a_vp;
33354371Ssemenu		struct uio *a_uio;
33454371Ssemenu		int  a_ioflag;
33554371Ssemenu		struct ucred *a_cred;
33654371Ssemenu	} */ *ap;
33754371Ssemenu{
33854371Ssemenu	register struct vnode *vp = ap->a_vp;
33954371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
34054371Ssemenu	struct uio *uio = ap->a_uio;
34154371Ssemenu	struct buf *bp;
34254371Ssemenu	u_int xfersz, towrite;
34354371Ssemenu	u_int off;
34454371Ssemenu	daddr_t lbn, bn;
34554371Ssemenu	int runl;
34654371Ssemenu	int error = 0;
34754371Ssemenu
34854371Ssemenu	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));
34954371Ssemenu
35054371Ssemenu	if (ap->a_ioflag & IO_APPEND) {
35154371Ssemenu		dprintf(("hpfs_write: APPEND mode\n"));
35254371Ssemenu		uio->uio_offset = hp->h_fn.fn_size;
35354371Ssemenu	}
35454371Ssemenu	if (uio->uio_offset + uio->uio_resid > hp->h_fn.fn_size) {
35554371Ssemenu		error = hpfs_extend (hp, uio->uio_offset + uio->uio_resid);
35654371Ssemenu		if (error) {
35754371Ssemenu			printf("hpfs_write: hpfs_extend FAILED %d\n", error);
35854371Ssemenu			return (error);
35954371Ssemenu		}
36054371Ssemenu	}
36154371Ssemenu
36254371Ssemenu	while (uio->uio_resid) {
36354371Ssemenu		lbn = uio->uio_offset >> DEV_BSHIFT;
36454371Ssemenu		off = uio->uio_offset & (DEV_BSIZE - 1);
36554371Ssemenu		dprintf(("hpfs_write: resid: 0x%x lbn: 0x%x off: 0x%x\n",
36654371Ssemenu			uio->uio_resid, lbn, off));
36754371Ssemenu		error = hpfs_hpbmap(hp, lbn, &bn, &runl);
36854371Ssemenu		if (error)
36954371Ssemenu			return (error);
37054371Ssemenu
37154371Ssemenu		towrite = min(off + uio->uio_resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE));
37254371Ssemenu		xfersz = (towrite + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
37354371Ssemenu		dprintf(("hpfs_write: bn: 0x%x (0x%x) towrite: 0x%x (0x%x)\n",
37454371Ssemenu			bn, runl, towrite, xfersz));
37554371Ssemenu
37654371Ssemenu		if ((off == 0) && (towrite == xfersz)) {
377111856Sjeff			bp = getblk(hp->h_devvp, bn, xfersz, 0, 0, 0);
37854371Ssemenu			clrbuf(bp);
37954371Ssemenu		} else {
38054371Ssemenu			error = bread(hp->h_devvp, bn, xfersz, NOCRED, &bp);
38154371Ssemenu			if (error) {
38254371Ssemenu				brelse(bp);
38354371Ssemenu				return (error);
38454371Ssemenu			}
38554371Ssemenu		}
38654371Ssemenu
38754371Ssemenu		error = uiomove(bp->b_data + off, towrite - off, uio);
38854371Ssemenu		if(error) {
38954371Ssemenu			brelse(bp);
39054371Ssemenu			return (error);
39154371Ssemenu		}
39254371Ssemenu
39354371Ssemenu		if (ap->a_ioflag & IO_SYNC)
39454371Ssemenu			bwrite(bp);
39554371Ssemenu		else
39654371Ssemenu			bawrite(bp);
39754371Ssemenu	}
39854371Ssemenu
39954371Ssemenu	dprintf(("hpfs_write: successful\n"));
40054371Ssemenu	return (0);
40154371Ssemenu}
40254371Ssemenu
40354371Ssemenu/*
40454371Ssemenu * XXXXX do we need hpfsnode locking inside?
40554371Ssemenu */
40654371Ssemenustatic int
40754371Ssemenuhpfs_getattr(ap)
40854371Ssemenu	struct vop_getattr_args /* {
40954371Ssemenu		struct vnode *a_vp;
41054371Ssemenu		struct vattr *a_vap;
41154371Ssemenu		struct ucred *a_cred;
41254371Ssemenu	} */ *ap;
41354371Ssemenu{
41454371Ssemenu	register struct vnode *vp = ap->a_vp;
41554371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
41654371Ssemenu	register struct vattr *vap = ap->a_vap;
41754371Ssemenu	int error;
41854371Ssemenu
41954371Ssemenu	dprintf(("hpfs_getattr(0x%x):\n", hp->h_no));
42054371Ssemenu
42154371Ssemenu	vap->va_fsid = dev2udev(hp->h_dev);
42254371Ssemenu	vap->va_fileid = hp->h_no;
42354371Ssemenu	vap->va_mode = hp->h_mode;
42454371Ssemenu	vap->va_nlink = 1;
42554371Ssemenu	vap->va_uid = hp->h_uid;
42654371Ssemenu	vap->va_gid = hp->h_gid;
427183214Skib	vap->va_rdev = NODEV;
42854371Ssemenu	vap->va_size = hp->h_fn.fn_size;
42954371Ssemenu	vap->va_bytes = ((hp->h_fn.fn_size + DEV_BSIZE-1) & ~(DEV_BSIZE-1)) +
43054371Ssemenu			DEV_BSIZE;
43154371Ssemenu
43254371Ssemenu	if (!(hp->h_flag & H_PARVALID)) {
43354371Ssemenu		error = hpfs_validateparent(hp);
43454371Ssemenu		if (error)
43554371Ssemenu			return (error);
43654371Ssemenu	}
43754371Ssemenu	vap->va_atime = hpfstimetounix(hp->h_atime);
43854371Ssemenu	vap->va_mtime = hpfstimetounix(hp->h_mtime);
43954371Ssemenu	vap->va_ctime = hpfstimetounix(hp->h_ctime);
44054371Ssemenu
44154371Ssemenu	vap->va_flags = 0;
44254371Ssemenu	vap->va_gen = 0;
44354371Ssemenu	vap->va_blocksize = DEV_BSIZE;
44454371Ssemenu	vap->va_type = vp->v_type;
44554371Ssemenu	vap->va_filerev = 0;
44654371Ssemenu
44754371Ssemenu	return (0);
44854371Ssemenu}
44954371Ssemenu
45054371Ssemenu/*
45154371Ssemenu * XXXXX do we need hpfsnode locking inside?
45254371Ssemenu */
45354371Ssemenustatic int
45454371Ssemenuhpfs_setattr(ap)
45554371Ssemenu	struct vop_setattr_args /* {
45654371Ssemenu		struct vnode *a_vp;
45754371Ssemenu		struct vattr *a_vap;
45854371Ssemenu		struct ucred *a_cred;
45954371Ssemenu	} */ *ap;
46054371Ssemenu{
46154371Ssemenu	struct vnode *vp = ap->a_vp;
46254371Ssemenu	struct hpfsnode *hp = VTOHP(vp);
46354371Ssemenu	struct vattr *vap = ap->a_vap;
46454371Ssemenu	struct ucred *cred = ap->a_cred;
465182371Sattilio	struct thread *td = curthread;
46654371Ssemenu	int error;
46754371Ssemenu
46854371Ssemenu	dprintf(("hpfs_setattr(0x%x):\n", hp->h_no));
46954371Ssemenu
47054371Ssemenu	/*
47154371Ssemenu	 * Check for unsettable attributes.
47254371Ssemenu	 */
47354371Ssemenu	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
47454371Ssemenu	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
47554371Ssemenu	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
47654371Ssemenu	    (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
47754371Ssemenu		dprintf(("hpfs_setattr: changing nonsettable attr\n"));
47854371Ssemenu		return (EINVAL);
47954371Ssemenu	}
48054371Ssemenu
48154371Ssemenu	/* Can't change flags XXX Could be implemented */
48254371Ssemenu	if (vap->va_flags != VNOVAL) {
48354371Ssemenu		printf("hpfs_setattr: FLAGS CANNOT BE SET\n");
48454371Ssemenu		return (EINVAL);
48554371Ssemenu	}
48654371Ssemenu
48754371Ssemenu	/* Can't change uid/gid XXX Could be implemented */
48854371Ssemenu	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
48954371Ssemenu		printf("hpfs_setattr: UID/GID CANNOT BE SET\n");
49054371Ssemenu		return (EINVAL);
49154371Ssemenu	}
49254371Ssemenu
49354371Ssemenu	/* Can't change mode XXX Could be implemented */
49454371Ssemenu	if (vap->va_mode != (mode_t)VNOVAL) {
49554371Ssemenu		printf("hpfs_setattr: MODE CANNOT BE SET\n");
49654371Ssemenu		return (EINVAL);
49754371Ssemenu	}
49854371Ssemenu
49954371Ssemenu	/* Update times */
50054371Ssemenu	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
50154371Ssemenu		if (vp->v_mount->mnt_flag & MNT_RDONLY)
50254371Ssemenu			return (EROFS);
503164033Srwatson		if (vap->va_vaflags & VA_UTIMES_NULL) {
504164033Srwatson			error = VOP_ACCESS(vp, VADMIN, cred, td);
505164033Srwatson			if (error)
506164033Srwatson				error = VOP_ACCESS(vp, VWRITE, cred, td);
507164033Srwatson		} else
508164033Srwatson			error = VOP_ACCESS(vp, VADMIN, cred, td);
50954371Ssemenu		if (vap->va_atime.tv_sec != VNOVAL)
51054371Ssemenu			hp->h_atime = vap->va_atime.tv_sec;
51154371Ssemenu		if (vap->va_mtime.tv_sec != VNOVAL)
51254371Ssemenu			hp->h_mtime = vap->va_mtime.tv_sec;
51354371Ssemenu
51454371Ssemenu		hp->h_flag |= H_PARCHANGE;
51554371Ssemenu	}
51654371Ssemenu
51754371Ssemenu	if (vap->va_size != VNOVAL) {
51854371Ssemenu		switch (vp->v_type) {
51954371Ssemenu		case VDIR:
52054371Ssemenu			return (EISDIR);
52154371Ssemenu		case VREG:
52254371Ssemenu			if (vp->v_mount->mnt_flag & MNT_RDONLY)
52354371Ssemenu				return (EROFS);
52454371Ssemenu			break;
52554371Ssemenu		default:
52654371Ssemenu			printf("hpfs_setattr: WRONG v_type\n");
52754371Ssemenu			return (EINVAL);
52854371Ssemenu		}
52954371Ssemenu
53054371Ssemenu		if (vap->va_size < hp->h_fn.fn_size) {
53186931Sjhb			error = vtruncbuf(vp, cred, td, vap->va_size, DEV_BSIZE);
53254371Ssemenu			if (error)
53354371Ssemenu				return (error);
53454371Ssemenu			error = hpfs_truncate(hp, vap->va_size);
53554371Ssemenu			if (error)
53654371Ssemenu				return (error);
53754371Ssemenu
53854371Ssemenu		} else if (vap->va_size > hp->h_fn.fn_size) {
53954371Ssemenu			vnode_pager_setsize(vp, vap->va_size);
54054371Ssemenu			error = hpfs_extend(hp, vap->va_size);
54154371Ssemenu			if (error)
54254371Ssemenu				return (error);
54354371Ssemenu		}
54454371Ssemenu	}
54554371Ssemenu
54654371Ssemenu	return (0);
54754371Ssemenu}
54854371Ssemenu
54954371Ssemenu/*
550108470Sschweikh * Last reference to a node.  If necessary, write or delete it.
55154371Ssemenu */
55254371Ssemenuint
55354371Ssemenuhpfs_inactive(ap)
55454371Ssemenu	struct vop_inactive_args /* {
55554371Ssemenu		struct vnode *a_vp;
55654371Ssemenu	} */ *ap;
55754371Ssemenu{
55854371Ssemenu	register struct vnode *vp = ap->a_vp;
55954371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
56054371Ssemenu	int error;
56154371Ssemenu
56254371Ssemenu	dprintf(("hpfs_inactive(0x%x): \n", hp->h_no));
56354371Ssemenu
56454371Ssemenu	if (hp->h_flag & H_CHANGE) {
56554371Ssemenu		dprintf(("hpfs_inactive: node changed, update\n"));
56654371Ssemenu		error = hpfs_update (hp);
56754371Ssemenu		if (error)
56854371Ssemenu			return (error);
56954371Ssemenu	}
57054371Ssemenu
57154371Ssemenu	if (hp->h_flag & H_PARCHANGE) {
57254371Ssemenu		dprintf(("hpfs_inactive: parent node changed, update\n"));
57354371Ssemenu		error = hpfs_updateparent (hp);
57454371Ssemenu		if (error)
57554371Ssemenu			return (error);
57654371Ssemenu	}
57754371Ssemenu
57854371Ssemenu	if (hp->h_flag & H_INVAL) {
579140936Sphk		vrecycle(vp, ap->a_td);
58054371Ssemenu		return (0);
58154371Ssemenu	}
58254371Ssemenu
58354371Ssemenu	return (0);
58454371Ssemenu}
58554371Ssemenu
58654371Ssemenu/*
58754371Ssemenu * Reclaim an inode so that it can be used for other purposes.
58854371Ssemenu */
58954371Ssemenuint
59054371Ssemenuhpfs_reclaim(ap)
59154371Ssemenu	struct vop_reclaim_args /* {
59254371Ssemenu		struct vnode *a_vp;
59354371Ssemenu	} */ *ap;
59454371Ssemenu{
59554371Ssemenu	register struct vnode *vp = ap->a_vp;
59654371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
59754371Ssemenu
59854371Ssemenu	dprintf(("hpfs_reclaim(0x%x0): \n", hp->h_no));
59954371Ssemenu
600154487Salfred	/*
601154487Salfred	 * Destroy the vm object and flush associated pages.
602154487Salfred	 */
603154487Salfred	vnode_destroy_vobject(vp);
604154487Salfred
605143588Sphk	vfs_hash_remove(vp);
60654371Ssemenu
60771576Sjasone	mtx_destroy(&hp->h_interlock);
60871509Sjhb
60954371Ssemenu	vp->v_data = NULL;
61054371Ssemenu
611184205Sdes	free(hp, M_HPFSNO);
61254371Ssemenu
61354371Ssemenu	return (0);
61454371Ssemenu}
61554371Ssemenu
61654371Ssemenustatic int
61754371Ssemenuhpfs_print(ap)
61854371Ssemenu	struct vop_print_args /* {
61954371Ssemenu		struct vnode *a_vp;
62054371Ssemenu	} */ *ap;
62154371Ssemenu{
62254371Ssemenu	register struct vnode *vp = ap->a_vp;
62354371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
62454371Ssemenu
625111841Snjl	printf("\tino 0x%x\n", hp->h_no);
62654371Ssemenu	return (0);
62754371Ssemenu}
62854371Ssemenu
62954371Ssemenu/*
63054371Ssemenu * Calculate the logical to physical mapping if not done already,
63154371Ssemenu * then call the device strategy routine.
63254371Ssemenu *
63376159Sphk * In order to be able to swap to a file, the hpfs_hpbmap operation may not
63454371Ssemenu * deadlock on memory.  See hpfs_bmap() for details. XXXXXXX (not impl)
63554371Ssemenu */
63654371Ssemenuint
63754371Ssemenuhpfs_strategy(ap)
63854371Ssemenu	struct vop_strategy_args /* {
63954371Ssemenu		struct buf *a_bp;
64054371Ssemenu	} */ *ap;
64154371Ssemenu{
64254371Ssemenu	register struct buf *bp = ap->a_bp;
64354371Ssemenu	register struct vnode *vp = ap->a_vp;
64476159Sphk	register struct hpfsnode *hp = VTOHP(ap->a_vp);
64592363Smckusick	daddr_t blkno;
646137040Sphk	struct bufobj *bo;
64754371Ssemenu	int error;
64854371Ssemenu
64954371Ssemenu	dprintf(("hpfs_strategy(): \n"));
65054371Ssemenu
65154371Ssemenu	if (vp->v_type == VBLK || vp->v_type == VCHR)
65254371Ssemenu		panic("hpfs_strategy: spec");
65354371Ssemenu	if (bp->b_blkno == bp->b_lblkno) {
65492363Smckusick		error = hpfs_hpbmap (hp, bp->b_lblkno, &blkno, NULL);
65592363Smckusick		bp->b_blkno = blkno;
65654371Ssemenu		if (error) {
65776159Sphk			printf("hpfs_strategy: hpfs_bpbmap FAILED %d\n", error);
65854371Ssemenu			bp->b_error = error;
65958934Sphk			bp->b_ioflags |= BIO_ERROR;
660133326Sphk			bufdone(bp);
661186194Strasz			return (0);
66254371Ssemenu		}
66354371Ssemenu		if ((long)bp->b_blkno == -1)
66454371Ssemenu			vfs_bio_clrbuf(bp);
66554371Ssemenu	}
66654371Ssemenu	if ((long)bp->b_blkno == -1) {
667133326Sphk		bufdone(bp);
66854371Ssemenu		return (0);
66954371Ssemenu	}
670121205Sphk	bp->b_iooffset = dbtob(bp->b_blkno);
671137040Sphk	bo = hp->h_hpmp->hpm_bo;
672140051Sphk	BO_STRATEGY(bo, bp);
67354371Ssemenu	return (0);
67454371Ssemenu}
67554371Ssemenu
67654371Ssemenu/*
67754371Ssemenu * XXXXX do we need hpfsnode locking inside?
67854371Ssemenu */
67954371Ssemenuint
68054371Ssemenuhpfs_access(ap)
68154371Ssemenu	struct vop_access_args /* {
68254371Ssemenu		struct vnode *a_vp;
683184413Strasz		accmode_t a_accmode;
68454371Ssemenu		struct ucred *a_cred;
68586928Sjhb		struct thread *a_td;
68654371Ssemenu	} */ *ap;
68754371Ssemenu{
68854371Ssemenu	struct vnode *vp = ap->a_vp;
68954371Ssemenu	struct hpfsnode *hp = VTOHP(vp);
690184413Strasz	accmode_t accmode = ap->a_accmode;
69154371Ssemenu
69254371Ssemenu	dprintf(("hpfs_access(0x%x):\n", hp->h_no));
69354371Ssemenu
69454371Ssemenu	/*
69596755Strhodes	 * Disallow write attempts on read-only filesystems;
69654371Ssemenu	 * unless the file is a socket, fifo, or a block or
69796755Strhodes	 * character device resident on the filesystem.
69854371Ssemenu	 */
699184413Strasz	if (accmode & VWRITE) {
70054371Ssemenu		switch ((int)vp->v_type) {
70154371Ssemenu		case VDIR:
70254371Ssemenu		case VLNK:
70354371Ssemenu		case VREG:
70454371Ssemenu			if (vp->v_mount->mnt_flag & MNT_RDONLY)
70554371Ssemenu				return (EROFS);
70654371Ssemenu			break;
70754371Ssemenu		}
70854371Ssemenu	}
70954371Ssemenu
71064865Sphk	return (vaccess(vp->v_type, hp->h_mode, hp->h_uid, hp->h_gid,
711184413Strasz	    ap->a_accmode, ap->a_cred, NULL));
71254371Ssemenu}
71354371Ssemenu
71454371Ssemenu/*
71554371Ssemenu * Open called.
71654371Ssemenu *
71754371Ssemenu * Nothing to do.
71854371Ssemenu */
71954371Ssemenu/* ARGSUSED */
72054371Ssemenustatic int
72154371Ssemenuhpfs_open(ap)
72254371Ssemenu	struct vop_open_args /* {
72354371Ssemenu		struct vnode *a_vp;
72454371Ssemenu		int  a_mode;
72554371Ssemenu		struct ucred *a_cred;
72686928Sjhb		struct thread *a_td;
72754371Ssemenu	} */ *ap;
72854371Ssemenu{
729153084Sru#ifdef HPFS_DEBUG
73054371Ssemenu	register struct vnode *vp = ap->a_vp;
73154371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
73254371Ssemenu
73354371Ssemenu	printf("hpfs_open(0x%x):\n",hp->h_no);
73454371Ssemenu#endif
73554371Ssemenu
73654371Ssemenu	/*
73754371Ssemenu	 * Files marked append-only must be opened for appending.
73854371Ssemenu	 */
73954371Ssemenu
74054371Ssemenu	return (0);
74154371Ssemenu}
74254371Ssemenu
74354371Ssemenu/*
74454371Ssemenu * Close called.
74554371Ssemenu *
74654371Ssemenu * Update the times on the inode.
74754371Ssemenu */
74854371Ssemenu/* ARGSUSED */
74954371Ssemenustatic int
75054371Ssemenuhpfs_close(ap)
75154371Ssemenu	struct vop_close_args /* {
75254371Ssemenu		struct vnode *a_vp;
75354371Ssemenu		int  a_fflag;
75454371Ssemenu		struct ucred *a_cred;
75586928Sjhb		struct thread *a_td;
75654371Ssemenu	} */ *ap;
75754371Ssemenu{
758153084Sru#ifdef HPFS_DEBUG
75954371Ssemenu	register struct vnode *vp = ap->a_vp;
76054371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
76154371Ssemenu
76254371Ssemenu	printf("hpfs_close: %d\n",hp->h_no);
76354371Ssemenu#endif
76454371Ssemenu
76554371Ssemenu	return (0);
76654371Ssemenu}
76754371Ssemenu
76854371Ssemenustatic int
76954371Ssemenuhpfs_de_uiomove (
77054371Ssemenu	struct hpfsmount *hpmp,
77154371Ssemenu	struct hpfsdirent *dep,
77254371Ssemenu	struct uio *uio)
77354371Ssemenu{
77454371Ssemenu	struct dirent cde;
77554371Ssemenu	int i, error;
77654371Ssemenu
77754371Ssemenu	dprintf(("[no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x] ",
77854371Ssemenu		dep->de_fnode, dep->de_size, dep->de_namelen,
77954371Ssemenu		dep->de_namelen, dep->de_name, dep->de_flag));
78054371Ssemenu
78154371Ssemenu	/*strncpy(cde.d_name, dep->de_name, dep->de_namelen);*/
78254371Ssemenu	for (i=0; i<dep->de_namelen; i++)
78354371Ssemenu		cde.d_name[i] = hpfs_d2u(hpmp, dep->de_name[i]);
78454371Ssemenu
78554371Ssemenu	cde.d_name[dep->de_namelen] = '\0';
78654371Ssemenu	cde.d_namlen = dep->de_namelen;
78754371Ssemenu	cde.d_fileno = dep->de_fnode;
78854371Ssemenu	cde.d_type = (dep->de_flag & DE_DIR) ? DT_DIR : DT_REG;
78954371Ssemenu	cde.d_reclen = sizeof(struct dirent);
79054371Ssemenu
79154371Ssemenu	error = uiomove((char *)&cde, sizeof(struct dirent), uio);
79254371Ssemenu	if (error)
79354371Ssemenu		return (error);
79454371Ssemenu
79554371Ssemenu	dprintf(("[0x%x] ", uio->uio_resid));
79654371Ssemenu	return (error);
79754371Ssemenu}
79854371Ssemenu
79954371Ssemenu
80054371Ssemenustatic struct dirent hpfs_de_dot =
80154371Ssemenu	{ 0, sizeof(struct dirent), DT_DIR, 1, "." };
80254371Ssemenustatic struct dirent hpfs_de_dotdot =
80354371Ssemenu	{ 0, sizeof(struct dirent), DT_DIR, 2, ".." };
80454371Ssemenuint
80554371Ssemenuhpfs_readdir(ap)
80654371Ssemenu	struct vop_readdir_args /* {
80754371Ssemenu		struct vnode *a_vp;
80854371Ssemenu		struct uio *a_uio;
80954371Ssemenu		struct ucred *a_cred;
81054371Ssemenu		int *a_ncookies;
81154371Ssemenu		u_int **cookies;
81254371Ssemenu	} */ *ap;
81354371Ssemenu{
81454371Ssemenu	register struct vnode *vp = ap->a_vp;
81554371Ssemenu	register struct hpfsnode *hp = VTOHP(vp);
81654371Ssemenu	struct hpfsmount *hpmp = hp->h_hpmp;
81754371Ssemenu	struct uio *uio = ap->a_uio;
81854371Ssemenu	int ncookies = 0, i, num, cnum;
81954371Ssemenu	int error = 0;
82054371Ssemenu	off_t off;
82154371Ssemenu	struct buf *bp;
82254371Ssemenu	struct dirblk *dp;
82354371Ssemenu	struct hpfsdirent *dep;
82454371Ssemenu	lsn_t olsn;
82554371Ssemenu	lsn_t lsn;
82654371Ssemenu	int level;
82754371Ssemenu
82854371Ssemenu	dprintf(("hpfs_readdir(0x%x, 0x%x, 0x%x): ",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid));
82954371Ssemenu
83054371Ssemenu	off = uio->uio_offset;
83154371Ssemenu
83254371Ssemenu	if( uio->uio_offset < sizeof(struct dirent) ) {
83354371Ssemenu		dprintf((". faked, "));
83454371Ssemenu		hpfs_de_dot.d_fileno = hp->h_no;
83554371Ssemenu		error = uiomove((char *)&hpfs_de_dot,sizeof(struct dirent),uio);
83654371Ssemenu		if(error) {
83754371Ssemenu			return (error);
83854371Ssemenu		}
83954371Ssemenu
84054371Ssemenu		ncookies ++;
84154371Ssemenu	}
84254371Ssemenu
84354371Ssemenu	if( uio->uio_offset < 2 * sizeof(struct dirent) ) {
84454371Ssemenu		dprintf((".. faked, "));
84554371Ssemenu		hpfs_de_dotdot.d_fileno = hp->h_fn.fn_parent;
84654371Ssemenu
84754371Ssemenu		error = uiomove((char *)&hpfs_de_dotdot, sizeof(struct dirent),
84854371Ssemenu				uio);
84954371Ssemenu		if(error) {
85054371Ssemenu			return (error);
85154371Ssemenu		}
85254371Ssemenu
85354371Ssemenu		ncookies ++;
85454371Ssemenu	}
85554371Ssemenu
85654371Ssemenu	num = uio->uio_offset / sizeof(struct dirent) - 2;
85754371Ssemenu	cnum = 0;
85854371Ssemenu
85954371Ssemenu	lsn = ((alleaf_t *)hp->h_fn.fn_abd)->al_lsn;
86054371Ssemenu
86154371Ssemenu	olsn = 0;
86254371Ssemenu	level = 1;
86354371Ssemenu
86454371Ssemenudive:
86554371Ssemenu	dprintf(("[dive 0x%x] ", lsn));
86654371Ssemenu	error = bread(hp->h_devvp, lsn, D_BSIZE, NOCRED, &bp);
86754371Ssemenu	if (error) {
86854371Ssemenu		brelse(bp);
86954371Ssemenu		return (error);
87054371Ssemenu	}
87154371Ssemenu
87254371Ssemenu	dp = (struct dirblk *) bp->b_data;
87354371Ssemenu	if (dp->d_magic != D_MAGIC) {
87454371Ssemenu		printf("hpfs_readdir: MAGIC DOESN'T MATCH\n");
87554371Ssemenu		brelse(bp);
87654371Ssemenu		return (EINVAL);
87754371Ssemenu	}
87854371Ssemenu
87954371Ssemenu	dep = D_DIRENT(dp);
88054371Ssemenu
88154371Ssemenu	if (olsn) {
88254371Ssemenu		dprintf(("[restore 0x%x] ", olsn));
88354371Ssemenu
88454371Ssemenu		while(!(dep->de_flag & DE_END) ) {
88554371Ssemenu			if((dep->de_flag & DE_DOWN) &&
88654371Ssemenu			   (olsn == DE_DOWNLSN(dep)))
88754371Ssemenu					 break;
88854371Ssemenu			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
88954371Ssemenu		}
89054371Ssemenu
89154371Ssemenu		if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
89254371Ssemenu			if (dep->de_flag & DE_END)
89354371Ssemenu				goto blockdone;
89454371Ssemenu
89554371Ssemenu			if (!(dep->de_flag & DE_SPECIAL)) {
89654371Ssemenu				if (num <= cnum) {
89754371Ssemenu					if (uio->uio_resid < sizeof(struct dirent)) {
89854371Ssemenu						brelse(bp);
89954371Ssemenu						dprintf(("[resid] "));
90054371Ssemenu						goto readdone;
90154371Ssemenu					}
90254371Ssemenu
90354371Ssemenu					error = hpfs_de_uiomove(hpmp, dep, uio);
90454371Ssemenu					if (error) {
90554371Ssemenu						brelse (bp);
90654371Ssemenu						return (error);
90754371Ssemenu					}
90854371Ssemenu					ncookies++;
90954371Ssemenu
91054371Ssemenu					if (uio->uio_resid < sizeof(struct dirent)) {
91154371Ssemenu						brelse(bp);
91254371Ssemenu						dprintf(("[resid] "));
91354371Ssemenu						goto readdone;
91454371Ssemenu					}
91554371Ssemenu				}
91654371Ssemenu				cnum++;
91754371Ssemenu			}
91854371Ssemenu
91954371Ssemenu			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
92054371Ssemenu		} else {
92154371Ssemenu			printf("hpfs_readdir: ERROR! oLSN not found\n");
92254371Ssemenu			brelse(bp);
92354371Ssemenu			return (EINVAL);
92454371Ssemenu		}
92554371Ssemenu	}
92654371Ssemenu
92754371Ssemenu	olsn = 0;
92854371Ssemenu
92954371Ssemenu	while(!(dep->de_flag & DE_END)) {
93054371Ssemenu		if(dep->de_flag & DE_DOWN) {
93154371Ssemenu			lsn = DE_DOWNLSN(dep);
93254371Ssemenu			brelse(bp);
93354371Ssemenu			level++;
93454371Ssemenu			goto dive;
93554371Ssemenu		}
93654371Ssemenu
93754371Ssemenu		if (!(dep->de_flag & DE_SPECIAL)) {
93854371Ssemenu			if (num <= cnum) {
93954371Ssemenu				if (uio->uio_resid < sizeof(struct dirent)) {
94054371Ssemenu					brelse(bp);
94154371Ssemenu					dprintf(("[resid] "));
94254371Ssemenu					goto readdone;
94354371Ssemenu				}
94454371Ssemenu
94554371Ssemenu				error = hpfs_de_uiomove(hpmp, dep, uio);
94654371Ssemenu				if (error) {
94754371Ssemenu					brelse (bp);
94854371Ssemenu					return (error);
94954371Ssemenu				}
95054371Ssemenu				ncookies++;
95154371Ssemenu
95254371Ssemenu				if (uio->uio_resid < sizeof(struct dirent)) {
95354371Ssemenu					brelse(bp);
95454371Ssemenu					dprintf(("[resid] "));
95554371Ssemenu					goto readdone;
95654371Ssemenu				}
95754371Ssemenu			}
95854371Ssemenu			cnum++;
95954371Ssemenu		}
96054371Ssemenu
96154371Ssemenu		dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
96254371Ssemenu	}
96354371Ssemenu
96454371Ssemenu	if(dep->de_flag & DE_DOWN) {
96554371Ssemenu		dprintf(("[enddive] "));
96654371Ssemenu		lsn = DE_DOWNLSN(dep);
96754371Ssemenu		brelse(bp);
96854371Ssemenu		level++;
96954371Ssemenu		goto dive;
97054371Ssemenu	}
97154371Ssemenu
97254371Ssemenublockdone:
97354371Ssemenu	dprintf(("[EOB] "));
97454371Ssemenu	olsn = lsn;
97554371Ssemenu	lsn = dp->d_parent;
97654371Ssemenu	brelse(bp);
97754371Ssemenu	level--;
97854371Ssemenu
97954371Ssemenu	dprintf(("[level %d] ", level));
98054371Ssemenu
98154371Ssemenu	if (level > 0)
98254371Ssemenu		goto dive;	/* undive really */
98354371Ssemenu
98454371Ssemenu	if (ap->a_eofflag) {
98554371Ssemenu	    dprintf(("[EOF] "));
98654371Ssemenu	    *ap->a_eofflag = 1;
98754371Ssemenu	}
98854371Ssemenu
98954371Ssemenureaddone:
99054371Ssemenu	dprintf(("[readdone]\n"));
99154371Ssemenu	if (!error && ap->a_ncookies != NULL) {
99254371Ssemenu		struct dirent* dpStart;
99354371Ssemenu		struct dirent* dp;
99454371Ssemenu		u_long *cookies;
99554371Ssemenu		u_long *cookiep;
99654371Ssemenu
99754371Ssemenu		dprintf(("%d cookies, ",ncookies));
99854371Ssemenu		if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
99954371Ssemenu			panic("hpfs_readdir: unexpected uio from NFS server");
100054371Ssemenu		dpStart = (struct dirent *)
100154371Ssemenu		     ((caddr_t)uio->uio_iov->iov_base -
100254371Ssemenu			 (uio->uio_offset - off));
1003184205Sdes		cookies = malloc(ncookies * sizeof(u_long),
1004111119Simp		       M_TEMP, M_WAITOK);
100554371Ssemenu		for (dp = dpStart, cookiep = cookies, i=0;
100654371Ssemenu		     i < ncookies;
100754371Ssemenu		     dp = (struct dirent *)((caddr_t) dp + dp->d_reclen), i++) {
100854371Ssemenu			off += dp->d_reclen;
100954371Ssemenu			*cookiep++ = (u_int) off;
101054371Ssemenu		}
101154371Ssemenu		*ap->a_ncookies = ncookies;
101254371Ssemenu		*ap->a_cookies = cookies;
101354371Ssemenu	}
101454371Ssemenu
101554371Ssemenu	return (0);
101654371Ssemenu}
101754371Ssemenu
101854371Ssemenuint
101954371Ssemenuhpfs_lookup(ap)
1020138279Sphk	struct vop_cachedlookup_args /* {
102154371Ssemenu		struct vnode *a_dvp;
102254371Ssemenu		struct vnode **a_vpp;
102354371Ssemenu		struct componentname *a_cnp;
102454371Ssemenu	} */ *ap;
102554371Ssemenu{
102654371Ssemenu	register struct vnode *dvp = ap->a_dvp;
102754371Ssemenu	register struct hpfsnode *dhp = VTOHP(dvp);
102854371Ssemenu	struct hpfsmount *hpmp = dhp->h_hpmp;
102954371Ssemenu	struct componentname *cnp = ap->a_cnp;
103054371Ssemenu	struct ucred *cred = cnp->cn_cred;
103154371Ssemenu	int error;
103254371Ssemenu	int nameiop = cnp->cn_nameiop;
103354371Ssemenu	int flags = cnp->cn_flags;
1034144230Sjeff	dprintf(("hpfs_lookup(0x%x, %s, %ld):\n",
1035144228Sjeff		dhp->h_no, cnp->cn_nameptr, cnp->cn_namelen));
103654371Ssemenu
103754371Ssemenu	if (nameiop != CREATE && nameiop != DELETE && nameiop != LOOKUP) {
103854371Ssemenu		printf("hpfs_lookup: LOOKUP, DELETE and CREATE are only supported\n");
103954371Ssemenu		return (EOPNOTSUPP);
104054371Ssemenu	}
104154371Ssemenu
104286928Sjhb	error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_thread);
104354371Ssemenu	if(error)
104454371Ssemenu		return (error);
104554371Ssemenu
104654371Ssemenu	if( (cnp->cn_namelen == 1) &&
104754371Ssemenu	    !strncmp(cnp->cn_nameptr,".",1) ) {
104854371Ssemenu		dprintf(("hpfs_lookup(0x%x,...): . faked\n",dhp->h_no));
104954371Ssemenu
105054371Ssemenu		VREF(dvp);
105154371Ssemenu		*ap->a_vpp = dvp;
105254371Ssemenu
105354371Ssemenu		return (0);
105454371Ssemenu	} else if( (cnp->cn_namelen == 2) &&
105554371Ssemenu	    !strncmp(cnp->cn_nameptr,"..",2) && (flags & ISDOTDOT) ) {
105654371Ssemenu		dprintf(("hpfs_lookup(0x%x,...): .. faked (0x%x)\n",
105754371Ssemenu			dhp->h_no, dhp->h_fn.fn_parent));
105854371Ssemenu
105992462Smckusick		if (VFS_VGET(hpmp->hpm_mp, dhp->h_fn.fn_parent,
106092462Smckusick		    LK_NOWAIT | LK_EXCLUSIVE, ap->a_vpp)) {
1061175294Sattilio			VOP_UNLOCK(dvp,0);
106292462Smckusick			error = VFS_VGET(hpmp->hpm_mp,
106392462Smckusick				 dhp->h_fn.fn_parent, LK_EXCLUSIVE, ap->a_vpp);
1064175202Sattilio			vn_lock(dvp, LK_EXCLUSIVE|LK_RETRY);
1065145006Sjeff			if (error)
106692462Smckusick				return(error);
106754371Ssemenu		}
106892462Smckusick		return (0);
106954371Ssemenu	} else {
107054371Ssemenu		struct buf *bp;
107154371Ssemenu		struct hpfsdirent *dep;
107254371Ssemenu		struct hpfsnode *hp;
107354371Ssemenu
107454371Ssemenu		error = hpfs_genlookupbyname(dhp,
107554371Ssemenu				cnp->cn_nameptr, cnp->cn_namelen, &bp, &dep);
107654371Ssemenu		if (error) {
107754371Ssemenu			if ((error == ENOENT) && (flags & ISLASTCN) &&
107854371Ssemenu			    (nameiop == CREATE || nameiop == RENAME)) {
107954371Ssemenu				cnp->cn_flags |= SAVENAME;
108054371Ssemenu				return (EJUSTRETURN);
108154371Ssemenu			}
108254371Ssemenu
108354371Ssemenu			return (error);
108454371Ssemenu		}
108554371Ssemenu
108654371Ssemenu		dprintf(("hpfs_lookup: fnode: 0x%x, CPID: 0x%x\n",
108754371Ssemenu			 dep->de_fnode, dep->de_cpid));
108854371Ssemenu
108954371Ssemenu		if (nameiop == DELETE && (flags & ISLASTCN)) {
109086928Sjhb			error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_thread);
109154371Ssemenu			if (error) {
109254371Ssemenu				brelse(bp);
109354371Ssemenu				return (error);
109454371Ssemenu			}
109554371Ssemenu		}
109654371Ssemenu
109754371Ssemenu		if (dhp->h_no == dep->de_fnode) {
109854371Ssemenu			brelse(bp);
109954371Ssemenu			VREF(dvp);
110054371Ssemenu			*ap->a_vpp = dvp;
110154371Ssemenu			return (0);
110254371Ssemenu		}
110354371Ssemenu
110492462Smckusick		error = VFS_VGET(hpmp->hpm_mp, dep->de_fnode, LK_EXCLUSIVE,
110592462Smckusick				 ap->a_vpp);
110654371Ssemenu		if (error) {
110754371Ssemenu			printf("hpfs_lookup: VFS_VGET FAILED %d\n", error);
110854371Ssemenu			brelse(bp);
110954371Ssemenu			return(error);
111054371Ssemenu		}
111154371Ssemenu
111254371Ssemenu		hp = VTOHP(*ap->a_vpp);
111354371Ssemenu
111454371Ssemenu		hp->h_mtime = dep->de_mtime;
111554371Ssemenu		hp->h_ctime = dep->de_ctime;
111654371Ssemenu		hp->h_atime = dep->de_atime;
111754371Ssemenu		bcopy(dep->de_name, hp->h_name, dep->de_namelen);
111854371Ssemenu		hp->h_name[dep->de_namelen] = '\0';
111954371Ssemenu		hp->h_namelen = dep->de_namelen;
112054371Ssemenu		hp->h_flag |= H_PARVALID;
112154371Ssemenu
112254371Ssemenu		brelse(bp);
112354371Ssemenu
112454371Ssemenu		if ((flags & MAKEENTRY) &&
112554371Ssemenu		    (!(flags & ISLASTCN) ||
112654371Ssemenu		     (nameiop != DELETE && nameiop != CREATE)))
112754371Ssemenu			cache_enter(dvp, *ap->a_vpp, cnp);
112854371Ssemenu	}
112954371Ssemenu	return (error);
113054371Ssemenu}
113154371Ssemenu
113254371Ssemenuint
113354371Ssemenuhpfs_remove(ap)
113454371Ssemenu	struct vop_remove_args /* {
113554371Ssemenu		struct vnode *a_dvp;
113654371Ssemenu		struct vnode *a_vp;
113754371Ssemenu		struct componentname *a_cnp;
113854371Ssemenu	} */ *ap;
113954371Ssemenu{
114054371Ssemenu	int error;
114154371Ssemenu
114254371Ssemenu	dprintf(("hpfs_remove(0x%x, %s, %ld): \n", VTOHP(ap->a_vp)->h_no,
114354371Ssemenu		ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
114454371Ssemenu
114554371Ssemenu	if (ap->a_vp->v_type == VDIR)
114654371Ssemenu		return (EPERM);
114754371Ssemenu
114854371Ssemenu	error = hpfs_removefnode (ap->a_dvp, ap->a_vp, ap->a_cnp);
114954371Ssemenu	return (error);
115054371Ssemenu}
115154371Ssemenu
115254371Ssemenuint
115354371Ssemenuhpfs_create(ap)
115454371Ssemenu	struct vop_create_args /* {
115554371Ssemenu		struct vnode *a_dvp;
115654371Ssemenu		struct vnode **a_vpp;
115754371Ssemenu		struct componentname *a_cnp;
115854371Ssemenu		struct vattr *a_vap;
115954371Ssemenu	} */ *ap;
116054371Ssemenu{
116154371Ssemenu	int error;
116254371Ssemenu
116354371Ssemenu	dprintf(("hpfs_create(0x%x, %s, %ld): \n", VTOHP(ap->a_dvp)->h_no,
116454371Ssemenu		ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
116554371Ssemenu
116654371Ssemenu	if (!(ap->a_cnp->cn_flags & HASBUF))
116754371Ssemenu		panic ("hpfs_create: no name\n");
116854371Ssemenu
116954371Ssemenu	error = hpfs_makefnode (ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
117054371Ssemenu
117154371Ssemenu	return (error);
117254371Ssemenu}
117354371Ssemenu
117454371Ssemenu/*
117554371Ssemenu * Return POSIX pathconf information applicable to NTFS filesystem
117654371Ssemenu */
117754371Ssemenuint
117854371Ssemenuhpfs_pathconf(ap)
117954371Ssemenu	struct vop_pathconf_args /* {
118054371Ssemenu		struct vnode *a_vp;
118154371Ssemenu		int a_name;
118254371Ssemenu		register_t *a_retval;
118354371Ssemenu	} */ *ap;
118454371Ssemenu{
118554371Ssemenu	switch (ap->a_name) {
118654371Ssemenu	case _PC_LINK_MAX:
118754371Ssemenu		*ap->a_retval = 1;
118854371Ssemenu		return (0);
118954371Ssemenu	case _PC_NAME_MAX:
119054371Ssemenu		*ap->a_retval = HPFS_MAXFILENAME;
119154371Ssemenu		return (0);
119254371Ssemenu	case _PC_PATH_MAX:
119354371Ssemenu		*ap->a_retval = PATH_MAX;
119454371Ssemenu		return (0);
119554371Ssemenu	case _PC_CHOWN_RESTRICTED:
119654371Ssemenu		*ap->a_retval = 1;
119754371Ssemenu		return (0);
119854371Ssemenu	case _PC_NO_TRUNC:
119954371Ssemenu		*ap->a_retval = 0;
120054371Ssemenu		return (0);
120154371Ssemenu	default:
120254371Ssemenu		return (EINVAL);
120354371Ssemenu	}
120454371Ssemenu	/* NOTREACHED */
120554371Ssemenu}
120654371Ssemenu
1207166774Spjdint
1208166774Spjdhpfs_vptofh(ap)
1209166774Spjd	struct vop_vptofh_args /* {
1210166774Spjd		struct vnode *a_vp;
1211166774Spjd		struct fid *a_fhp;
1212166774Spjd	} */ *ap;
1213166774Spjd{
1214166774Spjd	register struct hpfsnode *hpp;
1215166774Spjd	register struct hpfid *hpfhp;
121654371Ssemenu
1217166774Spjd	hpp = VTOHP(ap->a_vp);
1218166774Spjd	hpfhp = (struct hpfid *)ap->a_fhp;
1219166774Spjd	hpfhp->hpfid_len = sizeof(struct hpfid);
1220166774Spjd	hpfhp->hpfid_ino = hpp->h_no;
1221166774Spjd	/* hpfhp->hpfid_gen = hpp->h_gen; */
1222166774Spjd	return (0);
1223166774Spjd}
1224166774Spjd
1225166774Spjd
122654371Ssemenu/*
122754371Ssemenu * Global vfs data structures
122854371Ssemenu */
1229138290Sphkstruct vop_vector hpfs_vnodeops = {
1230140196Sphk	.vop_default =		&default_vnodeops,
123154371Ssemenu
1232140196Sphk	.vop_access =		hpfs_access,
1233140196Sphk	.vop_bmap =		hpfs_bmap,
1234140196Sphk	.vop_cachedlookup =	hpfs_lookup,
1235140196Sphk	.vop_close =		hpfs_close,
1236140196Sphk	.vop_create =		hpfs_create,
1237140196Sphk	.vop_fsync =		hpfs_fsync,
1238140196Sphk	.vop_getattr =		hpfs_getattr,
1239140196Sphk	.vop_inactive =		hpfs_inactive,
1240140196Sphk	.vop_ioctl =		hpfs_ioctl,
1241140196Sphk	.vop_lookup =		vfs_cache_lookup,
1242140196Sphk	.vop_open =		hpfs_open,
1243140196Sphk	.vop_pathconf =		hpfs_pathconf,
1244140196Sphk	.vop_print =		hpfs_print,
1245140196Sphk	.vop_read =		hpfs_read,
1246140196Sphk	.vop_readdir =		hpfs_readdir,
1247140196Sphk	.vop_reclaim =		hpfs_reclaim,
1248140196Sphk	.vop_remove =		hpfs_remove,
1249140196Sphk	.vop_setattr =		hpfs_setattr,
1250140196Sphk	.vop_strategy =		hpfs_strategy,
1251140196Sphk	.vop_write =		hpfs_write,
1252166774Spjd	.vop_vptofh =		hpfs_vptofh,
125354371Ssemenu};
1254