xref: /netbsd/sys/fs/adosfs/advnops.c (revision 753f02d2)
1 /*	$NetBSD: advnops.c,v 1.59 2022/04/04 19:33:45 andvar 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.59 2022/04/04 19:33:45 andvar 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
adosfs_getattr(void * v)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
adosfs_read(void * v)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 contigous
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
adosfs_write(void * v)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
adosfs_strategy(void * v)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
adosfs_bmap(void * v)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
adosfs_print(void * v)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
adosfs_readdir(void * v)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
adosfs_check_possible(struct vnode * vp,struct anode * ap,accmode_t accmode)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
adosfs_check_permitted(struct vnode * vp,struct anode * ap,accmode_t accmode,kauth_cred_t cred)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
adosfs_access(void * v)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
adosfs_readlink(void * v)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
adosfs_inactive(void * v)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
adosfs_reclaim(void * v)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
adosfs_pathconf(void * v)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