|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1991, 1993, 1994 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * (c) UNIX System Laboratories, Inc. ! 26: * All or some portions of this file are derived from material licensed ! 27: * to the University of California by American Telephone and Telegraph ! 28: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 29: * the permission of UNIX System Laboratories, Inc. ! 30: * ! 31: * Redistribution and use in source and binary forms, with or without ! 32: * modification, are permitted provided that the following conditions ! 33: * are met: ! 34: * 1. Redistributions of source code must retain the above copyright ! 35: * notice, this list of conditions and the following disclaimer. ! 36: * 2. Redistributions in binary form must reproduce the above copyright ! 37: * notice, this list of conditions and the following disclaimer in the ! 38: * documentation and/or other materials provided with the distribution. ! 39: * 3. All advertising materials mentioning features or use of this software ! 40: * must display the following acknowledgement: ! 41: * This product includes software developed by the University of ! 42: * California, Berkeley and its contributors. ! 43: * 4. Neither the name of the University nor the names of its contributors ! 44: * may be used to endorse or promote products derived from this software ! 45: * without specific prior written permission. ! 46: * ! 47: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 48: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 49: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 50: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 51: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 52: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 53: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 54: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 55: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 56: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 57: * SUCH DAMAGE. ! 58: * ! 59: * hfs_vfsops.c ! 60: * derived from @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 ! 61: * ! 62: * (c) Copyright 1997-1998 Apple Computer, Inc. All rights reserved. ! 63: * ! 64: * hfs_vfsops.c -- VFS layer for loadable HFS file system. ! 65: * ! 66: * HISTORY ! 67: * 9-Nov-1999 Don Brady Fix error handling in hfs_unmount [2399157]. ! 68: * 9-Sep-1999 Don Brady Clear system file fcbModified flags in hfs_flushvolumeheader/hfs_flushMDB. ! 69: * 5-Aug-1999 Pat Dirks Moved special HFS flag from f_fsid.val[0][0] to mount flags (#2293117). ! 70: * 23-Jul-1999 Pat Dirks Added special-case code for root's parent directory in hfs_vget (#2263664). ! 71: * 9-Jun-1999 Don Brady Fix hfs_mount for reload and read-only downgrade cases. ! 72: * 2-Jun-1999 Don Brady Fix hfs_statfs to return correct f_files value. ! 73: * 4-May-1999 Don Brady Remove obsolete loadable module code. ! 74: * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget. ! 75: * 18-May-1999 Don Brady Add hfs_mountroot for HFS Plus rooting. ! 76: * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget. ! 77: * 12-Nov-1998 Pat Dirks Changed hfs_statfs to return volume's actual log. block size (#2286198). ! 78: * 22-Aug-1998 Scott Roberts Assign uid,gid, and mask for default on objects. ! 79: * 29-Jul-1998 Pat Dirks Fixed changed hfs_vget() to release complex node when retrying for data fork node. ! 80: * 27-Jul-1998 Scott Roberts Changes hfs_vget() to return data forks instead of complex. ! 81: * 14-Jul-1998 CHW Added check for use count of device node in hfs_mountfs ! 82: * 1-Jul-1998 Don Brady Always set kHFSVolumeUnmountedMask bit of vcb->vcbAtrb in hfs_unmount. ! 83: * 30-Jun-1998 Don Brady Removed hard-coded EINVAL error in hfs_mountfs (for radar #2249539). ! 84: * 24-Jun-1998 Don Brady Added setting of timezone to hfs_mount (radar #2226387). ! 85: * 4-Jun-1998 Don Brady Use VPUT/VRELE macros instead of vput/vrele. ! 86: * 6-May-1998 Scott Roberts Updated hfs_vget with kernel changes. ! 87: * 29-Apr-1998 Don Brady Update hfs_statfs to actually fill in statfs fields (radar #2227092). ! 88: * 23-Apr-1998 Pat Dirks Cleaned up code to call brelse() on errors from bread(). ! 89: * 4/20/1998 Don Brady Remove course-grained hfs metadata locking. ! 90: * 4/18/1998 Don Brady Add VCB locking. ! 91: * 4/16/1998 Don Brady hfs_unmount now flushes the volume bitmap. Add b-tree locking to hfs_vget. ! 92: * 4/8/1998 Don Brady Replace hfs_mdbupdate with hfs_flushvolumeheader and hfs_flushMDB. ! 93: * 4/8/1998 Don Brady In hfs_unmount call hfs_mdbupdate before trashing metafiles! ! 94: * 4/3/1998 Don Brady Call InitCatalogCache instead of PostInitFS. ! 95: * 4/1/1998 Don Brady Get rid of gHFSFlags, gReqstVol and gFlushOnlyFlag globals (not used). ! 96: * 3/30/1998 Don Brady In hfs_unmount use SKIPSYSTEM option on first vflush. ! 97: * 3/26/1998 Don Brady Changed hfs_unmount to call vflush before calling hfsUnmount. ! 98: * In hfs_mountfs don't mount hfs-wrapper. ! 99: * 3/19/1998 Pat Dirks Fixed bug in hfs_mount where device vnode was being ! 100: * released on way out. ! 101: * 11/14/1997 Pat Dirks Derived from hfs_vfsops.c ! 102: */ ! 103: #include <sys/param.h> ! 104: #include <sys/systm.h> ! 105: ! 106: #include <sys/namei.h> ! 107: #include <sys/vnode.h> ! 108: #include <sys/mount.h> ! 109: #include <sys/malloc.h> ! 110: #include <sys/stat.h> ! 111: #include <dev/disk.h> ! 112: #include <sys/lock.h> ! 113: ! 114: #include <miscfs/specfs/specdev.h> ! 115: #include <kern/mapfs.h> ! 116: ! 117: #include <hfs/hfs_mount.h> ! 118: ! 119: #include "hfs.h" ! 120: #include "hfs_dbg.h" ! 121: ! 122: #include "hfscommon/headers/FileMgrInternal.h" ! 123: ! 124: #if HFS_DIAGNOSTIC ! 125: int hfs_dbg_all = 0; ! 126: int hfs_dbg_vfs = 0; ! 127: int hfs_dbg_vop = 0; ! 128: int hfs_dbg_load = 0; ! 129: int hfs_dbg_io = 0; ! 130: int hfs_dbg_utils = 0; ! 131: int hfs_dbg_rw = 0; ! 132: int hfs_dbg_lookup = 0; ! 133: int hfs_dbg_tree = 0; ! 134: int hfs_dbg_err = 0; ! 135: int hfs_dbg_test = 0; ! 136: #endif ! 137: ! 138: /* ! 139: * HFS File System globals: ! 140: */ ! 141: Ptr gBufferAddress[BUFFERPTRLISTSIZE]; ! 142: struct buf *gBufferHeaderPtr[BUFFERPTRLISTSIZE]; ! 143: int gBufferListIndex; ! 144: simple_lock_data_t gBufferPtrListLock; ! 145: ! 146: //static char hfs_fs_name[MFSNAMELEN] = "hfs"; ! 147: ! 148: /* The following represent information held in low-memory on the MacOS: */ ! 149: ! 150: struct FSVarsRec *gFSMVars; ! 151: ! 152: /* ! 153: * Global variables defined in other modules: ! 154: */ ! 155: extern struct vnodeopv_desc hfs_vnodeop_opv_desc; ! 156: ! 157: extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType); ! 158: ! 159: extern OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents); ! 160: ! 161: ! 162: extern void inittodr( time_t base); ! 163: extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb); ! 164: extern void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm); ! 165: extern void CopyCatalogToFCB(struct hfsCatalogInfo *catalogInfo, struct vnode *vp); ! 166: ! 167: int hfs_changefs(struct mount *mp, struct hfs_mount_args *args, struct proc *p); ! 168: ! 169: int hfs_reload(struct mount *mp, struct ucred *cred, struct proc *p); ! 170: int hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args); ! 171: int hfs_vget(struct mount *mp, void *objID, struct vnode **vpp); ! 172: void hfs_vhashinit(); ! 173: void hfs_converterinit(void); ! 174: ! 175: ! 176: static int hfs_statfs(); ! 177: ! 178: ! 179: /* ! 180: * Called by vfs_mountroot when mounting HFS Plus as root. ! 181: */ ! 182: int ! 183: hfs_mountroot() ! 184: { ! 185: extern struct vnode *rootvp; ! 186: struct mount *mp; ! 187: struct proc *p = current_proc(); /* XXX */ ! 188: struct hfsmount *hfsmp; ! 189: int error; ! 190: ! 191: /* ! 192: * Get vnode for rootdev. ! 193: */ ! 194: if ((error = bdevvp(rootdev, &rootvp))) { ! 195: printf("hfs_mountroot: can't setup bdevvp"); ! 196: return (error); ! 197: } ! 198: if ((error = vfs_rootmountalloc("hfs", "root_device", &mp))) ! 199: return (error); ! 200: if ((error = hfs_mountfs(rootvp, mp, p, NULL))) { ! 201: mp->mnt_vfc->vfc_refcount--; ! 202: vfs_unbusy(mp, p); ! 203: _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); ! 204: return (error); ! 205: } ! 206: simple_lock(&mountlist_slock); ! 207: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); ! 208: simple_unlock(&mountlist_slock); ! 209: ! 210: /* Init hfsmp */ ! 211: hfsmp = VFSTOHFS(mp); ! 212: ! 213: hfsmp->hfs_dir_mask = (S_IRWXU|S_IRWXG|S_IRWXO); /* 0777 */ ! 214: hfsmp->hfs_file_mask = (S_IRWXU|S_IRWXG|S_IRWXO); /* 0777 */ ! 215: ! 216: (void)hfs_statfs(mp, &mp->mnt_stat, p); ! 217: ! 218: vfs_unbusy(mp, p); ! 219: inittodr(to_bsd_time(HFSTOVCB(hfsmp)->vcbLsMod)); ! 220: return (0); ! 221: } ! 222: ! 223: ! 224: /* ! 225: * VFS Operations. ! 226: * ! 227: * mount system call ! 228: */ ! 229: ! 230: int ! 231: hfs_mount (mp, path, data, ndp, p) ! 232: register struct mount *mp; ! 233: char *path; ! 234: caddr_t data; ! 235: struct nameidata *ndp; ! 236: struct proc *p; ! 237: { ! 238: struct hfsmount *hfsmp = NULL; ! 239: struct vnode *devvp; ! 240: struct hfs_mount_args args; ! 241: size_t size; ! 242: int retval = E_NONE; ! 243: int flags; ! 244: mode_t accessmode; ! 245: int loadconv = 0; ! 246: ! 247: if ((retval = copyin(data, (caddr_t)&args, sizeof(args)))) ! 248: goto error_exit; ! 249: ! 250: /* ! 251: * If updating, check whether changing from read-only to ! 252: * read/write; if there is no device name, that's all we do. ! 253: */ ! 254: if (mp->mnt_flag & MNT_UPDATE) { ! 255: ! 256: hfsmp = VFSTOHFS(mp); ! 257: if (hfsmp->hfs_fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { ! 258: ! 259: /* use VFS_SYNC to push out System (btree) files */ ! 260: retval = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p); ! 261: if (retval && (mp->mnt_flag & MNT_FORCE) == 0) ! 262: goto error_exit; ! 263: ! 264: flags = WRITECLOSE; ! 265: if (mp->mnt_flag & MNT_FORCE) ! 266: flags |= FORCECLOSE; ! 267: ! 268: if ((retval = hfs_flushfiles(mp, flags))) ! 269: goto error_exit; ! 270: hfsmp->hfs_fs_clean = 1; ! 271: hfsmp->hfs_fs_ronly = 1; ! 272: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) ! 273: retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT); ! 274: else ! 275: retval = hfs_flushMDB(hfsmp, MNT_WAIT); ! 276: ! 277: /* also get the volume bitmap blocks */ ! 278: if (!retval) ! 279: retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p); ! 280: ! 281: if (retval) { ! 282: hfsmp->hfs_fs_clean = 0; ! 283: hfsmp->hfs_fs_ronly = 0; ! 284: goto error_exit; ! 285: } ! 286: } ! 287: ! 288: if ((mp->mnt_flag & MNT_RELOAD) && ! 289: (retval = hfs_reload(mp, ndp->ni_cnd.cn_cred, p))) ! 290: goto error_exit; ! 291: ! 292: if (hfsmp->hfs_fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { ! 293: /* ! 294: * If upgrade to read-write by non-root, then verify ! 295: * that user has necessary permissions on the device. ! 296: */ ! 297: if (p->p_ucred->cr_uid != 0) { ! 298: devvp = hfsmp->hfs_devvp; ! 299: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); ! 300: if ((retval = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p))) { ! 301: VOP_UNLOCK(devvp, 0, p); ! 302: goto error_exit; ! 303: } ! 304: VOP_UNLOCK(devvp, 0, p); ! 305: } ! 306: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) ! 307: retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT); ! 308: else ! 309: retval = hfs_flushMDB(hfsmp, MNT_WAIT); ! 310: ! 311: if (retval != E_NONE) ! 312: goto error_exit; ! 313: ! 314: /* only change hfs_fs_ronly after a successfull write */ ! 315: hfsmp->hfs_fs_ronly = 0; ! 316: hfsmp->hfs_fs_clean = 0; ! 317: } ! 318: ! 319: if (hfsmp->hfs_fs_ronly == 0) { ! 320: /* setup private/hidden directory for unlinked files */ ! 321: hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(HFSTOVCB(hfsmp)); ! 322: } ! 323: ! 324: #if 0 /* XXX PPD */ ! 325: if (args.fspec == 0) { ! 326: /* ! 327: * Process export requests. ! 328: */ ! 329: retval = (vfs_export(mp, &hfsmp->hfs_export, &args.export)); ! 330: } ! 331: #endif ! 332: ! 333: } ! 334: ! 335: /* ! 336: * Not an update, or updating the name: look up the name ! 337: * and verify that it refers to a sensible block device. ! 338: */ ! 339: NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); ! 340: retval = namei(ndp); ! 341: if (retval != E_NONE) { ! 342: DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args.fspec, ndp->ni_vp->v_rdev)); ! 343: goto error_exit; ! 344: } ! 345: ! 346: devvp = ndp->ni_vp; ! 347: ! 348: if (devvp->v_type != VBLK) { ! 349: VRELE(devvp); ! 350: retval = ENOTBLK; ! 351: goto error_exit; ! 352: } ! 353: if (major(devvp->v_rdev) >= nblkdev) { ! 354: VRELE(devvp); ! 355: retval = ENXIO; ! 356: goto error_exit; ! 357: } ! 358: ! 359: /* ! 360: * If mount by non-root, then verify that user has necessary ! 361: * permissions on the device. ! 362: */ ! 363: if (p->p_ucred->cr_uid != 0) { ! 364: accessmode = VREAD; ! 365: if ((mp->mnt_flag & MNT_RDONLY) == 0) ! 366: accessmode |= VWRITE; ! 367: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); ! 368: if ((retval = VOP_ACCESS(devvp, accessmode, p->p_ucred, p))) { ! 369: VPUT(devvp); ! 370: goto error_exit; ! 371: } ! 372: VOP_UNLOCK(devvp, 0, p); ! 373: } ! 374: ! 375: if ((mp->mnt_flag & MNT_UPDATE) == 0) { ! 376: retval = hfs_mountfs(devvp, mp, p, &args); ! 377: if (retval != E_NONE) ! 378: VRELE(devvp); ! 379: } else { ! 380: if (devvp != hfsmp->hfs_devvp) ! 381: retval = EINVAL; /* needs translation */ ! 382: else ! 383: retval = hfs_changefs(mp, &args, p); ! 384: VRELE(devvp); ! 385: } ! 386: ! 387: if (retval != E_NONE) { ! 388: goto error_exit; ! 389: } ! 390: ! 391: ! 392: /* Set the mount flag to indicate that we support volfs */ ! 393: mp->mnt_flag |= MNT_DOVOLFS; ! 394: if (VFSTOVCB(mp)->vcbSigWord == kHFSSigWord) { ! 395: /* HFS volumes only want roman-encoded names: */ ! 396: mp->mnt_flag |= MNT_ROMANONLY; ! 397: } ! 398: (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size); ! 399: bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); ! 400: (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); ! 401: bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); ! 402: (void)hfs_statfs(mp, &mp->mnt_stat, p); ! 403: return (E_NONE); ! 404: ! 405: error_exit: ! 406: ! 407: return (retval); ! 408: } ! 409: ! 410: ! 411: /* change fs mount parameters */ ! 412: int ! 413: hfs_changefs(mp, args, p) ! 414: struct mount *mp; ! 415: struct hfs_mount_args *args; ! 416: struct proc *p; ! 417: { ! 418: int retval; ! 419: int namefix, permfix; ! 420: struct hfsmount *hfsmp; ! 421: struct hfsnode *hp; ! 422: mode_t hfs_file_mask; ! 423: ExtendedVCB *vcb; ! 424: register struct vnode *vp, *nvp; ! 425: ! 426: namefix = permfix = 0; ! 427: hfsmp = VFSTOHFS(mp); ! 428: vcb = HFSTOVCB(hfsmp); ! 429: ! 430: /* change the hfs timezone (Note: this affects all hfs volumes) */ ! 431: if ((VFSTOVCB(mp)->vcbSigWord == kHFSSigWord) && ! 432: (args->hfs_timezone.tz_minuteswest != VNOVAL)) { ! 433: gTimeZone = args->hfs_timezone; ! 434: } ! 435: ! 436: /* change the default uid, gid and/or mask */ ! 437: if (args->hfs_uid != (uid_t)VNOVAL && hfsmp->hfs_uid != args->hfs_uid) { ! 438: hfsmp->hfs_uid = args->hfs_uid; ! 439: ++permfix; ! 440: } ! 441: if (args->hfs_gid != (gid_t)VNOVAL && hfsmp->hfs_gid != args->hfs_gid) { ! 442: hfsmp->hfs_gid = args->hfs_gid; ! 443: ++permfix; ! 444: } ! 445: if (args->hfs_mask != (mode_t)VNOVAL) { ! 446: if (hfsmp->hfs_dir_mask != (args->hfs_mask & ALLPERMS)) { ! 447: hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS; ! 448: hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS; ! 449: if ((args->flags != VNOVAL) && (args->flags & HFSFSMNT_NOXONFILES)) ! 450: hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE); ! 451: ++permfix; ! 452: } ! 453: } ! 454: ! 455: /* change the hfs encoding value (hfs only) */ ! 456: if ((HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) && ! 457: (hfsmp->hfs_encoding != (u_long)VNOVAL) && ! 458: (hfsmp->hfs_encoding != args->hfs_encoding)) { ! 459: hfs_to_unicode_func_t get_unicode_func; ! 460: unicode_to_hfs_func_t get_hfsname_func; ! 461: ! 462: retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func); ! 463: if (retval) goto error_exit; ! 464: ! 465: /* now release the old one */ ! 466: (void) hfs_relconverter(hfsmp->hfs_encoding); ! 467: ! 468: hfsmp->hfs_encoding = args->hfs_encoding; ! 469: hfsmp->hfs_get_unicode = get_unicode_func; ! 470: hfsmp->hfs_get_hfsname = get_hfsname_func; ! 471: ++namefix; ! 472: } ! 473: ! 474: ! 475: if (!(namefix || permfix)) ! 476: goto exit; ! 477: ! 478: /* ! 479: * For each active vnode fix things that changed ! 480: * ! 481: * Note that we can visit a vnode more than once ! 482: * and we can race with fsync. ! 483: */ ! 484: simple_lock(&mntvnode_slock); ! 485: loop: ! 486: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { ! 487: /* ! 488: * If the vnode that we are about to fix is no longer ! 489: * associated with this mount point, start over. ! 490: */ ! 491: if (vp->v_mount != mp) ! 492: goto loop; ! 493: ! 494: simple_lock(&vp->v_interlock); ! 495: nvp = vp->v_mntvnodes.le_next; ! 496: if (vp->v_flag & VSYSTEM) { ! 497: simple_unlock(&vp->v_interlock); ! 498: continue; ! 499: } ! 500: simple_unlock(&mntvnode_slock); ! 501: retval = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); ! 502: if (retval) { ! 503: simple_lock(&mntvnode_slock); ! 504: if (retval == ENOENT) ! 505: goto loop; ! 506: continue; ! 507: } ! 508: ! 509: hp = VTOH(vp); ! 510: ! 511: if (permfix && (hp->h_meta->h_metaflags & IN_UNSETACCESS)) { ! 512: hp->h_meta->h_uid = hfsmp->hfs_uid; ! 513: hp->h_meta->h_gid = hfsmp->hfs_gid; ! 514: /* Default access is full read/write/execute: */ ! 515: hp->h_meta->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */ ! 516: ! 517: /* ... but no more than that permitted by the mount point's: */ ! 518: if ((hp->h_meta->h_mode & IFMT) == IFDIR) ! 519: hp->h_meta->h_mode &= hfsmp->hfs_dir_mask; ! 520: else ! 521: hp->h_meta->h_mode &= hfsmp->hfs_file_mask; ! 522: } ! 523: ! 524: if (namefix) { ! 525: hfsCatalogInfo catInfo; ! 526: ! 527: /* lookup by fileID since UTF-8 name will change */ ! 528: catInfo.hint = kNoHint; ! 529: if (hfsLookup(vcb, H_FILEID(hp), NULL, -1, &catInfo) == 0) { ! 530: H_HINT(hp) = catInfo.hint; ! 531: hfs_set_metaname(catInfo.spec.name, hp->h_meta); ! 532: } ! 533: H_HINT(hp) = catInfo.hint; ! 534: hfs_set_metaname(catInfo.spec.name, hp->h_meta); ! 535: } ! 536: ! 537: VPUT(vp); ! 538: simple_lock(&mntvnode_slock); ! 539: ! 540: } /* end for (vp...) */ ! 541: simple_unlock(&mntvnode_slock); ! 542: ! 543: ! 544: exit: ! 545: return (0); ! 546: ! 547: error_exit: ! 548: ! 549: return (retval); ! 550: } ! 551: ! 552: ! 553: /* ! 554: * Reload all incore data for a filesystem (used after running fsck on ! 555: * the root filesystem and finding things to fix). The filesystem must ! 556: * be mounted read-only. ! 557: * ! 558: * Things to do to update the mount: ! 559: * 1) invalidate all cached meta-data. ! 560: * 2) re-read volume header from disk. ! 561: * 3) re-load meta-file info (extents, file size). ! 562: * 4) invalidate all inactive vnodes. ! 563: * 5) invalidate all cached file data. ! 564: * 6) re-read hfsnode data for all active vnodes. ! 565: */ ! 566: int ! 567: hfs_reload(mountp, cred, p) ! 568: register struct mount *mountp; ! 569: struct ucred *cred; ! 570: struct proc *p; ! 571: { ! 572: register struct vnode *vp, *nvp, *devvp; ! 573: struct hfsnode *hp; ! 574: struct buf *bp; ! 575: int size, error; ! 576: struct hfsmount *hfsmp; ! 577: struct HFSPlusVolumeHeader *vhp; ! 578: ExtendedVCB *vcb; ! 579: FCB *fcb; ! 580: ! 581: if ((mountp->mnt_flag & MNT_RDONLY) == 0) ! 582: return (EINVAL); ! 583: ! 584: hfsmp = VFSTOHFS(mountp); ! 585: vcb = HFSTOVCB(hfsmp); ! 586: ! 587: if (vcb->vcbSigWord == kHFSSigWord) ! 588: return (EINVAL); /* rooting from HFS is not supported! */ ! 589: ! 590: /* ! 591: * Step 1: invalidate all cached meta-data. ! 592: */ ! 593: devvp = hfsmp->hfs_devvp; ! 594: if (vinvalbuf(devvp, 0, cred, p, 0, 0)) ! 595: panic("hfs_reload: dirty1"); ! 596: InvalidateCatalogCache(vcb); ! 597: ! 598: /* ! 599: * Step 2: re-read VolumeHeader from disk. ! 600: */ ! 601: size = kMDBSize; ! 602: error = bread( hfsmp->hfs_devvp, ! 603: IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size), ! 604: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), ! 605: NOCRED, ! 606: &bp); ! 607: if (error) { ! 608: if (bp != NULL) ! 609: brelse(bp); ! 610: return (error); ! 611: } ! 612: ! 613: vhp = (HFSPlusVolumeHeader *) ((char *)bp->b_data + ! 614: IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size)); ! 615: ! 616: if ((ValidVolumeHeader(vhp) != 0) || (vcb->blockSize != vhp->blockSize)) { ! 617: brelse(bp); ! 618: return (EIO); /* XXX needs translation */ ! 619: } ! 620: ! 621: vcb->vcbCrDate = LocalToUTC(vhp->createDate); ! 622: vcb->vcbLsMod = vhp->modifyDate; ! 623: vcb->vcbAtrb = (UInt16) vhp->attributes; /* VCB only uses lower 16 bits */ ! 624: vcb->vcbClpSiz = vhp->rsrcClumpSize; ! 625: vcb->vcbNxtCNID = vhp->nextCatalogID; ! 626: vcb->vcbVolBkUp = vhp->backupDate; ! 627: vcb->vcbWrCnt = vhp->writeCount; ! 628: vcb->vcbFilCnt = vhp->fileCount; ! 629: vcb->vcbDirCnt = vhp->folderCount; ! 630: vcb->nextAllocation = vhp->nextAllocation; ! 631: vcb->totalBlocks = vhp->totalBlocks; ! 632: vcb->freeBlocks = vhp->freeBlocks; ! 633: vcb->checkedDate = vhp->checkedDate; ! 634: vcb->encodingsBitmap = vhp->encodingsBitmap; ! 635: ! 636: bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo)); ! 637: ! 638: /* ! 639: * Step 3: re-load meta-file vnode data (extent info, file size, etc). ! 640: */ ! 641: fcb = VTOFCB((struct vnode *)vcb->extentsRefNum); ! 642: bcopy(vhp->extentsFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); ! 643: fcb->fcbEOF = vhp->extentsFile.logicalSize; ! 644: fcb->fcbPLen = vhp->extentsFile.totalBlocks * vcb->blockSize; ! 645: fcb->fcbClmpSize = vhp->extentsFile.clumpSize; ! 646: ! 647: fcb = VTOFCB((struct vnode *)vcb->catalogRefNum); ! 648: bcopy(vhp->catalogFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); ! 649: fcb->fcbPLen = vhp->catalogFile.logicalSize; ! 650: fcb->fcbPLen = vhp->catalogFile.totalBlocks * vcb->blockSize; ! 651: fcb->fcbClmpSize = vhp->catalogFile.clumpSize; ! 652: ! 653: fcb = VTOFCB((struct vnode *)vcb->allocationsRefNum); ! 654: bcopy(vhp->allocationFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); ! 655: fcb->fcbEOF = vhp->allocationFile.logicalSize; ! 656: fcb->fcbPLen = vhp->allocationFile.totalBlocks * vcb->blockSize; ! 657: fcb->fcbClmpSize = vhp->allocationFile.clumpSize; ! 658: ! 659: /* Now that the catalog vnode is ready, get the volume name */ ! 660: if ((error = MacToVFSError( GetVolumeNameFromCatalog(vcb) ))) { ! 661: brelse(bp); ! 662: return (error); ! 663: } ! 664: ! 665: /* reestablish private/hidden directory for unlinked files */ ! 666: hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb); ! 667: ! 668: brelse(bp); ! 669: ! 670: loop: ! 671: simple_lock(&mntvnode_slock); ! 672: for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { ! 673: if (vp->v_mount != mountp) { ! 674: simple_unlock(&mntvnode_slock); ! 675: goto loop; ! 676: } ! 677: nvp = vp->v_mntvnodes.le_next; ! 678: ! 679: /* ! 680: * Step 4: invalidate all inactive vnodes. ! 681: */ ! 682: if (vrecycle(vp, &mntvnode_slock, p)) ! 683: goto loop; ! 684: ! 685: /* ! 686: * Step 5: invalidate all cached file data. ! 687: */ ! 688: simple_lock(&vp->v_interlock); ! 689: simple_unlock(&mntvnode_slock); ! 690: if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { ! 691: goto loop; ! 692: } ! 693: if (vinvalbuf(vp, 0, cred, p, 0, 0)) ! 694: panic("hfs_reload: dirty2"); ! 695: ! 696: /* ! 697: * Step 6: re-read hfsnode data for all active vnodes (non-metadata files). ! 698: */ ! 699: hp = VTOH(vp); ! 700: if ((vp->v_flag & VSYSTEM) == 0) { ! 701: hfsCatalogInfo catInfo; ! 702: ! 703: /* lookup by fileID since name could have changed */ ! 704: catInfo.hint = kNoHint; ! 705: if ((error = hfsLookup(vcb, H_FILEID(hp), NULL, -1, &catInfo))) { ! 706: vput(vp); ! 707: return (error); ! 708: } ! 709: H_HINT(hp) = catInfo.hint; ! 710: if (hp->h_meta->h_metaflags & IN_LONGNAME) ! 711: FREE(H_NAME(hp), M_TEMP); ! 712: H_NAME(hp) = NULL; ! 713: CopyCatalogToObjectMeta(&catInfo, vp, hp->h_meta); ! 714: CopyCatalogToFCB(&catInfo, vp); ! 715: } ! 716: ! 717: vput(vp); ! 718: simple_lock(&mntvnode_slock); ! 719: } ! 720: simple_unlock(&mntvnode_slock); ! 721: ! 722: return (0); ! 723: } ! 724: ! 725: ! 726: /* ! 727: * Common code for mount and mountroot ! 728: */ ! 729: int ! 730: hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args) ! 731: { ! 732: int retval = E_NONE; ! 733: register struct hfsmount *hfsmp; ! 734: struct buf *bp; ! 735: dev_t dev; ! 736: HFSMasterDirectoryBlock *mdbp; ! 737: int ronly; ! 738: struct ucred *cred; ! 739: u_long diskBlks; ! 740: u_long blksize; ! 741: DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long)mp)); ! 742: ! 743: dev = devvp->v_rdev; ! 744: cred = p ? p->p_ucred : NOCRED; ! 745: /* ! 746: * Disallow multiple mounts of the same device. ! 747: * Disallow mounting of a device that is currently in use ! 748: * (except for root, which might share swap device for miniroot). ! 749: * Flush out any old buffers remaining from a previous use. ! 750: */ ! 751: if ((retval = vfs_mountedon(devvp))) ! 752: return (retval); ! 753: if (vcount(devvp) > 1 && devvp != rootvp) ! 754: return (EBUSY); ! 755: if ((retval = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0))) ! 756: return (retval); ! 757: ! 758: ronly = (mp->mnt_flag & MNT_RDONLY) != 0; ! 759: DBG_VFS(("hfs_mountfs: opening device...\n")); ! 760: if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))) ! 761: return (retval); ! 762: ! 763: blksize = kHFSBlockSize; ! 764: DBG_VFS(("hfs_mountfs: size = %d (DEV_BSIZE = %d).\n", blksize, DEV_BSIZE)); ! 765: ! 766: bp = NULL; ! 767: hfsmp = NULL; ! 768: ! 769: /* ! 770: * XXX SER Currently we only support 512 block size systems. This might change ! 771: * So this is a place holder to remind us that the mdb might not be 512 aligned ! 772: * retval = VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, &blksize, FWRITE, cred, p); ! 773: * if (retval) return retval; ! 774: */ ! 775: ! 776: retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p); ! 777: if (retval) return retval; ! 778: ! 779: ! 780: DBG_VFS(("hfs_mountfs: reading MDB [block no. %d + %d bytes, size %d bytes]...\n", ! 781: IOBLKNOFORBLK(kMasterDirectoryBlock, blksize), ! 782: IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize), ! 783: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize))); ! 784: ! 785: if ((retval = bread(devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, blksize), ! 786: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize), cred, &bp))) { ! 787: goto error_exit; ! 788: }; ! 789: mdbp = (HFSMasterDirectoryBlock*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize)); ! 790: ! 791: MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK); ! 792: bzero(hfsmp, sizeof(struct hfsmount)); ! 793: ! 794: DBG_VFS(("hfs_mountfs: Initializing hfsmount structure at 0x%lX...\n", (u_long)hfsmp)); ! 795: /* ! 796: * Init the volume information structure ! 797: */ ! 798: mp->mnt_data = (qaddr_t)hfsmp; ! 799: hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */ ! 800: hfsmp->hfs_vcb.vcb_hfsmp = hfsmp; /* Make VCBTOHFS work */ ! 801: hfsmp->hfs_raw_dev = devvp->v_rdev; ! 802: hfsmp->hfs_devvp = devvp; ! 803: hfsmp->hfs_phys_block_size = blksize; ! 804: /* The hfs_log_block_size field is updated in the respective hfs_MountHFS[Plus]Volume routine */ ! 805: hfsmp->hfs_logBlockSize = BestBlockSizeFit(mdbp->drAlBlkSiz, MAXBSIZE, hfsmp->hfs_phys_block_size); ! 806: hfsmp->hfs_fs_ronly = ronly; ! 807: if (args) { ! 808: hfsmp->hfs_uid = args->hfs_uid; ! 809: hfsmp->hfs_gid = args->hfs_gid; ! 810: hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS; ! 811: if (args->flags & HFSFSMNT_NOXONFILES) ! 812: hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE); ! 813: else ! 814: hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS; ! 815: } ! 816: ! 817: /* See above comment for DKIOCGETBLOCKSIZE ! 818: * retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p); ! 819: * if (retval) return retval; ! 820: */ ! 821: ! 822: retval = VOP_IOCTL(devvp, DKIOCNUMBLKS, &diskBlks, 0, cred, p); ! 823: if (retval) return retval; ! 824: ! 825: if (mdbp->drSigWord == kHFSPlusSigWord) { ! 826: /* mount wrapper-less HFS-Plus volume */ ! 827: (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname); ! 828: retval = hfs_MountHFSPlusVolume(hfsmp, (HFSPlusVolumeHeader*) bp->b_data, 0, diskBlks, p); ! 829: ! 830: } else if (mdbp->drEmbedSigWord == kHFSPlusSigWord) { ! 831: u_long embBlkOffset; ! 832: HFSPlusVolumeHeader *vhp; ! 833: ! 834: embBlkOffset = mdbp->drAlBlSt + ! 835: (mdbp->drEmbedExtent.startBlock * (mdbp->drAlBlkSiz/kHFSBlockSize)); ! 836: /* calculate virtual number of 512-byte sectors */ ! 837: diskBlks = mdbp->drEmbedExtent.blockCount * (mdbp->drAlBlkSiz/kHFSBlockSize); ! 838: brelse(bp); ! 839: bp = NULL; /* done with MDB, go grab Volume Header */ ! 840: mdbp = NULL; ! 841: ! 842: retval = bread( devvp, ! 843: IOBLKNOFORBLK(kMasterDirectoryBlock+embBlkOffset, blksize), ! 844: IOBYTECCNTFORBLK(kMasterDirectoryBlock+embBlkOffset, kMDBSize, blksize), ! 845: cred, ! 846: &bp); ! 847: if (retval) { ! 848: goto error_exit; ! 849: }; ! 850: vhp = (HFSPlusVolumeHeader*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize)); ! 851: ! 852: /* mount embedded HFS Plus volume */ ! 853: (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname); ! 854: retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embBlkOffset, diskBlks, p); ! 855: ! 856: } else if (devvp != rootvp) { ! 857: if (args) { ! 858: hfsmp->hfs_encoding = args->hfs_encoding; ! 859: ! 860: /* establish the zimezone (not used by HFS Plus) */ ! 861: gTimeZone = args->hfs_timezone; ! 862: } ! 863: ! 864: retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname); ! 865: if (retval) goto error_exit; ! 866: ! 867: /* mount HFS volume */ ! 868: retval = hfs_MountHFSVolume( hfsmp, mdbp, diskBlks, p); ! 869: ! 870: if (retval) ! 871: (void) hfs_relconverter(hfsmp->hfs_encoding); ! 872: ! 873: } else { ! 874: /* sorry, we cannot root from HFS */ ! 875: retval = EINVAL; ! 876: } ! 877: ! 878: if ( retval ) { ! 879: goto error_exit; ! 880: } ! 881: ! 882: brelse(bp); ! 883: bp = NULL; ! 884: ! 885: mp->mnt_stat.f_fsid.val[0] = (long)dev; ! 886: mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; ! 887: mp->mnt_maxsymlinklen = 0; ! 888: devvp->v_specflags |= SI_MOUNTEDON; ! 889: ! 890: if (ronly == 0) { ! 891: hfsmp->hfs_fs_clean = 0; ! 892: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) ! 893: (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT); ! 894: else ! 895: (void) hfs_flushMDB(hfsmp, MNT_WAIT); ! 896: } ! 897: goto std_exit; ! 898: ! 899: error_exit: ! 900: DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval)); ! 901: ! 902: if (bp) ! 903: brelse(bp); ! 904: (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); ! 905: if (hfsmp) { ! 906: FREE(hfsmp, M_HFSMNT); ! 907: mp->mnt_data = (qaddr_t)0; ! 908: } ! 909: ! 910: std_exit: ! 911: return (retval); ! 912: } ! 913: ! 914: ! 915: /* ! 916: * Make a filesystem operational. ! 917: * Nothing to do at the moment. ! 918: */ ! 919: /* ARGSUSED */ ! 920: int hfs_start(mp, flags, p) ! 921: struct mount *mp; ! 922: int flags; ! 923: struct proc *p; ! 924: { ! 925: DBG_FUNC_NAME("hfs_start"); ! 926: DBG_PRINT_FUNC_NAME(); ! 927: ! 928: return (0); ! 929: } ! 930: ! 931: ! 932: /* ! 933: * unmount system call ! 934: */ ! 935: int ! 936: hfs_unmount(mp, mntflags, p) ! 937: struct mount *mp; ! 938: int mntflags; ! 939: struct proc *p; ! 940: { ! 941: struct hfsmount *hfsmp = VFSTOHFS(mp); ! 942: int retval = E_NONE; ! 943: int flags; ! 944: ! 945: flags = 0; ! 946: if (mntflags & MNT_FORCE) ! 947: flags |= FORCECLOSE; ! 948: ! 949: if ((retval = hfs_flushfiles(mp, flags))) ! 950: return (retval); ! 951: ! 952: /* ! 953: * Flush out the volume bitmap and MDB/Volume Header ! 954: */ ! 955: if (hfsmp->hfs_fs_ronly == 0) { ! 956: if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) { ! 957: if ((mntflags & MNT_FORCE) == 0) ! 958: return (retval); ! 959: } ! 960: ! 961: /* See if this volume is damaged, is so do not unmount cleanly */ ! 962: if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) { ! 963: hfsmp->hfs_fs_clean = 0; ! 964: HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask; ! 965: } else { ! 966: hfsmp->hfs_fs_clean = 1; ! 967: HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask; ! 968: } ! 969: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) ! 970: retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT); ! 971: else ! 972: retval = hfs_flushMDB(hfsmp, MNT_WAIT); ! 973: ! 974: if (retval) { ! 975: hfsmp->hfs_fs_clean = 0; ! 976: HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask; ! 977: if ((mntflags & MNT_FORCE) == 0) ! 978: return (retval); /* could not flush everything */ ! 979: } ! 980: } ! 981: ! 982: /* ! 983: * Invalidate our caches and release metadata vnodes ! 984: */ ! 985: (void) hfsUnmount(hfsmp, p); ! 986: ! 987: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) ! 988: (void) hfs_relconverter(hfsmp->hfs_encoding); ! 989: ! 990: hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON; ! 991: retval = VOP_CLOSE(hfsmp->hfs_devvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, ! 992: NOCRED, p); ! 993: VRELE(hfsmp->hfs_devvp); ! 994: ! 995: FREE(hfsmp, M_HFSMNT); ! 996: mp->mnt_data = (qaddr_t)0; ! 997: ! 998: return (retval); ! 999: } ! 1000: ! 1001: ! 1002: /* ! 1003: * Return the root of a filesystem. ! 1004: * ! 1005: * OUT - vpp, should be locked and vget()'d (to increment usecount and lock) ! 1006: */ ! 1007: int hfs_root(mp, vpp) ! 1008: struct mount *mp; ! 1009: struct vnode **vpp; ! 1010: { ! 1011: struct vnode *nvp; ! 1012: int retval; ! 1013: UInt32 rootObjID = kRootDirID; ! 1014: ! 1015: DBG_FUNC_NAME("hfs_root"); ! 1016: DBG_PRINT_FUNC_NAME(); ! 1017: ! 1018: if ((retval = VFS_VGET(mp, &rootObjID, &nvp))) ! 1019: return (retval); ! 1020: ! 1021: *vpp = nvp; ! 1022: return (0); ! 1023: } ! 1024: ! 1025: /* ! 1026: * Do operations associated with quotas ! 1027: */ ! 1028: int hfs_quotactl(mp, cmds, uid, arg, p) ! 1029: struct mount *mp; ! 1030: int cmds; ! 1031: uid_t uid; ! 1032: caddr_t arg; ! 1033: struct proc *p; ! 1034: { ! 1035: DBG_FUNC_NAME("hfs_quotactl"); ! 1036: DBG_PRINT_FUNC_NAME(); ! 1037: ! 1038: return (EOPNOTSUPP); ! 1039: } ! 1040: ! 1041: ! 1042: ! 1043: /* ! 1044: * Get file system statistics. ! 1045: */ ! 1046: static int ! 1047: hfs_statfs(mp, sbp, p) ! 1048: struct mount *mp; ! 1049: register struct statfs *sbp; ! 1050: struct proc *p; ! 1051: { ! 1052: ExtendedVCB *vcb = VFSTOVCB(mp); ! 1053: struct hfsmount *hfsmp = VFSTOHFS(mp); ! 1054: u_long freeCNIDs; ! 1055: ! 1056: DBG_FUNC_NAME("hfs_statfs"); ! 1057: DBG_PRINT_FUNC_NAME(); ! 1058: ! 1059: freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID; ! 1060: ! 1061: sbp->f_bsize = vcb->blockSize; ! 1062: sbp->f_iosize = hfsmp->hfs_logBlockSize; ! 1063: sbp->f_blocks = vcb->totalBlocks; ! 1064: sbp->f_bfree = vcb->freeBlocks; ! 1065: sbp->f_bavail = vcb->freeBlocks; ! 1066: sbp->f_files = vcb->totalBlocks - 2; /* max files is constrained by total blocks */ ! 1067: sbp->f_ffree = MIN(freeCNIDs, vcb->freeBlocks); ! 1068: ! 1069: sbp->f_type = 0; ! 1070: if (sbp != &mp->mnt_stat) { ! 1071: sbp->f_type = mp->mnt_vfc->vfc_typenum; ! 1072: bcopy((caddr_t)mp->mnt_stat.f_mntonname, ! 1073: (caddr_t)&sbp->f_mntonname[0], MNAMELEN); ! 1074: bcopy((caddr_t)mp->mnt_stat.f_mntfromname, ! 1075: (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); ! 1076: } ! 1077: return (0); ! 1078: } ! 1079: ! 1080: ! 1081: /* ! 1082: * Go through the disk queues to initiate sandbagged IO; ! 1083: * go through the inodes to write those that have been modified; ! 1084: * initiate the writing of the super block if it has been modified. ! 1085: * ! 1086: * Note: we are always called with the filesystem marked `MPBUSY'. ! 1087: */ ! 1088: static int hfs_sync(mp, waitfor, cred, p) ! 1089: struct mount *mp; ! 1090: int waitfor; ! 1091: struct ucred *cred; ! 1092: struct proc *p; ! 1093: { ! 1094: struct vnode *nvp, *vp; ! 1095: struct hfsnode *hp; ! 1096: struct hfsmount *hfsmp = VFSTOHFS(mp); ! 1097: ExtendedVCB *vcb; ! 1098: int error, allerror = 0; ! 1099: ! 1100: DBG_FUNC_NAME("hfs_sync"); ! 1101: DBG_PRINT_FUNC_NAME(); ! 1102: ! 1103: hfsmp = VFSTOHFS(mp); ! 1104: if (hfsmp->hfs_fs_ronly != 0) { ! 1105: panic("update: rofs mod"); ! 1106: }; ! 1107: ! 1108: /* ! 1109: * Write back each 'modified' vnode ! 1110: */ ! 1111: simple_lock(&mntvnode_slock); ! 1112: ! 1113: loop:; ! 1114: ! 1115: for (vp = mp->mnt_vnodelist.lh_first; ! 1116: vp != NULL; ! 1117: vp = nvp) { ! 1118: /* ! 1119: * If the vnode that we are about to sync is no longer ! 1120: * associated with this mount point, start over. ! 1121: */ ! 1122: if (vp->v_mount != mp) ! 1123: goto loop; ! 1124: simple_lock(&vp->v_interlock); ! 1125: nvp = vp->v_mntvnodes.le_next; ! 1126: hp = VTOH(vp); ! 1127: ! 1128: if ((vp->v_type == VNON) || (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) && ! 1129: (vp->v_dirtyblkhd.lh_first == NULL))) { ! 1130: simple_unlock(&vp->v_interlock); ! 1131: continue; ! 1132: } ! 1133: ! 1134: simple_unlock(&mntvnode_slock); ! 1135: error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); ! 1136: if (error) { ! 1137: simple_lock(&mntvnode_slock); ! 1138: if (error == ENOENT) ! 1139: goto loop; ! 1140: continue; ! 1141: } ! 1142: ! 1143: if ((error = VOP_FSYNC(vp, cred, waitfor, p))) { ! 1144: DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error, (u_int)vp)); ! 1145: allerror = error; ! 1146: }; ! 1147: DBG_ASSERT(*((volatile int *)(&(vp)->v_interlock))==0); ! 1148: VPUT(vp); ! 1149: simple_lock(&mntvnode_slock); ! 1150: }; ! 1151: ! 1152: vcb = HFSTOVCB(hfsmp); ! 1153: ! 1154: /* Now reprocess the BTree node, stored above */ ! 1155: { ! 1156: struct vnode *btvp; ! 1157: /* ! 1158: * If the vnode that we are about to sync is no longer ! 1159: * associated with this mount point, start over. ! 1160: */ ! 1161: btvp = vcb->extentsRefNum; ! 1162: if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp)) ! 1163: goto skipBtree; ! 1164: simple_lock(&btvp->v_interlock); ! 1165: hp = VTOH(btvp); ! 1166: if ((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && ! 1167: btvp->v_dirtyblkhd.lh_first == NULL) { ! 1168: simple_unlock(&btvp->v_interlock); ! 1169: goto skipBtree; ! 1170: } ! 1171: simple_unlock(&mntvnode_slock); ! 1172: error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); ! 1173: if (error) { ! 1174: simple_lock(&mntvnode_slock); ! 1175: goto skipBtree; ! 1176: } ! 1177: if ((error = VOP_FSYNC(btvp, cred, waitfor, p))) ! 1178: allerror = error; ! 1179: VOP_UNLOCK(btvp, 0, p); ! 1180: VRELE(btvp); ! 1181: simple_lock(&mntvnode_slock); ! 1182: }; ! 1183: ! 1184: skipBtree:; ! 1185: ! 1186: simple_unlock(&mntvnode_slock); ! 1187: ! 1188: /* ! 1189: * Force stale file system control information to be flushed. ! 1190: */ ! 1191: if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p))) ! 1192: allerror = error; ! 1193: /* ! 1194: * Write back modified superblock. ! 1195: */ ! 1196: ! 1197: if (IsVCBDirty(vcb)) { ! 1198: if (vcb->vcbSigWord == kHFSPlusSigWord) ! 1199: error = hfs_flushvolumeheader(hfsmp, waitfor); ! 1200: else ! 1201: error = hfs_flushMDB(hfsmp, waitfor); ! 1202: ! 1203: if (error) ! 1204: allerror = error; ! 1205: }; ! 1206: ! 1207: return (allerror); ! 1208: } ! 1209: ! 1210: ! 1211: /* ! 1212: * File handle to vnode ! 1213: * ! 1214: * Have to be really careful about stale file handles: ! 1215: * - check that the hfsnode number is valid ! 1216: * - call hfs_vget() to get the locked hfsnode ! 1217: * - check for an unallocated hfsnode (i_mode == 0) ! 1218: * - check that the given client host has export rights and return ! 1219: * those rights via. exflagsp and credanonp ! 1220: */ ! 1221: int ! 1222: hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) ! 1223: register struct mount *mp; ! 1224: struct fid *fhp; ! 1225: struct mbuf *nam; ! 1226: struct vnode **vpp; ! 1227: int *exflagsp; ! 1228: struct ucred **credanonp; ! 1229: { ! 1230: DBG_FUNC_NAME("hfs_fhtovp"); ! 1231: DBG_PRINT_FUNC_NAME(); ! 1232: ! 1233: return (EOPNOTSUPP); ! 1234: } ! 1235: ! 1236: /* ! 1237: * Vnode pointer to File handle ! 1238: */ ! 1239: /* ARGSUSED */ ! 1240: static int hfs_vptofh(vp, fhp) ! 1241: struct vnode *vp; ! 1242: struct fid *fhp; ! 1243: { ! 1244: DBG_FUNC_NAME("hfs_vptofh"); ! 1245: DBG_PRINT_FUNC_NAME(); ! 1246: ! 1247: return (EOPNOTSUPP); ! 1248: } ! 1249: ! 1250: ! 1251: ! 1252: /* ! 1253: * Initial HFS filesystems, done only once. ! 1254: */ ! 1255: int ! 1256: hfs_init(vfsp) ! 1257: struct vfsconf *vfsp; ! 1258: { ! 1259: int i; ! 1260: static int done = 0; ! 1261: OSErr err; ! 1262: ! 1263: DBG_FUNC_NAME("hfs_init"); ! 1264: DBG_PRINT_FUNC_NAME(); ! 1265: ! 1266: if (done) ! 1267: return (0); ! 1268: done = 1; ! 1269: hfs_vhashinit(); ! 1270: hfs_converterinit(); ! 1271: ! 1272: simple_lock_init (&gBufferPtrListLock); ! 1273: ! 1274: for (i = BUFFERPTRLISTSIZE - 1; i >= 0; --i) { ! 1275: gBufferAddress[i] = NULL; ! 1276: gBufferHeaderPtr[i] = NULL; ! 1277: }; ! 1278: gBufferListIndex = 0; ! 1279: ! 1280: /* ! 1281: * Do any initialization that the MacOS/MacOS X shared code relies on ! 1282: * (normally done as part of MacOS's startup): ! 1283: */ ! 1284: MALLOC(gFSMVars, FSVarsRec *, sizeof(FSVarsRec), M_TEMP, M_WAITOK); ! 1285: bzero(gFSMVars, sizeof(FSVarsRec)); ! 1286: ! 1287: /* ! 1288: * Allocate Catalog Iterator cache... ! 1289: */ ! 1290: err = InitCatalogCache(); ! 1291: #if HFS_DIAGNOSTIC ! 1292: if (err) panic("hfs_init: Error returned from InitCatalogCache() call."); ! 1293: #endif ! 1294: /* ! 1295: * XXX do we need to setup the following? ! 1296: * ! 1297: * GMT offset, Unicode globals, CatSearch Buffers, BTSscanner ! 1298: */ ! 1299: ! 1300: return E_NONE; ! 1301: } ! 1302: ! 1303: /* ! 1304: * fast filesystem related variables. ! 1305: */ ! 1306: static int hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) ! 1307: int *name; ! 1308: u_int namelen; ! 1309: void *oldp; ! 1310: size_t *oldlenp; ! 1311: void *newp; ! 1312: size_t newlen; ! 1313: struct proc *p; ! 1314: { ! 1315: DBG_FUNC_NAME("hfs_sysctl"); ! 1316: DBG_PRINT_FUNC_NAME(); ! 1317: ! 1318: return (EOPNOTSUPP); ! 1319: } ! 1320: ! 1321: /* This will return a vnode of either a directory or a data vnode based on an object id. If ! 1322: * it is a file id, its data fork will be returned. ! 1323: */ ! 1324: ! 1325: int hfs_vget(struct mount *mp, ! 1326: void *ino, ! 1327: struct vnode **vpp) ! 1328: { ! 1329: struct hfsmount *hfsmp; ! 1330: dev_t dev; ! 1331: hfsCatalogInfo catInfo; ! 1332: int retval = E_NONE; ! 1333: ! 1334: DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32 *)ino)); ! 1335: ! 1336: /* Check if unmount in progress */ ! 1337: if (mp->mnt_flag & MNT_UNMOUNT) { ! 1338: return (EPERM); ! 1339: } ! 1340: ! 1341: hfsmp = VFSTOHFS(mp); ! 1342: dev = hfsmp->hfs_raw_dev; ! 1343: ! 1344: /* First check to see if it is in the cache */ ! 1345: *vpp = hfs_vhashget(dev, *(UInt32 *)ino, kDefault); ! 1346: ! 1347: /* hide open files that have been deleted */ ! 1348: if (*vpp != NULL && H_DIRID(VTOH(*vpp)) == hfsmp->hfs_private_metadata_dir) { ! 1349: vput(*vpp); ! 1350: retval = ENOENT; ! 1351: goto Err_Exit; ! 1352: } ! 1353: ! 1354: /* The vnode is not in the cache, so lets make it */ ! 1355: if (*vpp == NULL) ! 1356: { ! 1357: struct proc *p = current_proc(); ! 1358: UInt8 forkType; ! 1359: ! 1360: /* Special-case the root's parent directory (DirID = 1) because ! 1361: it doesn't actually exist in the catalog: */ ! 1362: if ((*vpp == NULL) && (*(UInt32 *)ino == kRootParID)) { ! 1363: bzero(&catInfo, sizeof(catInfo)); ! 1364: catInfo.nodeData.cnd_type = kCatalogFolderNode; ! 1365: catInfo.nodeData.cnd_nodeID = kRootParID; ! 1366: catInfo.nodeData.cnd_valence = 1; ! 1367: catInfo.nodeData.cnd_ownerID = 0; ! 1368: catInfo.nodeData.cnd_groupID = 0; ! 1369: catInfo.nodeData.cnd_permissions = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); ! 1370: } else { ! 1371: /* lock catalog b-tree */ ! 1372: retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); ! 1373: if (retval != E_NONE) goto Err_Exit; ! 1374: ! 1375: catInfo.hint = kNoHint; ! 1376: retval = hfsLookup(VFSTOVCB(mp), *(UInt32 *)ino, NULL, -1, &catInfo); ! 1377: ! 1378: /* unlock catalog b-tree */ ! 1379: (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); ! 1380: ! 1381: if (retval != E_NONE) goto Err_Exit; ! 1382: ! 1383: /* hide open files that have been deleted */ ! 1384: if (catInfo.spec.parID == hfsmp->hfs_private_metadata_dir) { ! 1385: retval = ENOENT; ! 1386: goto Err_Exit; ! 1387: }; ! 1388: }; ! 1389: forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork; ! 1390: retval = hfs_vcreate(VFSTOVCB(mp), &catInfo, forkType, vpp); ! 1391: }; ! 1392: ! 1393: #if MACH_NBC ! 1394: if (*vpp && ((*vpp)->v_type == VREG) && !((*vpp)->v_vm_info)){ ! 1395: vm_info_init(*vpp); ! 1396: } ! 1397: #endif /* MACH_NBC */ ! 1398: ! 1399: Err_Exit: ! 1400: ! 1401: if (retval != E_NONE) { ! 1402: DBG_VFS(("hfs_vget: Error returned of %d\n", retval)); ! 1403: } ! 1404: else { ! 1405: DBG_VFS(("hfs_vget: vp = 0x%x\n", (u_int)*vpp)); ! 1406: } ! 1407: ! 1408: return (retval); ! 1409: ! 1410: } ! 1411: ! 1412: /* ! 1413: * Flush out all the files in a filesystem. ! 1414: */ ! 1415: int ! 1416: hfs_flushfiles(struct mount *mp, int flags) ! 1417: { ! 1418: int error; ! 1419: ! 1420: error = vflush(mp, NULLVP, SKIPSYSTEM | flags); ! 1421: ! 1422: return (error); ! 1423: } ! 1424: ! 1425: short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor) ! 1426: { ! 1427: ExtendedVCB *vcb = HFSTOVCB(hfsmp); ! 1428: FCB *fcb; ! 1429: HFSMasterDirectoryBlock *mdb; ! 1430: struct buf *bp; ! 1431: int retval; ! 1432: int size = kMDBSize; /* 512 */ ! 1433: size_t namelen; ! 1434: ! 1435: if (vcb->vcbSigWord != kHFSSigWord) ! 1436: return EINVAL; ! 1437: ! 1438: DBG_ASSERT(hfsmp->hfs_devvp != NULL); ! 1439: ! 1440: retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size), ! 1441: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp); ! 1442: if (retval) { ! 1443: DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval)); ! 1444: if (bp) brelse(bp); ! 1445: return retval; ! 1446: } ! 1447: ! 1448: DBG_ASSERT(bp != NULL); ! 1449: DBG_ASSERT(bp->b_data != NULL); ! 1450: DBG_ASSERT(bp->b_bcount == size); ! 1451: ! 1452: mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size)); ! 1453: ! 1454: VCB_LOCK(vcb); ! 1455: mdb->drCrDate = UTCToLocal(vcb->vcbCrDate); ! 1456: mdb->drLsMod = UTCToLocal(vcb->vcbLsMod); ! 1457: mdb->drAtrb = vcb->vcbAtrb; ! 1458: mdb->drNmFls = vcb->vcbNmFls; ! 1459: mdb->drAllocPtr = vcb->nextAllocation; ! 1460: mdb->drClpSiz = vcb->vcbClpSiz; ! 1461: mdb->drNxtCNID = vcb->vcbNxtCNID; ! 1462: mdb->drFreeBks = vcb->freeBlocks; ! 1463: ! 1464: /* XXX need to do a real UTF-8 conversion here... */ ! 1465: copystr(vcb->vcbVN, &mdb->drVN[1], sizeof(mdb->drVN)-1, &namelen); ! 1466: mdb->drVN[0] = namelen-1; ! 1467: mdb->drVN[namelen] = '\0'; ! 1468: ! 1469: mdb->drVolBkUp = UTCToLocal(vcb->vcbVolBkUp); ! 1470: mdb->drVSeqNum = vcb->vcbVSeqNum; ! 1471: mdb->drWrCnt = vcb->vcbWrCnt; ! 1472: mdb->drNmRtDirs = vcb->vcbNmRtDirs; ! 1473: mdb->drFilCnt = vcb->vcbFilCnt; ! 1474: mdb->drDirCnt = vcb->vcbDirCnt; ! 1475: ! 1476: bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo)); ! 1477: ! 1478: fcb = VTOFCB(vcb->extentsRefNum); ! 1479: HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drXTExtRec); ! 1480: mdb->drXTFlSize = fcb->fcbPLen; ! 1481: mdb->drXTClpSiz = fcb->fcbClmpSize; ! 1482: ! 1483: fcb = VTOFCB(vcb->catalogRefNum); ! 1484: HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drCTExtRec); ! 1485: mdb->drCTFlSize = fcb->fcbPLen; ! 1486: mdb->drCTClpSiz = fcb->fcbClmpSize; ! 1487: VCB_UNLOCK(vcb); ! 1488: ! 1489: ! 1490: if (waitfor != MNT_WAIT) ! 1491: bawrite(bp); ! 1492: else ! 1493: retval = bwrite(bp); ! 1494: ! 1495: MarkVCBClean( vcb ); ! 1496: ! 1497: return (retval); ! 1498: } ! 1499: ! 1500: ! 1501: short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor) ! 1502: { ! 1503: ExtendedVCB *vcb = HFSTOVCB(hfsmp); ! 1504: FCB *fcb; ! 1505: HFSPlusVolumeHeader *volumeHeader; ! 1506: int retval; ! 1507: int size = sizeof(HFSPlusVolumeHeader); ! 1508: struct buf *bp; ! 1509: ! 1510: if (vcb->vcbSigWord != kHFSPlusSigWord) ! 1511: return EINVAL; ! 1512: ! 1513: retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size), ! 1514: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp); ! 1515: if (retval) { ! 1516: DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval)); ! 1517: if (bp) brelse(bp); ! 1518: return retval; ! 1519: } ! 1520: ! 1521: DBG_ASSERT(bp != NULL); ! 1522: DBG_ASSERT(bp->b_data != NULL); ! 1523: DBG_ASSERT(bp->b_bcount == size); ! 1524: ! 1525: volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data + ! 1526: IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size)); ! 1527: ! 1528: /* ! 1529: * For embedded HFS+ volumes, update create date if neccessary ! 1530: */ ! 1531: if (vcb->hfsPlusIOPosOffset != 0 && volumeHeader->createDate != UTCToLocal(vcb->vcbCrDate)) ! 1532: { ! 1533: struct buf *bp2; ! 1534: HFSMasterDirectoryBlock *mdb; ! 1535: ! 1536: retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, kMDBSize), ! 1537: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, kMDBSize), NOCRED, &bp2); ! 1538: if (retval != E_NONE) { ! 1539: if (bp2) brelse(bp2); ! 1540: } else { ! 1541: mdb = (HFSMasterDirectoryBlock *)((char *)bp2->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, kMDBSize)); ! 1542: if ( mdb->drCrDate != UTCToLocal(vcb->vcbCrDate) ) ! 1543: { ! 1544: mdb->drCrDate = UTCToLocal(vcb->vcbCrDate); /* pick up the new create date */ ! 1545: (void) bwrite(bp2); /* write out the changes */ ! 1546: } ! 1547: else ! 1548: { ! 1549: brelse(bp2); /* just release it */ ! 1550: } ! 1551: } ! 1552: } ! 1553: ! 1554: VCB_LOCK(vcb); ! 1555: /* Note: only update the lower 16 bits worth of attributes */ ! 1556: volumeHeader->attributes = (volumeHeader->attributes & 0xFFFF0000) + (UInt16) vcb->vcbAtrb; ! 1557: volumeHeader->lastMountedVersion = kHFSPlusMountVersion; ! 1558: volumeHeader->createDate = UTCToLocal(vcb->vcbCrDate); ! 1559: volumeHeader->modifyDate = vcb->vcbLsMod; ! 1560: volumeHeader->backupDate = vcb->vcbVolBkUp; ! 1561: volumeHeader->checkedDate = vcb->checkedDate; ! 1562: volumeHeader->fileCount = vcb->vcbFilCnt; ! 1563: volumeHeader->folderCount = vcb->vcbDirCnt; ! 1564: volumeHeader->freeBlocks = vcb->freeBlocks; ! 1565: volumeHeader->nextAllocation = vcb->nextAllocation; ! 1566: volumeHeader->rsrcClumpSize = vcb->vcbClpSiz; ! 1567: volumeHeader->dataClumpSize = vcb->vcbClpSiz; ! 1568: volumeHeader->nextCatalogID = vcb->vcbNxtCNID; ! 1569: volumeHeader->writeCount = vcb->vcbWrCnt; ! 1570: volumeHeader->encodingsBitmap = vcb->encodingsBitmap; ! 1571: ! 1572: bcopy( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) ); ! 1573: ! 1574: VCB_UNLOCK(vcb); ! 1575: ! 1576: fcb = VTOFCB(vcb->extentsRefNum); ! 1577: bcopy( fcb->fcbExtents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); ! 1578: fcb->fcbFlags &= ~fcbModifiedMask; ! 1579: volumeHeader->extentsFile.logicalSize = fcb->fcbEOF; ! 1580: volumeHeader->extentsFile.totalBlocks = fcb->fcbPLen / vcb->blockSize; ! 1581: volumeHeader->extentsFile.clumpSize = fcb->fcbClmpSize; ! 1582: ! 1583: fcb = VTOFCB(vcb->catalogRefNum); ! 1584: bcopy( fcb->fcbExtents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); ! 1585: fcb->fcbFlags &= ~fcbModifiedMask; ! 1586: volumeHeader->catalogFile.logicalSize = fcb->fcbEOF; ! 1587: volumeHeader->catalogFile.totalBlocks = fcb->fcbPLen / vcb->blockSize; ! 1588: volumeHeader->catalogFile.clumpSize = fcb->fcbClmpSize; ! 1589: ! 1590: fcb = VTOFCB(vcb->allocationsRefNum); ! 1591: bcopy( fcb->fcbExtents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); ! 1592: fcb->fcbFlags &= ~fcbModifiedMask; ! 1593: volumeHeader->allocationFile.logicalSize = fcb->fcbEOF; ! 1594: volumeHeader->allocationFile.totalBlocks = fcb->fcbPLen / vcb->blockSize; ! 1595: volumeHeader->allocationFile.clumpSize = fcb->fcbClmpSize; ! 1596: ! 1597: if (waitfor != MNT_WAIT) ! 1598: bawrite(bp); ! 1599: else ! 1600: retval = bwrite(bp); ! 1601: ! 1602: MarkVCBClean( vcb ); ! 1603: ! 1604: return (retval); ! 1605: } ! 1606: ! 1607: ! 1608: /* ! 1609: * Moved here to avoid having to define prototypes ! 1610: */ ! 1611: ! 1612: /* ! 1613: * hfs vfs operations. ! 1614: */ ! 1615: struct vfsops hfs_vfsops = { ! 1616: hfs_mount, ! 1617: hfs_start, ! 1618: hfs_unmount, ! 1619: hfs_root, ! 1620: hfs_quotactl, ! 1621: hfs_statfs, ! 1622: hfs_sync, ! 1623: hfs_vget, ! 1624: hfs_fhtovp, ! 1625: hfs_vptofh, ! 1626: hfs_init, ! 1627: hfs_sysctl ! 1628: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.