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