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