1/* $NetBSD: advnops.c,v 1.37 2010/06/24 13:03:09 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.37 2010/06/24 13:03:09 hannken 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 58extern struct vnodeops adosfs_vnodeops; 59 60#define adosfs_open genfs_nullop 61int adosfs_getattr(void *); 62int adosfs_read(void *); 63int adosfs_write(void *); 64#define adosfs_fcntl genfs_fcntl 65#define adosfs_ioctl genfs_enoioctl 66#define adosfs_poll genfs_poll 67int adosfs_strategy(void *); 68int adosfs_link(void *); 69int adosfs_symlink(void *); 70#define adosfs_abortop genfs_abortop 71int adosfs_bmap(void *); 72int adosfs_print(void *); 73int adosfs_readdir(void *); 74int adosfs_access(void *); 75int adosfs_readlink(void *); 76int adosfs_inactive(void *); 77int adosfs_reclaim(void *); 78int 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 96const 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_getattr_desc, adosfs_getattr }, /* getattr */ 105 { &vop_setattr_desc, adosfs_setattr }, /* setattr */ 106 { &vop_read_desc, adosfs_read }, /* read */ 107 { &vop_write_desc, adosfs_write }, /* write */ 108 { &vop_fcntl_desc, adosfs_fcntl }, /* fcntl */ 109 { &vop_ioctl_desc, adosfs_ioctl }, /* ioctl */ 110 { &vop_poll_desc, adosfs_poll }, /* poll */ 111 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 112 { &vop_revoke_desc, adosfs_revoke }, /* revoke */ 113 { &vop_mmap_desc, adosfs_mmap }, /* mmap */ 114 { &vop_fsync_desc, adosfs_fsync }, /* fsync */ 115 { &vop_seek_desc, adosfs_seek }, /* seek */ 116 { &vop_remove_desc, adosfs_remove }, /* remove */ 117 { &vop_link_desc, adosfs_link }, /* link */ 118 { &vop_rename_desc, adosfs_rename }, /* rename */ 119 { &vop_mkdir_desc, adosfs_mkdir }, /* mkdir */ 120 { &vop_rmdir_desc, adosfs_rmdir }, /* rmdir */ 121 { &vop_symlink_desc, adosfs_symlink }, /* symlink */ 122 { &vop_readdir_desc, adosfs_readdir }, /* readdir */ 123 { &vop_readlink_desc, adosfs_readlink }, /* readlink */ 124 { &vop_abortop_desc, adosfs_abortop }, /* abortop */ 125 { &vop_inactive_desc, adosfs_inactive }, /* inactive */ 126 { &vop_reclaim_desc, adosfs_reclaim }, /* reclaim */ 127 { &vop_lock_desc, genfs_lock }, /* lock */ 128 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 129 { &vop_bmap_desc, adosfs_bmap }, /* bmap */ 130 { &vop_strategy_desc, adosfs_strategy }, /* strategy */ 131 { &vop_print_desc, adosfs_print }, /* print */ 132 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 133 { &vop_pathconf_desc, adosfs_pathconf }, /* pathconf */ 134 { &vop_advlock_desc, adosfs_advlock }, /* advlock */ 135 { &vop_bwrite_desc, adosfs_bwrite }, /* bwrite */ 136 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 137 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 138 { NULL, NULL } 139}; 140 141const struct vnodeopv_desc adosfs_vnodeop_opv_desc = 142 { &adosfs_vnodeop_p, adosfs_vnodeop_entries }; 143 144int 145adosfs_getattr(void *v) 146{ 147 struct vop_getattr_args /* { 148 struct vnode *a_vp; 149 struct vattr *a_vap; 150 kauth_cred_t a_cred; 151 } */ *sp = v; 152 struct vattr *vap; 153 struct adosfsmount *amp; 154 struct anode *ap; 155 u_long fblks; 156 157#ifdef ADOSFS_DIAGNOSTIC 158 advopprint(sp); 159#endif 160 vap = sp->a_vap; 161 ap = VTOA(sp->a_vp); 162 amp = ap->amp; 163 vattr_null(vap); 164 vap->va_uid = ap->uid; 165 vap->va_gid = ap->gid; 166 vap->va_fsid = sp->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 167 vap->va_atime.tv_sec = vap->va_mtime.tv_sec = vap->va_ctime.tv_sec = 168 ap->mtime.days * 24 * 60 * 60 + ap->mtime.mins * 60 + 169 ap->mtime.ticks / 50 + (8 * 365 + 2) * 24 * 60 * 60; 170 vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec = vap->va_ctime.tv_nsec = 0; 171 vap->va_gen = 0; 172 vap->va_flags = 0; 173 vap->va_rdev = NODEV; 174 vap->va_fileid = ap->block; 175 vap->va_type = sp->a_vp->v_type; 176 vap->va_mode = adunixprot(ap->adprot) & amp->mask; 177 if (sp->a_vp->v_type == VDIR) { 178 vap->va_nlink = 1; /* XXX bogus, oh well */ 179 vap->va_bytes = amp->bsize; 180 vap->va_size = amp->bsize; 181 } else { 182 /* 183 * XXX actually we can track this if we were to walk the list 184 * of links if it exists. 185 * XXX for now, just set nlink to 2 if this is a hard link 186 * to a file, or a file with a hard link. 187 */ 188 vap->va_nlink = 1 + (ap->linkto != 0); 189 /* 190 * round up to nearest blocks add number of file list 191 * blocks needed and mutiply by number of bytes per block. 192 */ 193 fblks = howmany(ap->fsize, amp->dbsize); 194 fblks += howmany(fblks, ANODENDATBLKENT(ap)); 195 vap->va_bytes = fblks * amp->dbsize; 196 vap->va_size = ap->fsize; 197 198 vap->va_blocksize = amp->dbsize; 199 } 200#ifdef ADOSFS_DIAGNOSTIC 201 printf(" 0)"); 202#endif 203 return(0); 204} 205/* 206 * are things locked??? they need to be to avoid this being 207 * deleted or changed (data block pointer blocks moving about.) 208 */ 209int 210adosfs_read(void *v) 211{ 212 struct vop_read_args /* { 213 struct vnode *a_vp; 214 struct uio *a_uio; 215 int a_ioflag; 216 kauth_cred_t a_cred; 217 } */ *sp = v; 218 struct vnode *vp = sp->a_vp; 219 struct adosfsmount *amp; 220 struct anode *ap; 221 struct uio *uio; 222 struct buf *bp; 223 daddr_t lbn; 224 int size, diff, error; 225 long n, on; 226 227#ifdef ADOSFS_DIAGNOSTIC 228 advopprint(sp); 229#endif 230 error = 0; 231 uio = sp->a_uio; 232 ap = VTOA(sp->a_vp); 233 amp = ap->amp; 234 /* 235 * Return EOF for character devices, EIO for others 236 */ 237 if (sp->a_vp->v_type != VREG) { 238 error = EIO; 239 goto reterr; 240 } 241 if (uio->uio_resid == 0) 242 goto reterr; 243 if (uio->uio_offset < 0) { 244 error = EINVAL; 245 goto reterr; 246 } 247 248 /* 249 * to expensive to let general algorithm figure out that 250 * we are beyond the file. Do it now. 251 */ 252 if (uio->uio_offset >= ap->fsize) 253 goto reterr; 254 255 /* 256 * taken from ufs_read() 257 */ 258 259 if (vp->v_type == VREG && IS_FFS(amp)) { 260 const int advice = IO_ADV_DECODE(sp->a_ioflag); 261 error = 0; 262 263 while (uio->uio_resid > 0) { 264 vsize_t bytelen = MIN(ap->fsize - uio->uio_offset, 265 uio->uio_resid); 266 267 if (bytelen == 0) { 268 break; 269 } 270 error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, 271 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); 272 if (error) { 273 break; 274 } 275 } 276 goto out; 277 } 278 279 do { 280 size = amp->dbsize; 281 lbn = uio->uio_offset / size; 282 on = uio->uio_offset % size; 283 n = MIN(size - on, uio->uio_resid); 284 diff = ap->fsize - uio->uio_offset; 285 /* 286 * check for EOF 287 */ 288 if (diff <= 0) 289 return(0); 290 if (diff < n) 291 n = diff; 292 /* 293 * read ahead could possibly be worth something 294 * but not much as ados makes little attempt to 295 * make things contigous 296 */ 297 error = bread(sp->a_vp, lbn, amp->bsize, NOCRED, 0, &bp); 298 if (error) { 299 brelse(bp, 0); 300 goto reterr; 301 } 302 if (!IS_FFS(amp)) { 303 if (bp->b_resid > 0) 304 error = EIO; /* OFS needs the complete block */ 305 else if (adoswordn(bp, 0) != BPT_DATA) { 306#ifdef DIAGNOSTIC 307 printf("adosfs: bad primary type blk %" PRId64 "\n", 308 bp->b_blkno / (amp->bsize / DEV_BSIZE)); 309#endif 310 error = EINVAL; 311 } else if (adoscksum(bp, ap->nwords)) { 312#ifdef DIAGNOSTIC 313 printf("adosfs: blk %" PRId64 " failed cksum.\n", 314 bp->b_blkno / (amp->bsize / DEV_BSIZE)); 315#endif 316 error = EINVAL; 317 } 318 } 319 320 if (error) { 321 brelse(bp, 0); 322 goto reterr; 323 } 324#ifdef ADOSFS_DIAGNOSTIC 325 printf(" %" PRId64 "+%ld-%" PRId64 "+%ld", lbn, on, lbn, n); 326#endif 327 n = MIN(n, size - bp->b_resid); 328 error = uiomove((char *)bp->b_data + on + 329 amp->bsize - amp->dbsize, (int)n, uio); 330 brelse(bp, 0); 331 } while (error == 0 && uio->uio_resid > 0 && n != 0); 332 333out: 334reterr: 335#ifdef ADOSFS_DIAGNOSTIC 336 printf(" %d)", error); 337#endif 338 return(error); 339} 340 341int 342adosfs_write(void *v) 343{ 344#ifdef ADOSFS_DIAGNOSTIC 345#if 0 346 struct vop_write_args /* { 347 struct vnode *a_vp; 348 struct uio *a_uio; 349 int a_ioflag; 350 kauth_cred_t a_cred; 351 } */ *sp = v; 352 advopprint(sp); 353#endif 354 printf(" EOPNOTSUPP)"); 355#endif 356 return(EOPNOTSUPP); 357} 358 359/* 360 * Just call the device strategy routine 361 */ 362int 363adosfs_strategy(void *v) 364{ 365 struct vop_strategy_args /* { 366 struct vnode *a_vp; 367 struct buf *a_bp; 368 } */ *sp = v; 369 struct buf *bp; 370 struct anode *ap; 371 struct vnode *vp; 372 int error; 373 374#ifdef ADOSFS_DIAGNOSTIC 375 advopprint(sp); 376#endif 377 bp = sp->a_bp; 378 if (bp->b_vp == NULL) { 379 bp->b_error = EIO; 380 biodone(bp); 381 error = EIO; 382 goto reterr; 383 } 384 vp = sp->a_vp; 385 ap = VTOA(vp); 386 if (bp->b_blkno == bp->b_lblkno) { 387 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 388 if (error) { 389 bp->b_flags = error; 390 biodone(bp); 391 goto reterr; 392 } 393 } 394 if ((long)bp->b_blkno == -1) { 395 biodone(bp); 396 error = 0; 397 goto reterr; 398 } 399 vp = ap->amp->devvp; 400 error = VOP_STRATEGY(vp, bp); 401reterr: 402#ifdef ADOSFS_DIAGNOSTIC 403 printf(" %d)", error); 404#endif 405 return(error); 406} 407 408int 409adosfs_link(void *v) 410{ 411 struct vop_link_args /* { 412 struct vnode *a_dvp; 413 struct vnode *a_vp; 414 struct componentname *a_cnp; 415 } */ *ap = v; 416 417 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 418 vput(ap->a_dvp); 419 return (EROFS); 420} 421 422int 423adosfs_symlink(void *v) 424{ 425 struct vop_symlink_args /* { 426 struct vnode *a_dvp; 427 struct vnode **a_vpp; 428 struct componentname *a_cnp; 429 struct vattr *a_vap; 430 char *a_target; 431 } */ *ap = v; 432 433 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 434 vput(ap->a_dvp); 435 return (EROFS); 436} 437 438/* 439 * Wait until the vnode has finished changing state. 440 */ 441int 442adosfs_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, NOCRED, 0, &flbp); 520 if (error) { 521 brelse(flbp, 0); 522 goto reterr; 523 } 524 if (adoscksum(flbp, ap->nwords)) { 525#ifdef DIAGNOSTIC 526 printf("adosfs: blk %ld failed cksum.\n", nb); 527#endif 528 brelse(flbp, 0); 529 error = EINVAL; 530 goto reterr; 531 } 532 /* 533 * update last indirect block cache 534 */ 535 ap->lastlindblk = fcnt++; 536 ap->lastindblk = nb; 537 538 nb = adoswordn(flbp, ap->nwords - 2); 539 flblk--; 540 } 541 /* 542 * calculate offset of block number in table. The table starts 543 * at nwords - 51 and goes to offset 6 or less if indicated by the 544 * valid table entries stored at offset ADBI_NBLKTABENT. 545 */ 546 flblkoff = bn % ANODENDATBLKENT(ap); 547 if (flblkoff < adoswordn(flbp, 2 /* ADBI_NBLKTABENT */)) { 548 flblkoff = (ap->nwords - 51) - flblkoff; 549 *bnp = adoswordn(flbp, flblkoff) * ap->amp->bsize / DEV_BSIZE; 550 } else { 551#ifdef DIAGNOSTIC 552 printf("flblk offset %ld too large in lblk %ld blk %" PRId64 "\n", 553 flblkoff, (long)bn, flbp->b_blkno); 554#endif 555 error = EINVAL; 556 } 557 brelse(flbp, 0); 558reterr: 559#ifdef ADOSFS_DIAGNOSTIC 560 if (error == 0 && bnp) 561 printf(" %lld => %lld", (long long)bn, (long long)*bnp); 562 printf(" %d)\n", error); 563#endif 564 return(error); 565} 566 567/* 568 * Print out the contents of a adosfs vnode. 569 */ 570/* ARGSUSED */ 571int 572adosfs_print(void *v) 573{ 574#if 0 575 struct vop_print_args /* { 576 struct vnode *a_vp; 577 } */ *sp = v; 578#endif 579 return(0); 580} 581 582int 583adosfs_readdir(void *v) 584{ 585 struct vop_readdir_args /* { 586 struct vnode *a_vp; 587 struct uio *a_uio; 588 kauth_cred_t a_cred; 589 int *a_eofflag; 590 off_t **a_cookies; 591 int *a_ncookies; 592 } */ *sp = v; 593 int error, first, useri, chainc, hashi, scanned; 594 u_long nextbn; 595 struct dirent ad, *adp; 596 struct anode *pap, *ap; 597 struct vnode *vp; 598 struct uio *uio = sp->a_uio; 599 off_t uoff = uio->uio_offset; 600 off_t *cookies = NULL; 601 int ncookies = 0; 602 603#ifdef ADOSFS_DIAGNOSTIC 604 advopprint(sp); 605#endif 606 607 if (sp->a_vp->v_type != VDIR) { 608 error = ENOTDIR; 609 goto reterr; 610 } 611 612 if (uoff < 0) { 613 error = EINVAL; 614 goto reterr; 615 } 616 617 pap = VTOA(sp->a_vp); 618 adp = &ad; 619 error = nextbn = hashi = chainc = scanned = 0; 620 first = useri = uoff / sizeof ad; 621 622 /* 623 * If offset requested is not on a slot boundary 624 */ 625 if (uoff % sizeof ad) { 626 error = EINVAL; 627 goto reterr; 628 } 629 630 for (;;) { 631 if (hashi == pap->ntabent) { 632 *sp->a_eofflag = 1; 633 break; 634 } 635 if (pap->tab[hashi] == 0) { 636 hashi++; 637 continue; 638 } 639 if (nextbn == 0) 640 nextbn = pap->tab[hashi]; 641 642 /* 643 * First determine if we can skip this chain 644 */ 645 if (chainc == 0) { 646 int skip; 647 648 skip = useri - scanned; 649 if (pap->tabi[hashi] > 0 && pap->tabi[hashi] <= skip) { 650 scanned += pap->tabi[hashi]; 651 hashi++; 652 nextbn = 0; 653 continue; 654 } 655 } 656 657 /* 658 * Now [continue to] walk the chain 659 */ 660 ap = NULL; 661 do { 662 error = VFS_VGET(pap->amp->mp, (ino_t)nextbn, &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; 731reterr: 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 752static int 753adosfs_check_possible(struct vnode *vp, struct anode *ap, mode_t mode) 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 (mode & 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 775static int 776adosfs_check_permitted(struct vnode *vp, struct anode *ap, mode_t mode, 777 kauth_cred_t cred) 778{ 779 780 return genfs_can_access(vp->v_type, 781 adunixprot(ap->adprot) & ap->amp->mask, ap->uid, ap->gid, mode, 782 cred); 783} 784 785int 786adosfs_access(void *v) 787{ 788 struct vop_access_args /* { 789 struct vnode *a_vp; 790 int a_mode; 791 kauth_cred_t a_cred; 792 } */ *sp = v; 793 struct anode *ap; 794 struct vnode *vp = sp->a_vp; 795 int error; 796 797#ifdef ADOSFS_DIAGNOSTIC 798 advopprint(sp); 799#endif 800 801 ap = VTOA(vp); 802#ifdef DIAGNOSTIC 803 if (!VOP_ISLOCKED(vp)) { 804 vprint("adosfs_access: not locked", sp->a_vp); 805 panic("adosfs_access: not locked"); 806 } 807#endif 808 809 error = adosfs_check_possible(vp, ap, sp->a_mode); 810 if (error) 811 return error; 812 813 error = adosfs_check_permitted(vp, ap, sp->a_mode, sp->a_cred); 814 815#ifdef ADOSFS_DIAGNOSTIC 816 printf(" %d)", error); 817#endif 818 return(error); 819} 820 821int 822adosfs_readlink(void *v) 823{ 824 struct vop_readlink_args /* { 825 struct vnode *a_vp; 826 struct uio *a_uio; 827 kauth_cred_t a_cred; 828 } */ *sp = v; 829 struct anode *ap; 830 int error; 831 832#ifdef ADOSFS_DIAGNOSTIC 833 advopprint(sp); 834#endif 835 ap = VTOA(sp->a_vp); 836 error = uiomove(ap->slinkto, strlen(ap->slinkto), sp->a_uio); 837#ifdef ADOSFS_DIAGNOSTIC 838 printf(" %d)", error); 839#endif 840 return (error); 841} 842 843/*ARGSUSED*/ 844int 845adosfs_inactive(void *v) 846{ 847 struct vop_inactive_args /* { 848 struct vnode *a_vp; 849 bool *a_recycle; 850 } */ *sp = v; 851 struct vnode *vp = sp->a_vp; 852#ifdef ADOSFS_DIAGNOSTIC 853 advopprint(sp); 854#endif 855 VOP_UNLOCK(vp); 856 /* XXX this needs to check if file was deleted */ 857 *sp->a_recycle = true; 858 859#ifdef ADOSFS_DIAGNOSTIC 860 printf(" 0)"); 861#endif 862 return(0); 863} 864 865/* 866 * the kernel wants its vnode back. 867 * no lock needed we are being called from vclean() 868 */ 869int 870adosfs_reclaim(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 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 */ 899int 900adosfs_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 (EINVAL); 935 } 936 /* NOTREACHED */ 937} 938