/*
- * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
* hfs_vfsops.c
* derived from @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95
*
- * (c) Copyright 1997-1998 Apple Computer, Inc. All rights reserved.
+ * (c) Copyright 1997-2002 Apple Computer, Inc. All rights reserved.
*
* hfs_vfsops.c -- VFS layer for loadable HFS file system.
*
- * HISTORY
- * 9-Nov-1999 Don Brady Fix error handling in hfs_unmount [2399157].
- * 9-Sep-1999 Don Brady Clear system file fcbModified flags in hfs_flushvolumeheader/hfs_flushMDB.
- * 5-Aug-1999 Pat Dirks Moved special HFS flag from f_fsid.val[0][0] to mount flags (#2293117).
- * 23-Jul-1999 Pat Dirks Added special-case code for root's parent directory in hfs_vget (#2263664).
- * 9-Jun-1999 Don Brady Fix hfs_mount for reload and read-only downgrade cases.
- * 2-Jun-1999 Don Brady Fix hfs_statfs to return correct f_files value.
- * 4-May-1999 Don Brady Remove obsolete loadable module code.
- * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget.
- * 18-May-1999 Don Brady Add hfs_mountroot for HFS Plus rooting.
- * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget.
- * 12-Nov-1998 Pat Dirks Changed hfs_statfs to return volume's actual log. block size (#2286198).
- * 22-Aug-1998 Scott Roberts Assign uid,gid, and mask for default on objects.
- * 29-Jul-1998 Pat Dirks Fixed changed hfs_vget() to release complex node when retrying for data fork node.
- * 27-Jul-1998 Scott Roberts Changes hfs_vget() to return data forks instead of complex.
- * 14-Jul-1998 CHW Added check for use count of device node in hfs_mountfs
- * 1-Jul-1998 Don Brady Always set kHFSVolumeUnmountedMask bit of vcb->vcbAtrb in hfs_unmount.
- * 30-Jun-1998 Don Brady Removed hard-coded EINVAL error in hfs_mountfs (for radar #2249539).
- * 24-Jun-1998 Don Brady Added setting of timezone to hfs_mount (radar #2226387).
- * 4-Jun-1998 Don Brady Use VPUT/VRELE macros instead of vput/vrele.
- * 6-May-1998 Scott Roberts Updated hfs_vget with kernel changes.
- * 29-Apr-1998 Don Brady Update hfs_statfs to actually fill in statfs fields (radar #2227092).
- * 23-Apr-1998 Pat Dirks Cleaned up code to call brelse() on errors from bread().
- * 4/20/1998 Don Brady Remove course-grained hfs metadata locking.
- * 4/18/1998 Don Brady Add VCB locking.
- * 4/16/1998 Don Brady hfs_unmount now flushes the volume bitmap. Add b-tree locking to hfs_vget.
- * 4/8/1998 Don Brady Replace hfs_mdbupdate with hfs_flushvolumeheader and hfs_flushMDB.
- * 4/8/1998 Don Brady In hfs_unmount call hfs_mdbupdate before trashing metafiles!
- * 4/3/1998 Don Brady Call InitCatalogCache instead of PostInitFS.
- * 4/1/1998 Don Brady Get rid of gHFSFlags, gReqstVol and gFlushOnlyFlag globals (not used).
- * 3/30/1998 Don Brady In hfs_unmount use SKIPSYSTEM option on first vflush.
- * 3/26/1998 Don Brady Changed hfs_unmount to call vflush before calling hfsUnmount.
- * In hfs_mountfs don't mount hfs-wrapper.
- * 3/19/1998 Pat Dirks Fixed bug in hfs_mount where device vnode was being
- * released on way out.
- * 11/14/1997 Pat Dirks Derived from hfs_vfsops.c
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mount.h>
#include <sys/malloc.h>
#include <sys/stat.h>
-#include <dev/disk.h>
#include <sys/lock.h>
+#include <sys/quota.h>
+#include <sys/disk.h>
+
+// XXXdbg
+#include <vfs/vfs_journal.h>
+
#include <miscfs/specfs/specdev.h>
#include <hfs/hfs_mount.h>
#include "hfs.h"
+#include "hfs_catalog.h"
+#include "hfs_cnode.h"
#include "hfs_dbg.h"
#include "hfs_endian.h"
+#include "hfs_quota.h"
#include "hfscommon/headers/FileMgrInternal.h"
#include "hfscommon/headers/BTreesInternal.h"
+
#if HFS_DIAGNOSTIC
int hfs_dbg_all = 0;
-int hfs_dbg_vfs = 0;
-int hfs_dbg_vop = 0;
-int hfs_dbg_load = 0;
-int hfs_dbg_io = 0;
-int hfs_dbg_utils = 0;
-int hfs_dbg_rw = 0;
-int hfs_dbg_lookup = 0;
-int hfs_dbg_tree = 0;
int hfs_dbg_err = 0;
-int hfs_dbg_test = 0;
#endif
-/*
- * HFS File System globals:
- */
-Ptr gBufferAddress[BUFFERPTRLISTSIZE];
-struct buf *gBufferHeaderPtr[BUFFERPTRLISTSIZE];
-int gBufferListIndex;
-simple_lock_data_t gBufferPtrListLock;
-
-//static char hfs_fs_name[MFSNAMELEN] = "hfs";
-
-/*
- * Global variables defined in other modules:
- */
extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
-extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType);
-
-extern OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents);
-
+extern void hfs_converterinit(void);
extern void inittodr( time_t base);
-extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
-extern void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catInfo, struct vnode *vp, struct hfsfilemeta *fm);
-extern void CopyCatalogToFCB(struct hfsCatalogInfo *catInfo, struct vnode *vp);
-extern void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm);
-int hfs_changefs(struct mount *mp, struct hfs_mount_args *args, struct proc *p);
-int hfs_reload(struct mount *mp, struct ucred *cred, struct proc *p);
-int hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args);
-int hfs_vget(struct mount *mp, void *objID, struct vnode **vpp);
-void hfs_vhashinit();
-void hfs_converterinit(void);
+static int hfs_changefs __P((struct mount *mp, struct hfs_mount_args *args,
+ struct proc *p));
+static int hfs_reload __P((struct mount *mp, struct ucred *cred, struct proc *p));
-
-static int hfs_statfs();
+static int hfs_mountfs __P((struct vnode *devvp, struct mount *mp, struct proc *p,
+ struct hfs_mount_args *args));
+static int hfs_statfs __P((struct mount *mp, register struct statfs *sbp,
+ struct proc *p));
/*
struct mount *mp;
struct proc *p = current_proc(); /* XXX */
struct hfsmount *hfsmp;
+ ExtendedVCB *vcb;
int error;
/*
printf("hfs_mountroot: can't setup bdevvp");
return (error);
}
- if ((error = vfs_rootmountalloc("hfs", "root_device", &mp)))
+ if ((error = vfs_rootmountalloc("hfs", "root_device", &mp))) {
+ vrele(rootvp); /* release the reference from bdevvp() */
return (error);
+ }
if ((error = hfs_mountfs(rootvp, mp, p, NULL))) {
mp->mnt_vfc->vfc_refcount--;
vfs_unbusy(mp, p);
+ vrele(rootvp); /* release the reference from bdevvp() */
_FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
return (error);
}
hfsmp->hfs_dir_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
hfsmp->hfs_file_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
+ /* Establish the free block reserve. */
+ vcb = HFSTOVCB(hfsmp);
+ vcb->reserveBlocks = ((u_int64_t)vcb->totalBlocks * HFS_MINFREE) / 100;
+ vcb->reserveBlocks = MIN(vcb->reserveBlocks, HFS_MAXRESERVE / vcb->blockSize);
+
(void)hfs_statfs(mp, &mp->mnt_stat, p);
vfs_unbusy(mp, p);
- inittodr(to_bsd_time(HFSTOVCB(hfsmp)->vcbLsMod));
+ inittodr(HFSTOVCB(hfsmp)->vcbLsMod);
return (0);
}
* mount system call
*/
-int
-hfs_mount (mp, path, data, ndp, p)
+static int
+hfs_mount(mp, path, data, ndp, p)
register struct mount *mp;
char *path;
caddr_t data;
int retval = E_NONE;
int flags;
mode_t accessmode;
- int loadconv = 0;
if ((retval = copyin(data, (caddr_t)&args, sizeof(args))))
goto error_exit;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
- if ((retval = hfs_flushfiles(mp, flags)))
+ if ((retval = hfs_flushfiles(mp, flags, p)))
goto error_exit;
- hfsmp->hfs_fs_clean = 1;
hfsmp->hfs_fs_ronly = 1;
- if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
- retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
- else
- retval = hfs_flushMDB(hfsmp, MNT_WAIT);
+ retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
/* also get the volume bitmap blocks */
if (!retval)
retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p);
if (retval) {
- hfsmp->hfs_fs_clean = 0;
hfsmp->hfs_fs_ronly = 0;
goto error_exit;
}
}
VOP_UNLOCK(devvp, 0, p);
}
- if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
- retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
- else
- retval = hfs_flushMDB(hfsmp, MNT_WAIT);
+ retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
if (retval != E_NONE)
goto error_exit;
/* only change hfs_fs_ronly after a successfull write */
hfsmp->hfs_fs_ronly = 0;
- hfsmp->hfs_fs_clean = 0;
}
if ((hfsmp->hfs_fs_ronly == 0) &&
(HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)) {
/* setup private/hidden directory for unlinked files */
hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(HFSTOVCB(hfsmp));
+ if (hfsmp->jnl)
+ hfs_remove_orphans(hfsmp);
}
if (args.fspec == 0) {
goto error_exit;
}
-
/* Set the mount flag to indicate that we support volfs */
mp->mnt_flag |= MNT_DOVOLFS;
if (VFSTOVCB(mp)->vcbSigWord == kHFSSigWord) {
mp->mnt_flag |= MNT_FIXEDSCRIPTENCODING;
}
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size);
+
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
}
-/* change fs mount parameters */
-int
+/* Change fs mount parameters */
+static int
hfs_changefs(mp, args, p)
struct mount *mp;
struct hfs_mount_args *args;
struct proc *p;
{
- int retval;
+ int retval = 0;
int namefix, permfix, permswitch;
struct hfsmount *hfsmp;
- struct hfsnode *hp;
- mode_t hfs_file_mask;
+ struct cnode *cp;
ExtendedVCB *vcb;
- hfsCatalogInfo catInfo;
register struct vnode *vp, *nvp;
hfs_to_unicode_func_t get_unicode_func;
unicode_to_hfs_func_t get_hfsname_func;
+ struct cat_desc cndesc;
+ struct cat_attr cnattr;
+ u_long old_encoding;
hfsmp = VFSTOHFS(mp);
vcb = HFSTOVCB(hfsmp);
hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
namefix = permfix = 0;
- /* change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
+ /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
if (args->hfs_timezone.tz_minuteswest != VNOVAL) {
gTimeZone = args->hfs_timezone;
}
- /* change the default uid, gid and/or mask */
+ /* Change the default uid, gid and/or mask */
if ((args->hfs_uid != (uid_t)VNOVAL) && (hfsmp->hfs_uid != args->hfs_uid)) {
hfsmp->hfs_uid = args->hfs_uid;
- ++permfix;
+ if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
+ ++permfix;
}
if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) {
hfsmp->hfs_gid = args->hfs_gid;
- ++permfix;
+ if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
+ ++permfix;
}
if (args->hfs_mask != (mode_t)VNOVAL) {
if (hfsmp->hfs_dir_mask != (args->hfs_mask & ALLPERMS)) {
hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
if ((args->flags != VNOVAL) && (args->flags & HFSFSMNT_NOXONFILES))
hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
- ++permfix;
+ if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
+ ++permfix;
}
}
- /* change the hfs encoding value (hfs only) */
+ /* Change the hfs encoding value (hfs only) */
if ((HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) &&
(hfsmp->hfs_encoding != (u_long)VNOVAL) &&
(hfsmp->hfs_encoding != args->hfs_encoding)) {
retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func);
- if (retval) goto error_exit;
+ if (retval)
+ goto exit;
/*
* Connect the new hfs_get_unicode converter but leave
* in the old converters.
*/
hfsmp->hfs_get_unicode = get_unicode_func;
+ old_encoding = hfsmp->hfs_encoding;
+ hfsmp->hfs_encoding = args->hfs_encoding;
++namefix;
}
-
- if (!(namefix || permfix || permswitch)) goto exit;
+ if (!(namefix || permfix || permswitch))
+ goto exit;
/*
* For each active vnode fix things that changed
continue;
}
- hp = VTOH(vp);
+ cp = VTOC(vp);
- INIT_CATALOGDATA(&catInfo.nodeData, 0);
-
- catInfo.hint = kNoHint;
- retval = hfs_getcatalog(vcb, H_DIRID(hp), H_NAME(hp), hp->h_meta->h_namelen, &catInfo);
+ retval = cat_lookup(hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL);
/* If we couldn't find this guy skip to the next one */
if (retval) {
if (namefix)
continue;
}
- H_HINT(hp) = catInfo.hint;
- if (permswitch || (permfix && (hp->h_meta->h_metaflags & IN_UNSETACCESS))) {
- if ((vcb->vcbSigWord == kHFSPlusSigWord) && (catInfo.nodeData.cnd_mode & IFMT)) {
- if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
- /*
- * Override the permissions as determined by the mount auguments
- * in ALMOST the same way unset permissions are treated but keep
- * track of whether or not the file or folder is hfs locked
- * by leaving the h_pflags field unchanged from what was unpacked
- * out of the catalog.
- */
- hp->h_meta->h_metaflags |= IN_UNSETACCESS;
- hp->h_meta->h_uid = VTOHFS(vp)->hfs_uid;
- hp->h_meta->h_gid = VTOHFS(vp)->hfs_gid;
- } else {
- hp->h_meta->h_uid = catInfo.nodeData.cnd_ownerID;
- hp->h_meta->h_gid = catInfo.nodeData.cnd_groupID;
- };
- hp->h_meta->h_mode = (mode_t)catInfo.nodeData.cnd_mode;
- } else {
- /*
- * Set the permissions as determined by the mount auguments
- * but keep in account if the file or folder is hfs locked
- */
- hp->h_meta->h_metaflags |= IN_UNSETACCESS;
- hp->h_meta->h_uid = VTOHFS(vp)->hfs_uid;
- hp->h_meta->h_gid = VTOHFS(vp)->hfs_gid;
-
- /* Default access is full read/write/execute: */
- hp->h_meta->h_mode &= IFMT;
- hp->h_meta->h_mode |= ACCESSPERMS; /* 0777: rwxrwxrwx */
- /* ... but no more than that permitted by the mount point's: */
- if ((hp->h_meta->h_mode & IFMT) == IFDIR) {
- hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_dir_mask;
- } else {
- hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_file_mask;
- }
- };
- };
+ if (permswitch || permfix) {
+ cp->c_uid = cnattr.ca_uid;
+ cp->c_gid = cnattr.ca_gid;
+ cp->c_mode = cnattr.ca_mode;
+ }
/*
* If we're switching name converters then...
*/
if (namefix) {
cache_purge(vp);
- hfs_name_CatToMeta(&catInfo.nodeData, hp->h_meta);
+ replace_desc(cp, &cndesc);
- if (catInfo.nodeData.cnd_nodeID == kHFSRootFolderID)
- strncpy(vcb->vcbVN, H_NAME(hp), NAME_MAX);
+ if (cndesc.cd_cnid == kHFSRootFolderID) {
+ strncpy(vcb->vcbVN, cp->c_desc.cd_nameptr, NAME_MAX);
+ cp->c_desc.cd_encoding = hfsmp->hfs_encoding;
+ }
+ } else {
+ cat_releasedesc(&cndesc);
}
-
- CLEAN_CATALOGDATA(&catInfo.nodeData);
-
vput(vp);
simple_lock(&mntvnode_slock);
- } /* end for (vp...) */
- simple_unlock(&mntvnode_slock);
-
-
-exit:
+ } /* end for (vp...) */
+ simple_unlock(&mntvnode_slock);
/*
* If we're switching name converters we can now
* connect the new hfs_get_hfsname converter and
* release our interest in the old converters.
*/
if (namefix) {
- u_long old_encoding = hfsmp->hfs_encoding;
-
hfsmp->hfs_get_hfsname = get_hfsname_func;
- hfsmp->hfs_encoding = args->hfs_encoding;
vcb->volumeNameEncodingHint = args->hfs_encoding;
-
(void) hfs_relconverter(old_encoding);
}
-
- return (0);
-
-error_exit:
-
+exit:
return (retval);
}
* be mounted read-only.
*
* Things to do to update the mount:
- * 1) invalidate all cached meta-data.
- * 2) re-read volume header from disk.
- * 3) re-load meta-file info (extents, file size).
- * 4) re-load B-tree header data.
- * 5) invalidate all inactive vnodes.
- * 6) invalidate all cached file data.
- * 7) re-read hfsnode data for all active vnodes.
+ * invalidate all cached meta-data.
+ * invalidate all inactive vnodes.
+ * invalidate all cached file data.
+ * re-read volume header from disk.
+ * re-load meta-file info (extents, file size).
+ * re-load B-tree header data.
+ * re-read cnode data for all active vnodes.
*/
-int
+static int
hfs_reload(mountp, cred, p)
register struct mount *mountp;
struct ucred *cred;
struct proc *p;
{
register struct vnode *vp, *nvp, *devvp;
- struct hfsnode *hp;
+ struct cnode *cp;
struct buf *bp;
- int size, error, i;
+ int sectorsize;
+ int error, i;
struct hfsmount *hfsmp;
struct HFSPlusVolumeHeader *vhp;
ExtendedVCB *vcb;
- FCB *fcb;
+ struct filefork *forkp;
+ struct cat_desc cndesc;
if ((mountp->mnt_flag & MNT_RDONLY) == 0)
return (EINVAL);
panic("hfs_reload: dirty1");
InvalidateCatalogCache(vcb);
+loop:
+ simple_lock(&mntvnode_slock);
+ for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
+ if (vp->v_mount != mountp) {
+ simple_unlock(&mntvnode_slock);
+ goto loop;
+ }
+ nvp = vp->v_mntvnodes.le_next;
+
+ /*
+ * Invalidate all inactive vnodes.
+ */
+ if (vrecycle(vp, &mntvnode_slock, p))
+ goto loop;
+
+ /*
+ * Invalidate all cached file data.
+ */
+ simple_lock(&vp->v_interlock);
+ simple_unlock(&mntvnode_slock);
+ if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
+ goto loop;
+ }
+ if (vinvalbuf(vp, 0, cred, p, 0, 0))
+ panic("hfs_reload: dirty2");
+
+ /*
+ * Re-read cnode data for all active vnodes (non-metadata files).
+ */
+ cp = VTOC(vp);
+ if ((vp->v_flag & VSYSTEM) == 0 && !VNODE_IS_RSRC(vp)) {
+ struct cat_fork *datafork;
+ struct cat_desc desc;
+
+ datafork = cp->c_datafork ? &cp->c_datafork->ff_data : NULL;
+
+ /* lookup by fileID since name could have changed */
+ if ((error = cat_idlookup(hfsmp, cp->c_fileid, &desc, &cp->c_attr, datafork))) {
+ vput(vp);
+ return (error);
+ }
+
+
+ /* update cnode's catalog descriptor */
+ (void) replace_desc(cp, &desc);
+ }
+ vput(vp);
+ simple_lock(&mntvnode_slock);
+ }
+ simple_unlock(&mntvnode_slock);
+
/*
* Re-read VolumeHeader from disk.
*/
- size = kMDBSize;
- error = bread( hfsmp->hfs_devvp,
- IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
- IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size),
- NOCRED,
- &bp);
+ sectorsize = hfsmp->hfs_phys_block_size;
+
+ error = meta_bread(hfsmp->hfs_devvp,
+ (vcb->hfsPlusIOPosOffset / sectorsize) + HFS_PRI_SECTOR(sectorsize),
+ sectorsize, NOCRED, &bp);
if (error) {
if (bp != NULL)
brelse(bp);
return (error);
}
- vhp = (HFSPlusVolumeHeader *) ((char *)bp->b_data +
- IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
+ vhp = (HFSPlusVolumeHeader *) (bp->b_data + HFS_PRI_OFFSET(sectorsize));
- if ((ValidVolumeHeader(vhp) != 0) || (vcb->blockSize != SWAP_BE32 (vhp->blockSize))) {
+ /* Do a quick sanity check */
+ if (SWAP_BE16(vhp->signature) != kHFSPlusSigWord ||
+ SWAP_BE16(vhp->version) != kHFSPlusVersion ||
+ SWAP_BE32(vhp->blockSize) != vcb->blockSize) {
brelse(bp);
- return (EIO); /* XXX needs translation */
+ return (EIO);
}
- vcb->vcbLsMod = SWAP_BE32 (vhp->modifyDate);
- vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */
- vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize);
- vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID);
- vcb->vcbVolBkUp = SWAP_BE32 (vhp->backupDate);
- vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount);
- vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount);
- vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount);
+ vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate));
+ vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */
+ vcb->vcbJinfoBlock = SWAP_BE32(vhp->journalInfoBlock);
+ vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize);
+ vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID);
+ vcb->vcbVolBkUp = to_bsd_time(SWAP_BE32(vhp->backupDate));
+ vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount);
+ vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount);
+ vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount);
vcb->nextAllocation = SWAP_BE32 (vhp->nextAllocation);
- vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks);
- vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks);
- vcb->checkedDate = SWAP_BE32 (vhp->checkedDate);
+ vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks);
+ vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks);
vcb->encodingsBitmap = SWAP_BE64 (vhp->encodingsBitmap);
bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));
vcb->localCreateDate = SWAP_BE32 (vhp->createDate); /* hfs+ create date is in local time */
/*
* Re-load meta-file vnode data (extent info, file size, etc).
*/
- fcb = VTOFCB((struct vnode *)vcb->extentsRefNum);
- /* bcopy(vhp->extentsFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
- for (i = 0; i < kHFSPlusExtentDensity; i++) {
- fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
- fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
- }
- fcb->fcbEOF = SWAP_BE64 (vhp->extentsFile.logicalSize);
- fcb->fcbPLen = SWAP_BE32 (vhp->extentsFile.totalBlocks) * vcb->blockSize;
- fcb->fcbClmpSize = SWAP_BE32 (vhp->extentsFile.clumpSize);
-
- fcb = VTOFCB((struct vnode *)vcb->catalogRefNum);
- /* bcopy(vhp->catalogFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
- for (i = 0; i < kHFSPlusExtentDensity; i++) {
- fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
- fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
- }
- fcb->fcbPLen = SWAP_BE64 (vhp->catalogFile.logicalSize);
- fcb->fcbPLen = SWAP_BE32 (vhp->catalogFile.totalBlocks) * vcb->blockSize;
- fcb->fcbClmpSize = SWAP_BE32 (vhp->catalogFile.clumpSize);
-
- fcb = VTOFCB((struct vnode *)vcb->allocationsRefNum);
- /* bcopy(vhp->allocationFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
- for (i = 0; i < kHFSPlusExtentDensity; i++) {
- fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
- fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
- }
- fcb->fcbEOF = SWAP_BE64 (vhp->allocationFile.logicalSize);
- fcb->fcbPLen = SWAP_BE32 (vhp->allocationFile.totalBlocks) * vcb->blockSize;
- fcb->fcbClmpSize = SWAP_BE32 (vhp->allocationFile.clumpSize);
+ forkp = VTOF((struct vnode *)vcb->extentsRefNum);
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ forkp->ff_extents[i].startBlock =
+ SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
+ forkp->ff_extents[i].blockCount =
+ SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
+ }
+ forkp->ff_size = SWAP_BE64 (vhp->extentsFile.logicalSize);
+ forkp->ff_blocks = SWAP_BE32 (vhp->extentsFile.totalBlocks);
+ forkp->ff_clumpsize = SWAP_BE32 (vhp->extentsFile.clumpSize);
+
+
+ forkp = VTOF((struct vnode *)vcb->catalogRefNum);
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ forkp->ff_extents[i].startBlock =
+ SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
+ forkp->ff_extents[i].blockCount =
+ SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
+ }
+ forkp->ff_size = SWAP_BE64 (vhp->catalogFile.logicalSize);
+ forkp->ff_blocks = SWAP_BE32 (vhp->catalogFile.totalBlocks);
+ forkp->ff_clumpsize = SWAP_BE32 (vhp->catalogFile.clumpSize);
+
+
+ forkp = VTOF((struct vnode *)vcb->allocationsRefNum);
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ forkp->ff_extents[i].startBlock =
+ SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
+ forkp->ff_extents[i].blockCount =
+ SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
+ }
+ forkp->ff_size = SWAP_BE64 (vhp->allocationFile.logicalSize);
+ forkp->ff_blocks = SWAP_BE32 (vhp->allocationFile.totalBlocks);
+ forkp->ff_clumpsize = SWAP_BE32 (vhp->allocationFile.clumpSize);
brelse(bp);
vhp = NULL;
/*
* Re-load B-tree header data
*/
- fcb = VTOFCB((struct vnode *)vcb->extentsRefNum);
- if (error = MacToVFSError( BTReloadData(fcb) ))
+ forkp = VTOF((struct vnode *)vcb->extentsRefNum);
+ if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
return (error);
- fcb = VTOFCB((struct vnode *)vcb->catalogRefNum);
- if (error = MacToVFSError( BTReloadData(fcb) ))
+ forkp = VTOF((struct vnode *)vcb->catalogRefNum);
+ if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
return (error);
- /* Now that the catalog is ready, get the volume name */
- /* also picks up the create date in GMT */
- if ((error = MacToVFSError( GetVolumeNameFromCatalog(vcb) )))
+ /* Reload the volume name */
+ if ((error = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, NULL, NULL)))
return (error);
+ vcb->volumeNameEncodingHint = cndesc.cd_encoding;
+ bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen));
+ cat_releasedesc(&cndesc);
/* Re-establish private/hidden directory for unlinked files */
hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
-loop:
- simple_lock(&mntvnode_slock);
- for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
- if (vp->v_mount != mountp) {
- simple_unlock(&mntvnode_slock);
- goto loop;
- }
- nvp = vp->v_mntvnodes.le_next;
+ return (0);
+}
- /*
- * Invalidate all inactive vnodes.
- */
- if (vrecycle(vp, &mntvnode_slock, p))
- goto loop;
- /*
- * Invalidate all cached file data.
- */
- simple_lock(&vp->v_interlock);
- simple_unlock(&mntvnode_slock);
- if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
- goto loop;
- }
- if (vinvalbuf(vp, 0, cred, p, 0, 0))
- panic("hfs_reload: dirty2");
+static int
+get_raw_device(char *fspec, int is_user, int ronly, struct vnode **rvp, struct ucred *cred, struct proc *p)
+{
+ char *rawbuf;
+ char *dp;
+ size_t namelen;
+ struct nameidata nd;
+ int retval;
- /*
- * Re-read hfsnode data for all active vnodes (non-metadata files).
- */
- hp = VTOH(vp);
- if ((vp->v_flag & VSYSTEM) == 0) {
- hfsCatalogInfo catInfo;
+ *rvp = NULL;
- /* lookup by fileID since name could have changed */
- catInfo.hint = kNoHint;
- INIT_CATALOGDATA(&catInfo.nodeData, 0);
+ MALLOC(rawbuf, char *, MAXPATHLEN, M_HFSMNT, M_WAITOK);
+ if (rawbuf == NULL) {
+ retval = ENOMEM;
+ goto error_exit;
+ }
- if ((error = hfs_getcatalog(vcb, H_FILEID(hp), NULL, -1, &catInfo))) {
- vput(vp);
- CLEAN_CATALOGDATA(&catInfo.nodeData);
- return (error);
- }
+ if (is_user) {
+ retval = copyinstr(fspec, rawbuf, MAXPATHLEN - 1, &namelen);
+ if (retval != E_NONE) {
+ FREE(rawbuf, M_HFSMNT);
+ goto error_exit;
+ }
+ } else {
+ strcpy(rawbuf, fspec);
+ namelen = strlen(rawbuf);
+ }
+
+ /* make sure it's null terminated */
+ rawbuf[MAXPATHLEN-1] = '\0';
- H_HINT(hp) = catInfo.hint;
- if (hp->h_meta->h_metaflags & IN_LONGNAME)
- FREE(H_NAME(hp), M_TEMP);
- H_NAME(hp) = NULL;
- hp->h_meta->h_namelen = 0;
- CopyCatalogToObjectMeta(&catInfo, vp, hp->h_meta);
- CopyCatalogToFCB(&catInfo, vp);
+ dp = &rawbuf[namelen-1];
+ while(dp >= rawbuf && *dp != '/') {
+ dp--;
+ }
- CLEAN_CATALOGDATA(&catInfo.nodeData);
- }
+ if (dp != NULL) {
+ dp++;
+ } else {
+ dp = rawbuf;
+ }
+
+ /* make room for and insert the 'r' for the raw device */
+ memmove(dp+1, dp, strlen(dp)+1);
+ *dp = 'r';
- vput(vp);
- simple_lock(&mntvnode_slock);
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, rawbuf, p);
+ retval = namei(&nd);
+ if (retval != E_NONE) {
+ DBG_ERR(("hfs_mountfs: can't open raw device for journal: %s, %x\n", rawbuf, nd.ni_vp->v_rdev));
+ FREE(rawbuf, M_HFSMNT);
+ goto error_exit;
}
- simple_unlock(&mntvnode_slock);
- return (0);
+ *rvp = nd.ni_vp;
+ if ((retval = VOP_OPEN(*rvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))) {
+ *rvp = NULL;
+ goto error_exit;
+ }
+
+ // don't need this any more
+ FREE(rawbuf, M_HFSMNT);
+
+ return 0;
+
+ error_exit:
+ if (*rvp) {
+ (void)VOP_CLOSE(*rvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
+ }
+
+ if (rawbuf) {
+ FREE(rawbuf, M_HFSMNT);
+ }
+ return retval;
}
+
/*
* Common code for mount and mountroot
*/
-int
-hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args)
+static int
+hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
+ struct hfs_mount_args *args)
{
- int retval = E_NONE;
- register struct hfsmount *hfsmp;
- struct buf *bp;
- dev_t dev;
- HFSMasterDirectoryBlock *mdbp;
- int ronly;
- struct ucred *cred;
- u_long diskBlks;
- u_long blksize;
- DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long)mp));
-
- dev = devvp->v_rdev;
- cred = p ? p->p_ucred : NOCRED;
+ int retval = E_NONE;
+ struct hfsmount *hfsmp;
+ struct buf *bp;
+ dev_t dev;
+ HFSMasterDirectoryBlock *mdbp;
+ int ronly;
+ int i;
+ int mntwrapper;
+ struct ucred *cred;
+ u_int64_t disksize;
+ u_int64_t blkcnt;
+ u_int32_t blksize;
+ u_int32_t minblksize;
+ u_int32_t iswritable;
+ daddr_t mdb_offset;
+
+ dev = devvp->v_rdev;
+ cred = p ? p->p_ucred : NOCRED;
+ mntwrapper = 0;
/*
* Disallow multiple mounts of the same device.
* Disallow mounting of a device that is currently in use
return (retval);
ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
- DBG_VFS(("hfs_mountfs: opening device...\n"));
if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
return (retval);
- blksize = kHFSBlockSize;
- DBG_VFS(("hfs_mountfs: size = %d (DEV_BSIZE = %d).\n", blksize, DEV_BSIZE));
+ bp = NULL;
+ hfsmp = NULL;
+ mdbp = NULL;
+ minblksize = kHFSBlockSize;
+
+ /* Get the real physical block size. */
+ if (VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ /* Switch to 512 byte sectors (temporarily) */
+ if (blksize > 512) {
+ u_int32_t size512 = 512;
- bp = NULL;
- hfsmp = NULL;
+ if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&size512, FWRITE, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ }
+ /* Get the number of 512 byte physical blocks. */
+ if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ /* Compute an accurate disk size (i.e. within 512 bytes) */
+ disksize = blkcnt * (u_int64_t)512;
- /*
- * XXX SER Currently we only support 512 block size systems. This might change
- * So this is a place holder to remind us that the mdb might not be 512 aligned
- * retval = VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, &blksize, FWRITE, cred, p);
- * if (retval) return retval;
+ /*
+ * There are only 31 bits worth of block count in
+ * the buffer cache. So for large volumes a 4K
+ * physical block size is needed.
*/
+ if (blkcnt > (u_int64_t)0x000000007fffffff) {
+ minblksize = blksize = 4096;
+ }
+ /* Now switch to our prefered physical block size. */
+ if (blksize > 512) {
+ if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ /* Get the count of physical blocks. */
+ if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ }
- /*
- * the next three lines should probably be replaced
- * with a call to the yet unimplemented function VOP_SETBLOCKSIZE
+ /*
+ * At this point:
+ * minblksize is the minimum physical block size
+ * blksize has our prefered physical block size
+ * blkcnt has the total number of physical blocks
*/
- retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
- if (retval) return retval;
devvp->v_specsize = blksize;
/* cache the IO attributes */
return (retval);
}
- DBG_VFS(("hfs_mountfs: reading MDB [block no. %d + %d bytes, size %d bytes]...\n",
- IOBLKNOFORBLK(kMasterDirectoryBlock, blksize),
- IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize),
- IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize)));
-
- if ((retval = bread(devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, blksize),
- IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize), cred, &bp))) {
- goto error_exit;
- };
- mdbp = (HFSMasterDirectoryBlock*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize));
+ mdb_offset = HFS_PRI_SECTOR(blksize);
+ if ((retval = meta_bread(devvp, HFS_PRI_SECTOR(blksize), blksize, cred, &bp))) {
+ goto error_exit;
+ }
+ MALLOC(mdbp, HFSMasterDirectoryBlock *, kMDBSize, M_TEMP, M_WAITOK);
+ bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, kMDBSize);
+ brelse(bp);
+ bp = NULL;
- MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
- bzero(hfsmp, sizeof(struct hfsmount));
+ MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
+ bzero(hfsmp, sizeof(struct hfsmount));
simple_lock_init(&hfsmp->hfs_renamelock);
+
+ /*
+ * Init the volume information structure
+ */
+ mp->mnt_data = (qaddr_t)hfsmp;
+ hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */
+ hfsmp->hfs_vcb.vcb_hfsmp = hfsmp; /* Make VCBTOHFS work */
+ hfsmp->hfs_raw_dev = devvp->v_rdev;
+ hfsmp->hfs_devvp = devvp;
+ hfsmp->hfs_phys_block_size = blksize;
+ hfsmp->hfs_phys_block_count = blkcnt;
+ hfsmp->hfs_media_writeable = 1;
+ hfsmp->hfs_fs_ronly = ronly;
+ hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
+ for (i = 0; i < MAXQUOTAS; i++)
+ hfsmp->hfs_qfiles[i].qf_vp = NULLVP;
- DBG_VFS(("hfs_mountfs: Initializing hfsmount structure at 0x%lX...\n", (u_long)hfsmp));
- /*
- * Init the volume information structure
- */
- mp->mnt_data = (qaddr_t)hfsmp;
- hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */
- hfsmp->hfs_vcb.vcb_hfsmp = hfsmp; /* Make VCBTOHFS work */
- hfsmp->hfs_raw_dev = devvp->v_rdev;
- hfsmp->hfs_devvp = devvp;
- hfsmp->hfs_phys_block_size = blksize;
-
- /* The hfs_log_block_size field is updated in the respective hfs_MountHFS[Plus]Volume routine */
- hfsmp->hfs_logBlockSize = BestBlockSizeFit(SWAP_BE32 (mdbp->drAlBlkSiz), MAXBSIZE, hfsmp->hfs_phys_block_size);
- hfsmp->hfs_fs_ronly = ronly;
- hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
if (args) {
hfsmp->hfs_uid = (args->hfs_uid == (uid_t)VNOVAL) ? UNKNOWNUID : args->hfs_uid;
if (hfsmp->hfs_uid == 0xfffffffd) hfsmp->hfs_uid = UNKNOWNUID;
} else {
hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
- };
+ }
+ if ((args->flags != (int)VNOVAL) && (args->flags & HFSFSMNT_WRAPPER))
+ mntwrapper = 1;
} else {
/* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
hfsmp->hfs_gid = UNKNOWNGID;
hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
- };
- };
-
- /* See above comment for DKIOCGETBLOCKSIZE
- * retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
- * if (retval) return retval;
- */
-
- retval = VOP_IOCTL(devvp, DKIOCNUMBLKS, (caddr_t)&diskBlks, 0, cred, p);
- if (retval) return retval;
-
- if (SWAP_BE16 (mdbp->drSigWord) == kHFSPlusSigWord) {
- /* Enidan swap volume header in place */
- /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
-
- /* mount wrapper-less HFS-Plus volume */
- (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
- retval = hfs_MountHFSPlusVolume(hfsmp, (HFSPlusVolumeHeader*) bp->b_data, 0, diskBlks, p);
-
- /* Enidan un-swap volume header in place */
- /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
-
- } else if (SWAP_BE16 (mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
- u_long embBlkOffset;
- HFSPlusVolumeHeader *vhp;
+ }
+ }
- embBlkOffset = SWAP_BE16 (mdbp->drAlBlSt) +
- (SWAP_BE16 (mdbp->drEmbedExtent.startBlock) * (SWAP_BE32 (mdbp->drAlBlkSiz)/kHFSBlockSize));
- /* calculate virtual number of 512-byte sectors */
- diskBlks = SWAP_BE16 (mdbp->drEmbedExtent.blockCount) * (SWAP_BE32 (mdbp->drAlBlkSiz)/kHFSBlockSize);
+ /* Find out if disk media is writable. */
+ if (VOP_IOCTL(devvp, DKIOCISWRITABLE, (caddr_t)&iswritable, 0, cred, p) == 0) {
+ if (iswritable)
+ hfsmp->hfs_media_writeable = 1;
+ else
+ hfsmp->hfs_media_writeable = 0;
+ }
- brelse(bp);
- bp = NULL; /* done with MDB, go grab Volume Header */
- mdbp = NULL;
-
- retval = bread( devvp,
- IOBLKNOFORBLK(kMasterDirectoryBlock+embBlkOffset, blksize),
- IOBYTECCNTFORBLK(kMasterDirectoryBlock+embBlkOffset, kMDBSize, blksize),
- cred,
- &bp);
- if (retval) {
+ /* Mount a standard HFS disk */
+ if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) &&
+ (mntwrapper || (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord))) {
+ if (devvp == rootvp) {
+ retval = EINVAL; /* Cannot root from HFS standard disks */
goto error_exit;
- };
- vhp = (HFSPlusVolumeHeader*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize));
-
- /* Enidan swap volume header in place */
- /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
-
- /* mount embedded HFS Plus volume */
- (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
- retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embBlkOffset, diskBlks, p);
-
- /* Enidan un-swap volume header in place */
- /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
-
- } else if (devvp != rootvp) {
+ }
+ /* HFS disks can only use 512 byte physical blocks */
+ if (blksize > kHFSBlockSize) {
+ blksize = kHFSBlockSize;
+ if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ devvp->v_specsize = blksize;
+ hfsmp->hfs_phys_block_size = blksize;
+ hfsmp->hfs_phys_block_count = blkcnt;
+ }
if (args) {
hfsmp->hfs_encoding = args->hfs_encoding;
HFSTOVCB(hfsmp)->volumeNameEncodingHint = args->hfs_encoding;
-
/* establish the timezone */
gTimeZone = args->hfs_timezone;
}
- retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
- if (retval) goto error_exit;
+ retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode,
+ &hfsmp->hfs_get_hfsname);
+ if (retval)
+ goto error_exit;
- /* mount HFS volume */
- retval = hfs_MountHFSVolume( hfsmp, mdbp, diskBlks, p);
-
+ retval = hfs_MountHFSVolume(hfsmp, mdbp, p);
if (retval)
(void) hfs_relconverter(hfsmp->hfs_encoding);
- } else {
- /* sorry, we cannot root from HFS */
- retval = EINVAL;
- }
-
- if ( retval ) {
- goto error_exit;
- }
-
- brelse(bp);
- bp = NULL;
+ } else /* Mount an HFS Plus disk */ {
+ HFSPlusVolumeHeader *vhp;
+ off_t embeddedOffset;
+ int jnl_disable = 0;
- mp->mnt_stat.f_fsid.val[0] = (long)dev;
- mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
- mp->mnt_maxsymlinklen = 0;
- devvp->v_specflags |= SI_MOUNTEDON;
-
- if (ronly == 0) {
- hfsmp->hfs_fs_clean = 0;
- if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
- (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT);
- else
- (void) hfs_flushMDB(hfsmp, MNT_WAIT);
- }
- goto std_exit;
+ /* Get the embedded Volume Header */
+ if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
+ embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * kHFSBlockSize;
+ embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) *
+ (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
-error_exit:
- DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval));
-
- if (bp)
- brelse(bp);
- (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
- if (hfsmp) {
- FREE(hfsmp, M_HFSMNT);
- mp->mnt_data = (qaddr_t)0;
- }
+ /*
+ * If the embedded volume doesn't start on a block
+ * boundary, then switch the device to a 512-byte
+ * block size so everything will line up on a block
+ * boundary.
+ */
+ if ((embeddedOffset % blksize) != 0) {
+ printf("HFS Mount: embedded volume offset not"
+ " a multiple of physical block size (%d);"
+ " switching to 512\n", blksize);
+ blksize = 512;
+ if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
+ (caddr_t)&blksize, FWRITE, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT,
+ (caddr_t)&blkcnt, 0, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ /* XXX do we need to call vfs_init_io_attributes again? */
+ devvp->v_specsize = blksize;
+ /* Note: relative block count adjustment */
+ hfsmp->hfs_phys_block_count *=
+ hfsmp->hfs_phys_block_size / blksize;
+ hfsmp->hfs_phys_block_size = blksize;
+ }
+
+ disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) *
+ (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
+
+ hfsmp->hfs_phys_block_count = disksize / blksize;
+
+ mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
+ retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp);
+ if (retval)
+ goto error_exit;
+ bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512);
+ brelse(bp);
+ bp = NULL;
+ vhp = (HFSPlusVolumeHeader*) mdbp;
+
+ } else /* pure HFS+ */ {
+ embeddedOffset = 0;
+ vhp = (HFSPlusVolumeHeader*) mdbp;
+ }
+
+ // XXXdbg
+ //
+ hfsmp->jnl = NULL;
+ hfsmp->jvp = NULL;
+ if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS) && args->journal_disable) {
+ jnl_disable = 1;
+ }
+
+ //
+ // We only initialize the journal here if the last person
+ // to mount this volume was journaling aware. Otherwise
+ // we delay journal initialization until later at the end
+ // of hfs_MountHFSPlusVolume() because the last person who
+ // mounted it could have messed things up behind our back
+ // (so we need to go find the .journal file, make sure it's
+ // the right size, re-sync up if it was moved, etc).
+ //
+ if ( (SWAP_BE32(vhp->lastMountedVersion) == kHFSJMountVersion)
+ && (SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask)
+ && !jnl_disable) {
+
+ // if we're able to init the journal, mark the mount
+ // point as journaled.
+ //
+ if (hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred) == 0) {
+ mp->mnt_flag |= MNT_JOURNALED;
+ } else {
+ retval = EINVAL;
+ goto error_exit;
+ }
+ }
+ // XXXdbg
+
+ (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
+
+ retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
+ /*
+ * If the backend didn't like our physical blocksize
+ * then retry with physical blocksize of 512.
+ */
+ if ((retval == ENXIO) && (blksize > 512) && (blksize != minblksize)) {
+ printf("HFS Mount: could not use physical block size "
+ "(%d) switching to 512\n", blksize);
+ blksize = 512;
+ if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
+ retval = ENXIO;
+ goto error_exit;
+ }
+ devvp->v_specsize = blksize;
+ /* Note: relative block count adjustment (in case this is an embedded volume). */
+ hfsmp->hfs_phys_block_count *= hfsmp->hfs_phys_block_size / blksize;
+ hfsmp->hfs_phys_block_size = blksize;
+
+ /* Try again with a smaller block size... */
+ retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
+ }
+ if (retval)
+ (void) hfs_relconverter(0);
+ }
-std_exit:
+ if ( retval ) {
+ goto error_exit;
+ }
+
+ mp->mnt_stat.f_fsid.val[0] = (long)dev;
+ mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
+ mp->mnt_maxsymlinklen = 0;
+ devvp->v_specflags |= SI_MOUNTEDON;
+
+ if (ronly == 0) {
+ (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
+ }
+ FREE(mdbp, M_TEMP);
+ return (0);
+
+error_exit:
+ if (bp)
+ brelse(bp);
+ if (mdbp)
+ FREE(mdbp, M_TEMP);
+ (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
+ if (hfsmp && hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
+ (void)VOP_CLOSE(hfsmp->jvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
+ hfsmp->jvp = NULL;
+ }
+ if (hfsmp) {
+ FREE(hfsmp, M_HFSMNT);
+ mp->mnt_data = (qaddr_t)0;
+ }
return (retval);
}
* Nothing to do at the moment.
*/
/* ARGSUSED */
-int hfs_start(mp, flags, p)
-struct mount *mp;
-int flags;
-struct proc *p;
+static int
+hfs_start(mp, flags, p)
+ struct mount *mp;
+ int flags;
+ struct proc *p;
{
- DBG_FUNC_NAME("hfs_start");
- DBG_PRINT_FUNC_NAME();
-
- return (0);
+ return (0);
}
/*
* unmount system call
*/
-int
+static int
hfs_unmount(mp, mntflags, p)
struct mount *mp;
int mntflags;
struct hfsmount *hfsmp = VFSTOHFS(mp);
int retval = E_NONE;
int flags;
+ int force;
+ int started_tr = 0, grabbed_lock = 0;
flags = 0;
- if (mntflags & MNT_FORCE)
+ force = 0;
+ if (mntflags & MNT_FORCE) {
flags |= FORCECLOSE;
+ force = 1;
+ }
- if ((retval = hfs_flushfiles(mp, flags)))
+ if ((retval = hfs_flushfiles(mp, flags, p)) && !force)
return (retval);
/*
* Flush out the b-trees, volume bitmap and Volume Header
*/
if (hfsmp->hfs_fs_ronly == 0) {
+ hfs_global_shared_lock_acquire(hfsmp);
+ grabbed_lock = 1;
+ if (hfsmp->jnl) {
+ journal_start_transaction(hfsmp->jnl);
+ started_tr = 1;
+ }
+
retval = VOP_FSYNC(HFSTOVCB(hfsmp)->catalogRefNum, NOCRED, MNT_WAIT, p);
- if (retval && ((mntflags & MNT_FORCE) == 0))
- return (retval);
-
+ if (retval && !force)
+ goto err_exit;
+
retval = VOP_FSYNC(HFSTOVCB(hfsmp)->extentsRefNum, NOCRED, MNT_WAIT, p);
- if (retval && ((mntflags & MNT_FORCE) == 0))
- return (retval);
+ if (retval && !force)
+ goto err_exit;
+
+ // if we have an allocation file, sync it too so we don't leave dirty
+ // blocks around
+ if (HFSTOVCB(hfsmp)->allocationsRefNum) {
+ if (retval = VOP_FSYNC(HFSTOVCB(hfsmp)->allocationsRefNum, NOCRED, MNT_WAIT, p)) {
+ if (!force)
+ goto err_exit;
+ }
+ }
if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) {
- if ((mntflags & MNT_FORCE) == 0)
- return (retval);
+ if (!force)
+ goto err_exit;
}
/* See if this volume is damaged, is so do not unmount cleanly */
if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) {
- hfsmp->hfs_fs_clean = 0;
HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
} else {
- hfsmp->hfs_fs_clean = 1;
- HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
+ HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
}
- if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
- retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
- else
- retval = hfs_flushMDB(hfsmp, MNT_WAIT);
-
+
+ retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
if (retval) {
- hfsmp->hfs_fs_clean = 0;
HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
- if ((mntflags & MNT_FORCE) == 0)
- return (retval); /* could not flush everything */
+ if (!force)
+ goto err_exit; /* could not flush everything */
+ }
+
+ if (hfsmp->jnl) {
+ journal_end_transaction(hfsmp->jnl);
+ started_tr = 0;
+ }
+ if (grabbed_lock) {
+ hfs_global_shared_lock_release(hfsmp);
+ grabbed_lock = 0;
}
}
+ if (hfsmp->jnl) {
+ journal_flush(hfsmp->jnl);
+ }
+
/*
* Invalidate our caches and release metadata vnodes
*/
if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)
(void) hfs_relconverter(hfsmp->hfs_encoding);
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_close(hfsmp->jnl);
+ }
+
+ if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
+ retval = VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
+ NOCRED, p);
+ vrele(hfsmp->jvp);
+ hfsmp->jvp = NULL;
+ }
+ // XXXdbg
+
hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON;
- retval = VOP_CLOSE(hfsmp->hfs_devvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
- NOCRED, p);
- vrele(hfsmp->hfs_devvp);
+ retval = VOP_CLOSE(hfsmp->hfs_devvp,
+ hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
+ NOCRED, p);
+ if (retval && !force)
+ return(retval);
+ vrele(hfsmp->hfs_devvp);
FREE(hfsmp, M_HFSMNT);
mp->mnt_data = (qaddr_t)0;
+ return (0);
- return (retval);
+ err_exit:
+ if (hfsmp->jnl && started_tr) {
+ journal_end_transaction(hfsmp->jnl);
+ }
+ if (grabbed_lock) {
+ hfs_global_shared_lock_release(hfsmp);
+ }
+ return retval;
}
*
* OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
*/
-int hfs_root(mp, vpp)
-struct mount *mp;
-struct vnode **vpp;
+static int
+hfs_root(mp, vpp)
+ struct mount *mp;
+ struct vnode **vpp;
{
- struct vnode *nvp;
- int retval;
- UInt32 rootObjID = kRootDirID;
-
- DBG_FUNC_NAME("hfs_root");
- DBG_PRINT_FUNC_NAME();
+ struct vnode *nvp;
+ int retval;
+ UInt32 rootObjID = kRootDirID;
- if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
- return (retval);
+ if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
+ return (retval);
- *vpp = nvp;
- return (0);
+ *vpp = nvp;
+ return (0);
}
/*
* Do operations associated with quotas
*/
-int hfs_quotactl(mp, cmds, uid, arg, p)
-struct mount *mp;
-int cmds;
-uid_t uid;
-caddr_t arg;
-struct proc *p;
+int
+hfs_quotactl(mp, cmds, uid, arg, p)
+ struct mount *mp;
+ int cmds;
+ uid_t uid;
+ caddr_t arg;
+ struct proc *p;
{
- DBG_FUNC_NAME("hfs_quotactl");
- DBG_PRINT_FUNC_NAME();
+ int cmd, type, error;
+
+#if !QUOTA
+ return (EOPNOTSUPP);
+#else
+ if (uid == -1)
+ uid = p->p_cred->p_ruid;
+ cmd = cmds >> SUBCMDSHIFT;
+
+ switch (cmd) {
+ case Q_SYNC:
+ case Q_QUOTASTAT:
+ break;
+ case Q_GETQUOTA:
+ if (uid == p->p_cred->p_ruid)
+ break;
+ /* fall through */
+ default:
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ }
- return (EOPNOTSUPP);
+ type = cmds & SUBCMDMASK;
+ if ((u_int)type >= MAXQUOTAS)
+ return (EINVAL);
+ if (vfs_busy(mp, LK_NOWAIT, 0, p))
+ return (0);
+
+ switch (cmd) {
+
+ case Q_QUOTAON:
+ error = hfs_quotaon(p, mp, type, arg, UIO_USERSPACE);
+ break;
+
+ case Q_QUOTAOFF:
+ error = hfs_quotaoff(p, mp, type);
+ break;
+
+ case Q_SETQUOTA:
+ error = hfs_setquota(mp, uid, type, arg);
+ break;
+
+ case Q_SETUSE:
+ error = hfs_setuse(mp, uid, type, arg);
+ break;
+
+ case Q_GETQUOTA:
+ error = hfs_getquota(mp, uid, type, arg);
+ break;
+
+ case Q_SYNC:
+ error = hfs_qsync(mp);
+ break;
+
+ case Q_QUOTASTAT:
+ error = hfs_quotastat(mp, type, arg);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ vfs_unbusy(mp, p);
+ return (error);
+#endif /* QUOTA */
}
+
+
/*
* Get file system statistics.
*/
struct hfsmount *hfsmp = VFSTOHFS(mp);
u_long freeCNIDs;
- DBG_FUNC_NAME("hfs_statfs");
- DBG_PRINT_FUNC_NAME();
-
freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID;
sbp->f_bsize = vcb->blockSize;
sbp->f_iosize = hfsmp->hfs_logBlockSize;
sbp->f_blocks = vcb->totalBlocks;
- sbp->f_bfree = vcb->freeBlocks;
- sbp->f_bavail = vcb->freeBlocks;
+ sbp->f_bfree = hfs_freeblks(hfsmp, 0);
+ sbp->f_bavail = hfs_freeblks(hfsmp, 1);
sbp->f_files = vcb->totalBlocks - 2; /* max files is constrained by total blocks */
- sbp->f_ffree = MIN(freeCNIDs, vcb->freeBlocks);
+ sbp->f_ffree = MIN(freeCNIDs, sbp->f_bavail);
sbp->f_type = 0;
if (sbp != &mp->mnt_stat) {
}
+//
+// XXXdbg -- this is a callback to be used by the journal to
+// get meta data blocks flushed out to disk.
+//
+// XXXdbg -- be smarter and don't flush *every* block on each
+// call. try to only flush some so we don't wind up
+// being too synchronous.
+//
+__private_extern__
+void
+hfs_sync_metadata(void *arg)
+{
+ struct mount *mp = (struct mount *)arg;
+ struct cnode *cp;
+ struct hfsmount *hfsmp;
+ ExtendedVCB *vcb;
+ struct vnode *meta_vp[3];
+ struct buf *bp;
+ int i, sectorsize, priIDSector, altIDSector, retval;
+ int error, allerror = 0;
+
+ hfsmp = VFSTOHFS(mp);
+ vcb = HFSTOVCB(hfsmp);
+
+ bflushq(BQ_META, mp);
+
+
+#if 1 // XXXdbg - I do not believe this is necessary...
+ // but if I pull it out, then the journal
+ // does not seem to get flushed properly
+ // when it is closed....
+
+ // now make sure the super block is flushed
+ sectorsize = hfsmp->hfs_phys_block_size;
+ priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
+ HFS_PRI_SECTOR(sectorsize);
+ retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
+ if (retval != 0) {
+ panic("hfs: sync_metadata: can't read super-block?! (retval 0x%x, priIDSector)\n",
+ retval, priIDSector);
+ }
+
+ if (retval == 0 && (bp->b_flags & B_DELWRI) && (bp->b_flags & B_LOCKED) == 0) {
+ bwrite(bp);
+ } else if (bp) {
+ brelse(bp);
+ }
+
+ // the alternate super block...
+ // XXXdbg - we probably don't need to do this each and every time.
+ // hfs_btreeio.c:FlushAlternate() should flag when it was
+ // written...
+ altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
+ HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
+ retval = meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &bp);
+ if (retval == 0 && (bp->b_flags & B_DELWRI) && (bp->b_flags & B_LOCKED) == 0) {
+ bwrite(bp);
+ } else if (bp) {
+ brelse(bp);
+ }
+#endif
+
+}
+
/*
* Go through the disk queues to initiate sandbagged IO;
* go through the inodes to write those that have been modified;
*
* Note: we are always called with the filesystem marked `MPBUSY'.
*/
-static int hfs_sync(mp, waitfor, cred, p)
-struct mount *mp;
-int waitfor;
-struct ucred *cred;
-struct proc *p;
+static int
+hfs_sync(mp, waitfor, cred, p)
+ struct mount *mp;
+ int waitfor;
+ struct ucred *cred;
+ struct proc *p;
{
- struct vnode *nvp, *vp;
- struct hfsnode *hp;
- struct hfsmount *hfsmp = VFSTOHFS(mp);
- ExtendedVCB *vcb;
- struct vnode *meta_vp[3];
- int i;
- int error, allerror = 0;
-
- DBG_FUNC_NAME("hfs_sync");
- DBG_PRINT_FUNC_NAME();
+ struct vnode *nvp, *vp;
+ struct cnode *cp;
+ struct hfsmount *hfsmp;
+ ExtendedVCB *vcb;
+ struct vnode *meta_vp[3];
+ int i;
+ int error, allerror = 0;
/*
* During MNT_UPDATE hfs_changefs might be manipulating
if (mp->mnt_flag & MNT_UPDATE)
return (0);
- hfsmp = VFSTOHFS(mp);
- if (hfsmp->hfs_fs_ronly != 0) {
- panic("update: rofs mod");
- };
+ hfsmp = VFSTOHFS(mp);
+ if (hfsmp->hfs_fs_ronly != 0) {
+ panic("update: rofs mod");
+ };
- /*
- * Write back each 'modified' vnode
- */
+#if 0
+ // XXXdbg first go through and flush out any modified
+ // meta data blocks so they go out in order...
+ bflushq(BQ_META, mp);
+ bflushq(BQ_LRU, mp);
+ // only flush locked blocks if we're not doing journaling
+ if (hfsmp->jnl == NULL) {
+ bflushq(BQ_LOCKED, mp);
+ }
+#endif
+
+ /*
+ * Write back each 'modified' vnode
+ */
-loop:;
- simple_lock(&mntvnode_slock);
- for (vp = mp->mnt_vnodelist.lh_first;
- vp != NULL;
- vp = nvp) {
+loop:
+ simple_lock(&mntvnode_slock);
+ for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
int didhold;
- /*
- * If the vnode that we are about to sync is no longer
- * associated with this mount point, start over.
- */
- if (vp->v_mount != mp) {
- simple_unlock(&mntvnode_slock);
- goto loop;
- }
- simple_lock(&vp->v_interlock);
- nvp = vp->v_mntvnodes.le_next;
- hp = VTOH(vp);
-
- if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) ||
- (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) &&
- (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) {
- simple_unlock(&vp->v_interlock);
- simple_unlock(&mntvnode_slock);
- simple_lock(&mntvnode_slock);
- continue;
- }
-
- simple_unlock(&mntvnode_slock);
- error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
- if (error) {
- if (error == ENOENT)
- goto loop;
- simple_lock(&mntvnode_slock);
- continue;
- }
+ /*
+ * If the vnode that we are about to sync is no longer
+ * associated with this mount point, start over.
+ */
+ if (vp->v_mount != mp) {
+ simple_unlock(&mntvnode_slock);
+ goto loop;
+ }
+
+ simple_lock(&vp->v_interlock);
+ nvp = vp->v_mntvnodes.le_next;
+
+ cp = VTOC(vp);
+
+ // restart our whole search if this guy is locked
+ // or being reclaimed.
+ // XXXdbg - at some point this should go away or we
+ // need to change all file systems to have
+ // this same code. vget() should never return
+ // success if either of these conditions is
+ // true.
+ if (vp->v_tag != VT_HFS || cp == NULL) {
+ simple_unlock(&vp->v_interlock);
+ continue;
+ }
+
+ if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) ||
+ (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
+ (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) {
+ simple_unlock(&vp->v_interlock);
+ simple_unlock(&mntvnode_slock);
+ simple_lock(&mntvnode_slock);
+ continue;
+ }
+
+ simple_unlock(&mntvnode_slock);
+ error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
+ if (error) {
+ if (error == ENOENT)
+ goto loop;
+ simple_lock(&mntvnode_slock);
+ continue;
+ }
didhold = ubc_hold(vp);
- if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
- DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error, (u_int)vp));
- allerror = error;
- };
- DBG_ASSERT(*((volatile int *)(&(vp)->v_interlock))==0);
- VOP_UNLOCK(vp, 0, p);
+ if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
+ allerror = error;
+ };
+ VOP_UNLOCK(vp, 0, p);
if (didhold)
ubc_rele(vp);
- vrele(vp);
- simple_lock(&mntvnode_slock);
- };
-
- vcb = HFSTOVCB(hfsmp);
- meta_vp[0] = vcb->extentsRefNum;
- meta_vp[1] = vcb->catalogRefNum;
- meta_vp[2] = vcb->allocationsRefNum; /* This is NULL for standard HFS */
-
- /* Now sync our three metadata files */
- for (i = 0; i < 3; ++i) {
- struct vnode *btvp;
-
- btvp = meta_vp[i];
-
- if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
- continue;
- simple_lock(&btvp->v_interlock);
- hp = VTOH(btvp);
- if (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) &&
- (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) {
- simple_unlock(&btvp->v_interlock);
- continue;
- }
- simple_unlock(&mntvnode_slock);
- error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
- if (error) {
- simple_lock(&mntvnode_slock);
- continue;
- }
- if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
- allerror = error;
- VOP_UNLOCK(btvp, 0, p);
- vrele(btvp);
- simple_lock(&mntvnode_slock);
- };
-
- simple_unlock(&mntvnode_slock);
+ vrele(vp);
+ simple_lock(&mntvnode_slock);
+ };
- /*
- * Force stale file system control information to be flushed.
- */
- if (vcb->vcbSigWord == kHFSSigWord) {
- if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
- allerror = error;
- }
- /*
- * Write back modified superblock.
- */
+ vcb = HFSTOVCB(hfsmp);
+
+ meta_vp[0] = vcb->extentsRefNum;
+ meta_vp[1] = vcb->catalogRefNum;
+ meta_vp[2] = vcb->allocationsRefNum; /* This is NULL for standard HFS */
+
+ /* Now sync our three metadata files */
+ for (i = 0; i < 3; ++i) {
+ struct vnode *btvp;
- if (IsVCBDirty(vcb)) {
- if (vcb->vcbSigWord == kHFSPlusSigWord)
- error = hfs_flushvolumeheader(hfsmp, waitfor);
- else
- error = hfs_flushMDB(hfsmp, waitfor);
-
- if (error)
- allerror = error;
- };
-
- return (allerror);
+ btvp = btvp = meta_vp[i];;
+ if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
+ continue;
+
+ simple_lock(&btvp->v_interlock);
+ cp = VTOC(btvp);
+ if (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
+ (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) {
+ simple_unlock(&btvp->v_interlock);
+ continue;
+ }
+ simple_unlock(&mntvnode_slock);
+ error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
+ if (error) {
+ simple_lock(&mntvnode_slock);
+ continue;
+ }
+ if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
+ allerror = error;
+ VOP_UNLOCK(btvp, 0, p);
+ vrele(btvp);
+ simple_lock(&mntvnode_slock);
+ };
+
+ simple_unlock(&mntvnode_slock);
+
+ /*
+ * Force stale file system control information to be flushed.
+ */
+ if (vcb->vcbSigWord == kHFSSigWord) {
+ if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
+ allerror = error;
+ }
+#if QUOTA
+ hfs_qsync(mp);
+#endif /* QUOTA */
+ /*
+ * Write back modified superblock.
+ */
+
+ if (IsVCBDirty(vcb)) {
+ // XXXdbg - debugging, remove
+ if (hfsmp->jnl) {
+ //printf("hfs: sync: strange, a journaled volume w/dirty VCB? jnl 0x%x hfsmp 0x%x\n",
+ // hfsmp->jnl, hfsmp);
+ }
+
+ error = hfs_flushvolumeheader(hfsmp, waitfor, 0);
+ if (error)
+ allerror = error;
+ }
+
+ if (hfsmp->jnl) {
+ journal_flush(hfsmp->jnl);
+ }
+
+ err_exit:
+ return (allerror);
}
* File handle to vnode
*
* Have to be really careful about stale file handles:
- * - check that the hfsnode number is valid
- * - call hfs_vget() to get the locked hfsnode
- * - check for an unallocated hfsnode (i_mode == 0)
+ * - check that the cnode id is valid
+ * - call hfs_vget() to get the locked cnode
+ * - check for an unallocated cnode (i_mode == 0)
* - check that the given client host has export rights and return
* those rights via. exflagsp and credanonp
*/
-int
+static int
hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
-register struct mount *mp;
-struct fid *fhp;
-struct mbuf *nam;
-struct vnode **vpp;
-int *exflagsp;
-struct ucred **credanonp;
+ register struct mount *mp;
+ struct fid *fhp;
+ struct mbuf *nam;
+ struct vnode **vpp;
+ int *exflagsp;
+ struct ucred **credanonp;
{
struct hfsfid *hfsfhp;
struct vnode *nvp;
int result;
struct netcred *np;
- DBG_FUNC_NAME("hfs_fhtovp");
- DBG_PRINT_FUNC_NAME();
*vpp = NULL;
hfsfhp = (struct hfsfid *)fhp;
* error prone. Future, would be change the "wrap bit" to a unique
* wrap number and use that for generation number. For now do this.
*/
- if ((hfsfhp->hfsfid_gen < VTOH(nvp)->h_meta->h_crtime)) {
+ if ((hfsfhp->hfsfid_gen < VTOC(nvp)->c_itime)) {
vput(nvp);
- return ESTALE;
+ return (ESTALE);
};
*vpp = nvp;
*exflagsp = np->netc_exflags;
*credanonp = &np->netc_anon;
- return 0;
+ return (0);
}
* Vnode pointer to File handle
*/
/* ARGSUSED */
-static int hfs_vptofh(vp, fhp)
-struct vnode *vp;
-struct fid *fhp;
+static int
+hfs_vptofh(vp, fhp)
+ struct vnode *vp;
+ struct fid *fhp;
{
- struct hfsnode *hp;
+ struct cnode *cp;
struct hfsfid *hfsfhp;
- struct proc *p = current_proc();
- int result;
- u_int32_t fileID;
- DBG_FUNC_NAME("hfs_vptofh");
- DBG_PRINT_FUNC_NAME();
- hp = VTOH(vp);
- hfsfhp = (struct hfsfid *)fhp;
-
- /* If a file handle is requested for a file on an HFS volume we must be sure
- to create the thread record before returning the object id in the filehandle
- to make sure the file can be retrieved by fileid if necessary:
- */
- if ((vp->v_type == VREG) && ISHFS(VTOVCB(vp))) {
- /* Create a thread record and return the FileID [which is the file's fileNumber] */
- /* lock catalog b-tree */
- if ((result = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p)) != 0) return result;
- result = hfsCreateFileID(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &fileID);
- (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
- if (result) {
- DBG_ERR(("hfs_vptofh: error %d on CreateFileIDRef.\n", result));
- return result;
- };
- DBG_ASSERT(fileID == H_FILEID(hp));
- };
+ if (ISHFS(VTOVCB(vp)))
+ return (EOPNOTSUPP); /* hfs standard is not exportable */
+ cp = VTOC(vp);
+ hfsfhp = (struct hfsfid *)fhp;
hfsfhp->hfsfid_len = sizeof(struct hfsfid);
hfsfhp->hfsfid_pad = 0;
- hfsfhp->hfsfid_cnid = H_FILEID(hp);
- hfsfhp->hfsfid_gen = hp->h_meta->h_crtime;
+ hfsfhp->hfsfid_cnid = cp->c_cnid;
+ hfsfhp->hfsfid_gen = cp->c_itime;
- return 0;
+ return (0);
}
/*
* Initial HFS filesystems, done only once.
*/
-int
+static int
hfs_init(vfsp)
-struct vfsconf *vfsp;
+ struct vfsconf *vfsp;
{
- int i;
- static int done = 0;
- OSErr err;
+ static int done = 0;
- DBG_FUNC_NAME("hfs_init");
- DBG_PRINT_FUNC_NAME();
-
- if (done)
- return (0);
- done = 1;
- hfs_vhashinit();
- hfs_converterinit();
-
- simple_lock_init (&gBufferPtrListLock);
-
- for (i = BUFFERPTRLISTSIZE - 1; i >= 0; --i) {
- gBufferAddress[i] = NULL;
- gBufferHeaderPtr[i] = NULL;
- };
- gBufferListIndex = 0;
+ if (done)
+ return (0);
+ done = 1;
+ hfs_chashinit();
+ hfs_converterinit();
+#if QUOTA
+ dqinit();
+#endif /* QUOTA */
/*
* Allocate Catalog Iterator cache...
*/
- err = InitCatalogCache();
+ (void) InitCatalogCache();
- return E_NONE;
+ return (0);
}
+// XXXdbg
+#include <sys/filedesc.h>
+
+
/*
- * fast filesystem related variables.
+ * HFS filesystem related variables.
*/
-static int hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
-int *name;
-u_int namelen;
-void *oldp;
-size_t *oldlenp;
-void *newp;
-size_t newlen;
-struct proc *p;
+static int
+hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
+ int *name;
+ u_int namelen;
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ size_t newlen;
+ struct proc *p;
{
- DBG_FUNC_NAME("hfs_sysctl");
- DBG_PRINT_FUNC_NAME();
+ extern u_int32_t hfs_encodingbias;
+
+ /* all sysctl names at this level are terminal */
+
+ if (name[0] == HFS_ENCODINGBIAS)
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
+ &hfs_encodingbias));
+ else if (name[0] == 0x082969) {
+ // make the file system journaled...
+ struct vnode *vp = p->p_fd->fd_cdir, *jvp;
+ struct hfsmount *hfsmp;
+ ExtendedVCB *vcb;
+ int retval;
+ struct cat_attr jnl_attr, jinfo_attr;
+ struct cat_fork jnl_fork, jinfo_fork;
+ void *jnl = NULL;
+
+ /* Only root can enable journaling */
+ if (current_proc()->p_ucred->cr_uid != 0) {
+ return (EPERM);
+ }
+ hfsmp = VTOHFS(vp);
+ if (hfsmp->hfs_fs_ronly) {
+ return EROFS;
+ }
+ if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
+ printf("hfs: can't make a plain hfs volume journaled.\n");
+ return EINVAL;
+ }
- return (EOPNOTSUPP);
-}
+ if (hfsmp->jnl) {
+ printf("hfs: volume @ mp 0x%x is already journaled!\n", vp->v_mount);
+ return EAGAIN;
+ }
+ vcb = HFSTOVCB(hfsmp);
+ if (BTHasContiguousNodes(VTOF(vcb->catalogRefNum)) == 0 ||
+ BTHasContiguousNodes(VTOF(vcb->extentsRefNum)) == 0) {
-/* This will return a vnode of either a directory or a data vnode based on an object id. If
- * it is a file id, its data fork will be returned.
- */
-int
-hfs_vget(struct mount *mp,
- void *ino,
- struct vnode **vpp)
-{
- struct hfsmount *hfsmp;
- dev_t dev;
- int retval = E_NONE;
+ printf("hfs: volume has a btree w/non-contiguous nodes. can not enable journaling.\n");
+ return EINVAL;
+ }
- DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32 *)ino));
+ // make sure these both exist!
+ if ( GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jinfo_attr, &jinfo_fork) == 0
+ || GetFileInfo(vcb, kRootDirID, ".journal", &jnl_attr, &jnl_fork) == 0) {
- /* Check if unmount in progress */
- if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
- *vpp = NULL;
- return (EPERM);
- }
+ return EINVAL;
+ }
- hfsmp = VFSTOHFS(mp);
- dev = hfsmp->hfs_raw_dev;
-
- /* First check to see if it is in the cache */
- *vpp = hfs_vhashget(dev, *(UInt32 *)ino, kDefault);
-
- /* hide open files that have been deleted */
- if (*vpp != NULL) {
- if ((VTOH(*vpp)->h_meta->h_metaflags & IN_NOEXISTS) ||
- (hfsmp->hfs_private_metadata_dir != 0) &&
- (H_DIRID(VTOH(*vpp)) == hfsmp->hfs_private_metadata_dir)) {
- vput(*vpp);
- retval = ENOENT;
- goto Err_Exit;
- }
- }
-
- /* The vnode is not in the cache, so lets make it */
- if (*vpp == NULL)
- {
- hfsCatalogInfo catInfo;
- struct proc *p = current_proc();
- UInt8 forkType;
-
- INIT_CATALOGDATA(&catInfo.nodeData, 0);
- catInfo.hint = kNoHint;
- /* Special-case the root's parent directory (DirID = 1) because
- it doesn't actually exist in the catalog: */
- if ((*vpp == NULL) && (*(UInt32 *)ino == kRootParID)) {
- bzero(&catInfo, sizeof(catInfo));
- catInfo.nodeData.cnd_type = kCatalogFolderNode;
- catInfo.nodeData.cnm_nameptr = catInfo.nodeData.cnm_namespace;
- catInfo.nodeData.cnm_namespace[0] = '/';
- catInfo.nodeData.cnm_length = 1;
- catInfo.nodeData.cnd_nodeID = kRootParID;
- catInfo.nodeData.cnm_parID = kRootParID;
- catInfo.nodeData.cnd_valence = 1;
- catInfo.nodeData.cnd_ownerID = 0;
- catInfo.nodeData.cnd_groupID = 0;
- catInfo.nodeData.cnd_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
- } else {
-
- /* lock catalog b-tree */
- retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p);
- if (retval != E_NONE) goto Lookup_Err_Exit;
-
- retval = hfs_getcatalog(VFSTOVCB(mp), *(UInt32 *)ino, NULL, -1, &catInfo);
-
- /* unlock catalog b-tree */
- (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
-
- if (retval != E_NONE) goto Lookup_Err_Exit;
-
- /* hide open files that have been deleted */
- if ((hfsmp->hfs_private_metadata_dir != 0) &&
- (catInfo.nodeData.cnm_parID == hfsmp->hfs_private_metadata_dir)) {
- retval = ENOENT;
- goto Lookup_Err_Exit;
- };
- };
-
- forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork;
- retval = hfs_vcreate(VFSTOVCB(mp), &catInfo, forkType, vpp);
+ hfs_sync(hfsmp->hfs_mp, MNT_WAIT, FSCRED, p);
+ bflushq(BQ_META);
+
+ printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
+ (off_t)name[2], (off_t)name[3]);
+
+ jvp = hfsmp->hfs_devvp;
+ jnl = journal_create(jvp,
+ (off_t)name[2] * (off_t)HFSTOVCB(hfsmp)->blockSize
+ + HFSTOVCB(hfsmp)->hfsPlusIOPosOffset,
+ (off_t)name[3],
+ hfsmp->hfs_devvp,
+ hfsmp->hfs_phys_block_size,
+ 0,
+ 0,
+ hfs_sync_metadata, hfsmp->hfs_mp);
+
+ if (jnl == NULL) {
+ printf("hfs: FAILED to create the journal!\n");
+ if (jvp && jvp != hfsmp->hfs_devvp) {
+ VOP_CLOSE(jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
+ }
+ jvp = NULL;
+
+ return EINVAL;
+ }
+
+ hfs_global_exclusive_lock_acquire(hfsmp);
-Lookup_Err_Exit:
- CLEAN_CATALOGDATA(&catInfo.nodeData);
- };
+ HFSTOVCB(hfsmp)->vcbJinfoBlock = name[1];
+ HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeJournaledMask;
+ hfsmp->jvp = jvp;
+ hfsmp->jnl = jnl;
+
+ // save this off for the hack-y check in hfs_remove()
+ hfsmp->jnl_start = (u_int32_t)name[2];
+ hfsmp->hfs_jnlinfoblkid = jinfo_attr.ca_fileid;
+ hfsmp->hfs_jnlfileid = jnl_attr.ca_fileid;
+
+ hfsmp->hfs_mp->mnt_flag |= MNT_JOURNALED;
+
+ hfs_global_exclusive_lock_release(hfsmp);
+ hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
+
+ return 0;
+ } else if (name[0] == 0x031272) {
+ // clear the journaling bit
+ struct vnode *vp = p->p_fd->fd_cdir;
+ struct hfsmount *hfsmp;
+ void *jnl;
+ int retval;
+
+ /* Only root can disable journaling */
+ if (current_proc()->p_ucred->cr_uid != 0) {
+ return (EPERM);
+ }
+ hfsmp = VTOHFS(vp);
+ if (hfsmp->jnl == NULL) {
+ return EINVAL;
+ }
+
+ printf("hfs: disabling journaling for mount @ 0x%x\n", vp->v_mount);
+
+ jnl = hfsmp->jnl;
+
+ hfs_global_exclusive_lock_acquire(hfsmp);
- UBCINFOCHECK("hfs_vget", *vpp);
+ // Lights out for you buddy!
+ hfsmp->jnl = NULL;
+ journal_close(jnl);
-Err_Exit:
+ if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
+ VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
+ }
+ hfsmp->jnl = NULL;
+ hfsmp->jvp = NULL;
+ hfsmp->hfs_mp->mnt_flag &= ~MNT_JOURNALED;
+ hfsmp->jnl_start = 0;
+ hfsmp->hfs_jnlinfoblkid = 0;
+ hfsmp->hfs_jnlfileid = 0;
+
+ HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeJournaledMask;
+
+ hfs_global_exclusive_lock_release(hfsmp);
+ hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
+
+ return 0;
+ }
- /* rember if a parent directory was looked up by CNID */
- if (retval == 0 && ((*vpp)->v_type == VDIR)
- && lockstatus(&mp->mnt_lock) != LK_SHARED)
- VTOH(*vpp)->h_nodeflags |= IN_BYCNID;
+ return (EOPNOTSUPP);
+}
- return (retval);
+/* This will return a vnode of either a directory or a data vnode based on an object id. If
+ * it is a file id, its data fork will be returned.
+ */
+static int
+hfs_vget(mp, ino, vpp)
+ struct mount *mp;
+ void *ino;
+ struct vnode **vpp;
+{
+ cnid_t cnid = *(cnid_t *)ino;
+
+ /* Check for cnids that should't be exported. */
+ if ((cnid < kHFSFirstUserCatalogNodeID)
+ && (cnid != kHFSRootFolderID && cnid != kHFSRootParentID))
+ return (ENOENT);
+ /* Don't export HFS Private Data dir. */
+ if (cnid == VFSTOHFS(mp)->hfs_privdir_desc.cd_cnid)
+ return (ENOENT);
+
+ return (hfs_getcnode(VFSTOHFS(mp), cnid, NULL, 0, NULL, NULL, vpp));
}
/*
* Flush out all the files in a filesystem.
*/
int
-hfs_flushfiles(struct mount *mp, int flags)
+hfs_flushfiles(struct mount *mp, int flags, struct proc *p)
{
+ register struct hfsmount *hfsmp;
+ int i;
int error;
+#if QUOTA
+ hfsmp = VFSTOHFS(mp);
+
+ if (mp->mnt_flag & MNT_QUOTA) {
+ if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
+ return (error);
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP)
+ continue;
+ hfs_quotaoff(p, mp, i);
+ }
+ /*
+ * Here we fall through to vflush again to ensure
+ * that we have gotten rid of all the system vnodes.
+ */
+ }
+#endif /* QUOTA */
+
error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags));
error = vflush(mp, NULLVP, (SKIPSYSTEM | flags));
return (error);
}
-short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor)
+/*
+ * Update volume encoding bitmap (HFS Plus only)
+ */
+__private_extern__
+void
+hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding)
{
- ExtendedVCB *vcb = HFSTOVCB(hfsmp);
- FCB *fcb;
- HFSMasterDirectoryBlock *mdb;
- struct buf *bp;
- int retval;
- int size = kMDBSize; /* 512 */
- ByteCount namelen;
+#define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
+#define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
+
+ UInt32 index;
+
+ switch (encoding) {
+ case kTextEncodingMacUkrainian:
+ index = kIndexMacUkrainian;
+ break;
+ case kTextEncodingMacFarsi:
+ index = kIndexMacFarsi;
+ break;
+ default:
+ index = encoding;
+ break;
+ }
+
+ if (index < 128) {
+ HFSTOVCB(hfsmp)->encodingsBitmap |= (1 << index);
+ HFSTOVCB(hfsmp)->vcbFlags |= 0xFF00;
+ }
+}
+
+/*
+ * Update volume stats
+ */
+__private_extern__
+int
+hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot)
+{
+ ExtendedVCB *vcb;
+
+ vcb = HFSTOVCB(hfsmp);
+ vcb->vcbFlags |= 0xFF00;
+ vcb->vcbLsMod = time.tv_sec;
+
+ switch (op) {
+ case VOL_UPDATE:
+ break;
+ case VOL_MKDIR:
+ if (vcb->vcbDirCnt != 0xFFFFFFFF)
+ ++vcb->vcbDirCnt;
+ if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
+ ++vcb->vcbNmRtDirs;
+ break;
+ case VOL_RMDIR:
+ if (vcb->vcbDirCnt != 0)
+ --vcb->vcbDirCnt;
+ if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
+ --vcb->vcbNmRtDirs;
+ break;
+ case VOL_MKFILE:
+ if (vcb->vcbFilCnt != 0xFFFFFFFF)
+ ++vcb->vcbFilCnt;
+ if (inroot && vcb->vcbNmFls != 0xFFFF)
+ ++vcb->vcbNmFls;
+ break;
+ case VOL_RMFILE:
+ if (vcb->vcbFilCnt != 0)
+ --vcb->vcbFilCnt;
+ if (inroot && vcb->vcbNmFls != 0xFFFF)
+ --vcb->vcbNmFls;
+ break;
+ }
+
+ if (hfsmp->jnl) {
+ hfs_flushvolumeheader(hfsmp, 0, 0);
+ }
+
+ return (0);
+}
- if (vcb->vcbSigWord != kHFSSigWord)
- return EINVAL;
- DBG_ASSERT(hfsmp->hfs_devvp != NULL);
+static int
+hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush)
+{
+ ExtendedVCB *vcb = HFSTOVCB(hfsmp);
+ struct filefork *fp;
+ HFSMasterDirectoryBlock *mdb;
+ struct buf *bp = NULL;
+ int retval;
+ int sectorsize;
+ ByteCount namelen;
- retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
- IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
+ sectorsize = hfsmp->hfs_phys_block_size;
+ retval = bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize), sectorsize, NOCRED, &bp);
if (retval) {
- DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval));
- if (bp) brelse(bp);
+ if (bp)
+ brelse(bp);
return retval;
}
- DBG_ASSERT(bp != NULL);
- DBG_ASSERT(bp->b_data != NULL);
- DBG_ASSERT(bp->b_bcount == size);
+ DBG_ASSERT(bp != NULL);
+ DBG_ASSERT(bp->b_data != NULL);
+ DBG_ASSERT(bp->b_bcount == size);
+
+ if (hfsmp->jnl) {
+ panic("hfs: standard hfs volumes should not be journaled!\n");
+ }
- mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
+ mdb = (HFSMasterDirectoryBlock *)(bp->b_data + HFS_PRI_OFFSET(sectorsize));
- VCB_LOCK(vcb);
- mdb->drCrDate = SWAP_BE32 (UTCToLocal(vcb->vcbCrDate));
- mdb->drLsMod = SWAP_BE32 (UTCToLocal(vcb->vcbLsMod));
- mdb->drAtrb = SWAP_BE16 (vcb->vcbAtrb);
+ mdb->drCrDate = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbCrDate)));
+ mdb->drLsMod = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbLsMod)));
+ mdb->drAtrb = SWAP_BE16 (vcb->vcbAtrb);
mdb->drNmFls = SWAP_BE16 (vcb->vcbNmFls);
mdb->drAllocPtr = SWAP_BE16 (vcb->nextAllocation);
mdb->drClpSiz = SWAP_BE32 (vcb->vcbClpSiz);
if (retval)
retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN);
- mdb->drVolBkUp = SWAP_BE32 (UTCToLocal(vcb->vcbVolBkUp));
+ mdb->drVolBkUp = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbVolBkUp)));
mdb->drWrCnt = SWAP_BE32 (vcb->vcbWrCnt);
mdb->drNmRtDirs = SWAP_BE16 (vcb->vcbNmRtDirs);
mdb->drFilCnt = SWAP_BE32 (vcb->vcbFilCnt);
bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
- fcb = VTOFCB(vcb->extentsRefNum);
- /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drXTExtRec); */
- mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fcb->fcbExtents[0].startBlock);
- mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fcb->fcbExtents[0].blockCount);
- mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fcb->fcbExtents[1].startBlock);
- mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fcb->fcbExtents[1].blockCount);
- mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fcb->fcbExtents[2].startBlock);
- mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fcb->fcbExtents[2].blockCount);
-
- mdb->drXTFlSize = SWAP_BE32 (fcb->fcbPLen);
- mdb->drXTClpSiz = SWAP_BE32 (fcb->fcbClmpSize);
+ fp = VTOF(vcb->extentsRefNum);
+ mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
+ mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
+ mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
+ mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
+ mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
+ mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
+ mdb->drXTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
+ mdb->drXTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
- fcb = VTOFCB(vcb->catalogRefNum);
- /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drCTExtRec); */
- mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fcb->fcbExtents[0].startBlock);
- mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fcb->fcbExtents[0].blockCount);
- mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fcb->fcbExtents[1].startBlock);
- mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fcb->fcbExtents[1].blockCount);
- mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fcb->fcbExtents[2].startBlock);
- mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fcb->fcbExtents[2].blockCount);
-
- mdb->drCTFlSize = SWAP_BE32 (fcb->fcbPLen);
- mdb->drCTClpSiz = SWAP_BE32 (fcb->fcbClmpSize);
- VCB_UNLOCK(vcb);
+ fp = VTOF(vcb->catalogRefNum);
+ mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
+ mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
+ mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
+ mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
+ mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
+ mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
+ mdb->drCTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
+ mdb->drCTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
+
+ /* If requested, flush out the alternate MDB */
+ if (altflush) {
+ struct buf *alt_bp = NULL;
+ u_long altIDSector;
+
+ altIDSector = HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
+
+ if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
+ bcopy(mdb, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
+
+ (void) VOP_BWRITE(alt_bp);
+ } else if (alt_bp)
+ brelse(alt_bp);
+ }
- if (waitfor != MNT_WAIT)
+ if (waitfor != MNT_WAIT)
bawrite(bp);
- else
+ else
retval = VOP_BWRITE(bp);
MarkVCBClean( vcb );
}
-short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor)
+__private_extern__
+int
+hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush)
{
- ExtendedVCB *vcb = HFSTOVCB(hfsmp);
- FCB *fcb;
- HFSPlusVolumeHeader *volumeHeader;
- int retval;
- int size = sizeof(HFSPlusVolumeHeader);
- struct buf *bp;
- int i;
-
- if (vcb->vcbSigWord != kHFSPlusSigWord)
- return EINVAL;
+ ExtendedVCB *vcb = HFSTOVCB(hfsmp);
+ struct filefork *fp;
+ HFSPlusVolumeHeader *volumeHeader;
+ int retval;
+ struct buf *bp;
+ int i;
+ int sectorsize;
+ int priIDSector;
+ int critical = 0;
- retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
- IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
+ if (vcb->vcbSigWord == kHFSSigWord)
+ return hfs_flushMDB(hfsmp, waitfor, altflush);
+
+ if (altflush)
+ critical = 1;
+ sectorsize = hfsmp->hfs_phys_block_size;
+ priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
+ HFS_PRI_SECTOR(sectorsize);
+
+ // XXXdbg
+ hfs_global_shared_lock_acquire(hfsmp);
+ if (hfsmp->jnl) {
+ if (journal_start_transaction(hfsmp->jnl) != 0) {
+ hfs_global_shared_lock_release(hfsmp);
+ return EINVAL;
+ }
+ }
+
+ retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
if (retval) {
- DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval));
- if (bp) brelse(bp);
- return retval;
+ if (bp)
+ brelse(bp);
+
+ if (hfsmp->jnl) {
+ journal_end_transaction(hfsmp->jnl);
+ }
+ hfs_global_shared_lock_release(hfsmp);
+
+ return (retval);
}
- DBG_ASSERT(bp != NULL);
- DBG_ASSERT(bp->b_data != NULL);
- DBG_ASSERT(bp->b_bcount == size);
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, bp);
+ }
- volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data +
- IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
+ volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data + HFS_PRI_OFFSET(sectorsize));
/*
* For embedded HFS+ volumes, update create date if it changed
* (ie from a setattrlist call)
*/
- if ((vcb->hfsPlusIOPosOffset != 0) && (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate))
- {
- struct buf *bp2;
+ if ((vcb->hfsPlusIOPosOffset != 0) &&
+ (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate)) {
+ struct buf *bp2;
HFSMasterDirectoryBlock *mdb;
- retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, kMDBSize),
- IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, kMDBSize), NOCRED, &bp2);
- if (retval != E_NONE) {
- if (bp2) brelse(bp2);
+ retval = meta_bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize),
+ sectorsize, NOCRED, &bp2);
+ if (retval) {
+ if (bp2)
+ brelse(bp2);
+ retval = 0;
} else {
- mdb = (HFSMasterDirectoryBlock *)((char *)bp2->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, kMDBSize));
+ mdb = (HFSMasterDirectoryBlock *)(bp2->b_data +
+ HFS_PRI_OFFSET(sectorsize));
if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
{
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, bp2);
+ }
+
mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate); /* pick up the new create date */
- (void) VOP_BWRITE(bp2); /* write out the changes */
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_end(hfsmp->jnl, bp2);
+ } else {
+ (void) VOP_BWRITE(bp2); /* write out the changes */
+ }
}
else
{
brelse(bp2); /* just release it */
}
}
- }
+ }
+
+// XXXdbg - only monkey around with the volume signature on non-root volumes
+//
+#if 0
+ if (hfsmp->jnl &&
+ hfsmp->hfs_fs_ronly == 0 &&
+ (HFSTOVFS(hfsmp)->mnt_flag & MNT_ROOTFS) == 0) {
+
+ int old_sig = volumeHeader->signature;
+
+ if (vcb->vcbAtrb & kHFSVolumeUnmountedMask) {
+ volumeHeader->signature = kHFSPlusSigWord;
+ } else {
+ volumeHeader->signature = kHFSJSigWord;
+ }
+
+ if (old_sig != volumeHeader->signature) {
+ altflush = 1;
+ }
+ }
+#endif
+// XXXdbg
- VCB_LOCK(vcb);
/* Note: only update the lower 16 bits worth of attributes */
- volumeHeader->attributes = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb);
- volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
- volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */
- volumeHeader->modifyDate = SWAP_BE32 (vcb->vcbLsMod);
- volumeHeader->backupDate = SWAP_BE32 (vcb->vcbVolBkUp);
- volumeHeader->checkedDate = SWAP_BE32 (vcb->checkedDate);
- volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt);
- volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt);
- volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks);
- volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation);
- volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
- volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
- volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID);
- volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt);
- volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap);
-
- bcopy( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
-
- VCB_UNLOCK(vcb);
-
- fcb = VTOFCB(vcb->extentsRefNum);
- /* bcopy( fcb->fcbExtents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); */
- for (i = 0; i < kHFSPlusExtentDensity; i++) {
- volumeHeader->extentsFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
- volumeHeader->extentsFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
- }
-
- fcb->fcbFlags &= ~fcbModifiedMask;
- volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
- volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
- volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize);
-
- fcb = VTOFCB(vcb->catalogRefNum);
- /* bcopy( fcb->fcbExtents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); */
- for (i = 0; i < kHFSPlusExtentDensity; i++) {
- volumeHeader->catalogFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
- volumeHeader->catalogFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
- }
-
- fcb->fcbFlags &= ~fcbModifiedMask;
- volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
- volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
- volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize);
-
- fcb = VTOFCB(vcb->allocationsRefNum);
- /* bcopy( fcb->fcbExtents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); */
- for (i = 0; i < kHFSPlusExtentDensity; i++) {
- volumeHeader->allocationFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
- volumeHeader->allocationFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
- }
-
- fcb->fcbFlags &= ~fcbModifiedMask;
- volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
- volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
- volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize);
-
- if (waitfor != MNT_WAIT)
- bawrite(bp);
- else
- retval = VOP_BWRITE(bp);
-
- MarkVCBClean( vcb );
+ volumeHeader->attributes = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb);
+ volumeHeader->journalInfoBlock = SWAP_BE32(vcb->vcbJinfoBlock);
+ if (hfsmp->jnl) {
+ volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSJMountVersion);
+ } else {
+ volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
+ }
+ volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */
+ volumeHeader->modifyDate = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod));
+ volumeHeader->backupDate = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp));
+ volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt);
+ volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt);
+ volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks);
+ volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation);
+ volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
+ volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
+ volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID);
+ volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt);
+ volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap);
+
+ if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0)
+ critical = 1;
+ bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo));
+
+ /* Sync Extents over-flow file meta data */
+ fp = VTOF(vcb->extentsRefNum);
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ volumeHeader->extentsFile.extents[i].startBlock =
+ SWAP_BE32 (fp->ff_extents[i].startBlock);
+ volumeHeader->extentsFile.extents[i].blockCount =
+ SWAP_BE32 (fp->ff_extents[i].blockCount);
+ }
+ FTOC(fp)->c_flag &= ~C_MODIFIED;
+ volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size);
+ volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
+ volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
+
+ /* Sync Catalog file meta data */
+ fp = VTOF(vcb->catalogRefNum);
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ volumeHeader->catalogFile.extents[i].startBlock =
+ SWAP_BE32 (fp->ff_extents[i].startBlock);
+ volumeHeader->catalogFile.extents[i].blockCount =
+ SWAP_BE32 (fp->ff_extents[i].blockCount);
+ }
+ FTOC(fp)->c_flag &= ~C_MODIFIED;
+ volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size);
+ volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
+ volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
+
+ /* Sync Allocation file meta data */
+ fp = VTOF(vcb->allocationsRefNum);
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ volumeHeader->allocationFile.extents[i].startBlock =
+ SWAP_BE32 (fp->ff_extents[i].startBlock);
+ volumeHeader->allocationFile.extents[i].blockCount =
+ SWAP_BE32 (fp->ff_extents[i].blockCount);
+ }
+ FTOC(fp)->c_flag &= ~C_MODIFIED;
+ volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size);
+ volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
+ volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
+
+ /* If requested, flush out the alternate volume header */
+ if (altflush) {
+ struct buf *alt_bp = NULL;
+ u_long altIDSector;
+
+ altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
+ HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
+
+ if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, alt_bp);
+ }
+
+ bcopy(volumeHeader, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
+ if (hfsmp->jnl) {
+ journal_modify_block_end(hfsmp->jnl, alt_bp);
+ } else {
+ (void) VOP_BWRITE(alt_bp);
+ }
+ } else if (alt_bp)
+ brelse(alt_bp);
+ }
+
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_end(hfsmp->jnl, bp);
+ journal_end_transaction(hfsmp->jnl);
+ } else {
+ if (waitfor != MNT_WAIT)
+ bawrite(bp);
+ else {
+ retval = VOP_BWRITE(bp);
+ /* When critical data changes, flush the device cache */
+ if (critical && (retval == 0)) {
+ (void) VOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE,
+ NULL, FWRITE, NOCRED, current_proc());
+ }
+ }
+ }
+ hfs_global_shared_lock_release(hfsmp);
+
+ vcb->vcbFlags &= 0x00FF;
return (retval);
}
-/*
- * Moved here to avoid having to define prototypes
- */
-
/*
* hfs vfs operations.
*/
struct vfsops hfs_vfsops = {
- hfs_mount,
- hfs_start,
- hfs_unmount,
- hfs_root,
- hfs_quotactl,
- hfs_statfs,
- hfs_sync,
- hfs_vget,
- hfs_fhtovp,
- hfs_vptofh,
- hfs_init,
- hfs_sysctl
+ hfs_mount,
+ hfs_start,
+ hfs_unmount,
+ hfs_root,
+ hfs_quotactl,
+ hfs_statfs,
+ hfs_sync,
+ hfs_vget,
+ hfs_fhtovp,
+ hfs_vptofh,
+ hfs_init,
+ hfs_sysctl
};