|
|
1.1 ! root 1: /* ! 2: * Written by Paul Popelka ([email protected]) ! 3: * ! 4: * You can do anything you want with this software, ! 5: * just don't say you wrote it, ! 6: * and don't remove this notice. ! 7: * ! 8: * This software is provided "as is". ! 9: * ! 10: * The author supplies this software to be publicly ! 11: * redistributed on the understanding that the author ! 12: * is not responsible for the correct functioning of ! 13: * this software in any circumstances and is not liable ! 14: * for any damages caused by this software. ! 15: * ! 16: * October 1992 ! 17: * ! 18: * April 6, 1993: ! 19: * Changed MOUNT_PCFS to MOUNT_MSDOS, this whole package should be renamed ! 20: * to msdosfs, but I did not have the time to do it. Some one please do ! 21: * this and resubmit it to the patchkit! ! 22: * Rodney W. Grimes ! 23: * ! 24: * pcfs_vfsops.c,v 1.4.2.1 1993/08/05 02:37:21 cgd Exp ! 25: */ ! 26: ! 27: #include "param.h" ! 28: #include "systm.h" ! 29: #include "namei.h" ! 30: #include "proc.h" ! 31: #include "kernel.h" ! 32: #include "vnode.h" ! 33: #include "specdev.h" /* defines v_rdev */ ! 34: #include "mount.h" ! 35: #include "buf.h" ! 36: #include "file.h" ! 37: #include "malloc.h" ! 38: ! 39: #include "bpb.h" ! 40: #include "bootsect.h" ! 41: #include "direntry.h" ! 42: #include "denode.h" ! 43: #include "pcfsmount.h" ! 44: #include "fat.h" ! 45: ! 46: int pcfsdoforce = 0; /* 1 = force unmount */ ! 47: ! 48: /* ! 49: * mp - ! 50: * path - addr in user space of mount point (ie /usr or whatever) ! 51: * data - addr in user space of mount params including the ! 52: * name of the block special file to treat as a filesystem. ! 53: * ndp - ! 54: * p - ! 55: */ ! 56: int ! 57: pcfs_mount(mp, path, data, ndp, p) ! 58: struct mount *mp; ! 59: char *path; ! 60: caddr_t data; ! 61: struct nameidata *ndp; ! 62: struct proc *p; ! 63: { ! 64: struct vnode *devvp; /* vnode for blk device to mount */ ! 65: struct pcfs_args args; /* will hold data from mount request */ ! 66: struct pcfsmount *pmp; /* pcfs specific mount control block */ ! 67: int error; ! 68: u_int size; ! 69: ! 70: /* ! 71: * Copy in the args for the mount request. ! 72: */ ! 73: if (error = copyin(data, (caddr_t)&args, sizeof(struct pcfs_args))) ! 74: return error; ! 75: ! 76: /* ! 77: * Check to see if they want it to be an exportable ! 78: * filesystem via nfs. And, if they do, should it ! 79: * be read only, and what uid is root to be mapped ! 80: * to. ! 81: */ ! 82: if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { ! 83: if (args.exflags & MNT_EXPORTED) ! 84: mp->mnt_flag |= MNT_EXPORTED; ! 85: else ! 86: mp->mnt_flag &= ~MNT_EXPORTED; ! 87: if (args.exflags & MNT_EXRDONLY) ! 88: mp->mnt_flag |= MNT_EXRDONLY; ! 89: else ! 90: mp->mnt_flag &= ~MNT_EXRDONLY; ! 91: mp->mnt_exroot = args.exroot; ! 92: } ! 93: ! 94: /* ! 95: * If they just want to update then be sure we can ! 96: * do what is asked. Can't change a filesystem from ! 97: * read/write to read only. Why? ! 98: * And if they've supplied a new device file name then we ! 99: * continue, otherwise return. ! 100: */ ! 101: if (mp->mnt_flag & MNT_UPDATE) { ! 102: pmp = (struct pcfsmount *)mp->mnt_data; ! 103: if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) ! 104: pmp->pm_ronly = 0; ! 105: if (args.fspec == 0) ! 106: return 0; ! 107: } ! 108: ! 109: /* ! 110: * Now, lookup the name of the block device this ! 111: * mount or name update request is to apply to. ! 112: */ ! 113: ndp->ni_nameiop = LOOKUP | FOLLOW; ! 114: ndp->ni_segflg = UIO_USERSPACE; ! 115: ndp->ni_dirp = args.fspec; ! 116: if (error = namei(ndp, p)) ! 117: return error; ! 118: ! 119: /* ! 120: * Be sure they've given us a block device to treat ! 121: * as a filesystem. And, that its major number is ! 122: * within the bdevsw table. ! 123: */ ! 124: devvp = ndp->ni_vp; ! 125: if (devvp->v_type != VBLK) { ! 126: vrele(devvp); /* namei() acquires this? */ ! 127: return ENOTBLK; ! 128: } ! 129: if (major(devvp->v_rdev) >= nblkdev) { ! 130: vrele(devvp); ! 131: return ENXIO; ! 132: } ! 133: ! 134: /* ! 135: * If this is an update, then make sure the vnode ! 136: * for the block special device is the same as the ! 137: * one our filesystem is in. ! 138: */ ! 139: if (mp->mnt_flag & MNT_UPDATE) { ! 140: if (devvp != pmp->pm_devvp) ! 141: error = EINVAL; ! 142: else ! 143: vrele(devvp); ! 144: } else { ! 145: ! 146: /* ! 147: * Well, it's not an update, it's a real mount request. ! 148: * Time to get dirty. ! 149: */ ! 150: error = mountpcfs(devvp, mp, p); ! 151: } ! 152: if (error) { ! 153: vrele(devvp); ! 154: return error; ! 155: } ! 156: ! 157: /* ! 158: * Copy in the name of the directory the filesystem ! 159: * is to be mounted on. ! 160: * Then copy in the name of the block special file ! 161: * representing the filesystem being mounted. ! 162: * And we clear the remainder of the character strings ! 163: * to be tidy. ! 164: * Then, we try to fill in the filesystem stats structure ! 165: * as best we can with whatever applies from a dos file ! 166: * system. ! 167: */ ! 168: pmp = (struct pcfsmount *)mp->mnt_data; ! 169: copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, ! 170: sizeof(mp->mnt_stat.f_mntonname)-1, &size); ! 171: bzero(mp->mnt_stat.f_mntonname + size, ! 172: sizeof(mp->mnt_stat.f_mntonname) - size); ! 173: copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN-1, &size); ! 174: bzero(mp->mnt_stat.f_mntfromname + size, ! 175: MNAMELEN - size); ! 176: (void)pcfs_statfs(mp, &mp->mnt_stat, p); ! 177: #if defined(PCFSDEBUG) ! 178: printf("pcfs_mount(): mp %x, pmp %x, inusemap %x\n", mp, pmp, pmp->pm_inusemap); ! 179: #endif /* defined(PCFSDEBUG) */ ! 180: return 0; ! 181: } ! 182: ! 183: int ! 184: mountpcfs(devvp, mp, p) ! 185: struct vnode *devvp; ! 186: struct mount *mp; ! 187: struct proc *p; ! 188: { ! 189: int i; ! 190: u_long bpc; ! 191: int bit; ! 192: int error = 0; ! 193: int needclose; ! 194: int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; ! 195: dev_t dev = devvp->v_rdev; ! 196: union bootsector *bsp; ! 197: struct pcfsmount *pmp = NULL; ! 198: struct buf *bp0 = NULL; ! 199: struct byte_bpb33 *b33; ! 200: struct byte_bpb50 *b50; ! 201: ! 202: /* ! 203: * Multiple mounts of the same block special file ! 204: * aren't allowed. Make sure no one else has the ! 205: * special file open. And flush any old buffers ! 206: * from this filesystem. Presumably this prevents ! 207: * us from running into buffers that are the wrong ! 208: * blocksize. ! 209: * NOTE: mountedon() is a part of the ufs filesystem. ! 210: * If the ufs filesystem is not gen'ed into the system ! 211: * we will get an unresolved reference. ! 212: */ ! 213: if (error = mountedon(devvp)) ! 214: return error; ! 215: if (vcount(devvp) > 1) ! 216: return EBUSY; ! 217: vinvalbuf(devvp, 1); ! 218: ! 219: /* ! 220: * Now open the block special file. ! 221: */ ! 222: if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) ! 223: return error; ! 224: needclose = 1; ! 225: ! 226: /* ! 227: * Read the boot sector of the filesystem, and then ! 228: * check the boot signature. If not a dos boot sector ! 229: * then error out. We could also add some checking on ! 230: * the bsOemName field. So far I've seen the following ! 231: * values: ! 232: * "IBM 3.3" ! 233: * "MSDOS3.3" ! 234: * "MSDOS5.0" ! 235: */ ! 236: if (error = bread(devvp, 0, 512, NOCRED, &bp0)) ! 237: goto error_exit; ! 238: bp0->b_flags |= B_AGE; ! 239: bsp = (union bootsector *)bp0->b_un.b_addr; ! 240: b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; ! 241: b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; ! 242: if (bsp->bs50.bsBootSectSig != BOOTSIG) { ! 243: error = EINVAL; ! 244: goto error_exit; ! 245: } ! 246: ! 247: pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); ! 248: pmp->pm_inusemap = NULL; ! 249: pmp->pm_mountp = mp; ! 250: ! 251: /* ! 252: * Compute several useful quantities from the bpb in ! 253: * the bootsector. Copy in the dos 5 variant of the ! 254: * bpb then fix up the fields that are different between ! 255: * dos 5 and dos 3.3. ! 256: */ ! 257: pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); ! 258: pmp->pm_SectPerClust = b50->bpbSecPerClust; ! 259: pmp->pm_ResSectors = getushort(b50->bpbResSectors); ! 260: pmp->pm_FATs = b50->bpbFATs; ! 261: pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); ! 262: pmp->pm_Sectors = getushort(b50->bpbSectors); ! 263: pmp->pm_Media = b50->bpbMedia; ! 264: pmp->pm_FATsecs = getushort(b50->bpbFATsecs); ! 265: pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); ! 266: pmp->pm_Heads = getushort(b50->bpbHeads); ! 267: if (pmp->pm_Sectors == 0) { ! 268: pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); ! 269: pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); ! 270: } else { ! 271: pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); ! 272: pmp->pm_HugeSectors = pmp->pm_Sectors; ! 273: } ! 274: pmp->pm_fatblk = pmp->pm_ResSectors; ! 275: pmp->pm_rootdirblk = pmp->pm_fatblk + ! 276: (pmp->pm_FATs * pmp->pm_FATsecs); ! 277: pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) ! 278: / ! 279: pmp->pm_BytesPerSec; /* in sectors */ ! 280: pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; ! 281: pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / ! 282: pmp->pm_SectPerClust; ! 283: pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; ! 284: pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; ! 285: if (FAT12(pmp)) ! 286: /* This will usually be a floppy disk. ! 287: * This size makes sure that one fat entry will not be split ! 288: * across multiple blocks. */ ! 289: pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; ! 290: else ! 291: /* This will usually be a hard disk. ! 292: * Reading or writing one block should be quite fast. */ ! 293: pmp->pm_fatblocksize = MAXBSIZE; ! 294: pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; ! 295: ! 296: if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) ! 297: printf("mountpcfs(): root directory is not a multiple of the clustersize in length\n"); ! 298: ! 299: /* ! 300: * Compute mask and shift value for isolating cluster relative ! 301: * byte offsets and cluster numbers from a file offset. ! 302: */ ! 303: bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; ! 304: if (!bpc || (bpc & (bpc - 1))) { ! 305: error = EINVAL; ! 306: goto error_exit; ! 307: } ! 308: pmp->pm_bpcluster = bpc; ! 309: pmp->pm_depclust = bpc/sizeof(struct direntry); ! 310: pmp->pm_crbomask = bpc - 1; ! 311: pmp->pm_cnshift = ffs(bpc) - 1; ! 312: ! 313: pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ ! 314: pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ ! 315: ! 316: /* ! 317: * Release the bootsector buffer. ! 318: */ ! 319: brelse(bp0); ! 320: bp0 = NULL; ! 321: ! 322: /* ! 323: * Allocate memory for the bitmap of allocated clusters, ! 324: * and then fill it in. ! 325: */ ! 326: pmp->pm_inusemap = malloc((pmp->pm_maxcluster / 8) + 1, ! 327: M_MSDOSFSFAT, M_WAITOK); ! 328: ! 329: /* ! 330: * fillinusemap() needs pm_devvp. ! 331: */ ! 332: pmp->pm_dev = dev; ! 333: pmp->pm_devvp = devvp; ! 334: ! 335: /* ! 336: * Have the inuse map filled in. ! 337: */ ! 338: error = fillinusemap(pmp); ! 339: if (error) ! 340: goto error_exit; ! 341: ! 342: /* ! 343: * If they want fat updates to be synchronous then let ! 344: * them suffer the performance degradation in exchange ! 345: * for the on disk copy of the fat being correct just ! 346: * about all the time. I suppose this would be a good ! 347: * thing to turn on if the kernel is still flakey. ! 348: */ ! 349: pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; ! 350: ! 351: /* ! 352: * Finish up. ! 353: */ ! 354: pmp->pm_ronly = ronly; ! 355: if (ronly == 0) ! 356: pmp->pm_fmod = 1; ! 357: mp->mnt_data = (qaddr_t)pmp; ! 358: mp->mnt_stat.f_fsid.val[0] = (long)dev; ! 359: mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS; ! 360: mp->mnt_flag |= MNT_LOCAL; ! 361: #if defined(QUOTA) ! 362: /* ! 363: * If we ever do quotas for DOS filesystems this would ! 364: * be a place to fill in the info in the pcfsmount ! 365: * structure. ! 366: * You dolt, quotas on dos filesystems make no sense ! 367: * because files have no owners on dos filesystems. ! 368: * of course there is some empty space in the directory ! 369: * entry where we could put uid's and gid's. ! 370: */ ! 371: #endif /* defined(QUOTA) */ ! 372: devvp->v_specflags |= SI_MOUNTEDON; ! 373: ! 374: return 0; ! 375: ! 376: error_exit:; ! 377: if (bp0) ! 378: brelse(bp0); ! 379: if (needclose) ! 380: (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, ! 381: NOCRED, p); ! 382: if (pmp) { ! 383: if (pmp->pm_inusemap) ! 384: free((caddr_t)pmp->pm_inusemap, M_MSDOSFSFAT); ! 385: free((caddr_t)pmp, M_MSDOSFSMNT); ! 386: mp->mnt_data = (qaddr_t)0; ! 387: } ! 388: return error; ! 389: } ! 390: ! 391: int ! 392: pcfs_start(mp, flags, p) ! 393: struct mount *mp; ! 394: int flags; ! 395: struct proc *p; ! 396: { ! 397: return 0; ! 398: } ! 399: ! 400: /* ! 401: * Unmount the filesystem described by mp. ! 402: */ ! 403: int ! 404: pcfs_unmount(mp, mntflags, p) ! 405: struct mount *mp; ! 406: int mntflags; ! 407: struct proc *p; ! 408: { ! 409: int flags = 0; ! 410: int error; ! 411: struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data; ! 412: struct vnode *vp = pmp->pm_devvp; ! 413: ! 414: if (mntflags & MNT_FORCE) { ! 415: if (!pcfsdoforce) ! 416: return EINVAL; ! 417: flags |= FORCECLOSE; ! 418: } ! 419: mntflushbuf(mp, 0); ! 420: if (mntinvalbuf(mp)) ! 421: return EBUSY; ! 422: #if defined(QUOTA) ! 423: #endif /* defined(QUOTA) */ ! 424: if (error = vflush(mp, NULLVP, flags)) ! 425: return error; ! 426: pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; ! 427: #if defined(PCFSDEBUG) ! 428: printf("pcfs_umount(): just before calling VOP_CLOSE()\n"); ! 429: printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n", ! 430: vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); ! 431: printf("lastr %d, id %d, mount %08x, op %08x\n", ! 432: vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op); ! 433: printf("freef %08x, freeb %08x, mountf %08x, mountb %08x\n", ! 434: vp->v_freef, vp->v_freeb, vp->v_mountf, vp->v_mountb); ! 435: printf("cleanblkhd %08x, dirtyblkhd %08x, numoutput %d, type %d\n", ! 436: vp->v_cleanblkhd, vp->v_dirtyblkhd, vp->v_numoutput, vp->v_type); ! 437: printf("union %08x, tag %d, data[0] %08x, data[1] %08x\n", ! 438: vp->v_socket, vp->v_tag, vp->v_data[0], vp->v_data[1]); ! 439: #endif /* defined(PCFSDEBUG) */ ! 440: error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD|FWRITE, ! 441: NOCRED, p); ! 442: vrele(pmp->pm_devvp); ! 443: free((caddr_t)pmp->pm_inusemap, M_MSDOSFSFAT); ! 444: free((caddr_t)pmp, M_MSDOSFSMNT); ! 445: mp->mnt_data = (qaddr_t)0; ! 446: mp->mnt_flag &= ~MNT_LOCAL; ! 447: return error; ! 448: } ! 449: ! 450: int ! 451: pcfs_root(mp, vpp) ! 452: struct mount *mp; ! 453: struct vnode **vpp; ! 454: { ! 455: struct denode *ndep; ! 456: struct pcfsmount *pmp = (struct pcfsmount *)(mp->mnt_data); ! 457: int error; ! 458: ! 459: error = deget(pmp, PCFSROOT, PCFSROOT_OFS, NULL, &ndep); ! 460: #if defined(PCFSDEBUG) ! 461: printf("pcfs_root(); mp %08x, pmp %08x, ndep %08x, vp %08x\n", ! 462: mp, pmp, ndep, DETOV(ndep)); ! 463: #endif /* defined(PCFSDEBUG) */ ! 464: if (error == 0) ! 465: *vpp = DETOV(ndep); ! 466: return error; ! 467: } ! 468: ! 469: int ! 470: pcfs_quotactl(mp, cmds, uid, arg, p) ! 471: struct mount *mp; ! 472: int cmds; ! 473: uid_t uid; ! 474: caddr_t arg; ! 475: struct proc *p; ! 476: { ! 477: #if defined(QUOTA) ! 478: #else ! 479: return EOPNOTSUPP; ! 480: #endif /* defined(QUOTA) */ ! 481: } ! 482: ! 483: int ! 484: pcfs_statfs(mp, sbp, p) ! 485: struct mount *mp; ! 486: struct statfs *sbp; ! 487: struct proc *p; ! 488: { ! 489: struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data; ! 490: ! 491: /* ! 492: * Fill in the stat block. ! 493: */ ! 494: sbp->f_type = MOUNT_MSDOS; ! 495: sbp->f_fsize = pmp->pm_bpcluster; ! 496: sbp->f_bsize = pmp->pm_bpcluster; ! 497: sbp->f_blocks = pmp->pm_nmbrofclusters; ! 498: sbp->f_bfree = pmp->pm_freeclustercount; ! 499: sbp->f_bavail = pmp->pm_freeclustercount; ! 500: sbp->f_files = pmp->pm_RootDirEnts; ! 501: sbp->f_ffree = 0; /* what to put in here? */ ! 502: ! 503: /* ! 504: * Copy the mounted on and mounted from names into ! 505: * the passed in stat block, if it is not the one ! 506: * in the mount structure. ! 507: */ ! 508: if (sbp != &mp->mnt_stat) { ! 509: bcopy((caddr_t)mp->mnt_stat.f_mntonname, ! 510: (caddr_t)&sbp->f_mntonname[0], MNAMELEN); ! 511: bcopy((caddr_t)mp->mnt_stat.f_mntfromname, ! 512: (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); ! 513: } ! 514: return 0; ! 515: } ! 516: ! 517: int ! 518: pcfs_sync(mp, waitfor) ! 519: struct mount *mp; ! 520: int waitfor; ! 521: { ! 522: struct vnode *vp; ! 523: struct denode *dep; ! 524: struct pcfsmount *pmp; ! 525: int error; ! 526: int allerror = 0; ! 527: ! 528: pmp = (struct pcfsmount *)mp->mnt_data; ! 529: ! 530: /* ! 531: * If we ever switch to not updating all of the fats ! 532: * all the time, this would be the place to update them ! 533: * from the first one. ! 534: */ ! 535: if (pmp->pm_fmod) { ! 536: if (pmp->pm_ronly) { ! 537: printf("pcfs_sync(): writing to readonly filesystem\n"); ! 538: return EINVAL; ! 539: } else { ! 540: /* update fats here */ ! 541: } ! 542: } ! 543: ! 544: /* ! 545: * Go thru in memory denodes and write them out along ! 546: * with unwritten file blocks. ! 547: */ ! 548: loop: ! 549: for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { ! 550: if (vp->v_mount != mp) /* not ours anymore */ ! 551: goto loop; ! 552: if (VOP_ISLOCKED(vp)) /* file is busy */ ! 553: continue; ! 554: dep = VTODE(vp); ! 555: if ((dep->de_flag & DEUPD) == 0 && vp->v_dirtyblkhd == NULL) ! 556: continue; ! 557: if (vget(vp)) /* not there anymore? */ ! 558: goto loop; ! 559: if (vp->v_dirtyblkhd) /* flush dirty file blocks */ ! 560: vflushbuf(vp, 0); ! 561: if ((dep->de_flag & DEUPD) && ! 562: (error = deupdat(dep, &time, 0))) ! 563: allerror = error; ! 564: vput(vp); /* done with this one */ ! 565: } ! 566: ! 567: /* ! 568: * Flush filesystem control info. ! 569: */ ! 570: vflushbuf(pmp->pm_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); ! 571: return allerror; ! 572: } ! 573: ! 574: int ! 575: pcfs_fhtovp (mp, fhp, vpp) ! 576: struct mount *mp; ! 577: struct fid *fhp; ! 578: struct vnode **vpp; ! 579: { ! 580: struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data; ! 581: struct defid *defhp = (struct defid *)fhp; ! 582: struct denode *dep; ! 583: int error; ! 584: ! 585: error = deget (pmp, defhp->defid_dirclust, defhp->defid_dirofs, ! 586: NULL, &dep); ! 587: if (error) ! 588: return (error); ! 589: *vpp = DETOV (dep); ! 590: return (0); ! 591: } ! 592: ! 593: ! 594: int ! 595: pcfs_vptofh (vp, fhp) ! 596: struct vnode *vp; ! 597: struct fid *fhp; ! 598: { ! 599: struct denode *dep = VTODE(vp); ! 600: struct defid *defhp = (struct defid *)fhp; ! 601: ! 602: defhp->defid_len = sizeof(struct defid); ! 603: defhp->defid_dirclust = dep->de_dirclust; ! 604: defhp->defid_dirofs = dep->de_diroffset; ! 605: /* defhp->defid_gen = ip->i_gen; */ ! 606: return (0); ! 607: } ! 608: ! 609: struct vfsops pcfs_vfsops = { ! 610: pcfs_mount, ! 611: pcfs_start, ! 612: pcfs_unmount, ! 613: pcfs_root, ! 614: pcfs_quotactl, ! 615: pcfs_statfs, ! 616: pcfs_sync, ! 617: pcfs_fhtovp, ! 618: pcfs_vptofh, ! 619: pcfs_init ! 620: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.