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