Annotation of sys/msdosfs/msdosfs_vnops.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: msdosfs_vnops.c,v 1.64 2007/06/02 02:04:21 deraadt Exp $ */
! 2: /* $NetBSD: msdosfs_vnops.c,v 1.63 1997/10/17 11:24:19 ws Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (C) 2005 Thomas Wang.
! 6: * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
! 7: * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
! 8: * All rights reserved.
! 9: * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by TooLs GmbH.
! 22: * 4. The name of TooLs GmbH may not be used to endorse or promote products
! 23: * derived from this software without specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
! 26: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 27: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 28: * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! 29: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 30: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 31: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 32: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 33: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 34: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 35: */
! 36: /*
! 37: * Written by Paul Popelka (paulp@uts.amdahl.com)
! 38: *
! 39: * You can do anything you want with this software, just don't say you wrote
! 40: * it, and don't remove this notice.
! 41: *
! 42: * This software is provided "as is".
! 43: *
! 44: * The author supplies this software to be publicly redistributed on the
! 45: * understanding that the author is not responsible for the correct
! 46: * functioning of this software in any circumstances and is not liable for
! 47: * any damages caused by this software.
! 48: *
! 49: * October 1992
! 50: */
! 51:
! 52: #include <sys/param.h>
! 53: #include <sys/systm.h>
! 54: #include <sys/namei.h>
! 55: #include <sys/resourcevar.h> /* defines plimit structure in proc struct */
! 56: #include <sys/kernel.h>
! 57: #include <sys/file.h> /* define FWRITE ... */
! 58: #include <sys/stat.h>
! 59: #include <sys/buf.h>
! 60: #include <sys/proc.h>
! 61: #include <sys/mount.h>
! 62: #include <sys/vnode.h>
! 63: #include <sys/signalvar.h>
! 64: #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
! 65: #include <sys/malloc.h>
! 66: #include <sys/pool.h>
! 67: #include <sys/dirent.h> /* defines dirent structure */
! 68: #include <sys/lockf.h>
! 69: #include <sys/poll.h>
! 70:
! 71: #include <uvm/uvm_extern.h>
! 72:
! 73: #include <msdosfs/bpb.h>
! 74: #include <msdosfs/direntry.h>
! 75: #include <msdosfs/denode.h>
! 76: #include <msdosfs/msdosfsmount.h>
! 77: #include <msdosfs/fat.h>
! 78:
! 79: static uint32_t fileidhash(uint64_t);
! 80:
! 81: /*
! 82: * Some general notes:
! 83: *
! 84: * In the ufs filesystem the inodes, superblocks, and indirect blocks are
! 85: * read/written using the vnode for the filesystem. Blocks that represent
! 86: * the contents of a file are read/written using the vnode for the file
! 87: * (including directories when they are read/written as files). This
! 88: * presents problems for the dos filesystem because data that should be in
! 89: * an inode (if dos had them) resides in the directory itself. Since we
! 90: * must update directory entries without the benefit of having the vnode
! 91: * for the directory we must use the vnode for the filesystem. This means
! 92: * that when a directory is actually read/written (via read, write, or
! 93: * readdir, or seek) we must use the vnode for the filesystem instead of
! 94: * the vnode for the directory as would happen in ufs. This is to insure we
! 95: * retrieve the correct block from the buffer cache since the hash value is
! 96: * based upon the vnode address and the desired block number.
! 97: */
! 98:
! 99: /*
! 100: * Create a regular file. On entry the directory to contain the file being
! 101: * created is locked. We must release before we return. We must also free
! 102: * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
! 103: * only if the SAVESTART bit in cn_flags is clear on success.
! 104: */
! 105: int
! 106: msdosfs_create(v)
! 107: void *v;
! 108: {
! 109: struct vop_create_args *ap = v;
! 110: struct componentname *cnp = ap->a_cnp;
! 111: struct denode ndirent;
! 112: struct denode *dep;
! 113: struct denode *pdep = VTODE(ap->a_dvp);
! 114: int error;
! 115: struct timespec ts;
! 116:
! 117: #ifdef MSDOSFS_DEBUG
! 118: printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap);
! 119: #endif
! 120:
! 121: /*
! 122: * If this is the root directory and there is no space left we
! 123: * can't do anything. This is because the root directory can not
! 124: * change size.
! 125: */
! 126: if (pdep->de_StartCluster == MSDOSFSROOT
! 127: && pdep->de_fndoffset >= pdep->de_FileSize) {
! 128: error = ENOSPC;
! 129: goto bad;
! 130: }
! 131:
! 132: /*
! 133: * Create a directory entry for the file, then call createde() to
! 134: * have it installed. NOTE: DOS files are always executable. We
! 135: * use the absence of the owner write bit to make the file
! 136: * readonly.
! 137: */
! 138: #ifdef DIAGNOSTIC
! 139: if ((cnp->cn_flags & HASBUF) == 0)
! 140: panic("msdosfs_create: no name");
! 141: #endif
! 142: bzero(&ndirent, sizeof(ndirent));
! 143: if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0)
! 144: goto bad;
! 145:
! 146: ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
! 147: ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
! 148: ndirent.de_StartCluster = 0;
! 149: ndirent.de_FileSize = 0;
! 150: ndirent.de_dev = pdep->de_dev;
! 151: ndirent.de_devvp = pdep->de_devvp;
! 152: ndirent.de_pmp = pdep->de_pmp;
! 153: ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
! 154: getnanotime(&ts);
! 155: DETIMES(&ndirent, &ts, &ts, &ts);
! 156: if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0)
! 157: goto bad;
! 158: if ((cnp->cn_flags & SAVESTART) == 0)
! 159: pool_put(&namei_pool, cnp->cn_pnbuf);
! 160: vput(ap->a_dvp);
! 161: *ap->a_vpp = DETOV(dep);
! 162: return (0);
! 163:
! 164: bad:
! 165: pool_put(&namei_pool, cnp->cn_pnbuf);
! 166: vput(ap->a_dvp);
! 167: return (error);
! 168: }
! 169:
! 170: int
! 171: msdosfs_mknod(v)
! 172: void *v;
! 173: {
! 174: struct vop_mknod_args *ap = v;
! 175:
! 176: pool_put(&namei_pool, ap->a_cnp->cn_pnbuf);
! 177: vput(ap->a_dvp);
! 178: return (EINVAL);
! 179: }
! 180:
! 181: int
! 182: msdosfs_open(v)
! 183: void *v;
! 184: {
! 185: #if 0
! 186: struct vop_open_args /* {
! 187: struct vnode *a_vp;
! 188: int a_mode;
! 189: struct ucred *a_cred;
! 190: struct proc *a_p;
! 191: } */ *ap;
! 192: #endif
! 193:
! 194: return (0);
! 195: }
! 196:
! 197: int
! 198: msdosfs_close(v)
! 199: void *v;
! 200: {
! 201: struct vop_close_args *ap = v;
! 202: struct vnode *vp = ap->a_vp;
! 203: struct denode *dep = VTODE(vp);
! 204: struct timespec ts;
! 205:
! 206: if (vp->v_usecount > 1 && !VOP_ISLOCKED(vp)) {
! 207: getnanotime(&ts);
! 208: DETIMES(dep, &ts, &ts, &ts);
! 209: }
! 210: return (0);
! 211: }
! 212:
! 213: int
! 214: msdosfs_access(v)
! 215: void *v;
! 216: {
! 217: struct vop_access_args *ap = v;
! 218: struct denode *dep = VTODE(ap->a_vp);
! 219: struct msdosfsmount *pmp = dep->de_pmp;
! 220: mode_t dosmode;
! 221:
! 222: dosmode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH);
! 223: if ((dep->de_Attributes & ATTR_READONLY) == 0)
! 224: dosmode |= (S_IWUSR|S_IWGRP|S_IWOTH);
! 225: dosmode &= pmp->pm_mask;
! 226: if (dep->de_Attributes & ATTR_DIRECTORY
! 227: && pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) {
! 228: dosmode |= (dosmode & S_IRUSR) ? S_IXUSR : 0;
! 229: dosmode |= (dosmode & S_IRGRP) ? S_IXGRP : 0;
! 230: dosmode |= (dosmode & S_IROTH) ? S_IXOTH : 0;
! 231: }
! 232:
! 233: return (vaccess(dosmode, pmp->pm_uid, pmp->pm_gid, ap->a_mode,
! 234: ap->a_cred));
! 235: }
! 236:
! 237: int
! 238: msdosfs_getattr(v)
! 239: void *v;
! 240: {
! 241: struct vop_getattr_args *ap = v;
! 242: struct denode *dep = VTODE(ap->a_vp);
! 243: struct msdosfsmount *pmp = dep->de_pmp;
! 244: struct vattr *vap = ap->a_vap;
! 245: struct timespec ts;
! 246: uint32_t fileid;
! 247:
! 248: getnanotime(&ts);
! 249: DETIMES(dep, &ts, &ts, &ts);
! 250: vap->va_fsid = dep->de_dev;
! 251:
! 252: /*
! 253: * The following computation of the fileid must be the same as
! 254: * that used in msdosfs_readdir() to compute d_fileno. If not,
! 255: * pwd doesn't work.
! 256: *
! 257: * We now use the starting cluster number as the fileid/fileno.
! 258: * This works for both files and directories (including the root
! 259: * directory, on FAT32). Even on FAT32, this will at most be a
! 260: * 28-bit number, as the high 4 bits of FAT32 cluster numbers
! 261: * are reserved.
! 262: *
! 263: * However, we do need to do something for 0-length files, which
! 264: * will not have a starting cluster number.
! 265: *
! 266: * These files cannot be directories, since (except for /, which
! 267: * is special-cased anyway) directories contain entries for . and
! 268: * .., so must have non-zero length.
! 269: *
! 270: * In this case, we just create a non-cryptographic hash of the
! 271: * original fileid calculation, and set the top bit.
! 272: *
! 273: * This algorithm has the benefit that all directories, and all
! 274: * non-zero-length files, will have fileids that are persistent
! 275: * across mounts and reboots, and that cannot collide (as long
! 276: * as the filesystem is not corrupt). Zero-length files will
! 277: * have fileids that are persistent, but that may collide. We
! 278: * will just have to live with that.
! 279: */
! 280: fileid = dep->de_StartCluster;
! 281:
! 282: if (dep->de_Attributes & ATTR_DIRECTORY) {
! 283: /* Special-case root */
! 284: if (dep->de_StartCluster == MSDOSFSROOT)
! 285: fileid = FAT32(pmp) ? pmp->pm_rootdirblk : 1;
! 286: } else {
! 287: if (dep->de_FileSize == 0) {
! 288: uint32_t dirsperblk;
! 289: uint64_t fileid64;
! 290:
! 291: dirsperblk = pmp->pm_BytesPerSec /
! 292: sizeof(struct direntry);
! 293:
! 294: fileid64 = (dep->de_dirclust == MSDOSFSROOT) ?
! 295: roottobn(pmp, 0) : cntobn(pmp, dep->de_dirclust);
! 296: fileid64 *= dirsperblk;
! 297: fileid64 += dep->de_diroffset / sizeof(struct direntry);
! 298:
! 299: fileid = fileidhash(fileid64);
! 300: }
! 301: }
! 302:
! 303: vap->va_fileid = fileid;
! 304: vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
! 305: ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
! 306: vap->va_mode &= dep->de_pmp->pm_mask;
! 307: if (dep->de_Attributes & ATTR_DIRECTORY) {
! 308: vap->va_mode |= S_IFDIR;
! 309: if (pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) {
! 310: vap->va_mode |= (vap->va_mode & S_IRUSR) ? S_IXUSR : 0;
! 311: vap->va_mode |= (vap->va_mode & S_IRGRP) ? S_IXGRP : 0;
! 312: vap->va_mode |= (vap->va_mode & S_IROTH) ? S_IXOTH : 0;
! 313: }
! 314: }
! 315: vap->va_nlink = 1;
! 316: vap->va_gid = dep->de_pmp->pm_gid;
! 317: vap->va_uid = dep->de_pmp->pm_uid;
! 318: vap->va_rdev = 0;
! 319: vap->va_size = dep->de_FileSize;
! 320: dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
! 321: if (dep->de_pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
! 322: dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
! 323: dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CTimeHundredth, &vap->va_ctime);
! 324: } else {
! 325: vap->va_atime = vap->va_mtime;
! 326: vap->va_ctime = vap->va_mtime;
! 327: }
! 328: vap->va_flags = 0;
! 329: if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
! 330: vap->va_flags |= SF_ARCHIVED;
! 331: vap->va_gen = 0;
! 332: vap->va_blocksize = dep->de_pmp->pm_bpcluster;
! 333: vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
! 334: ~(dep->de_pmp->pm_crbomask);
! 335: vap->va_type = ap->a_vp->v_type;
! 336: return (0);
! 337: }
! 338:
! 339: int
! 340: msdosfs_setattr(v)
! 341: void *v;
! 342: {
! 343: struct vop_setattr_args *ap = v;
! 344: int error = 0;
! 345: struct denode *dep = VTODE(ap->a_vp);
! 346: struct vattr *vap = ap->a_vap;
! 347: struct ucred *cred = ap->a_cred;
! 348:
! 349: #ifdef MSDOSFS_DEBUG
! 350: printf("msdosfs_setattr(): vp %08x, vap %08x, cred %08x, p %08x\n",
! 351: ap->a_vp, vap, cred, ap->a_p);
! 352: #endif
! 353: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
! 354: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
! 355: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
! 356: (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL) ||
! 357: (vap->va_uid != VNOVAL) || (vap->va_gid != VNOVAL)) {
! 358: #ifdef MSDOSFS_DEBUG
! 359: printf("msdosfs_setattr(): returning EINVAL\n");
! 360: printf(" va_type %d, va_nlink %x, va_fsid %x, va_fileid %x\n",
! 361: vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
! 362: printf(" va_blocksize %x, va_rdev %x, va_bytes %x, va_gen %x\n",
! 363: vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
! 364: printf(" va_uid %x, va_gid %x\n",
! 365: vap->va_uid, vap->va_gid);
! 366: #endif
! 367: return (EINVAL);
! 368: }
! 369: /*
! 370: * Directories must not ever get their attributes modified
! 371: */
! 372: if (ap->a_vp->v_type == VDIR)
! 373: return EISDIR;
! 374:
! 375: if (vap->va_size != VNOVAL) {
! 376: error = detrunc(dep, (uint32_t)vap->va_size, 0, cred, ap->a_p);
! 377: if (error)
! 378: return (error);
! 379: }
! 380: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
! 381: if (cred->cr_uid != dep->de_pmp->pm_uid &&
! 382: (error = suser_ucred(cred)) &&
! 383: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
! 384: (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
! 385: return (error);
! 386: if (!(dep->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)
! 387: && vap->va_atime.tv_sec != VNOVAL)
! 388: unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
! 389: if (vap->va_mtime.tv_sec != VNOVAL)
! 390: unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
! 391: dep->de_Attributes |= ATTR_ARCHIVE;
! 392: dep->de_flag |= DE_MODIFIED;
! 393: }
! 394: /*
! 395: * DOS files only have the ability to have their writability
! 396: * attribute set, so we use the owner write bit to set the readonly
! 397: * attribute.
! 398: */
! 399: if (vap->va_mode != (mode_t)VNOVAL) {
! 400: if (cred->cr_uid != dep->de_pmp->pm_uid &&
! 401: (error = suser_ucred(cred)))
! 402: return (error);
! 403: /* We ignore the read and execute bits. */
! 404: if (vap->va_mode & VWRITE)
! 405: dep->de_Attributes &= ~ATTR_READONLY;
! 406: else
! 407: dep->de_Attributes |= ATTR_READONLY;
! 408: dep->de_flag |= DE_MODIFIED;
! 409: }
! 410: /*
! 411: * Allow the `archived' bit to be toggled.
! 412: */
! 413: if (vap->va_flags != VNOVAL) {
! 414: if (cred->cr_uid != dep->de_pmp->pm_uid &&
! 415: (error = suser_ucred(cred)))
! 416: return (error);
! 417: if (vap->va_flags & SF_ARCHIVED)
! 418: dep->de_Attributes &= ~ATTR_ARCHIVE;
! 419: else
! 420: dep->de_Attributes |= ATTR_ARCHIVE;
! 421: dep->de_flag |= DE_MODIFIED;
! 422: }
! 423: return (deupdat(dep, 1));
! 424: }
! 425:
! 426: int
! 427: msdosfs_read(v)
! 428: void *v;
! 429: {
! 430: struct vop_read_args *ap = v;
! 431: int error = 0;
! 432: uint32_t diff;
! 433: int blsize;
! 434: int isadir;
! 435: uint32_t n;
! 436: long on;
! 437: daddr64_t lbn, rablock, rablkno;
! 438: struct buf *bp;
! 439: struct vnode *vp = ap->a_vp;
! 440: struct denode *dep = VTODE(vp);
! 441: struct msdosfsmount *pmp = dep->de_pmp;
! 442: struct uio *uio = ap->a_uio;
! 443:
! 444: /*
! 445: * If they didn't ask for any data, then we are done.
! 446: */
! 447: if (uio->uio_resid == 0)
! 448: return (0);
! 449: if (uio->uio_offset < 0)
! 450: return (EINVAL);
! 451:
! 452: isadir = dep->de_Attributes & ATTR_DIRECTORY;
! 453: do {
! 454: if (uio->uio_offset >= dep->de_FileSize)
! 455: return (0);
! 456:
! 457: lbn = de_cluster(pmp, uio->uio_offset);
! 458: on = uio->uio_offset & pmp->pm_crbomask;
! 459: n = min((uint32_t) (pmp->pm_bpcluster - on), uio->uio_resid);
! 460:
! 461: /*
! 462: * de_FileSize is uint32_t, and we know that uio_offset <
! 463: * de_FileSize, so uio->uio_offset < 2^32. Therefore
! 464: * the cast to uint32_t on the next line is safe.
! 465: */
! 466: diff = dep->de_FileSize - (uint32_t)uio->uio_offset;
! 467: if (diff < n)
! 468: n = diff;
! 469:
! 470: /* convert cluster # to block # if a directory */
! 471: if (isadir) {
! 472: error = pcbmap(dep, lbn, &lbn, 0, &blsize);
! 473: if (error)
! 474: return (error);
! 475: }
! 476: /*
! 477: * If we are operating on a directory file then be sure to
! 478: * do i/o with the vnode for the filesystem instead of the
! 479: * vnode for the directory.
! 480: */
! 481: if (isadir) {
! 482: error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
! 483: } else {
! 484: rablock = lbn + 1;
! 485: rablkno = de_cn2bn(pmp, rablock);
! 486: if (dep->de_lastr + 1 == lbn &&
! 487: de_cn2off(pmp, rablock) < dep->de_FileSize)
! 488: error = breadn(vp, de_cn2bn(pmp, lbn),
! 489: pmp->pm_bpcluster, &rablkno,
! 490: &pmp->pm_bpcluster, 1, NOCRED, &bp);
! 491: else
! 492: error = bread(vp, de_cn2bn(pmp, lbn),
! 493: pmp->pm_bpcluster, NOCRED, &bp);
! 494: dep->de_lastr = lbn;
! 495: }
! 496: n = min(n, pmp->pm_bpcluster - bp->b_resid);
! 497: if (error) {
! 498: brelse(bp);
! 499: return (error);
! 500: }
! 501: error = uiomove(bp->b_data + on, (int) n, uio);
! 502: brelse(bp);
! 503: } while (error == 0 && uio->uio_resid > 0 && n != 0);
! 504: if (!isadir && !(vp->v_mount->mnt_flag & MNT_NOATIME))
! 505: dep->de_flag |= DE_ACCESS;
! 506: return (error);
! 507: }
! 508:
! 509: /*
! 510: * Write data to a file or directory.
! 511: */
! 512: int
! 513: msdosfs_write(v)
! 514: void *v;
! 515: {
! 516: struct vop_write_args *ap = v;
! 517: int n;
! 518: int croffset;
! 519: int resid;
! 520: uint32_t osize;
! 521: int error = 0;
! 522: uint32_t count, lastcn;
! 523: daddr64_t bn;
! 524: struct buf *bp;
! 525: int ioflag = ap->a_ioflag;
! 526: struct uio *uio = ap->a_uio;
! 527: struct proc *p = uio->uio_procp;
! 528: struct vnode *vp = ap->a_vp;
! 529: struct vnode *thisvp;
! 530: struct denode *dep = VTODE(vp);
! 531: struct msdosfsmount *pmp = dep->de_pmp;
! 532: struct ucred *cred = ap->a_cred;
! 533:
! 534: #ifdef MSDOSFS_DEBUG
! 535: printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
! 536: vp, uio, ioflag, cred);
! 537: printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n",
! 538: dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
! 539: #endif
! 540:
! 541: switch (vp->v_type) {
! 542: case VREG:
! 543: if (ioflag & IO_APPEND)
! 544: uio->uio_offset = dep->de_FileSize;
! 545: thisvp = vp;
! 546: break;
! 547: case VDIR:
! 548: return EISDIR;
! 549: default:
! 550: panic("msdosfs_write(): bad file type");
! 551: }
! 552:
! 553: if (uio->uio_offset < 0)
! 554: return (EINVAL);
! 555:
! 556: if (uio->uio_resid == 0)
! 557: return (0);
! 558:
! 559: /* Don't bother to try to write files larger than the f/s limit */
! 560: if (uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX)
! 561: return (EFBIG);
! 562:
! 563: /*
! 564: * If they've exceeded their filesize limit, tell them about it.
! 565: */
! 566: if (p &&
! 567: ((uio->uio_offset + uio->uio_resid) >
! 568: p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
! 569: psignal(p, SIGXFSZ);
! 570: return (EFBIG);
! 571: }
! 572:
! 573: /*
! 574: * If the offset we are starting the write at is beyond the end of
! 575: * the file, then they've done a seek. Unix filesystems allow
! 576: * files with holes in them, DOS doesn't so we must fill the hole
! 577: * with zeroed blocks.
! 578: */
! 579: if (uio->uio_offset > dep->de_FileSize) {
! 580: if ((error = deextend(dep, uio->uio_offset, cred)) != 0)
! 581: return (error);
! 582: }
! 583:
! 584: /*
! 585: * Remember some values in case the write fails.
! 586: */
! 587: resid = uio->uio_resid;
! 588: osize = dep->de_FileSize;
! 589:
! 590: /*
! 591: * If we write beyond the end of the file, extend it to its ultimate
! 592: * size ahead of the time to hopefully get a contiguous area.
! 593: */
! 594: if (uio->uio_offset + resid > osize) {
! 595: count = de_clcount(pmp, uio->uio_offset + resid) -
! 596: de_clcount(pmp, osize);
! 597: if ((error = extendfile(dep, count, NULL, NULL, 0)) &&
! 598: (error != ENOSPC || (ioflag & IO_UNIT)))
! 599: goto errexit;
! 600: lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
! 601: } else
! 602: lastcn = de_clcount(pmp, osize) - 1;
! 603:
! 604: do {
! 605: if (de_cluster(pmp, uio->uio_offset) > lastcn) {
! 606: error = ENOSPC;
! 607: break;
! 608: }
! 609:
! 610: bn = de_blk(pmp, uio->uio_offset);
! 611: if ((uio->uio_offset & pmp->pm_crbomask) == 0
! 612: && (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset)
! 613: || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
! 614: /*
! 615: * If either the whole cluster gets written,
! 616: * or we write the cluster from its start beyond EOF,
! 617: * then no need to read data from disk.
! 618: */
! 619: bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0);
! 620: clrbuf(bp);
! 621: /*
! 622: * Do the bmap now, since pcbmap needs buffers
! 623: * for the fat table. (see msdosfs_strategy)
! 624: */
! 625: if (bp->b_blkno == bp->b_lblkno) {
! 626: error = pcbmap(dep,
! 627: de_bn2cn(pmp, bp->b_lblkno),
! 628: &bp->b_blkno, 0, 0);
! 629: if (error)
! 630: bp->b_blkno = -1;
! 631: }
! 632: if (bp->b_blkno == -1) {
! 633: brelse(bp);
! 634: if (!error)
! 635: error = EIO; /* XXX */
! 636: break;
! 637: }
! 638: } else {
! 639: /*
! 640: * The block we need to write into exists, so read it in.
! 641: */
! 642: error = bread(thisvp, bn, pmp->pm_bpcluster,
! 643: NOCRED, &bp);
! 644: if (error) {
! 645: brelse(bp);
! 646: break;
! 647: }
! 648: }
! 649:
! 650: croffset = uio->uio_offset & pmp->pm_crbomask;
! 651: n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
! 652: if (uio->uio_offset + n > dep->de_FileSize) {
! 653: dep->de_FileSize = uio->uio_offset + n;
! 654: uvm_vnp_setsize(vp, dep->de_FileSize);
! 655: }
! 656: uvm_vnp_uncache(vp);
! 657: /*
! 658: * Should these vnode_pager_* functions be done on dir
! 659: * files?
! 660: */
! 661:
! 662: /*
! 663: * Copy the data from user space into the buf header.
! 664: */
! 665: error = uiomove(bp->b_data + croffset, n, uio);
! 666:
! 667: /*
! 668: * If they want this synchronous then write it and wait for
! 669: * it. Otherwise, if on a cluster boundary write it
! 670: * asynchronously so we can move on to the next block
! 671: * without delay. Otherwise do a delayed write because we
! 672: * may want to write somemore into the block later.
! 673: */
! 674: if (ioflag & IO_SYNC)
! 675: (void) bwrite(bp);
! 676: else if (n + croffset == pmp->pm_bpcluster)
! 677: bawrite(bp);
! 678: else
! 679: bdwrite(bp);
! 680: dep->de_flag |= DE_UPDATE;
! 681: } while (error == 0 && uio->uio_resid > 0);
! 682:
! 683: /*
! 684: * If the write failed and they want us to, truncate the file back
! 685: * to the size it was before the write was attempted.
! 686: */
! 687: errexit:
! 688: if (error) {
! 689: if (ioflag & IO_UNIT) {
! 690: detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL);
! 691: uio->uio_offset -= resid - uio->uio_resid;
! 692: uio->uio_resid = resid;
! 693: } else {
! 694: detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL);
! 695: if (uio->uio_resid != resid)
! 696: error = 0;
! 697: }
! 698: } else if (ioflag & IO_SYNC)
! 699: error = deupdat(dep, 1);
! 700: return (error);
! 701: }
! 702:
! 703: int
! 704: msdosfs_ioctl(v)
! 705: void *v;
! 706: {
! 707: #if 0
! 708: struct vop_ioctl_args /* {
! 709: struct vnode *a_vp;
! 710: uint32_t a_command;
! 711: caddr_t a_data;
! 712: int a_fflag;
! 713: struct ucred *a_cred;
! 714: struct proc *a_p;
! 715: } */ *ap;
! 716: #endif
! 717:
! 718: return (ENOTTY);
! 719: }
! 720:
! 721: int
! 722: msdosfs_poll(v)
! 723: void *v;
! 724: {
! 725: struct vop_poll_args *ap = v;
! 726:
! 727: return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
! 728: }
! 729:
! 730: /*
! 731: * Flush the blocks of a file to disk.
! 732: *
! 733: * This function is worthless for vnodes that represent directories. Maybe we
! 734: * could just do a sync if they try an fsync on a directory file.
! 735: */
! 736: int
! 737: msdosfs_fsync(v)
! 738: void *v;
! 739: {
! 740: struct vop_fsync_args *ap = v;
! 741: struct vnode *vp = ap->a_vp;
! 742:
! 743: vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
! 744: return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
! 745: }
! 746:
! 747: /*
! 748: * Flush the blocks of a file to disk.
! 749: *
! 750: * This function is worthless for vnodes that represent directories. Maybe we
! 751: * could just do a sync if they try an fsync on a directory file.
! 752: */
! 753: int
! 754: msdosfs_remove(v)
! 755: void *v;
! 756: {
! 757: struct vop_remove_args *ap = v;
! 758: struct denode *dep = VTODE(ap->a_vp);
! 759: struct denode *ddep = VTODE(ap->a_dvp);
! 760: int error;
! 761:
! 762: if (ap->a_vp->v_type == VDIR)
! 763: error = EPERM;
! 764: else
! 765: error = removede(ddep, dep);
! 766: #ifdef MSDOSFS_DEBUG
! 767: printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount);
! 768: #endif
! 769: if (ddep == dep)
! 770: vrele(ap->a_vp);
! 771: else
! 772: vput(ap->a_vp); /* causes msdosfs_inactive() to be called
! 773: * via vrele() */
! 774: vput(ap->a_dvp);
! 775: return (error);
! 776: }
! 777:
! 778: /*
! 779: * DOS filesystems don't know what links are. But since we already called
! 780: * msdosfs_lookup() with create and lockparent, the parent is locked so we
! 781: * have to free it before we return the error.
! 782: */
! 783: int
! 784: msdosfs_link(v)
! 785: void *v;
! 786: {
! 787: struct vop_link_args *ap = v;
! 788:
! 789: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
! 790: vput(ap->a_dvp);
! 791: return (EOPNOTSUPP);
! 792: }
! 793:
! 794: /*
! 795: * Renames on files require moving the denode to a new hash queue since the
! 796: * denode's location is used to compute which hash queue to put the file
! 797: * in. Unless it is a rename in place. For example "mv a b".
! 798: *
! 799: * What follows is the basic algorithm:
! 800: *
! 801: * if (file move) {
! 802: * if (dest file exists) {
! 803: * remove dest file
! 804: * }
! 805: * if (dest and src in same directory) {
! 806: * rewrite name in existing directory slot
! 807: * } else {
! 808: * write new entry in dest directory
! 809: * update offset and dirclust in denode
! 810: * move denode to new hash chain
! 811: * clear old directory entry
! 812: * }
! 813: * } else {
! 814: * directory move
! 815: * if (dest directory exists) {
! 816: * if (dest is not empty) {
! 817: * return ENOTEMPTY
! 818: * }
! 819: * remove dest directory
! 820: * }
! 821: * if (dest and src in same directory) {
! 822: * rewrite name in existing entry
! 823: * } else {
! 824: * be sure dest is not a child of src directory
! 825: * write entry in dest directory
! 826: * update "." and ".." in moved directory
! 827: * update offset and dirclust in denode
! 828: * move denode to new hash chain
! 829: * clear old directory entry for moved directory
! 830: * }
! 831: * }
! 832: *
! 833: * On entry:
! 834: * source's parent directory is unlocked
! 835: * source file or directory is unlocked
! 836: * destination's parent directory is locked
! 837: * destination file or directory is locked if it exists
! 838: *
! 839: * On exit:
! 840: * all denodes should be released
! 841: *
! 842: * Notes:
! 843: * I'm not sure how the memory containing the pathnames pointed at by the
! 844: * componentname structures is freed, there may be some memory bleeding
! 845: * for each rename done.
! 846: */
! 847: int
! 848: msdosfs_rename(v)
! 849: void *v;
! 850: {
! 851: struct vop_rename_args *ap = v;
! 852: struct vnode *tvp = ap->a_tvp;
! 853: register struct vnode *tdvp = ap->a_tdvp;
! 854: struct vnode *fvp = ap->a_fvp;
! 855: register struct vnode *fdvp = ap->a_fdvp;
! 856: register struct componentname *tcnp = ap->a_tcnp;
! 857: register struct componentname *fcnp = ap->a_fcnp;
! 858: struct proc *p = curproc; /* XXX */
! 859: register struct denode *ip, *xp, *dp, *zp;
! 860: u_char toname[11], oldname[11];
! 861: uint32_t from_diroffset, to_diroffset;
! 862: u_char to_count;
! 863: int doingdirectory = 0, newparent = 0;
! 864: int error;
! 865: uint32_t cn, pcl;
! 866: daddr64_t bn;
! 867: struct msdosfsmount *pmp;
! 868: struct direntry *dotdotp;
! 869: struct buf *bp;
! 870:
! 871: pmp = VFSTOMSDOSFS(fdvp->v_mount);
! 872:
! 873: #ifdef DIAGNOSTIC
! 874: if ((tcnp->cn_flags & HASBUF) == 0 ||
! 875: (fcnp->cn_flags & HASBUF) == 0)
! 876: panic("msdosfs_rename: no name");
! 877: #endif
! 878: /*
! 879: * Check for cross-device rename.
! 880: */
! 881: if ((fvp->v_mount != tdvp->v_mount) ||
! 882: (tvp && (fvp->v_mount != tvp->v_mount))) {
! 883: error = EXDEV;
! 884: abortit:
! 885: VOP_ABORTOP(tdvp, tcnp);
! 886: if (tdvp == tvp)
! 887: vrele(tdvp);
! 888: else
! 889: vput(tdvp);
! 890: if (tvp)
! 891: vput(tvp);
! 892: VOP_ABORTOP(fdvp, fcnp);
! 893: vrele(fdvp);
! 894: vrele(fvp);
! 895: return (error);
! 896: }
! 897:
! 898: /*
! 899: * If source and dest are the same, do nothing.
! 900: */
! 901: if (tvp == fvp) {
! 902: error = 0;
! 903: goto abortit;
! 904: }
! 905:
! 906: /* */
! 907: if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
! 908: goto abortit;
! 909: dp = VTODE(fdvp);
! 910: ip = VTODE(fvp);
! 911:
! 912: /*
! 913: * Be sure we are not renaming ".", "..", or an alias of ".". This
! 914: * leads to a crippled directory tree. It's pretty tough to do a
! 915: * "ls" or "pwd" with the "." directory entry missing, and "cd .."
! 916: * doesn't work if the ".." entry is missing.
! 917: */
! 918: if (ip->de_Attributes & ATTR_DIRECTORY) {
! 919: /*
! 920: * Avoid ".", "..", and aliases of "." for obvious reasons.
! 921: */
! 922: if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
! 923: dp == ip ||
! 924: (fcnp->cn_flags & ISDOTDOT) ||
! 925: (tcnp->cn_flags & ISDOTDOT) ||
! 926: (ip->de_flag & DE_RENAME)) {
! 927: VOP_UNLOCK(fvp, 0, p);
! 928: error = EINVAL;
! 929: goto abortit;
! 930: }
! 931: ip->de_flag |= DE_RENAME;
! 932: doingdirectory++;
! 933: }
! 934:
! 935: /*
! 936: * When the target exists, both the directory
! 937: * and target vnodes are returned locked.
! 938: */
! 939: dp = VTODE(tdvp);
! 940: xp = tvp ? VTODE(tvp) : NULL;
! 941: /*
! 942: * Remember direntry place to use for destination
! 943: */
! 944: to_diroffset = dp->de_fndoffset;
! 945: to_count = dp->de_fndcnt;
! 946:
! 947: /*
! 948: * If ".." must be changed (ie the directory gets a new
! 949: * parent) then the source directory must not be in the
! 950: * directory hierarchy above the target, as this would
! 951: * orphan everything below the source directory. Also
! 952: * the user must have write permission in the source so
! 953: * as to be able to change "..". We must repeat the call
! 954: * to namei, as the parent directory is unlocked by the
! 955: * call to doscheckpath().
! 956: */
! 957: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
! 958: VOP_UNLOCK(fvp, 0, p);
! 959: if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
! 960: newparent = 1;
! 961: vrele(fdvp);
! 962: if (doingdirectory && newparent) {
! 963: if (error) /* write access check above */
! 964: goto bad1;
! 965: if (xp != NULL)
! 966: vput(tvp);
! 967: /*
! 968: * doscheckpath() vput()'s dp,
! 969: * so we have to do a relookup afterwards
! 970: */
! 971: if ((error = doscheckpath(ip, dp)) != 0)
! 972: goto out;
! 973: if ((tcnp->cn_flags & SAVESTART) == 0)
! 974: panic("msdosfs_rename: lost to startdir");
! 975: if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
! 976: goto out;
! 977: dp = VTODE(tdvp);
! 978: xp = tvp ? VTODE(tvp) : NULL;
! 979: }
! 980:
! 981: if (xp != NULL) {
! 982: /*
! 983: * Target must be empty if a directory and have no links
! 984: * to it. Also, ensure source and target are compatible
! 985: * (both directories, or both not directories).
! 986: */
! 987: if (xp->de_Attributes & ATTR_DIRECTORY) {
! 988: if (!dosdirempty(xp)) {
! 989: error = ENOTEMPTY;
! 990: goto bad1;
! 991: }
! 992: if (!doingdirectory) {
! 993: error = ENOTDIR;
! 994: goto bad1;
! 995: }
! 996: cache_purge(tdvp);
! 997: } else if (doingdirectory) {
! 998: error = EISDIR;
! 999: goto bad1;
! 1000: }
! 1001: if ((error = removede(dp, xp)) != 0)
! 1002: goto bad1;
! 1003: vput(tvp);
! 1004: xp = NULL;
! 1005: }
! 1006:
! 1007: /*
! 1008: * Convert the filename in tcnp into a dos filename. We copy this
! 1009: * into the denode and directory entry for the destination
! 1010: * file/directory.
! 1011: */
! 1012: if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0)
! 1013: goto bad1;
! 1014:
! 1015: /*
! 1016: * Since from wasn't locked at various places above,
! 1017: * have to do a relookup here.
! 1018: */
! 1019: fcnp->cn_flags &= ~MODMASK;
! 1020: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
! 1021: if ((fcnp->cn_flags & SAVESTART) == 0)
! 1022: panic("msdosfs_rename: lost from startdir");
! 1023: if (!newparent)
! 1024: VOP_UNLOCK(tdvp, 0, p);
! 1025: (void) relookup(fdvp, &fvp, fcnp);
! 1026: if (fvp == NULL) {
! 1027: /*
! 1028: * From name has disappeared.
! 1029: */
! 1030: if (doingdirectory)
! 1031: panic("rename: lost dir entry");
! 1032: vrele(ap->a_fvp);
! 1033: if (newparent)
! 1034: VOP_UNLOCK(tdvp, 0, p);
! 1035: vrele(tdvp);
! 1036: return 0;
! 1037: }
! 1038: xp = VTODE(fvp);
! 1039: zp = VTODE(fdvp);
! 1040: from_diroffset = zp->de_fndoffset;
! 1041:
! 1042: /*
! 1043: * Ensure that the directory entry still exists and has not
! 1044: * changed till now. If the source is a file the entry may
! 1045: * have been unlinked or renamed. In either case there is
! 1046: * no further work to be done. If the source is a directory
! 1047: * then it cannot have been rmdir'ed or renamed; this is
! 1048: * prohibited by the DE_RENAME flag.
! 1049: */
! 1050: if (xp != ip) {
! 1051: if (doingdirectory)
! 1052: panic("rename: lost dir entry");
! 1053: vrele(ap->a_fvp);
! 1054: if (newparent)
! 1055: VOP_UNLOCK(fdvp, 0, p);
! 1056: xp = NULL;
! 1057: } else {
! 1058: vrele(fvp);
! 1059: xp = NULL;
! 1060:
! 1061: /*
! 1062: * First write a new entry in the destination
! 1063: * directory and mark the entry in the source directory
! 1064: * as deleted. Then move the denode to the correct hash
! 1065: * chain for its new location in the filesystem. And, if
! 1066: * we moved a directory, then update its .. entry to point
! 1067: * to the new parent directory.
! 1068: */
! 1069: bcopy(ip->de_Name, oldname, 11);
! 1070: bcopy(toname, ip->de_Name, 11); /* update denode */
! 1071: dp->de_fndoffset = to_diroffset;
! 1072: dp->de_fndcnt = to_count;
! 1073: error = createde(ip, dp, (struct denode **)0, tcnp);
! 1074: if (error) {
! 1075: bcopy(oldname, ip->de_Name, 11);
! 1076: if (newparent)
! 1077: VOP_UNLOCK(fdvp, 0, p);
! 1078: goto bad;
! 1079: }
! 1080: ip->de_refcnt++;
! 1081: zp->de_fndoffset = from_diroffset;
! 1082: if ((error = removede(zp, ip)) != 0) {
! 1083: /* XXX should really panic here, fs is corrupt */
! 1084: if (newparent)
! 1085: VOP_UNLOCK(fdvp, 0, p);
! 1086: goto bad;
! 1087: }
! 1088:
! 1089: cache_purge(fvp);
! 1090:
! 1091: if (!doingdirectory) {
! 1092: error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
! 1093: &ip->de_dirclust, 0);
! 1094: if (error) {
! 1095: /* XXX should really panic here, fs is corrupt */
! 1096: if (newparent)
! 1097: VOP_UNLOCK(fdvp, 0, p);
! 1098: goto bad;
! 1099: }
! 1100: if (ip->de_dirclust != MSDOSFSROOT)
! 1101: ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
! 1102: }
! 1103: reinsert(ip);
! 1104: if (newparent)
! 1105: VOP_UNLOCK(fdvp, 0, p);
! 1106: }
! 1107:
! 1108: /*
! 1109: * If we moved a directory to a new parent directory, then we must
! 1110: * fixup the ".." entry in the moved directory.
! 1111: */
! 1112: if (doingdirectory && newparent) {
! 1113: cn = ip->de_StartCluster;
! 1114: if (cn == MSDOSFSROOT) {
! 1115: /* this should never happen */
! 1116: panic("msdosfs_rename: updating .. in root directory?");
! 1117: } else
! 1118: bn = cntobn(pmp, cn);
! 1119: error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
! 1120: NOCRED, &bp);
! 1121: if (error) {
! 1122: /* XXX should really panic here, fs is corrupt */
! 1123: brelse(bp);
! 1124: goto bad;
! 1125: }
! 1126: dotdotp = (struct direntry *)bp->b_data;
! 1127: putushort(dotdotp[0].deStartCluster, cn);
! 1128: pcl = dp->de_StartCluster;
! 1129: if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
! 1130: pcl = 0;
! 1131: putushort(dotdotp[1].deStartCluster, pcl);
! 1132: if (FAT32(pmp)) {
! 1133: putushort(dotdotp[0].deHighClust, cn >> 16);
! 1134: putushort(dotdotp[1].deHighClust, pcl >> 16);
! 1135: }
! 1136: if ((error = bwrite(bp)) != 0) {
! 1137: /* XXX should really panic here, fs is corrupt */
! 1138: goto bad;
! 1139: }
! 1140: }
! 1141:
! 1142: bad:
! 1143: VOP_UNLOCK(fvp, 0, p);
! 1144: vrele(fdvp);
! 1145: bad1:
! 1146: if (xp)
! 1147: vput(tvp);
! 1148: vput(tdvp);
! 1149: out:
! 1150: ip->de_flag &= ~DE_RENAME;
! 1151: vrele(fvp);
! 1152: return (error);
! 1153:
! 1154: }
! 1155:
! 1156: struct {
! 1157: struct direntry dot;
! 1158: struct direntry dotdot;
! 1159: } dosdirtemplate = {
! 1160: { ". ", " ", /* the . entry */
! 1161: ATTR_DIRECTORY, /* file attribute */
! 1162: CASE_LOWER_BASE | CASE_LOWER_EXT, /* lower case */
! 1163: 0, /* create time 100ths */
! 1164: { 0, 0 }, { 0, 0 }, /* create time & date */
! 1165: { 0, 0 }, /* access date */
! 1166: { 0, 0 }, /* high bits of start cluster */
! 1167: { 210, 4 }, { 210, 4 }, /* modify time & date */
! 1168: { 0, 0 }, /* startcluster */
! 1169: { 0, 0, 0, 0 } /* filesize */
! 1170: },
! 1171: { ".. ", " ", /* the .. entry */
! 1172: ATTR_DIRECTORY, /* file attribute */
! 1173: CASE_LOWER_BASE | CASE_LOWER_EXT, /* lower case */
! 1174: 0, /* create time 100ths */
! 1175: { 0, 0 }, { 0, 0 }, /* create time & date */
! 1176: { 0, 0 }, /* access date */
! 1177: { 0, 0 }, /* high bits of start cluster */
! 1178: { 210, 4 }, { 210, 4 }, /* modify time & date */
! 1179: { 0, 0 }, /* startcluster */
! 1180: { 0, 0, 0, 0 } /* filesize */
! 1181: }
! 1182: };
! 1183:
! 1184: int
! 1185: msdosfs_mkdir(v)
! 1186: void *v;
! 1187: {
! 1188: struct vop_mkdir_args *ap = v;
! 1189: struct componentname *cnp = ap->a_cnp;
! 1190: struct denode ndirent;
! 1191: struct denode *dep;
! 1192: struct denode *pdep = VTODE(ap->a_dvp);
! 1193: int error;
! 1194: daddr64_t bn;
! 1195: uint32_t newcluster, pcl;
! 1196: struct direntry *denp;
! 1197: struct msdosfsmount *pmp = pdep->de_pmp;
! 1198: struct buf *bp;
! 1199: struct timespec ts;
! 1200:
! 1201: /*
! 1202: * If this is the root directory and there is no space left we
! 1203: * can't do anything. This is because the root directory can not
! 1204: * change size.
! 1205: */
! 1206: if (pdep->de_StartCluster == MSDOSFSROOT
! 1207: && pdep->de_fndoffset >= pdep->de_FileSize) {
! 1208: error = ENOSPC;
! 1209: goto bad2;
! 1210: }
! 1211:
! 1212: /*
! 1213: * Allocate a cluster to hold the about to be created directory.
! 1214: */
! 1215: error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
! 1216: if (error)
! 1217: goto bad2;
! 1218:
! 1219: bzero(&ndirent, sizeof(ndirent));
! 1220: ndirent.de_pmp = pmp;
! 1221: ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
! 1222: getnanotime(&ts);
! 1223: DETIMES(&ndirent, &ts, &ts, &ts);
! 1224:
! 1225: /*
! 1226: * Now fill the cluster with the "." and ".." entries. And write
! 1227: * the cluster to disk. This way it is there for the parent
! 1228: * directory to be pointing at if there were a crash.
! 1229: */
! 1230: bn = cntobn(pmp, newcluster);
! 1231: /* always succeeds */
! 1232: bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
! 1233: bzero(bp->b_data, pmp->pm_bpcluster);
! 1234: bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
! 1235: denp = (struct direntry *)bp->b_data;
! 1236: putushort(denp[0].deStartCluster, newcluster);
! 1237: putushort(denp[0].deCDate, ndirent.de_CDate);
! 1238: putushort(denp[0].deCTime, ndirent.de_CTime);
! 1239: denp[0].deCTimeHundredth = ndirent.de_CTimeHundredth;
! 1240: putushort(denp[0].deADate, ndirent.de_ADate);
! 1241: putushort(denp[0].deMDate, ndirent.de_MDate);
! 1242: putushort(denp[0].deMTime, ndirent.de_MTime);
! 1243: pcl = pdep->de_StartCluster;
! 1244: if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
! 1245: pcl = 0;
! 1246: putushort(denp[1].deStartCluster, pcl);
! 1247: putushort(denp[1].deCDate, ndirent.de_CDate);
! 1248: putushort(denp[1].deCTime, ndirent.de_CTime);
! 1249: denp[1].deCTimeHundredth = ndirent.de_CTimeHundredth;
! 1250: putushort(denp[1].deADate, ndirent.de_ADate);
! 1251: putushort(denp[1].deMDate, ndirent.de_MDate);
! 1252: putushort(denp[1].deMTime, ndirent.de_MTime);
! 1253: if (FAT32(pmp)) {
! 1254: putushort(denp[0].deHighClust, newcluster >> 16);
! 1255: putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
! 1256: }
! 1257:
! 1258: if ((error = bwrite(bp)) != 0)
! 1259: goto bad;
! 1260:
! 1261: /*
! 1262: * Now build up a directory entry pointing to the newly allocated
! 1263: * cluster. This will be written to an empty slot in the parent
! 1264: * directory.
! 1265: */
! 1266: #ifdef DIAGNOSTIC
! 1267: if ((cnp->cn_flags & HASBUF) == 0)
! 1268: panic("msdosfs_mkdir: no name");
! 1269: #endif
! 1270: if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0)
! 1271: goto bad;
! 1272:
! 1273: ndirent.de_Attributes = ATTR_DIRECTORY;
! 1274: ndirent.de_StartCluster = newcluster;
! 1275: ndirent.de_FileSize = 0;
! 1276: ndirent.de_dev = pdep->de_dev;
! 1277: ndirent.de_devvp = pdep->de_devvp;
! 1278: if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0)
! 1279: goto bad;
! 1280: if ((cnp->cn_flags & SAVESTART) == 0)
! 1281: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1282: vput(ap->a_dvp);
! 1283: *ap->a_vpp = DETOV(dep);
! 1284: return (0);
! 1285:
! 1286: bad:
! 1287: clusterfree(pmp, newcluster, NULL);
! 1288: bad2:
! 1289: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1290: vput(ap->a_dvp);
! 1291: return (error);
! 1292: }
! 1293:
! 1294: int
! 1295: msdosfs_rmdir(v)
! 1296: void *v;
! 1297: {
! 1298: struct vop_rmdir_args *ap = v;
! 1299: register struct vnode *vp = ap->a_vp;
! 1300: register struct vnode *dvp = ap->a_dvp;
! 1301: register struct componentname *cnp = ap->a_cnp;
! 1302: register struct denode *ip, *dp;
! 1303: int error;
! 1304:
! 1305: ip = VTODE(vp);
! 1306: dp = VTODE(dvp);
! 1307: /*
! 1308: * No rmdir "." please.
! 1309: */
! 1310: if (dp == ip) {
! 1311: vrele(dvp);
! 1312: vput(vp);
! 1313: return (EINVAL);
! 1314: }
! 1315: /*
! 1316: * Verify the directory is empty (and valid).
! 1317: * (Rmdir ".." won't be valid since
! 1318: * ".." will contain a reference to
! 1319: * the current directory and thus be
! 1320: * non-empty.)
! 1321: */
! 1322: error = 0;
! 1323: if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
! 1324: error = ENOTEMPTY;
! 1325: goto out;
! 1326: }
! 1327: /*
! 1328: * Delete the entry from the directory. For dos filesystems this
! 1329: * gets rid of the directory entry on disk, the in memory copy
! 1330: * still exists but the de_refcnt is <= 0. This prevents it from
! 1331: * being found by deget(). When the vput() on dep is done we give
! 1332: * up access and eventually msdosfs_reclaim() will be called which
! 1333: * will remove it from the denode cache.
! 1334: */
! 1335: if ((error = removede(dp, ip)) != 0)
! 1336: goto out;
! 1337: /*
! 1338: * This is where we decrement the link count in the parent
! 1339: * directory. Since dos filesystems don't do this we just purge
! 1340: * the name cache and let go of the parent directory denode.
! 1341: */
! 1342: cache_purge(dvp);
! 1343: vput(dvp);
! 1344: dvp = NULL;
! 1345: /*
! 1346: * Truncate the directory that is being deleted.
! 1347: */
! 1348: error = detrunc(ip, (uint32_t)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc);
! 1349: cache_purge(vp);
! 1350: out:
! 1351: if (dvp)
! 1352: vput(dvp);
! 1353: vput(vp);
! 1354: return (error);
! 1355: }
! 1356:
! 1357: /*
! 1358: * DOS filesystems don't know what symlinks are.
! 1359: */
! 1360: int
! 1361: msdosfs_symlink(v)
! 1362: void *v;
! 1363: {
! 1364: struct vop_symlink_args *ap = v;
! 1365:
! 1366: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
! 1367: vput(ap->a_dvp);
! 1368: return (EOPNOTSUPP);
! 1369: }
! 1370:
! 1371: int
! 1372: msdosfs_readdir(v)
! 1373: void *v;
! 1374: {
! 1375: struct vop_readdir_args *ap = v;
! 1376: int error = 0;
! 1377: int diff;
! 1378: long n;
! 1379: int blsize;
! 1380: long on;
! 1381: long lost;
! 1382: long count;
! 1383: uint32_t dirsperblk;
! 1384: uint32_t cn, lbn;
! 1385: uint32_t fileno;
! 1386: long bias = 0;
! 1387: daddr64_t bn;
! 1388: struct buf *bp;
! 1389: struct denode *dep = VTODE(ap->a_vp);
! 1390: struct msdosfsmount *pmp = dep->de_pmp;
! 1391: struct direntry *dentp;
! 1392: struct dirent dirbuf;
! 1393: struct uio *uio = ap->a_uio;
! 1394: u_long *cookies = NULL;
! 1395: int ncookies = 0;
! 1396: off_t offset, wlast = -1;
! 1397: int chksum = -1;
! 1398:
! 1399: #ifdef MSDOSFS_DEBUG
! 1400: printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
! 1401: ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
! 1402: #endif
! 1403:
! 1404: /*
! 1405: * msdosfs_readdir() won't operate properly on regular files since
! 1406: * it does i/o only with the filesystem vnode, and hence can
! 1407: * retrieve the wrong block from the buffer cache for a plain file.
! 1408: * So, fail attempts to readdir() on a plain file.
! 1409: */
! 1410: if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
! 1411: return (ENOTDIR);
! 1412:
! 1413: /*
! 1414: * To be safe, initialize dirbuf
! 1415: */
! 1416: bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
! 1417:
! 1418: /*
! 1419: * If the user buffer is smaller than the size of one dos directory
! 1420: * entry or the file offset is not a multiple of the size of a
! 1421: * directory entry, then we fail the read.
! 1422: */
! 1423: count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
! 1424: offset = uio->uio_offset;
! 1425: if (count < sizeof(struct direntry) ||
! 1426: (offset & (sizeof(struct direntry) - 1)))
! 1427: return (EINVAL);
! 1428: lost = uio->uio_resid - count;
! 1429: uio->uio_resid = count;
! 1430:
! 1431: if (ap->a_ncookies) {
! 1432: ncookies = uio->uio_resid / sizeof(struct direntry) + 3;
! 1433: MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
! 1434: M_WAITOK);
! 1435: *ap->a_cookies = cookies;
! 1436: *ap->a_ncookies = ncookies;
! 1437: }
! 1438:
! 1439: dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
! 1440:
! 1441: /*
! 1442: * If they are reading from the root directory then, we simulate
! 1443: * the . and .. entries since these don't exist in the root
! 1444: * directory. We also set the offset bias to make up for having to
! 1445: * simulate these entries. By this I mean that at file offset 64 we
! 1446: * read the first entry in the root directory that lives on disk.
! 1447: */
! 1448: if (dep->de_StartCluster == MSDOSFSROOT
! 1449: || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
! 1450: #if 0
! 1451: printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
! 1452: offset);
! 1453: #endif
! 1454: bias = 2 * sizeof(struct direntry);
! 1455: if (offset < bias) {
! 1456: for (n = (int)offset / sizeof(struct direntry);
! 1457: n < 2; n++) {
! 1458: if (FAT32(pmp))
! 1459: dirbuf.d_fileno = pmp->pm_rootdirblk;
! 1460: else
! 1461: dirbuf.d_fileno = 1;
! 1462: dirbuf.d_type = DT_DIR;
! 1463: switch (n) {
! 1464: case 0:
! 1465: dirbuf.d_namlen = 1;
! 1466: strlcpy(dirbuf.d_name, ".",
! 1467: sizeof dirbuf.d_name);
! 1468: break;
! 1469: case 1:
! 1470: dirbuf.d_namlen = 2;
! 1471: strlcpy(dirbuf.d_name, "..",
! 1472: sizeof dirbuf.d_name);
! 1473: break;
! 1474: }
! 1475: dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
! 1476: if (uio->uio_resid < dirbuf.d_reclen)
! 1477: goto out;
! 1478: error = uiomove((caddr_t) &dirbuf,
! 1479: dirbuf.d_reclen, uio);
! 1480: if (error)
! 1481: goto out;
! 1482: offset += sizeof(struct direntry);
! 1483: if (cookies) {
! 1484: *cookies++ = offset;
! 1485: if (--ncookies <= 0)
! 1486: goto out;
! 1487: }
! 1488: }
! 1489: }
! 1490: }
! 1491:
! 1492: while (uio->uio_resid > 0) {
! 1493: lbn = de_cluster(pmp, offset - bias);
! 1494: on = (offset - bias) & pmp->pm_crbomask;
! 1495: n = min(pmp->pm_bpcluster - on, uio->uio_resid);
! 1496: diff = dep->de_FileSize - (offset - bias);
! 1497: if (diff <= 0)
! 1498: break;
! 1499: n = min(n, diff);
! 1500: if ((error = pcbmap(dep, lbn, &bn, &cn, &blsize)) != 0)
! 1501: break;
! 1502: error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
! 1503: if (error) {
! 1504: brelse(bp);
! 1505: return (error);
! 1506: }
! 1507: n = min(n, blsize - bp->b_resid);
! 1508:
! 1509: /*
! 1510: * Convert from dos directory entries to fs-independent
! 1511: * directory entries.
! 1512: */
! 1513: for (dentp = (struct direntry *)(bp->b_data + on);
! 1514: (char *)dentp < bp->b_data + on + n;
! 1515: dentp++, offset += sizeof(struct direntry)) {
! 1516: #if 0
! 1517: printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
! 1518: dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
! 1519: #endif
! 1520: /*
! 1521: * If this is an unused entry, we can stop.
! 1522: */
! 1523: if (dentp->deName[0] == SLOT_EMPTY) {
! 1524: brelse(bp);
! 1525: goto out;
! 1526: }
! 1527: /*
! 1528: * Skip deleted entries.
! 1529: */
! 1530: if (dentp->deName[0] == SLOT_DELETED) {
! 1531: chksum = -1;
! 1532: wlast = -1;
! 1533: continue;
! 1534: }
! 1535:
! 1536: /*
! 1537: * Handle Win95 long directory entries
! 1538: */
! 1539: if (dentp->deAttributes == ATTR_WIN95) {
! 1540: struct winentry *wep;
! 1541: if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
! 1542: continue;
! 1543: wep = (struct winentry *)dentp;
! 1544: chksum = win2unixfn(wep, &dirbuf, chksum);
! 1545: if (wep->weCnt & WIN_LAST)
! 1546: wlast = offset;
! 1547: continue;
! 1548: }
! 1549:
! 1550: /*
! 1551: * Skip volume labels
! 1552: */
! 1553: if (dentp->deAttributes & ATTR_VOLUME) {
! 1554: chksum = -1;
! 1555: wlast = -1;
! 1556: continue;
! 1557: }
! 1558:
! 1559: /*
! 1560: * This computation of d_fileno must match
! 1561: * the computation of va_fileid in
! 1562: * msdosfs_getattr.
! 1563: */
! 1564: fileno = getushort(dentp->deStartCluster);
! 1565: if (FAT32(pmp))
! 1566: fileno |= getushort(dentp->deHighClust) << 16;
! 1567:
! 1568: if (dentp->deAttributes & ATTR_DIRECTORY) {
! 1569: /* Special-case root */
! 1570: if (fileno == MSDOSFSROOT) {
! 1571: fileno = FAT32(pmp) ?
! 1572: pmp->pm_rootdirblk : 1;
! 1573: }
! 1574:
! 1575: dirbuf.d_fileno = fileno;
! 1576: dirbuf.d_type = DT_DIR;
! 1577: } else {
! 1578: if (getulong(dentp->deFileSize) == 0) {
! 1579: uint64_t fileno64;
! 1580:
! 1581: fileno64 = (cn == MSDOSFSROOT) ?
! 1582: roottobn(pmp, 0) : cntobn(pmp, cn);
! 1583:
! 1584: fileno64 *= dirsperblk;
! 1585: fileno64 += dentp -
! 1586: (struct direntry *)bp->b_data;
! 1587:
! 1588: fileno = fileidhash(fileno64);
! 1589: }
! 1590:
! 1591: dirbuf.d_fileno = fileno;
! 1592: dirbuf.d_type = DT_REG;
! 1593: }
! 1594:
! 1595: if (chksum != winChksum(dentp->deName))
! 1596: dirbuf.d_namlen = dos2unixfn(dentp->deName,
! 1597: (u_char *)dirbuf.d_name,
! 1598: pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
! 1599: else
! 1600: dirbuf.d_name[dirbuf.d_namlen] = 0;
! 1601: chksum = -1;
! 1602: dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
! 1603: if (uio->uio_resid < dirbuf.d_reclen) {
! 1604: brelse(bp);
! 1605: /* Remember long-name offset. */
! 1606: if (wlast != -1)
! 1607: offset = wlast;
! 1608: goto out;
! 1609: }
! 1610: wlast = -1;
! 1611: error = uiomove((caddr_t) &dirbuf,
! 1612: dirbuf.d_reclen, uio);
! 1613: if (error) {
! 1614: brelse(bp);
! 1615: goto out;
! 1616: }
! 1617: if (cookies) {
! 1618: *cookies++ = offset + sizeof(struct direntry);
! 1619: if (--ncookies <= 0) {
! 1620: brelse(bp);
! 1621: goto out;
! 1622: }
! 1623: }
! 1624: }
! 1625: brelse(bp);
! 1626: }
! 1627:
! 1628: out:
! 1629: /* Subtract unused cookies */
! 1630: if (ap->a_ncookies)
! 1631: *ap->a_ncookies -= ncookies;
! 1632:
! 1633: uio->uio_offset = offset;
! 1634: uio->uio_resid += lost;
! 1635: if (dep->de_FileSize - (offset - bias) <= 0)
! 1636: *ap->a_eofflag = 1;
! 1637: else
! 1638: *ap->a_eofflag = 0;
! 1639: return (error);
! 1640: }
! 1641:
! 1642: /*
! 1643: * DOS filesystems don't know what symlinks are.
! 1644: */
! 1645: int
! 1646: msdosfs_readlink(v)
! 1647: void *v;
! 1648: {
! 1649: #if 0
! 1650: struct vop_readlink_args /* {
! 1651: struct vnode *a_vp;
! 1652: struct uio *a_uio;
! 1653: struct ucred *a_cred;
! 1654: } */ *ap;
! 1655: #endif
! 1656:
! 1657: return (EINVAL);
! 1658: }
! 1659:
! 1660: int
! 1661: msdosfs_lock(v)
! 1662: void *v;
! 1663: {
! 1664: struct vop_lock_args *ap = v;
! 1665: struct vnode *vp = ap->a_vp;
! 1666:
! 1667: return (lockmgr(&VTODE(vp)->de_lock, ap->a_flags, NULL));
! 1668: }
! 1669:
! 1670: int
! 1671: msdosfs_unlock(v)
! 1672: void *v;
! 1673: {
! 1674: struct vop_unlock_args *ap = v;
! 1675: struct vnode *vp = ap->a_vp;
! 1676:
! 1677: return (lockmgr(&VTODE(vp)->de_lock, ap->a_flags | LK_RELEASE, NULL));
! 1678: }
! 1679:
! 1680: int
! 1681: msdosfs_islocked(v)
! 1682: void *v;
! 1683: {
! 1684: struct vop_islocked_args *ap = v;
! 1685:
! 1686: return (lockstatus(&VTODE(ap->a_vp)->de_lock));
! 1687: }
! 1688:
! 1689: /*
! 1690: * vp - address of vnode file the file
! 1691: * bn - which cluster we are interested in mapping to a filesystem block number.
! 1692: * vpp - returns the vnode for the block special file holding the filesystem
! 1693: * containing the file of interest
! 1694: * bnp - address of where to return the filesystem relative block number
! 1695: */
! 1696: int
! 1697: msdosfs_bmap(v)
! 1698: void *v;
! 1699: {
! 1700: struct vop_bmap_args *ap = v;
! 1701: struct denode *dep = VTODE(ap->a_vp);
! 1702: struct msdosfsmount *pmp = dep->de_pmp;
! 1703:
! 1704: if (ap->a_vpp != NULL)
! 1705: *ap->a_vpp = dep->de_devvp;
! 1706: if (ap->a_bnp == NULL)
! 1707: return (0);
! 1708: if (ap->a_runp) {
! 1709: /*
! 1710: * Sequential clusters should be counted here.
! 1711: */
! 1712: *ap->a_runp = 0;
! 1713: }
! 1714: return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
! 1715: }
! 1716:
! 1717: int
! 1718: msdosfs_strategy(v)
! 1719: void *v;
! 1720: {
! 1721: struct vop_strategy_args *ap = v;
! 1722: struct buf *bp = ap->a_bp;
! 1723: struct denode *dep = VTODE(bp->b_vp);
! 1724: struct vnode *vp;
! 1725: int error = 0;
! 1726: int s;
! 1727:
! 1728: if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
! 1729: panic("msdosfs_strategy: spec");
! 1730: /*
! 1731: * If we don't already know the filesystem relative block number
! 1732: * then get it using pcbmap(). If pcbmap() returns the block
! 1733: * number as -1 then we've got a hole in the file. DOS filesystems
! 1734: * don't allow files with holes, so we shouldn't ever see this.
! 1735: */
! 1736: if (bp->b_blkno == bp->b_lblkno) {
! 1737: error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
! 1738: &bp->b_blkno, 0, 0);
! 1739: if (error)
! 1740: bp->b_blkno = -1;
! 1741: if (bp->b_blkno == -1)
! 1742: clrbuf(bp);
! 1743: }
! 1744: if (bp->b_blkno == -1) {
! 1745: s = splbio();
! 1746: biodone(bp);
! 1747: splx(s);
! 1748: return (error);
! 1749: }
! 1750:
! 1751: /*
! 1752: * Read/write the block from/to the disk that contains the desired
! 1753: * file block.
! 1754: */
! 1755:
! 1756: vp = dep->de_devvp;
! 1757: bp->b_dev = vp->v_rdev;
! 1758: VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
! 1759: return (0);
! 1760: }
! 1761:
! 1762: int
! 1763: msdosfs_print(v)
! 1764: void *v;
! 1765: {
! 1766: struct vop_print_args *ap = v;
! 1767: struct denode *dep = VTODE(ap->a_vp);
! 1768:
! 1769: printf(
! 1770: "tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ",
! 1771: dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
! 1772: printf(" dev %d, %d, %s\n",
! 1773: major(dep->de_dev), minor(dep->de_dev),
! 1774: VOP_ISLOCKED(ap->a_vp) ? "(LOCKED)" : "");
! 1775: #ifdef DIAGNOSTIC
! 1776: lockmgr_printinfo(&dep->de_lock);
! 1777: #endif
! 1778:
! 1779: return (0);
! 1780: }
! 1781:
! 1782: int
! 1783: msdosfs_advlock(v)
! 1784: void *v;
! 1785: {
! 1786: struct vop_advlock_args *ap = v;
! 1787: register struct denode *dep = VTODE(ap->a_vp);
! 1788:
! 1789: return (lf_advlock(&dep->de_lockf, dep->de_FileSize, ap->a_id, ap->a_op,
! 1790: ap->a_fl, ap->a_flags));
! 1791: }
! 1792:
! 1793: int
! 1794: msdosfs_pathconf(v)
! 1795: void *v;
! 1796: {
! 1797: struct vop_pathconf_args *ap = v;
! 1798: struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
! 1799:
! 1800: switch (ap->a_name) {
! 1801: case _PC_LINK_MAX:
! 1802: *ap->a_retval = 1;
! 1803: return (0);
! 1804: case _PC_NAME_MAX:
! 1805: *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
! 1806: return (0);
! 1807: case _PC_PATH_MAX:
! 1808: *ap->a_retval = PATH_MAX;
! 1809: return (0);
! 1810: case _PC_CHOWN_RESTRICTED:
! 1811: *ap->a_retval = 1;
! 1812: return (0);
! 1813: case _PC_NO_TRUNC:
! 1814: *ap->a_retval = 0;
! 1815: return (0);
! 1816: default:
! 1817: return (EINVAL);
! 1818: }
! 1819: /* NOTREACHED */
! 1820: }
! 1821:
! 1822: /*
! 1823: * Thomas Wang's hash function, severely hacked to always set the high
! 1824: * bit on the number it returns (so no longer a proper hash function).
! 1825: */
! 1826: static uint32_t
! 1827: fileidhash(uint64_t fileid)
! 1828: {
! 1829: uint64_t c1 = 0x6e5ea73858134343LL;
! 1830: uint64_t c2 = 0xb34e8f99a2ec9ef5LL;
! 1831:
! 1832: /*
! 1833: * We now have the original fileid value, as 64-bit value.
! 1834: * We need to reduce it to 32-bits, with the top bit set.
! 1835: */
! 1836: fileid ^= ((c1 ^ fileid) >> 32);
! 1837: fileid *= c1;
! 1838: fileid ^= ((c2 ^ fileid) >> 31);
! 1839: fileid *= c2;
! 1840: fileid ^= ((c1 ^ fileid) >> 32);
! 1841:
! 1842: return (uint32_t)(fileid | 0x80000000);
! 1843: }
! 1844:
! 1845: /* Global vfs data structures for msdosfs */
! 1846: int (**msdosfs_vnodeop_p)(void *);
! 1847: struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
! 1848: { &vop_default_desc, vn_default_error },
! 1849: { &vop_lookup_desc, msdosfs_lookup }, /* lookup */
! 1850: { &vop_create_desc, msdosfs_create }, /* create */
! 1851: { &vop_mknod_desc, msdosfs_mknod }, /* mknod */
! 1852: { &vop_open_desc, msdosfs_open }, /* open */
! 1853: { &vop_close_desc, msdosfs_close }, /* close */
! 1854: { &vop_access_desc, msdosfs_access }, /* access */
! 1855: { &vop_getattr_desc, msdosfs_getattr }, /* getattr */
! 1856: { &vop_setattr_desc, msdosfs_setattr }, /* setattr */
! 1857: { &vop_read_desc, msdosfs_read }, /* read */
! 1858: { &vop_write_desc, msdosfs_write }, /* write */
! 1859: { &vop_ioctl_desc, msdosfs_ioctl }, /* ioctl */
! 1860: { &vop_poll_desc, msdosfs_poll }, /* poll */
! 1861: { &vop_fsync_desc, msdosfs_fsync }, /* fsync */
! 1862: { &vop_remove_desc, msdosfs_remove }, /* remove */
! 1863: { &vop_link_desc, msdosfs_link }, /* link */
! 1864: { &vop_rename_desc, msdosfs_rename }, /* rename */
! 1865: { &vop_mkdir_desc, msdosfs_mkdir }, /* mkdir */
! 1866: { &vop_rmdir_desc, msdosfs_rmdir }, /* rmdir */
! 1867: { &vop_symlink_desc, msdosfs_symlink }, /* symlink */
! 1868: { &vop_readdir_desc, msdosfs_readdir }, /* readdir */
! 1869: { &vop_readlink_desc, msdosfs_readlink }, /* readlink */
! 1870: { &vop_abortop_desc, vop_generic_abortop }, /* abortop */
! 1871: { &vop_inactive_desc, msdosfs_inactive }, /* inactive */
! 1872: { &vop_reclaim_desc, msdosfs_reclaim }, /* reclaim */
! 1873: { &vop_lock_desc, msdosfs_lock }, /* lock */
! 1874: { &vop_unlock_desc, msdosfs_unlock }, /* unlock */
! 1875: { &vop_bmap_desc, msdosfs_bmap }, /* bmap */
! 1876: { &vop_strategy_desc, msdosfs_strategy }, /* strategy */
! 1877: { &vop_print_desc, msdosfs_print }, /* print */
! 1878: { &vop_islocked_desc, msdosfs_islocked }, /* islocked */
! 1879: { &vop_pathconf_desc, msdosfs_pathconf }, /* pathconf */
! 1880: { &vop_advlock_desc, msdosfs_advlock }, /* advlock */
! 1881: { &vop_bwrite_desc, vop_generic_bwrite }, /* bwrite */
! 1882: { (struct vnodeop_desc *)NULL, (int (*)(void *))NULL }
! 1883: };
! 1884: struct vnodeopv_desc msdosfs_vnodeop_opv_desc =
! 1885: { &msdosfs_vnodeop_p, msdosfs_vnodeop_entries };
CVSweb