Home | History | Annotate | Line # | Download | only in adosfs
      1 /*	$NetBSD: advnops.c,v 1.60 2024/05/13 00:24:18 msaitoh Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1994 Christian E. Hopps
      5  * Copyright (c) 1996 Matthias Scheler
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *      This product includes software developed by Christian E. Hopps.
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: advnops.c,v 1.60 2024/05/13 00:24:18 msaitoh Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/vnode.h>
     40 #include <sys/mount.h>
     41 #include <sys/time.h>
     42 #include <sys/queue.h>
     43 #include <sys/namei.h>
     44 #include <sys/buf.h>
     45 #include <sys/dirent.h>
     46 #include <sys/inttypes.h>
     47 #include <sys/malloc.h>
     48 #include <sys/pool.h>
     49 #include <sys/stat.h>
     50 #include <sys/unistd.h>
     51 #include <sys/proc.h>
     52 #include <sys/kauth.h>
     53 
     54 #include <miscfs/genfs/genfs.h>
     55 #include <miscfs/specfs/specdev.h>
     56 #include <fs/adosfs/adosfs.h>
     57 
     58 extern struct vnodeops adosfs_vnodeops;
     59 
     60 int	adosfs_getattr(void *);
     61 int	adosfs_read(void *);
     62 int	adosfs_write(void *);
     63 int	adosfs_strategy(void *);
     64 int	adosfs_bmap(void *);
     65 int	adosfs_print(void *);
     66 int	adosfs_readdir(void *);
     67 int	adosfs_access(void *);
     68 int	adosfs_readlink(void *);
     69 int	adosfs_inactive(void *);
     70 int	adosfs_reclaim(void *);
     71 int	adosfs_pathconf(void *);
     72 
     73 const struct vnodeopv_entry_desc adosfs_vnodeop_entries[] = {
     74 	{ &vop_default_desc, vn_default_error },
     75 	{ &vop_parsepath_desc, genfs_parsepath },	/* parsepath */
     76 	{ &vop_lookup_desc, adosfs_lookup },		/* lookup */
     77 	{ &vop_create_desc, genfs_eopnotsupp },		/* create */
     78 	{ &vop_mknod_desc, genfs_eopnotsupp },		/* mknod */
     79 	{ &vop_open_desc, genfs_nullop },		/* open */
     80 	{ &vop_close_desc, genfs_nullop },		/* close */
     81 	{ &vop_access_desc, adosfs_access },		/* access */
     82 	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
     83 	{ &vop_getattr_desc, adosfs_getattr },		/* getattr */
     84 	{ &vop_setattr_desc, genfs_eopnotsupp },	/* setattr */
     85 	{ &vop_read_desc, adosfs_read },		/* read */
     86 	{ &vop_write_desc, adosfs_write },		/* write */
     87 	{ &vop_fallocate_desc, genfs_eopnotsupp },	/* fallocate */
     88 	{ &vop_fdiscard_desc, genfs_eopnotsupp },	/* fdiscard */
     89 	{ &vop_fcntl_desc, genfs_fcntl },		/* fcntl */
     90 	{ &vop_ioctl_desc, genfs_enoioctl },		/* ioctl */
     91 	{ &vop_poll_desc, genfs_poll },			/* poll */
     92 	{ &vop_kqfilter_desc, genfs_kqfilter },		/* kqfilter */
     93 	{ &vop_revoke_desc, genfs_revoke },		/* revoke */
     94 	{ &vop_mmap_desc, genfs_mmap },			/* mmap */
     95 	{ &vop_fsync_desc, genfs_nullop },		/* fsync */
     96 	{ &vop_seek_desc, genfs_seek },			/* seek */
     97 	{ &vop_remove_desc, genfs_eopnotsupp },		/* remove */
     98 	{ &vop_link_desc, genfs_erofs_link },		/* link */
     99 	{ &vop_rename_desc, genfs_eopnotsupp },		/* rename */
    100 	{ &vop_mkdir_desc, genfs_eopnotsupp },		/* mkdir */
    101 	{ &vop_rmdir_desc, genfs_eopnotsupp },		/* rmdir */
    102 	{ &vop_symlink_desc, genfs_erofs_symlink },	/* symlink */
    103 	{ &vop_readdir_desc, adosfs_readdir },		/* readdir */
    104 	{ &vop_readlink_desc, adosfs_readlink },	/* readlink */
    105 	{ &vop_abortop_desc, genfs_abortop },		/* abortop */
    106 	{ &vop_inactive_desc, adosfs_inactive },	/* inactive */
    107 	{ &vop_reclaim_desc, adosfs_reclaim },		/* reclaim */
    108 	{ &vop_lock_desc, genfs_lock },			/* lock */
    109 	{ &vop_unlock_desc, genfs_unlock },		/* unlock */
    110 	{ &vop_bmap_desc, adosfs_bmap },		/* bmap */
    111 	{ &vop_strategy_desc, adosfs_strategy },	/* strategy */
    112 	{ &vop_print_desc, adosfs_print },		/* print */
    113 	{ &vop_islocked_desc, genfs_islocked },		/* islocked */
    114 	{ &vop_pathconf_desc, adosfs_pathconf },	/* pathconf */
    115 	{ &vop_advlock_desc, genfs_einval },		/* advlock */
    116 	{ &vop_bwrite_desc, genfs_eopnotsupp },		/* bwrite */
    117 	{ &vop_getpages_desc, genfs_getpages },		/* getpages */
    118 	{ &vop_putpages_desc, genfs_putpages },		/* putpages */
    119 	{ NULL, NULL }
    120 };
    121 
    122 const struct vnodeopv_desc adosfs_vnodeop_opv_desc =
    123 	{ &adosfs_vnodeop_p, adosfs_vnodeop_entries };
    124 
    125 int
    126 adosfs_getattr(void *v)
    127 {
    128 	struct vop_getattr_args /* {
    129 		struct vnode *a_vp;
    130 		struct vattr *a_vap;
    131 		kauth_cred_t a_cred;
    132 	} */ *sp = v;
    133 	struct vattr *vap;
    134 	struct adosfsmount *amp;
    135 	struct anode *ap;
    136 	u_long fblks;
    137 
    138 #ifdef ADOSFS_DIAGNOSTIC
    139 	advopprint(sp);
    140 #endif
    141 	vap = sp->a_vap;
    142 	ap = VTOA(sp->a_vp);
    143 	amp = ap->amp;
    144 	vattr_null(vap);
    145 	vap->va_uid = ap->uid;
    146 	vap->va_gid = ap->gid;
    147 	vap->va_fsid = sp->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
    148 	vap->va_atime.tv_sec = vap->va_mtime.tv_sec = vap->va_ctime.tv_sec =
    149 		ap->mtime.days * 24 * 60 * 60 + ap->mtime.mins * 60 +
    150 		ap->mtime.ticks / 50 + (8 * 365 + 2) * 24 * 60 * 60;
    151 	vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec = vap->va_ctime.tv_nsec = 0;
    152 	vap->va_gen = 0;
    153 	vap->va_flags = 0;
    154 	vap->va_rdev = NODEV;
    155 	vap->va_fileid = ap->block;
    156 	vap->va_type = sp->a_vp->v_type;
    157 	vap->va_mode = adunixprot(ap->adprot) & amp->mask;
    158 	if (sp->a_vp->v_type == VDIR) {
    159 		vap->va_nlink = 1;	/* XXX bogus, oh well */
    160 		vap->va_bytes = amp->bsize;
    161 		vap->va_size = amp->bsize;
    162 	} else {
    163 		/*
    164 		 * XXX actually we can track this if we were to walk the list
    165 		 * of links if it exists.
    166 		 * XXX for now, just set nlink to 2 if this is a hard link
    167 		 * to a file, or a file with a hard link.
    168 		 */
    169 		vap->va_nlink = 1 + (ap->linkto != 0);
    170 		/*
    171 		 * round up to nearest blocks add number of file list
    172 		 * blocks needed and multiply by number of bytes per block.
    173 		 */
    174 		fblks = howmany(ap->fsize, amp->dbsize);
    175 		fblks += howmany(fblks, ANODENDATBLKENT(ap));
    176 		vap->va_bytes = fblks * amp->dbsize;
    177 		vap->va_size = ap->fsize;
    178 
    179 		vap->va_blocksize = amp->dbsize;
    180 	}
    181 #ifdef ADOSFS_DIAGNOSTIC
    182 	printf(" 0)");
    183 #endif
    184 	return(0);
    185 }
    186 /*
    187  * are things locked??? they need to be to avoid this being
    188  * deleted or changed (data block pointer blocks moving about.)
    189  */
    190 int
    191 adosfs_read(void *v)
    192 {
    193 	struct vop_read_args /* {
    194 		struct vnode *a_vp;
    195 		struct uio *a_uio;
    196 		int a_ioflag;
    197 		kauth_cred_t a_cred;
    198 	} */ *sp = v;
    199 	struct vnode *vp = sp->a_vp;
    200 	struct adosfsmount *amp;
    201 	struct anode *ap;
    202 	struct uio *uio;
    203 	struct buf *bp;
    204 	daddr_t lbn;
    205 	int size, diff, error;
    206 	long n, on;
    207 
    208 #ifdef ADOSFS_DIAGNOSTIC
    209 	advopprint(sp);
    210 #endif
    211 	error = 0;
    212 	uio = sp->a_uio;
    213 	ap = VTOA(sp->a_vp);
    214 	amp = ap->amp;
    215 	/*
    216 	 * Return EOF for character devices, EIO for others
    217 	 */
    218 	if (sp->a_vp->v_type != VREG) {
    219 		error = EIO;
    220 		goto reterr;
    221 	}
    222 	if (uio->uio_resid == 0)
    223 		goto reterr;
    224 	if (uio->uio_offset < 0) {
    225 		error = EINVAL;
    226 		goto reterr;
    227 	}
    228 
    229 	/*
    230 	 * to expensive to let general algorithm figure out that
    231 	 * we are beyond the file.  Do it now.
    232 	 */
    233 	if (uio->uio_offset >= ap->fsize)
    234 		goto reterr;
    235 
    236 	/*
    237 	 * taken from ufs_read()
    238 	 */
    239 
    240 	if (vp->v_type == VREG && IS_FFS(amp)) {
    241 		const int advice = IO_ADV_DECODE(sp->a_ioflag);
    242 		error = 0;
    243 
    244 		while (uio->uio_resid > 0) {
    245 			vsize_t bytelen = MIN(ap->fsize - uio->uio_offset,
    246 					      uio->uio_resid);
    247 
    248 			if (bytelen == 0) {
    249 				break;
    250 			}
    251 			error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
    252 			    UBC_READ | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp));
    253 			if (error) {
    254 				break;
    255 			}
    256 		}
    257 		goto out;
    258 	}
    259 
    260 	do {
    261 		size = amp->dbsize;
    262 		lbn = uio->uio_offset / size;
    263 		on = uio->uio_offset % size;
    264 		n = MIN(size - on, uio->uio_resid);
    265 		diff = ap->fsize - uio->uio_offset;
    266 		/*
    267 		 * check for EOF
    268 		 */
    269 		if (diff <= 0)
    270 			return(0);
    271 		if (diff < n)
    272 			n = diff;
    273 		/*
    274 		 * read ahead could possibly be worth something
    275 		 * but not much as ados makes little attempt to
    276 		 * make things contiguous
    277 		 */
    278 		error = bread(sp->a_vp, lbn, amp->bsize, 0, &bp);
    279 		if (error) {
    280 			goto reterr;
    281 		}
    282 		if (!IS_FFS(amp)) {
    283 			if (bp->b_resid > 0)
    284 				error = EIO; /* OFS needs the complete block */
    285 			else if (adoswordn(bp, 0) != BPT_DATA) {
    286 #ifdef DIAGNOSTIC
    287 				printf("adosfs: bad primary type blk %" PRId64 "\n",
    288 				    bp->b_blkno / (amp->bsize / DEV_BSIZE));
    289 #endif
    290 				error = EINVAL;
    291 			} else if (adoscksum(bp, ap->nwords)) {
    292 #ifdef DIAGNOSTIC
    293 				printf("adosfs: blk %" PRId64 " failed cksum.\n",
    294 				    bp->b_blkno / (amp->bsize / DEV_BSIZE));
    295 #endif
    296 				error = EINVAL;
    297 			}
    298 		}
    299 
    300 		if (error) {
    301 			brelse(bp, 0);
    302 			goto reterr;
    303 		}
    304 #ifdef ADOSFS_DIAGNOSTIC
    305 		printf(" %" PRId64 "+%ld-%" PRId64 "+%ld", lbn, on, lbn, n);
    306 #endif
    307 		n = MIN(n, size - bp->b_resid);
    308 		error = uiomove((char *)bp->b_data + on +
    309 				amp->bsize - amp->dbsize, (int)n, uio);
    310 		brelse(bp, 0);
    311 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
    312 
    313 out:
    314 reterr:
    315 #ifdef ADOSFS_DIAGNOSTIC
    316 	printf(" %d)", error);
    317 #endif
    318 	return(error);
    319 }
    320 
    321 int
    322 adosfs_write(void *v)
    323 {
    324 #ifdef ADOSFS_DIAGNOSTIC
    325 #if 0
    326 	struct vop_write_args /* {
    327 		struct vnode *a_vp;
    328 		struct uio *a_uio;
    329 		int a_ioflag;
    330 		kauth_cred_t a_cred;
    331 	} */ *sp = v;
    332 	advopprint(sp);
    333 #endif
    334 	printf(" EOPNOTSUPP)");
    335 #endif
    336 	return(EOPNOTSUPP);
    337 }
    338 
    339 /*
    340  * Just call the device strategy routine
    341  */
    342 int
    343 adosfs_strategy(void *v)
    344 {
    345 	struct vop_strategy_args /* {
    346 		struct vnode *a_vp;
    347 		struct buf *a_bp;
    348 	} */ *sp = v;
    349 	struct buf *bp;
    350 	struct anode *ap;
    351 	struct vnode *vp;
    352 	int error;
    353 
    354 #ifdef ADOSFS_DIAGNOSTIC
    355 	advopprint(sp);
    356 #endif
    357 	bp = sp->a_bp;
    358 	if (bp->b_vp == NULL) {
    359 		bp->b_error = EIO;
    360 		biodone(bp);
    361 		error = EIO;
    362 		goto reterr;
    363 	}
    364 	vp = sp->a_vp;
    365 	ap = VTOA(vp);
    366 	if (bp->b_blkno == bp->b_lblkno) {
    367 		error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
    368 		if (error) {
    369 			bp->b_error = error;
    370 			biodone(bp);
    371 			goto reterr;
    372 		}
    373 	}
    374 	if ((long)bp->b_blkno == -1) {
    375 		biodone(bp);
    376 		error = 0;
    377 		goto reterr;
    378 	}
    379 	vp = ap->amp->devvp;
    380 	error = VOP_STRATEGY(vp, bp);
    381 reterr:
    382 #ifdef ADOSFS_DIAGNOSTIC
    383 	printf(" %d)", error);
    384 #endif
    385 	return(error);
    386 }
    387 
    388 /*
    389  * Wait until the vnode has finished changing state.
    390  */
    391 int
    392 adosfs_bmap(void *v)
    393 {
    394 	struct vop_bmap_args /* {
    395 		struct vnode *a_vp;
    396 		daddr_t  a_bn;
    397 		struct vnode **a_vpp;
    398 		daddr_t *a_bnp;
    399 		int *a_runp;
    400 	} */ *sp = v;
    401 	struct anode *ap;
    402 	struct buf *flbp;
    403 	long nb, flblk, flblkoff, fcnt;
    404 	daddr_t *bnp;
    405 	daddr_t bn;
    406 	int error;
    407 
    408 #ifdef ADOSFS_DIAGNOSTIC
    409 	advopprint(sp);
    410 #endif
    411 	ap = VTOA(sp->a_vp);
    412 	bn = sp->a_bn;
    413 	bnp = sp->a_bnp;
    414 	if (sp->a_runp) {
    415 		*sp->a_runp = 0;
    416 	}
    417 	error = 0;
    418 
    419 	if (sp->a_vpp != NULL)
    420 		*sp->a_vpp = ap->amp->devvp;
    421 	if (bnp == NULL)
    422 		goto reterr;
    423 	if (bn < 0) {
    424 		error = EFBIG;
    425 		goto reterr;
    426 	}
    427 	if (sp->a_vp->v_type != VREG) {
    428 		error = EINVAL;
    429 		goto reterr;
    430 	}
    431 
    432 	/*
    433 	 * walk the chain of file list blocks until we find
    434 	 * the one that will yield the block pointer we need.
    435 	 */
    436 	if (ap->type == AFILE)
    437 		nb = ap->block;			/* pointer to ourself */
    438 	else if (ap->type == ALFILE)
    439 		nb = ap->linkto;		/* pointer to real file */
    440 	else {
    441 		error = EINVAL;
    442 		goto reterr;
    443 	}
    444 
    445 	flblk = bn / ANODENDATBLKENT(ap);
    446 	flbp = NULL;
    447 
    448 	/*
    449 	 * check last indirect block cache
    450 	 */
    451 	if (flblk < ap->lastlindblk)
    452 		fcnt = 0;
    453 	else {
    454 		flblk -= ap->lastlindblk;
    455 		fcnt = ap->lastlindblk;
    456 		nb = ap->lastindblk;
    457 	}
    458 	while (flblk >= 0) {
    459 		if (flbp)
    460 			brelse(flbp, 0);
    461 		if (nb == 0) {
    462 #ifdef DIAGNOSTIC
    463 			printf("adosfs: bad file list chain.\n");
    464 #endif
    465 			error = EINVAL;
    466 			goto reterr;
    467 		}
    468 		error = bread(ap->amp->devvp, nb * ap->amp->bsize / DEV_BSIZE,
    469 			      ap->amp->bsize, 0, &flbp);
    470 		if (error) {
    471 			goto reterr;
    472 		}
    473 		if (adoscksum(flbp, ap->nwords)) {
    474 #ifdef DIAGNOSTIC
    475 			printf("adosfs: blk %ld failed cksum.\n", nb);
    476 #endif
    477 			brelse(flbp, 0);
    478 			error = EINVAL;
    479 			goto reterr;
    480 		}
    481 		/*
    482 		 * update last indirect block cache
    483 		 */
    484 		ap->lastlindblk = fcnt++;
    485 		ap->lastindblk = nb;
    486 
    487 		nb = adoswordn(flbp, ap->nwords - 2);
    488 		flblk--;
    489 	}
    490 	/*
    491 	 * calculate offset of block number in table.  The table starts
    492 	 * at nwords - 51 and goes to offset 6 or less if indicated by the
    493 	 * valid table entries stored at offset ADBI_NBLKTABENT.
    494 	 */
    495 	flblkoff = bn % ANODENDATBLKENT(ap);
    496 	if (flblkoff < adoswordn(flbp, 2 /* ADBI_NBLKTABENT */)) {
    497 		flblkoff = (ap->nwords - 51) - flblkoff;
    498 		*bnp = adoswordn(flbp, flblkoff) * ap->amp->bsize / DEV_BSIZE;
    499 	} else {
    500 #ifdef DIAGNOSTIC
    501 		printf("flblk offset %ld too large in lblk %ld blk %" PRId64 "\n",
    502 		    flblkoff, (long)bn, flbp->b_blkno);
    503 #endif
    504 		error = EINVAL;
    505 	}
    506 	brelse(flbp, 0);
    507 reterr:
    508 #ifdef ADOSFS_DIAGNOSTIC
    509 	if (error == 0 && bnp)
    510 		printf(" %lld => %lld", (long long)bn, (long long)*bnp);
    511 	printf(" %d)\n", error);
    512 #endif
    513 	return(error);
    514 }
    515 
    516 /*
    517  * Print out the contents of a adosfs vnode.
    518  */
    519 /* ARGSUSED */
    520 int
    521 adosfs_print(void *v)
    522 {
    523 #if 0
    524 	struct vop_print_args /* {
    525 		struct vnode *a_vp;
    526 	} */ *sp = v;
    527 #endif
    528 	return(0);
    529 }
    530 
    531 int
    532 adosfs_readdir(void *v)
    533 {
    534 	struct vop_readdir_args /* {
    535 		struct vnode *a_vp;
    536 		struct uio *a_uio;
    537 		kauth_cred_t a_cred;
    538 		int *a_eofflag;
    539 		off_t **a_cookies;
    540 		int *a_ncookies;
    541 	} */ *sp = v;
    542 	int error, first, useri, chainc, hashi, scanned;
    543 	u_long nextbn;
    544 	struct dirent ad, *adp;
    545 	struct anode *pap, *ap;
    546 	struct vnode *vp;
    547 	struct uio *uio = sp->a_uio;
    548 	off_t uoff = uio->uio_offset;
    549 	off_t *cookies = NULL;
    550 	int ncookies = 0;
    551 
    552 #ifdef ADOSFS_DIAGNOSTIC
    553 	advopprint(sp);
    554 #endif
    555 
    556 	if (sp->a_vp->v_type != VDIR) {
    557 		error = ENOTDIR;
    558 		goto reterr;
    559 	}
    560 
    561 	if (uoff < 0) {
    562 		error = EINVAL;
    563 		goto reterr;
    564 	}
    565 
    566 	pap = VTOA(sp->a_vp);
    567 	adp = &ad;
    568 	error = nextbn = hashi = chainc = scanned = 0;
    569 	first = useri = uoff / sizeof ad;
    570 
    571 	/*
    572 	 * If offset requested is not on a slot boundary
    573 	 */
    574 	if (uoff % sizeof ad) {
    575 		error = EINVAL;
    576 		goto reterr;
    577 	}
    578 
    579 	for (;;) {
    580 		if (hashi == pap->ntabent) {
    581 			*sp->a_eofflag = 1;
    582 			break;
    583 		}
    584 		if (pap->tab[hashi] == 0) {
    585 			hashi++;
    586 			continue;
    587 		}
    588 		if (nextbn == 0)
    589 			nextbn = pap->tab[hashi];
    590 
    591 		/*
    592 		 * First determine if we can skip this chain
    593 		 */
    594 		if (chainc == 0) {
    595 			int skip;
    596 
    597 			skip = useri - scanned;
    598 			if (pap->tabi[hashi] > 0 && pap->tabi[hashi] <= skip) {
    599 				scanned += pap->tabi[hashi];
    600 				hashi++;
    601 				nextbn = 0;
    602 				continue;
    603 			}
    604 		}
    605 
    606 		/*
    607 		 * Now [continue to] walk the chain
    608 		 */
    609 		ap = NULL;
    610 		do {
    611 			error = VFS_VGET(pap->amp->mp, (ino_t)nextbn,
    612 			    LK_EXCLUSIVE, &vp);
    613 			if (error)
    614 				goto reterr;
    615 			ap = VTOA(vp);
    616 			scanned++;
    617 			chainc++;
    618 			nextbn = ap->hashf;
    619 
    620 			/*
    621 			 * check for end of chain.
    622 			 */
    623 			if (nextbn == 0) {
    624 				pap->tabi[hashi] = chainc;
    625 				hashi++;
    626 				chainc = 0;
    627 			} else if (pap->tabi[hashi] <= 0 &&
    628 			    -chainc < pap->tabi[hashi])
    629 				pap->tabi[hashi] = -chainc;
    630 
    631 			if (useri >= scanned) {
    632 				vput(vp);
    633 				ap = NULL;
    634 			}
    635 		} while (ap == NULL && nextbn != 0);
    636 
    637 		/*
    638 		 * We left the loop but without a result so do main over.
    639 		 */
    640 		if (ap == NULL)
    641 			continue;
    642 		/*
    643 		 * Fill in dirent record
    644 		 */
    645 		memset(adp, 0, sizeof *adp);
    646 		adp->d_fileno = ap->block;
    647 		/*
    648 		 * This deserves a function in kern/vfs_subr.c
    649 		 */
    650 		switch (ATOV(ap)->v_type) {
    651 		case VREG:
    652 			adp->d_type = DT_REG;
    653 			break;
    654 		case VDIR:
    655 			adp->d_type = DT_DIR;
    656 			break;
    657 		case VLNK:
    658 			adp->d_type = DT_LNK;
    659 			break;
    660 		default:
    661 			adp->d_type = DT_UNKNOWN;
    662 			break;
    663 		}
    664 		adp->d_namlen = strlen(ap->name);
    665 		memcpy(adp->d_name, ap->name, adp->d_namlen);
    666 		adp->d_reclen = _DIRENT_SIZE(adp);
    667 		vput(vp);
    668 
    669 		if (adp->d_reclen > uio->uio_resid) {
    670 			if (useri == first)	/* no room for even one entry */
    671 				error = EINVAL;
    672 			break;
    673 		}
    674 		error = uiomove(adp, adp->d_reclen, uio);
    675 		if (error)
    676 			break;
    677 		useri++;
    678 	}
    679 	ncookies = useri - first;
    680 	uio->uio_offset = uoff + ncookies * sizeof ad;
    681 reterr:
    682 #ifdef ADOSFS_DIAGNOSTIC
    683 	printf(" %d)", error);
    684 #endif
    685 	if (sp->a_ncookies != NULL) {
    686 		*sp->a_ncookies = ncookies;
    687 		if (!error) {
    688 			*sp->a_cookies = cookies =
    689 			   malloc(ncookies * sizeof *cookies, M_TEMP, M_WAITOK);
    690 
    691 			while (ncookies--) {
    692 				uoff += sizeof ad;
    693 				*cookies++ = uoff;
    694 			}
    695 		} else
    696 			*sp->a_cookies = NULL;
    697 	}
    698 
    699 	return(error);
    700 }
    701 
    702 static int
    703 adosfs_check_possible(struct vnode *vp, struct anode *ap, accmode_t accmode)
    704 {
    705 
    706 	/*
    707 	 * Disallow write attempts unless the file is a socket,
    708 	 * fifo, or a block or character device resident on the
    709 	 * file system.
    710 	 */
    711 	if (accmode & VWRITE) {
    712 		switch (vp->v_type) {
    713 		case VDIR:
    714 		case VLNK:
    715 		case VREG:
    716 			return (EROFS);
    717 		default:
    718 			break;
    719 		}
    720 	}
    721 
    722 	return 0;
    723 }
    724 
    725 static int
    726 adosfs_check_permitted(struct vnode *vp, struct anode *ap, accmode_t accmode,
    727     kauth_cred_t cred)
    728 {
    729 	mode_t file_mode = adunixprot(ap->adprot) & ap->amp->mask;
    730 
    731 	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
    732 	    vp->v_type, file_mode), vp, NULL, genfs_can_access(vp,
    733 	    cred, ap->uid, ap->gid, file_mode, NULL, accmode));
    734 }
    735 
    736 int
    737 adosfs_access(void *v)
    738 {
    739 	struct vop_access_args /* {
    740 		struct vnode *a_vp;
    741 		accmode_t  a_accmode;
    742 		kauth_cred_t a_cred;
    743 	} */ *sp = v;
    744 	struct anode *ap;
    745 	struct vnode *vp = sp->a_vp;
    746 	int error;
    747 
    748 #ifdef ADOSFS_DIAGNOSTIC
    749 	advopprint(sp);
    750 #endif
    751 
    752 	ap = VTOA(vp);
    753 #ifdef DIAGNOSTIC
    754 	if (!VOP_ISLOCKED(vp)) {
    755 		vprint("adosfs_access: not locked", sp->a_vp);
    756 		panic("adosfs_access: not locked");
    757 	}
    758 #endif
    759 
    760 	error = adosfs_check_possible(vp, ap, sp->a_accmode);
    761 	if (error)
    762 		return error;
    763 
    764 	error = adosfs_check_permitted(vp, ap, sp->a_accmode, sp->a_cred);
    765 
    766 #ifdef ADOSFS_DIAGNOSTIC
    767 	printf(" %d)", error);
    768 #endif
    769 	return(error);
    770 }
    771 
    772 int
    773 adosfs_readlink(void *v)
    774 {
    775 	struct vop_readlink_args /* {
    776 		struct vnode *a_vp;
    777 		struct uio *a_uio;
    778 		kauth_cred_t a_cred;
    779 	} */ *sp = v;
    780 	struct anode *ap;
    781 	int error;
    782 
    783 #ifdef ADOSFS_DIAGNOSTIC
    784 	advopprint(sp);
    785 #endif
    786 	ap = VTOA(sp->a_vp);
    787 	error = uiomove(ap->slinkto, strlen(ap->slinkto), sp->a_uio);
    788 #ifdef ADOSFS_DIAGNOSTIC
    789 	printf(" %d)", error);
    790 #endif
    791 	return (error);
    792 }
    793 
    794 /*ARGSUSED*/
    795 int
    796 adosfs_inactive(void *v)
    797 {
    798 	struct vop_inactive_v2_args /* {
    799 		struct vnode *a_vp;
    800 		bool *a_recycle;
    801 	} */ *sp = v;
    802 #ifdef ADOSFS_DIAGNOSTIC
    803 	advopprint(sp);
    804 #endif
    805 	/* XXX this needs to check if file was deleted */
    806 	*sp->a_recycle = true;
    807 
    808 #ifdef ADOSFS_DIAGNOSTIC
    809 	printf(" 0)");
    810 #endif
    811 	return(0);
    812 }
    813 
    814 /*
    815  * the kernel wants its vnode back.
    816  * no lock needed we are being called from vclean()
    817  */
    818 int
    819 adosfs_reclaim(void *v)
    820 {
    821 	struct vop_reclaim_v2_args /* {
    822 		struct vnode *a_vp;
    823 	} */ *sp = v;
    824 	struct vnode *vp;
    825 	struct anode *ap;
    826 
    827 	VOP_UNLOCK(sp->a_vp);
    828 
    829 #ifdef ADOSFS_DIAGNOSTIC
    830 	printf("(reclaim 0)");
    831 #endif
    832 	vp = sp->a_vp;
    833 	ap = VTOA(vp);
    834 	if (vp->v_type == VDIR && ap->tab)
    835 		free(ap->tab, M_ANODE);
    836 	else if (vp->v_type == VLNK && ap->slinkto)
    837 		free(ap->slinkto, M_ANODE);
    838 	genfs_node_destroy(vp);
    839 	pool_put(&adosfs_node_pool, ap);
    840 	vp->v_data = NULL;
    841 	return(0);
    842 }
    843 
    844 /*
    845  * POSIX pathconf info, grabbed from kern/u fs, probably need to
    846  * investigate exactly what each return type means as they are probably
    847  * not valid currently
    848  */
    849 int
    850 adosfs_pathconf(void *v)
    851 {
    852 	struct vop_pathconf_args /* {
    853 		struct vnode *a_vp;
    854 		int a_name;
    855 		register_t *a_retval;
    856 	} */ *ap = v;
    857 
    858 	switch (ap->a_name) {
    859 	case _PC_LINK_MAX:
    860 		*ap->a_retval = LINK_MAX;
    861 		return (0);
    862 	case _PC_NAME_MAX:
    863 		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_namemax;
    864 		return (0);
    865 	case _PC_PATH_MAX:
    866 		*ap->a_retval = PATH_MAX;
    867 		return (0);
    868 	case _PC_PIPE_BUF:
    869 		*ap->a_retval = PIPE_BUF;
    870 		return (0);
    871 	case _PC_CHOWN_RESTRICTED:
    872 		*ap->a_retval = 1;
    873 		return (0);
    874 	case _PC_VDISABLE:
    875 		*ap->a_retval = _POSIX_VDISABLE;
    876 		return (0);
    877 	case _PC_SYNC_IO:
    878 		*ap->a_retval = 1;
    879 		return (0);
    880 	case _PC_FILESIZEBITS:
    881 		*ap->a_retval = 32;
    882 		return (0);
    883 	default:
    884 		return genfs_pathconf(ap);
    885 	}
    886 	/* NOTREACHED */
    887 }
    888