/*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003 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_vfsutils.c 4.0
*
-* (c) 1997-2000 Apple Computer, Inc. All Rights Reserved
+* (c) 1997-2002 Apple Computer, Inc. All Rights Reserved
*
* hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS.
*
-* Change History (most recent first):
-*
-* 22-Jan-2000 Don Brady Remove calls to MountCheck.
-* 7-Sep-1999 Don Brady Add HFS Plus hard-link support.
-* 25-Aug-1999 Don Brady Dont't use vcbAlBlSt for HFS plus volumes (2350009).
-* 9-Aug-1999 Pat Dirks Added support for ATTR_VOL_ENCODINGSUSED [#2357367].
-* 16-Jul-1999 Pat Dirks Fixed PackCommonCatalogInfoAttributeBlock to return full range of possible vnode types [#2317604]
-* 15-Jun-1999 Pat Dirks Added support for return of mounted device in hfs_getattrlist [#2345297].
-* 9-Jun-1999 Don Brady Cleanup vcb accesses in hfs_MountHFSVolume.
-* 3-Jun-1999 Don Brady Remove references to unused/legacy vcb fields (eg vcbXTClpSiz).
-* 21-May-1999 Don Brady Add call to hfs_vinit in hfsGet to support mknod.
-* 6-Apr-1999 Don Brady Fixed de-reference of NULL dvp in hfsGet.
-* 22-Mar-1999 Don Brady Add support for UFS delete semantics.
-* 1-Mar-1999 Scott Roberts Dont double MALLOC on long names.
-* 23-Feb-1999 Pat Dirks Change incrementing of meta refcount to be done BEFORE lock is acquired.
-* 2-Feb-1999 Pat Dirks For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0.
-* 10-Mar-1999 Don Brady Removing obsolete code.
-* 2-Feb-1999 Don Brady For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0.
-* 18-Jan-1999 Pat Dirks Changed CopyCatalogToHFSNode to start with ACCESSPERMS instead of adding
-* write access only for unlocked files (now handled via IMMUTABLE setting)
-* 7-Dec-1998 Pat Dirks Changed PackCatalogInfoFileAttributeBlock to return proper I/O block size.
-* 7-Dec-1998 Don Brady Pack the real text encoding instead of zero.
-* 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist.
-* 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist.
-* 2-Dec-1998 Scott Roberts Copy the mdbVN correctly into the vcb.
-* 3-Dec-1998 Pat Dirks Added support for ATTR_VOL_MOUNTFLAGS.
-* 20-Nov-1998 Don Brady Add support for UTF-8 names.
-* 18-Nov-1998 Pat Dirks Changed UnpackCommonAttributeBlock to call wait for hfs_chflags to update catalog entry when changing flags
-* 13-Nov-1998 Pat Dirks Changed BestBlockSizeFit to try PAGE_SIZE only and skip check for MAXBSIZE.
-* 10-Nov-1998 Pat Dirks Changed CopyCatalogToHFSNode to ensure consistency between lock flag and IMMUTABLE bits.
-* 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines.
-* 18-Nov-1998 Pat Dirks Changed PackVolAttributeBlock to return proper logical block size
-* for ATTR_VOL_IOBLOCKSIZE attribute.
-* 3-Nov-1998 Umesh Vaishampayan Changes to deal with "struct timespec"
-* change in the kernel.
-* 23-Sep-1998 Don Brady In UnpackCommonAttributeBlock simplified setting of gid, uid and mode.
-* 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines.
-* 17-Sep-1998 Pat Dirks Changed BestBlockSizeFit to try MAXBSIZE and PAGE_SIZE first.
-* 8-Sep-1998 Don Brady Fix CopyVNodeToCatalogNode to use h_mtime for contentModDate (instead of h_ctime).
-* 4-Sep-1998 Pat Dirks Added BestBlockSizeFit routine.
-* 18-Aug-1998 Don Brady Change DEBUG_BREAK_MSG to a DBG_UTILS in MacToVFSError (radar #2262802).
-* 30-Jun-1998 Don Brady Add calls to MacToVFSError to hfs/hfsplus mount routines (for radar #2249539).
-* 22-Jun-1998 Don Brady Add more error cases to MacToVFSError; all HFS Common errors are negative.
-* Changed hfsDelete to call DeleteFile for files.
-* 4-Jun-1998 Pat Dirks Changed incorrect references to 'vcbAlBlkSize' to 'blockSize';
-* Added hfsCreateFileID.
-* 4-Jun-1998 Don Brady Add hfsMoveRename to replace hfsMove and hfsRename. Use VPUT/VRELE macros
-* instead of vput/vrele to catch bad ref counts.
-* 28-May-1998 Pat Dirks Adjusted for change in definition of ATTR_CMN_NAME and removed ATTR_CMN_RAWDEVICE.
-* 7-May-1998 Don Brady Added check for NULL vp to hfs_metafilelocking (radar #2233832).
-* 24-Apr-1998 Pat Dirks Fixed AttributeBlockSize to return only length of variable attribute block.
-* 4/21/1998 Don Brady Add SUPPORTS_MAC_ALIASES conditional (for radar #2225419).
-* 4/21/1998 Don Brady Map cmNotEmpty errors to ENOTEMPTY (radar #2229259).
-* 4/21/1998 Don Brady Fix up time/date conversions.
-* 4/20/1998 Don Brady Remove course-grained hfs metadata locking.
-* 4/18/1998 Don Brady Add VCB locking.
-* 4/17/1998 Pat Dirks Fixed PackFileAttributeBlock to return more up-to-date EOF/PEOF info from vnode.
-* 4/15/1998 Don Brady Add hasOverflowExtents and hfs_metafilelocking. Use ExtendBTreeFile instead
-* of SetEndOfForkProc. Set forktype for system files.
-* 4/14/1998 Deric Horn PackCatalogInfoAttributeBlock(), and related packing routines to
-* pack attribute data given hfsCatalogInfo, without the objects vnode;
-* 4/14/1998 Scott Roberts Add execute priviledges to all hfs objects.
-* 4/9/1998 Don Brady Add MDB/VolumeHeader flushing to hfsUnmount;
-* 4/8/1998 Don Brady Make sure vcbVRefNum field gets initialized (use MAKE_VREFNUM).
-* 4/6/1998 Don Brady Removed calls to CreateVolumeCatalogCache (obsolete).
-* 4/06/1998 Scott Roberts Added complex file support.
-* 4/02/1998 Don Brady UpdateCatalogNode now takes parID and name as input.
-* 3/31/1998 Don Brady Sync up with final HFSVolumes.h header file.
-* 3/31/1998 Don Brady Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater
-* than 31 characters.
-* 3/30/1998 Don Brady In InitMetaFileVNode set VSYSTEM bit in vnode's v_flag.
-* 3/26/1998 Don Brady Cleaned up hfs_MountXXX routines. Removed CloseBtreeFile and OpenBTreeFile.
-* Simplified hfsUnmount (removed MacOS specific code).
-* 3/17/1998 Don Brady AttributeBlockSize calculation did not account for the size field (4bytes).
-* PackVolCommonAttributes and PackCommonAttributeBlock for ATTR_CMN_NAME
-* were not setting up the name correctly.
-* 3/17/1998 Don Brady Changed CreateCatalogNode interface to take kCatalogFolderNode and
-* kCatalogFileNode as type input. Also, force MountCheck to always run.
-* 12-nov-1997 Scott Roberts Initially created file.
-* 17-Mar-98 ser Broke out and created CopyCatalogToHFSNode()
-*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/stat.h>
-#include <sys/attr.h>
#include <sys/mount.h>
+#include <sys/namei.h>
#include <sys/lock.h>
#include <sys/buf.h>
#include <sys/ubc.h>
#include <sys/unistd.h>
#include "hfs.h"
+#include "hfs_catalog.h"
#include "hfs_dbg.h"
#include "hfs_mount.h"
#include "hfs_endian.h"
+#include "hfs_cnode.h"
#include "hfscommon/headers/FileMgrInternal.h"
#include "hfscommon/headers/BTreesInternal.h"
#include "hfscommon/headers/HFSUnicodeWrappers.h"
-#define SUPPORTS_MAC_ALIASES 0
-#define kMaxSecsForFsync 5
-
-#define BYPASSBLOCKINGOPTIMIZATION 0
-extern int (**hfs_vnodeop_p)(void *);
-extern int (**hfs_specop_p)(void *);
-extern int (**hfs_fifoop_p)(void *);
extern int count_lock_queue __P((void));
-extern uid_t console_user;
-OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb );
-/* Externs from vhash */
-extern void hfs_vhashins_sibling(dev_t dev, UInt32 nodeID, struct hfsnode *hp, struct hfsfilemeta **fm);
-extern void hfs_vhashins(dev_t dev, UInt32 nodeID,struct hfsnode *hp);
-extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType);
-
-extern int hfs_vinit( struct mount *mntp, int (**specops)(void *), int (**fifoops)(), struct vnode **vpp);
-
-extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
+static void ReleaseMetaFileVNode(struct vnode *vp);
+static int hfs_late_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, void *_args);
-static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, const HFSPlusExtentRecord extents,
- HFSCatalogNodeID fileID, void * keyCompareProc);
+static void hfs_metadatazone_init(struct hfsmount *);
+static u_int32_t hfs_hotfile_freeblocks(struct hfsmount *);
-static void ReleaseMetaFileVNode(struct vnode *vp);
-static void RemovedMetaDataDirectory(ExtendedVCB *vcb);
-void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm);
-void CopyCatalogToFCB(struct hfsCatalogInfo *catalogInfo, struct vnode *vp);
-void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm);
u_int32_t GetLogicalBlockSize(struct vnode *vp);
/* BTree accessor routines */
//
//
//*******************************************************************************
+char hfs_catname[] = "Catalog B-tree";
+char hfs_extname[] = "Extents B-tree";
+char hfs_vbmname[] = "Volume Bitmap";
+char hfs_privdirname[] =
+ "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data";
+
+__private_extern__
OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb,
struct proc *p)
{
- ExtendedVCB *vcb = HFSTOVCB(hfsmp);
- struct vnode *tmpvnode;
- OSErr err;
- HFSPlusExtentRecord extents;
+ ExtendedVCB *vcb = HFSTOVCB(hfsmp);
+ int error;
ByteCount utf8chars;
- DBG_FUNC_NAME("hfs_MountHFSVolume");
- DBG_PRINT_FUNC_NAME();
+ struct cat_desc cndesc;
+ struct cat_attr cnattr;
+ struct cat_fork fork;
- if (hfsmp == nil || mdb == nil) /* exit if bad paramater */
+ /* Block size must be a multiple of 512 */
+ if (SWAP_BE32(mdb->drAlBlkSiz) == 0 ||
+ (SWAP_BE32(mdb->drAlBlkSiz) & 0x01FF) != 0)
return (EINVAL);
- err = ValidMasterDirectoryBlock( mdb ); /* make sure this is an HFS disk */
- if (err)
- return MacToVFSError(err);
-
/* don't mount a writeable volume if its dirty, it must be cleaned by fsck_hfs */
- if ((hfsmp->hfs_fs_ronly == 0) && ((SWAP_BE16 (mdb->drAtrb) & kHFSVolumeUnmountedMask) == 0))
+ if (((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) &&
+ ((SWAP_BE16(mdb->drAtrb) & kHFSVolumeUnmountedMask) == 0)) {
return (EINVAL);
-
+ }
+ hfsmp->hfs_flags |= HFS_STANDARD;
/*
* The MDB seems OK: transfer info from it into VCB
* Note - the VCB starts out clear (all zeros)
*
*/
- vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev);
-
- vcb->vcbSigWord = SWAP_BE16 (mdb->drSigWord);
- vcb->vcbCrDate = LocalToUTC (SWAP_BE32 (mdb->drCrDate));
+ vcb->vcbSigWord = SWAP_BE16 (mdb->drSigWord);
+ vcb->vcbCrDate = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drCrDate)));
vcb->localCreateDate = SWAP_BE32 (mdb->drCrDate);
- vcb->vcbLsMod = LocalToUTC (SWAP_BE32 (mdb->drLsMod));
- vcb->vcbAtrb = SWAP_BE16 (mdb->drAtrb);
- vcb->vcbNmFls = SWAP_BE16 (mdb->drNmFls);
- vcb->vcbVBMSt = SWAP_BE16 (mdb->drVBMSt);
- vcb->nextAllocation = SWAP_BE16 (mdb->drAllocPtr);
- vcb->totalBlocks = SWAP_BE16 (mdb->drNmAlBlks);
- vcb->blockSize = SWAP_BE32 (mdb->drAlBlkSiz);
- vcb->vcbClpSiz = SWAP_BE32 (mdb->drClpSiz);
- vcb->vcbAlBlSt = SWAP_BE16 (mdb->drAlBlSt);
- vcb->vcbNxtCNID = SWAP_BE32 (mdb->drNxtCNID);
- vcb->freeBlocks = SWAP_BE16 (mdb->drFreeBks);
- vcb->vcbVolBkUp = LocalToUTC (SWAP_BE32 (mdb->drVolBkUp));
- vcb->vcbWrCnt = SWAP_BE32 (mdb->drWrCnt);
- vcb->vcbNmRtDirs = SWAP_BE16 (mdb->drNmRtDirs);
- vcb->vcbFilCnt = SWAP_BE32 (mdb->drFilCnt);
- vcb->vcbDirCnt = SWAP_BE32 (mdb->drDirCnt);
+ vcb->vcbLsMod = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drLsMod)));
+ vcb->vcbAtrb = SWAP_BE16 (mdb->drAtrb);
+ vcb->vcbNmFls = SWAP_BE16 (mdb->drNmFls);
+ vcb->vcbVBMSt = SWAP_BE16 (mdb->drVBMSt);
+ vcb->nextAllocation = SWAP_BE16 (mdb->drAllocPtr);
+ vcb->totalBlocks = SWAP_BE16 (mdb->drNmAlBlks);
+ vcb->blockSize = SWAP_BE32 (mdb->drAlBlkSiz);
+ vcb->vcbClpSiz = SWAP_BE32 (mdb->drClpSiz);
+ vcb->vcbAlBlSt = SWAP_BE16 (mdb->drAlBlSt);
+ vcb->vcbNxtCNID = SWAP_BE32 (mdb->drNxtCNID);
+ vcb->freeBlocks = SWAP_BE16 (mdb->drFreeBks);
+ vcb->vcbVolBkUp = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drVolBkUp)));
+ vcb->vcbWrCnt = SWAP_BE32 (mdb->drWrCnt);
+ vcb->vcbNmRtDirs = SWAP_BE16 (mdb->drNmRtDirs);
+ vcb->vcbFilCnt = SWAP_BE32 (mdb->drFilCnt);
+ vcb->vcbDirCnt = SWAP_BE32 (mdb->drDirCnt);
bcopy(mdb->drFndrInfo, vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo));
- vcb->nextAllocation = SWAP_BE16 ( mdb->drAllocPtr); /* Duplicate?!?!?! */
- vcb->encodingsBitmap = 0;
- vcb->vcbWrCnt++; /* Compensate for write of MDB on last flush */
- /*
- * Copy the drVN field, which is a Pascal String to the vcb, which is a cstring
- */
+ if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0)
+ vcb->vcbWrCnt++; /* Compensate for write of MDB on last flush */
/* convert hfs encoded name into UTF-8 string */
- err = hfs_to_utf8(vcb, mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN);
+ error = hfs_to_utf8(vcb, mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN);
/*
* When an HFS name cannot be encoded with the current
* volume encoding we use MacRoman as a fallback.
*/
- if (err || (utf8chars == 0))
+ if (error || (utf8chars == 0))
(void) mac_roman_to_utf8(mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN);
- // Initialize our dirID/nodePtr cache associated with this volume.
- err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
- ReturnIfError( err );
-
- hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
+ hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
vcb->vcbVBMIOSize = kHFSBlockSize;
- // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
VCB_LOCK_INIT(vcb);
+ bzero(&cndesc, sizeof(cndesc));
+ cndesc.cd_parentcnid = kRootParID;
+ cndesc.cd_flags |= CD_ISMETA;
+ bzero(&cnattr, sizeof(cnattr));
+ cnattr.ca_nlink = 1;
+ cnattr.ca_mode = S_IFREG;
+ bzero(&fork, sizeof(fork));
+
/*
- * Set up Extents B-tree vnode...
- */
- err = GetInitializedVNode(hfsmp, &tmpvnode);
- if (err) goto MtVolErr;
- /* HFSToHFSPlusExtents(mdb->drXTExtRec, extents); */ /* ASDFADSFSD */
- extents[0].startBlock = SWAP_BE16 (mdb->drXTExtRec[0].startBlock);
- extents[0].blockCount = SWAP_BE16 (mdb->drXTExtRec[0].blockCount);
- extents[1].startBlock = SWAP_BE16 (mdb->drXTExtRec[1].startBlock);
- extents[1].blockCount = SWAP_BE16 (mdb->drXTExtRec[1].blockCount);
- extents[2].startBlock = SWAP_BE16 (mdb->drXTExtRec[2].startBlock);
- extents[2].blockCount = SWAP_BE16 (mdb->drXTExtRec[2].blockCount);
-
- err = InitMetaFileVNode(tmpvnode, SWAP_BE32 (mdb->drXTFlSize), SWAP_BE32 (mdb->drXTClpSiz), extents,
- kHFSExtentsFileID, CompareExtentKeys);
- if (err) goto MtVolErr;
+ * Set up Extents B-tree vnode
+ */
+ cndesc.cd_nameptr = hfs_extname;
+ cndesc.cd_namelen = strlen(hfs_extname);
+ cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID;
+ fork.cf_size = SWAP_BE32(mdb->drXTFlSize);
+ fork.cf_blocks = fork.cf_size / vcb->blockSize;
+ fork.cf_clump = SWAP_BE32(mdb->drXTClpSiz);
+ fork.cf_vblocks = 0;
+ fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drXTExtRec[0].startBlock);
+ fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drXTExtRec[0].blockCount);
+ fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drXTExtRec[1].startBlock);
+ fork.cf_extents[1].blockCount = SWAP_BE16(mdb->drXTExtRec[1].blockCount);
+ fork.cf_extents[2].startBlock = SWAP_BE16(mdb->drXTExtRec[2].startBlock);
+ fork.cf_extents[2].blockCount = SWAP_BE16(mdb->drXTExtRec[2].blockCount);
+ cnattr.ca_blocks = fork.cf_blocks;
+
+ error = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &fork,
+ &vcb->extentsRefNum);
+ if (error) goto MtVolErr;
+ error = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum),
+ (KeyCompareProcPtr)CompareExtentKeys));
+ if (error) {
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
+ goto MtVolErr;
+ }
/*
* Set up Catalog B-tree vnode...
*/
- err = GetInitializedVNode(hfsmp, &tmpvnode);
- if (err) goto MtVolErr;
- /* HFSToHFSPlusExtents(mdb->drCTExtRec, extents); */
- extents[0].startBlock = SWAP_BE16 (mdb->drCTExtRec[0].startBlock);
- extents[0].blockCount = SWAP_BE16 (mdb->drCTExtRec[0].blockCount);
- extents[1].startBlock = SWAP_BE16 (mdb->drCTExtRec[1].startBlock);
- extents[1].blockCount = SWAP_BE16 (mdb->drCTExtRec[1].blockCount);
- extents[2].startBlock = SWAP_BE16 (mdb->drCTExtRec[2].startBlock);
- extents[2].blockCount = SWAP_BE16 (mdb->drCTExtRec[2].blockCount);
-
- err = InitMetaFileVNode(tmpvnode, SWAP_BE32 (mdb->drCTFlSize), SWAP_BE32 (mdb->drCTClpSiz), extents,
- kHFSCatalogFileID, CompareCatalogKeys);
- if (err) goto MtVolErr;
+ cndesc.cd_nameptr = hfs_catname;
+ cndesc.cd_namelen = strlen(hfs_catname);
+ cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID;
+ fork.cf_size = SWAP_BE32(mdb->drCTFlSize);
+ fork.cf_blocks = fork.cf_size / vcb->blockSize;
+ fork.cf_clump = SWAP_BE32(mdb->drCTClpSiz);
+ fork.cf_vblocks = 0;
+ fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drCTExtRec[0].startBlock);
+ fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drCTExtRec[0].blockCount);
+ fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drCTExtRec[1].startBlock);
+ fork.cf_extents[1].blockCount = SWAP_BE16(mdb->drCTExtRec[1].blockCount);
+ fork.cf_extents[2].startBlock = SWAP_BE16(mdb->drCTExtRec[2].startBlock);
+ fork.cf_extents[2].blockCount = SWAP_BE16(mdb->drCTExtRec[2].blockCount);
+ cnattr.ca_blocks = fork.cf_blocks;
+
+ error = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &fork,
+ &vcb->catalogRefNum);
+ if (error) {
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
+ goto MtVolErr;
+ }
+ error = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum),
+ (KeyCompareProcPtr)CompareCatalogKeys));
+ if (error) {
+ VOP_UNLOCK(vcb->catalogRefNum, 0, p);
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
+ goto MtVolErr;
+ }
/* mark the volume dirty (clear clean unmount bit) */
vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
- /* Remove any MetaDataDirectory from hfs disks */
- if (hfsmp->hfs_fs_ronly == 0)
- RemovedMetaDataDirectory(vcb);
-
/*
* all done with b-trees so we can unlock now...
*/
- VOP_UNLOCK(vcb->catalogRefNum, 0, p);
- VOP_UNLOCK(vcb->extentsRefNum, 0, p);
-
- err = noErr;
+ VOP_UNLOCK(vcb->catalogRefNum, 0, p);
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
- if ( err == noErr )
+ if ( error == noErr )
{
if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
{
goto CmdDone;
//-- Release any resources allocated so far before exiting with an error:
-MtVolErr:;
+MtVolErr:
ReleaseMetaFileVNode(vcb->catalogRefNum);
ReleaseMetaFileVNode(vcb->extentsRefNum);
-CmdDone:;
- return( err );
+CmdDone:
+ return (error);
}
//*******************************************************************************
//
//*******************************************************************************
+__private_extern__
OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
- off_t embeddedOffset, off_t disksize, struct proc *p)
+ off_t embeddedOffset, u_int64_t disksize, struct proc *p, void *args)
{
- register ExtendedVCB *vcb;
- HFSPlusForkData *fdp;
- struct vnode *tmpvnode;
- OSErr retval;
-
- if (hfsmp == nil || vhp == nil) /* exit if bad paramater */
+ register ExtendedVCB *vcb;
+ struct cat_desc cndesc;
+ struct cat_attr cnattr;
+ struct cat_fork cfork;
+ UInt32 blockSize;
+ u_int64_t volumesize;
+ struct BTreeInfoRec btinfo;
+ u_int16_t signature;
+ u_int16_t version;
+ int i;
+ OSErr retval;
+
+ signature = SWAP_BE16(vhp->signature);
+ version = SWAP_BE16(vhp->version);
+
+ if (signature == kHFSPlusSigWord) {
+ if (version != kHFSPlusVersion) {
+ printf("hfs_mount: invalid HFS+ version: %d\n", version);
+ return (EINVAL);
+ }
+ } else if (signature == kHFSXSigWord) {
+ if (version != kHFSXVersion) {
+ printf("hfs_mount: invalid HFSX version: %d\n", version);
+ return (EINVAL);
+ }
+ /* The in-memory signature is always 'H+'. */
+ signature = kHFSPlusSigWord;
+ hfsmp->hfs_flags |= HFS_X;
+ } else {
+ printf("hfs_mount: invalid HFS+ sig 0x%04x\n", signature);
return (EINVAL);
+ }
- DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n",
- SWAP_BE16 (vhp->signature),
- SWAP_BE16 (vhp->version),
- SWAP_BE32 (vhp->blockSize)));
-
- retval = ValidVolumeHeader(vhp); /* make sure this is an HFS Plus disk */
- if (retval)
- return MacToVFSError(retval);
+ /* Block size must be at least 512 and a power of 2 */
+ blockSize = SWAP_BE32(vhp->blockSize);
+ if (blockSize < 512 || !powerof2(blockSize))
+ return (EINVAL);
/* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */
- if (hfsmp->hfs_fs_ronly == 0 && (SWAP_BE32 (vhp->attributes) & kHFSVolumeUnmountedMask) == 0)
+ if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0 && hfsmp->jnl == NULL &&
+ (SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) == 0)
return (EINVAL);
/* Make sure we can live with the physical block size. */
if ((disksize & (hfsmp->hfs_phys_block_size - 1)) ||
(embeddedOffset & (hfsmp->hfs_phys_block_size - 1)) ||
- (SWAP_BE32(vhp->blockSize) < hfsmp->hfs_phys_block_size)) {
+ (blockSize < hfsmp->hfs_phys_block_size)) {
return (ENXIO);
}
-
/*
* The VolumeHeader seems OK: transfer info from it into VCB
* Note - the VCB starts out clear (all zeros)
*/
vcb = HFSTOVCB(hfsmp);
- //DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
- vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev);
- vcb->vcbSigWord = SWAP_BE16 (vhp->signature);
- 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->vcbSigWord = signature;
+ vcb->vcbJinfoBlock = SWAP_BE32(vhp->journalInfoBlock);
+ vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate));
+ vcb->vcbAtrb = (UInt16)SWAP_BE32(vhp->attributes);
+ 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);
/* copy 32 bytes of Finder info */
bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));
vcb->vcbAlBlSt = 0; /* hfs+ allocation blocks start at first block of volume */
- vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */
+ if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0)
+ vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */
VCB_LOCK_INIT(vcb);
- /* Now fill in the Extended VCB info */
- vcb->nextAllocation = SWAP_BE32 (vhp->nextAllocation);
- vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks);
- vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks);
- vcb->blockSize = SWAP_BE32 (vhp->blockSize);
- vcb->checkedDate = SWAP_BE32 (vhp->checkedDate);
- vcb->encodingsBitmap = SWAP_BE64 (vhp->encodingsBitmap);
+ /* Now fill in the Extended VCB info */
+ vcb->nextAllocation = SWAP_BE32(vhp->nextAllocation);
+ vcb->totalBlocks = SWAP_BE32(vhp->totalBlocks);
+ vcb->freeBlocks = SWAP_BE32(vhp->freeBlocks);
+ vcb->blockSize = blockSize;
+ vcb->encodingsBitmap = SWAP_BE64(vhp->encodingsBitmap);
+ vcb->localCreateDate = SWAP_BE32(vhp->createDate);
- vcb->hfsPlusIOPosOffset = embeddedOffset;
+ vcb->hfsPlusIOPosOffset = embeddedOffset;
- vcb->localCreateDate = SWAP_BE32 (vhp->createDate); /* in local time, not GMT! */
+ /* Default to no free block reserve */
+ vcb->reserveBlocks = 0;
- /* Update the logical block size in the mount struct (currently set up from the wrapper MDB)
- using the new blocksize value: */
- hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
+ /*
+ * Update the logical block size in the mount struct
+ * (currently set up from the wrapper MDB) using the
+ * new blocksize value:
+ */
+ hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
vcb->vcbVBMIOSize = min(vcb->blockSize, MAXPHYSIO);
- // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
- // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!!
-
- // Initialize our dirID/nodePtr cache associated with this volume.
- retval = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
- if (retval != noErr) goto ErrorExit;
+ bzero(&cndesc, sizeof(cndesc));
+ cndesc.cd_parentcnid = kRootParID;
+ cndesc.cd_flags |= CD_ISMETA;
+ bzero(&cnattr, sizeof(cnattr));
+ cnattr.ca_nlink = 1;
+ cnattr.ca_mode = S_IFREG;
/*
- * Set up Extents B-tree vnode...
- */
- retval = GetInitializedVNode(hfsmp, &tmpvnode);
+ * Set up Extents B-tree vnode
+ */
+ cndesc.cd_nameptr = hfs_extname;
+ cndesc.cd_namelen = strlen(hfs_extname);
+ cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID;
+
+ cfork.cf_size = SWAP_BE64 (vhp->extentsFile.logicalSize);
+ cfork.cf_clump = SWAP_BE32 (vhp->extentsFile.clumpSize);
+ cfork.cf_blocks = SWAP_BE32 (vhp->extentsFile.totalBlocks);
+ cfork.cf_vblocks = 0;
+ cnattr.ca_blocks = cfork.cf_blocks;
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ cfork.cf_extents[i].startBlock =
+ SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
+ cfork.cf_extents[i].blockCount =
+ SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
+ }
+ retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork,
+ &vcb->extentsRefNum);
+
if (retval) goto ErrorExit;
- fdp = &vhp->extentsFile;
- SWAP_HFS_PLUS_FORK_DATA (fdp);
- retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
- kHFSExtentsFileID, CompareExtentKeysPlus);
- SWAP_HFS_PLUS_FORK_DATA (fdp);
- if (retval) goto ErrorExit;
+ retval = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum),
+ (KeyCompareProcPtr) CompareExtentKeysPlus));
+ if (retval) {
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
+ goto ErrorExit;
+ }
/*
- * Set up Catalog B-tree vnode...
+ * Set up Catalog B-tree vnode
*/
- retval = GetInitializedVNode(hfsmp, &tmpvnode);
- if (retval) goto ErrorExit;
- fdp = &vhp->catalogFile;
- SWAP_HFS_PLUS_FORK_DATA (fdp);
- retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
- kHFSCatalogFileID, CompareExtendedCatalogKeys);
- SWAP_HFS_PLUS_FORK_DATA (fdp);
- if (retval) goto ErrorExit;
+ cndesc.cd_nameptr = hfs_catname;
+ cndesc.cd_namelen = strlen(hfs_catname);
+ cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID;
+
+ cfork.cf_size = SWAP_BE64 (vhp->catalogFile.logicalSize);
+ cfork.cf_clump = SWAP_BE32 (vhp->catalogFile.clumpSize);
+ cfork.cf_blocks = SWAP_BE32 (vhp->catalogFile.totalBlocks);
+ cfork.cf_vblocks = 0;
+ cnattr.ca_blocks = cfork.cf_blocks;
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ cfork.cf_extents[i].startBlock =
+ SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
+ cfork.cf_extents[i].blockCount =
+ SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
+ }
+ retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork,
+ &vcb->catalogRefNum);
+ if (retval) {
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
+ goto ErrorExit;
+ }
+ retval = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum),
+ (KeyCompareProcPtr) CompareExtendedCatalogKeys));
+ if (retval) {
+ VOP_UNLOCK(vcb->catalogRefNum, 0, p);
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
+ goto ErrorExit;
+ }
+ if ((hfsmp->hfs_flags & HFS_X) &&
+ BTGetInformation(VTOF(vcb->catalogRefNum), 0, &btinfo) == 0) {
+ if (btinfo.keyCompareType == kHFSBinaryCompare) {
+ hfsmp->hfs_flags |= HFS_CASE_SENSITIVE;
+ /* Install a case-sensitive key compare */
+ (void) BTOpenPath(VTOF(vcb->catalogRefNum),
+ (KeyCompareProcPtr)cat_binarykeycompare);
+ }
+ }
/*
- * Set up Allocation file vnode...
+ * Set up Allocation file vnode
*/
- retval = GetInitializedVNode(hfsmp, &tmpvnode);
- if (retval) goto ErrorExit;
- fdp = &vhp->allocationFile;
- SWAP_HFS_PLUS_FORK_DATA (fdp);
- retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
- kHFSAllocationFileID, NULL);
- SWAP_HFS_PLUS_FORK_DATA (fdp);
- if (retval) goto ErrorExit;
-
- /*
- * Now that Catalog file is open get the volume name from the catalog
- */
- retval = MacToVFSError( GetVolumeNameFromCatalog(vcb) );
- if (retval != noErr) goto ErrorExit;
+ cndesc.cd_nameptr = hfs_vbmname;
+ cndesc.cd_namelen = strlen(hfs_vbmname);
+ cndesc.cd_cnid = cnattr.ca_fileid = kHFSAllocationFileID;
+
+ cfork.cf_size = SWAP_BE64 (vhp->allocationFile.logicalSize);
+ cfork.cf_clump = SWAP_BE32 (vhp->allocationFile.clumpSize);
+ cfork.cf_blocks = SWAP_BE32 (vhp->allocationFile.totalBlocks);
+ cfork.cf_vblocks = 0;
+ cnattr.ca_blocks = cfork.cf_blocks;
+ for (i = 0; i < kHFSPlusExtentDensity; i++) {
+ cfork.cf_extents[i].startBlock =
+ SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
+ cfork.cf_extents[i].blockCount =
+ SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
+ }
+ retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork,
+ &vcb->allocationsRefNum);
+ if (retval) {
+ VOP_UNLOCK(vcb->catalogRefNum, 0, p);
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
+ goto ErrorExit;
+ }
+
+ /* Pick up volume name and create date */
+ retval = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, &cnattr, NULL);
+ if (retval) {
+ VOP_UNLOCK(vcb->allocationsRefNum, 0, p);
+ VOP_UNLOCK(vcb->catalogRefNum, 0, p);
+ VOP_UNLOCK(vcb->extentsRefNum, 0, p);
+ goto ErrorExit;
+ }
+ vcb->vcbCrDate = cnattr.ca_itime;
+ vcb->volumeNameEncodingHint = cndesc.cd_encoding;
+ bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen));
+ cat_releasedesc(&cndesc);
/* mark the volume dirty (clear clean unmount bit) */
vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
-
- /* setup private/hidden directory for unlinked files */
- hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
+ if (hfsmp->jnl && (hfsmp->hfs_flags & HFS_READ_ONLY) == 0) {
+ hfs_flushvolumeheader(hfsmp, TRUE, TRUE);
+ }
/*
* all done with metadata files so we can unlock now...
VOP_UNLOCK(vcb->catalogRefNum, 0, p);
VOP_UNLOCK(vcb->extentsRefNum, 0, p);
- if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
+ //
+ // Check if we need to do late journal initialization. This only
+ // happens if a previous version of MacOS X (or 9) touched the disk.
+ // In that case hfs_late_journal_init() will go re-locate the journal
+ // and journal_info_block files and validate that they're still kosher.
+ //
+ if ( (vcb->vcbAtrb & kHFSVolumeJournaledMask)
+ && (SWAP_BE32(vhp->lastMountedVersion) != kHFSJMountVersion)
+ && (hfsmp->jnl == NULL)) {
+
+ retval = hfs_late_journal_init(hfsmp, vhp, args);
+ if (retval != 0) {
+ hfsmp->jnl = NULL;
+ goto ErrorExit;
+ } else if (hfsmp->jnl) {
+ hfsmp->hfs_mp->mnt_flag |= MNT_JOURNALED;
+ }
+ } else if (hfsmp->jnl) {
+ struct cat_attr jinfo_attr, jnl_attr;
+
+ // if we're here we need to fill in the fileid's for the
+ // journal and journal_info_block.
+ hfsmp->hfs_jnlinfoblkid = GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jinfo_attr, NULL);
+ hfsmp->hfs_jnlfileid = GetFileInfo(vcb, kRootDirID, ".journal", &jnl_attr, NULL);
+ if (hfsmp->hfs_jnlinfoblkid == 0 || hfsmp->hfs_jnlfileid == 0) {
+ printf("hfs: danger! couldn't find the file-id's for the journal or journal_info_block\n");
+ printf("hfs: jnlfileid %d, jnlinfoblkid %d\n", hfsmp->hfs_jnlfileid, hfsmp->hfs_jnlinfoblkid);
+ }
+ }
+
+ /*
+ * Establish a metadata allocation zone.
+ */
+ hfs_metadatazone_init(hfsmp);
+
+ /*
+ * Make any metadata zone adjustments.
+ */
+ if (hfsmp->hfs_flags & HFS_METADATA_ZONE) {
+ /* Keep the roving allocator out of the metadata zone. */
+ if (vcb->nextAllocation >= hfsmp->hfs_metazone_start &&
+ vcb->nextAllocation <= hfsmp->hfs_metazone_end) {
+ vcb->nextAllocation = hfsmp->hfs_metazone_end + 1;
+ }
+ }
+
+ /* setup private/hidden directory for unlinked files */
+ FindMetaDataDirectory(vcb);
+ if (hfsmp->jnl && ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0))
+ hfs_remove_orphans(hfsmp);
+
+ if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
{
- MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
+ MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
}
-
- DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval));
- return (0);
+ /*
+ * Allow hot file clustering if conditions allow.
+ */
+ if ((hfsmp->hfs_flags & HFS_METADATA_ZONE) &&
+ ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0)) {
+ (void) hfs_recording_init(hfsmp, p);
+ }
+
+ return (0);
ErrorExit:
/*
* release any resources that we aquired...
*/
- DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval));
-
- InvalidateCatalogCache(vcb);
-
+ InvalidateCatalogCache(vcb);
ReleaseMetaFileVNode(vcb->allocationsRefNum);
ReleaseMetaFileVNode(vcb->catalogRefNum);
ReleaseMetaFileVNode(vcb->extentsRefNum);
*/
static void ReleaseMetaFileVNode(struct vnode *vp)
{
- if (vp)
- {
- FCB *fcb = VTOFCB(vp);
+ struct filefork *fp;
- if (fcb->fcbBTCBPtr != NULL)
- (void) BTClosePath(fcb); /* ignore errors since there is only one path open */
+ if (vp && (fp = VTOF(vp))) {
+ if (fp->fcbBTCBPtr != NULL)
+ (void) BTClosePath(fp);
/* release the node even if BTClosePath fails */
- if (VOP_ISLOCKED(vp))
- vput(vp);
- else
- vrele(vp);
- }
-}
-
-
-/*
- * InitMetaFileVNode
- *
- * vp U L L
- */
-static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, const HFSPlusExtentRecord extents,
- HFSCatalogNodeID fileID, void * keyCompareProc)
-{
- FCB *fcb;
- ExtendedVCB *vcb;
- int result = 0;
-
- DBG_ASSERT(vp != NULL);
- DBG_ASSERT(vp->v_data != NULL);
-
- vcb = VTOVCB(vp);
- fcb = VTOFCB(vp);
-
- switch (fileID)
- {
- case kHFSExtentsFileID:
- vcb->extentsRefNum = vp;
- break;
-
- case kHFSCatalogFileID:
- vcb->catalogRefNum = vp;
- break;
-
- case kHFSAllocationFileID:
- vcb->allocationsRefNum = vp;
- break;
-
- default:
- panic("InitMetaFileVNode: invalid fileID!");
- }
-
- fcb->fcbEOF = eof;
- fcb->fcbPLen = eof;
- fcb->fcbClmpSize = clumpSize;
- H_FILEID(VTOH(vp)) = fileID;
- H_DIRID(VTOH(vp)) = kHFSRootParentID;
- H_FORKTYPE(VTOH(vp)) = kSysFile;
-
- bcopy(extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
-
- /*
- * Lock the hfsnode and insert the hfsnode into the hash queue:
- */
- hfs_vhashins(H_DEV(VTOH(vp)), fileID, VTOH(vp));
- vp->v_flag |= VSYSTEM; /* tag our metadata files (used by vflush call) */
-
- /* As the vnode is a system vnode we don't need UBC */
- if(UBCINFOEXISTS(vp)) {
- /* So something is wrong if the it exists */
- panic("ubc exists for system vnode");
+ vrele(vp);
+ vgone(vp);
}
-
- if (keyCompareProc != NULL) {
- result = BTOpenPath(fcb,
- (KeyCompareProcPtr) keyCompareProc,
- GetBTreeBlock,
- ReleaseBTreeBlock,
- ExtendBTreeFile,
- SetBTreeBlockSize);
- result = MacToVFSError(result);
- }
-
- return (result);
}
*
*************************************************************/
-short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p)
+__private_extern__
+int
+hfsUnmount( register struct hfsmount *hfsmp, struct proc *p)
{
- ExtendedVCB *vcb = HFSTOVCB(hfsmp);
- int retval = E_NONE;
+ ExtendedVCB *vcb = HFSTOVCB(hfsmp);
+ int retval = E_NONE;
- (void) DisposeMRUCache(vcb->hintCachePtr);
InvalidateCatalogCache( vcb );
- // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )?
-
- (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
- (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
+ if (hfsmp->hfc_filevp) {
+ ReleaseMetaFileVNode(hfsmp->hfc_filevp);
+ hfsmp->hfc_filevp = NULL;
+ }
+
if (vcb->vcbSigWord == kHFSPlusSigWord)
ReleaseMetaFileVNode(vcb->allocationsRefNum);
/*
- * hfs_resolvelink - auto resolve HFS+ hardlinks
- *
- * Used after calling GetCatalogNode or GetCatalogOffspring
+ * Test is fork has overflow extents.
*/
-void hfs_resolvelink(ExtendedVCB *vcb, CatalogNodeData *cndp)
+__private_extern__
+int
+overflow_extents(struct filefork *fp)
{
- struct FInfo *fip;
- char iNodeName[32];
- UInt32 hint;
- UInt32 indlinkno;
- UInt32 linkparid, linkcnid;
- OSErr result;
+ u_long blocks;
- fip = (struct FInfo *) &cndp->cnd_finderInfo;
+ if (VTOVCB(FTOV(fp))->vcbSigWord == kHFSPlusSigWord) {
+ if (fp->ff_extents[7].blockCount == 0)
+ return (0);
- /*
- * if this is an indirect link (hardlink) then auto resolve it...
- */
- if ((vcb->vcbSigWord == kHFSPlusSigWord)
- && (cndp->cnd_type == kCatalogFileNode)
- && (fip->fdType == kHardLinkFileType)
- && (fip->fdCreator == kHFSPlusCreator)
- && ((cndp->cnd_createDate == vcb->vcbCrDate) ||
- (cndp->cnd_createDate == VCBTOHFS(vcb)->hfs_metadata_createdate))) {
+ blocks = fp->ff_extents[0].blockCount +
+ fp->ff_extents[1].blockCount +
+ fp->ff_extents[2].blockCount +
+ fp->ff_extents[3].blockCount +
+ fp->ff_extents[4].blockCount +
+ fp->ff_extents[5].blockCount +
+ fp->ff_extents[6].blockCount +
+ fp->ff_extents[7].blockCount;
+ } else {
+ if (fp->ff_extents[2].blockCount == 0)
+ return false;
- indlinkno = cndp->cnd_iNodeNum;
- MAKE_INODE_NAME(iNodeName, indlinkno);
- /*
- * Get nodeData from the data node file.
- * Flag the node data to NOT copy the name (ie preserve the original)
- * Also preserve the parent directory ID.
- */
- linkparid = cndp->cnm_parID;
- linkcnid = cndp->cnd_nodeID;
- cndp->cnm_flags |= kCatNameNoCopyName;
- result = GetCatalogNode(vcb, VCBTOHFS(vcb)->hfs_private_metadata_dir,
- iNodeName, 0, 0, cndp, &hint);
- cndp->cnm_flags &= ~kCatNameNoCopyName;
-
- /* Make sure there's a reference */
- if (result == 0) {
- if (cndp->cnd_linkCount == 0) cndp->cnd_linkCount = 2;
-
- /* Keep a copy of iNodeNum to put into h_indnodeno */
- cndp->cnd_iNodeNumCopy = indlinkno;
- cndp->cnm_parID = linkparid;
- cndp->cnd_linkCNID = linkcnid;
- }
- }
+ blocks = fp->ff_extents[0].blockCount +
+ fp->ff_extents[1].blockCount +
+ fp->ff_extents[2].blockCount;
+ }
+
+ return (fp->ff_blocks > blocks);
}
/*
- * Performs a lookup on the given dirID, name. Returns the catalog info
- *
- * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen
+ * Lock/Unlock a metadata file.
*/
-
-short hfs_getcatalog (ExtendedVCB *vcb, UInt32 parentDirID, char *name, short len, hfsCatalogInfo *catInfo)
+__private_extern__
+int
+hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p)
{
- OSErr result;
- UInt32 length;
-
- if (len == -1 ) { /* Convert it to MacOS terms */
- if (name)
- length = strlen(name);
- else
- length = kUndefinedStrLen;
- }
- else
- length = len;
+ ExtendedVCB *vcb;
+ struct vnode *vp = NULL;
+ int numOfLockedBuffs;
+ int retval = 0;
+
+ vcb = HFSTOVCB(hfsmp);
+
+ switch (fileID) {
+ case kHFSExtentsFileID:
+ vp = vcb->extentsRefNum;
+ break;
- result = GetCatalogNode(vcb, parentDirID, name, length, catInfo->hint, &catInfo->nodeData, &catInfo->hint);
+ case kHFSCatalogFileID:
+ vp = vcb->catalogRefNum;
+ break;
-#if HFS_DIAGNOSTICS
- if (catInfo->nodeData.cnm_nameptr) {
- DBG_ASSERT(strlen(catInfo->nodeData.cnm_nameptr) == catInfo->nodeData.cnm_length);
+ case kHFSAllocationFileID:
+ /* bitmap is covered by Extents B-tree locking */
+ /* FALL THROUGH */
+ default:
+ panic("hfs_lockmetafile: invalid fileID");
}
-#endif
- if (result == 0)
- hfs_resolvelink(vcb, &catInfo->nodeData);
+ if ((flags & LK_TYPE_MASK) != LK_RELEASE) {
+ flags |= LK_RETRY;
+ } else if (hfsmp->jnl == NULL) {
+ struct timeval tv = time;
+ u_int32_t lastfsync = tv.tv_sec;
+
+ (void) BTGetLastSync((FCB*)VTOF(vp), &lastfsync);
+
+ numOfLockedBuffs = count_lock_queue();
+ if ((numOfLockedBuffs > kMaxLockedMetaBuffers) ||
+ ((numOfLockedBuffs > 1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) {
+ hfs_btsync(vp, HFS_SYNCTRANS);
+ }
+ }
+
+ retval = lockmgr(&VTOC(vp)->c_lock, flags, &vp->v_interlock, p);
- return MacToVFSError(result);
+ return (retval);
}
+/*
+ * RequireFileLock
+ *
+ * Check to see if a vnode is locked in the current context
+ * This is to be used for debugging purposes only!!
+ */
+#if HFS_DIAGNOSTIC
+void RequireFileLock(FileReference vp, int shareable)
+{
+ struct lock__bsd__ *lkp;
+ int locked = false;
+ pid_t pid;
+ void * self;
+
+ pid = current_proc()->p_pid;
+ self = (void *) current_act();
+ lkp = &VTOC(vp)->c_lock;
+ simple_lock(&lkp->lk_interlock);
+
+ if (shareable && (lkp->lk_sharecount > 0) && (lkp->lk_lockholder == LK_NOPROC))
+ locked = true;
+ else if ((lkp->lk_exclusivecount > 0) && (lkp->lk_lockholder == pid) && (lkp->lk_lockthread == self))
+ locked = true;
-short hfsDelete (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, short isfile, UInt32 catalogHint)
-{
- OSErr result = noErr;
-
- /* XXX have all the file's blocks been flushed/trashed? */
+ simple_unlock(&lkp->lk_interlock);
+
+ if (!locked) {
+ switch (VTOC(vp)->c_fileid) {
+ case 3:
+ DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp));
+ break;
- /*
- * DeleteFile will delete the catalog node and then
- * free up any disk space used by the file.
- */
- if (isfile)
- result = DeleteFile(vcb, parentDirID, name, catalogHint);
- else /* is a directory */
- result = DeleteCatalogNode(vcb, parentDirID, name, catalogHint);
+ case 4:
+ DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp));
+ break;
- if (result)
- DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result, parentDirID, name));
-
- return MacToVFSError(result);
+ default:
+ DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", VTOC(vp)->c_fileid, (u_int)vp));
+ break;
+ }
+ }
}
+#endif
-short hfsMoveRename (ExtendedVCB *vcb, UInt32 oldDirID, char *oldName, UInt32 newDirID, char *newName, UInt32 *hint)
+/*
+ * There are three ways to qualify for ownership rights on an object:
+ *
+ * 1. (a) Your UID matches the cnode's UID.
+ * (b) The object in question is owned by "unknown"
+ * 2. (a) Permissions on the filesystem are being ignored and
+ * your UID matches the replacement UID.
+ * (b) Permissions on the filesystem are being ignored and
+ * the replacement UID is "unknown".
+ * 3. You are root.
+ *
+ */
+int
+hfs_owner_rights(struct hfsmount *hfsmp, uid_t cnode_uid, struct ucred *cred,
+ struct proc *p, int invokesuperuserstatus)
{
- OSErr result = noErr;
+ if ((cred->cr_uid == cnode_uid) || /* [1a] */
+ (cnode_uid == UNKNOWNUID) || /* [1b] */
+ ((HFSTOVFS(hfsmp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */
+ ((cred->cr_uid == hfsmp->hfs_uid) || /* [2a] */
+ (hfsmp->hfs_uid == UNKNOWNUID))) || /* [2b] */
+ (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) { /* [3] */
+ return (0);
+ } else {
+ return (EPERM);
+ }
+}
- result = MoveRenameCatalogNode(vcb, oldDirID,oldName, *hint, newDirID, newName, hint, 0);
- if (result)
- DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result, newDirID, newName));
-
+unsigned long BestBlockSizeFit(unsigned long allocationBlockSize,
+ unsigned long blockSizeLimit,
+ unsigned long baseMultiple) {
+ /*
+ Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
+ specified limit but still an even multiple of the baseMultiple.
+ */
+ int baseBlockCount, blockCount;
+ unsigned long trialBlockSize;
- return MacToVFSError(result);
-}
+ if (allocationBlockSize % baseMultiple != 0) {
+ /*
+ Whoops: the allocation blocks aren't even multiples of the specified base:
+ no amount of dividing them into even parts will be a multiple, either then!
+ */
+ return 512; /* Hope for the best */
+ };
-/* XXX SER pass back the hint so other people can use it */
+ /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
+ from being handled as two 6K logical blocks instead of 3 4K logical blocks.
+ Even though the former (the result of the loop below) is the larger allocation
+ block size, the latter is more efficient: */
+ if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE;
+ /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
+ baseBlockCount = allocationBlockSize / baseMultiple; /* Now guaranteed to be an even multiple */
-short hfsCreate(ExtendedVCB *vcb, UInt32 dirID, char *name, int mode, UInt32 tehint)
-{
- OSErr result = noErr;
- HFSCatalogNodeID catalogNodeID;
- UInt32 catalogHint;
- UInt32 type;
-
- /* just test for directories, the default is to create a file (like symlinks) */
- if ((mode & IFMT) == IFDIR)
- type = kCatalogFolderNode;
- else
- type = kCatalogFileNode;
+ for (blockCount = baseBlockCount; blockCount > 0; --blockCount) {
+ trialBlockSize = blockCount * baseMultiple;
+ if (allocationBlockSize % trialBlockSize == 0) { /* An even multiple? */
+ if ((trialBlockSize <= blockSizeLimit) &&
+ (trialBlockSize % baseMultiple == 0)) {
+ return trialBlockSize;
+ };
+ };
+ };
- result = CreateCatalogNode (vcb, dirID, name, type, &catalogNodeID, &catalogHint, tehint);
-
- return MacToVFSError(result);
+ /* Note: we should never get here, since blockCount = 1 should always work,
+ but this is nice and safe and makes the compiler happy, too ... */
+ return 512;
}
-short hfsCreateFileID (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, UInt32 catalogHint, UInt32 *fileIDPtr)
+/*
+ * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
+ * of an active vnode is translated to a move/rename so the file appears
+ * deleted. The destination folder for these move/renames is setup here
+ * and a reference to it is place in hfsmp->hfs_privdir_desc.
+ */
+__private_extern__
+u_long
+FindMetaDataDirectory(ExtendedVCB *vcb)
{
- return MacToVFSError(CreateFileIDRef(vcb, parentDirID, name, catalogHint, fileIDPtr));
-}
-
+ struct hfsmount * hfsmp;
+ struct vnode * dvp = NULL;
+ struct cnode * dcp = NULL;
+ struct FndrDirInfo * fndrinfo;
+ struct cat_desc out_desc = {0};
+ struct proc *p = current_proc();
+ struct timeval tv;
+ cat_cookie_t cookie;
+ int error;
+
+ if (vcb->vcbSigWord != kHFSPlusSigWord)
+ return (0);
-/********************************************************************************/
-/* */
-/* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */
-/* */
-/********************************************************************************/
+ hfsmp = VCBTOHFS(vcb);
-int hfs_vget_catinfo(struct vnode *parent_vp, struct hfsCatalogInfo *catInfo, u_int32_t forkType, struct vnode **target_vp)
-{
- int retval = E_NONE;
-
- if (forkType == kDefault) {
- if (catInfo->nodeData.cnd_type == kCatalogFolderNode)
- forkType = kDirectory;
- else
- forkType = kDataFork;
- }
-
- *target_vp = hfs_vhashget(H_DEV(VTOH(parent_vp)), catInfo->nodeData.cnd_nodeID, forkType);
+ if (hfsmp->hfs_privdir_desc.cd_parentcnid == 0) {
+ hfsmp->hfs_privdir_desc.cd_parentcnid = kRootDirID;
+ hfsmp->hfs_privdir_desc.cd_nameptr = hfs_privdirname;
+ hfsmp->hfs_privdir_desc.cd_namelen = strlen(hfs_privdirname);
+ hfsmp->hfs_privdir_desc.cd_flags = CD_ISDIR;
+ }
- if (*target_vp == NULL)
- retval = hfs_vcreate( VTOVCB(parent_vp), catInfo, forkType, target_vp);
+ /* Lock catalog b-tree */
+ if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p) != 0)
+ return (0);
- return (retval);
-}
+ error = cat_lookup(hfsmp, &hfsmp->hfs_privdir_desc, 0, NULL,
+ &hfsmp->hfs_privdir_attr, NULL);
+ /* Unlock catalog b-tree */
+ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
+ if (error == 0) {
+ hfsmp->hfs_metadata_createdate = hfsmp->hfs_privdir_attr.ca_itime;
+ hfsmp->hfs_privdir_desc.cd_cnid = hfsmp->hfs_privdir_attr.ca_fileid;
+ /*
+ * Clear the system immutable flag if set...
+ */
+ if ((hfsmp->hfs_privdir_attr.ca_flags & SF_IMMUTABLE) &&
+ (hfsmp->hfs_flags & HFS_READ_ONLY) == 0) {
+ hfsmp->hfs_privdir_attr.ca_flags &= ~SF_IMMUTABLE;
+
+ hfs_global_shared_lock_acquire(hfsmp);
+ if (hfsmp->jnl) {
+ if ((error = journal_start_transaction(hfsmp->jnl)) != 0) {
+ hfs_global_shared_lock_release(hfsmp);
+ return (hfsmp->hfs_privdir_attr.ca_fileid);
+ }
+ }
+ if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p) == 0) {
+ (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc,
+ &hfsmp->hfs_privdir_attr, NULL, NULL);
+ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
+ }
+ if (hfsmp->jnl) {
+ journal_end_transaction(hfsmp->jnl);
+ }
+ hfs_global_shared_lock_release(hfsmp);
+ }
+ return (hfsmp->hfs_privdir_attr.ca_fileid);
-/************************************************************************/
-/* hfs_vcreate - Returns a vnode derived from hfs */
-/* */
-/* When creating the vnode, care must be made to set the */
-/* correct fields in the correct order. Calls to malloc() */
-/* and other subroutines, can cause a context switch, */
-/* and the fields must be ready for the possibility */
-/* */
-/* */
-/************************************************************************/
+ } else if (hfsmp->hfs_flags & HFS_READ_ONLY) {
-short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, struct vnode **vpp)
-{
- struct hfsnode *hp;
- struct vnode *vp;
- struct hfsmount *hfsmp;
- struct hfsfilemeta *fm;
- struct mount *mp;
- struct vfsFCB *xfcb;
- dev_t dev;
- short retval;
-
- hfsmp = VCBTOHFS(vcb);
- mp = HFSTOVFS(hfsmp);
- dev = hfsmp->hfs_raw_dev;
-
- /* Check if unmount in progress */
- if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
- *vpp = NULL;
- return (EPERM);
+ return (0);
}
-
- /*
- * If this is a hard link then check if the
- * data node already exists in our hash.
- */
- if ((forkType == kDataFork)
- && (catInfo->nodeData.cnd_type == kCatalogFileNode)
- && ((catInfo->nodeData.cnd_mode & IFMT) == IFREG)
- && (catInfo->nodeData.cnd_linkCount > 0)) {
- vp = hfs_vhashget(dev, catInfo->nodeData.cnd_nodeID, kDataFork);
- if (vp != NULL) {
- /* Use the name of the link and it's parent ID. */
- hp = VTOH(vp);
- H_DIRID(hp) = catInfo->nodeData.cnm_parID;
- hfs_set_metaname(catInfo->nodeData.cnm_nameptr, hp->h_meta, hfsmp);
- *vpp = vp;
+
+ /* Setup the default attributes */
+ bzero(&hfsmp->hfs_privdir_attr, sizeof(struct cat_attr));
+ hfsmp->hfs_privdir_attr.ca_mode = S_IFDIR;
+ hfsmp->hfs_privdir_attr.ca_nlink = 2;
+ hfsmp->hfs_privdir_attr.ca_itime = vcb->vcbCrDate;
+ hfsmp->hfs_privdir_attr.ca_mtime = time.tv_sec;
+
+ /* hidden and off the desktop view */
+ fndrinfo = (struct FndrDirInfo *)&hfsmp->hfs_privdir_attr.ca_finderinfo;
+ fndrinfo->frLocation.v = SWAP_BE16 (22460);
+ fndrinfo->frLocation.h = SWAP_BE16 (22460);
+ fndrinfo->frFlags |= SWAP_BE16 (kIsInvisible + kNameLocked);
+
+ // XXXdbg
+ hfs_global_shared_lock_acquire(hfsmp);
+ if (hfsmp->jnl) {
+ if ((error = journal_start_transaction(hfsmp->jnl)) != 0) {
+ hfs_global_shared_lock_release(hfsmp);
return (0);
+ }
+ }
+ /* Reserve some space in the Catalog file. */
+ if (cat_preflight(hfsmp, CAT_CREATE, &cookie, p) != 0) {
+ if (hfsmp->jnl) {
+ journal_end_transaction(hfsmp->jnl);
}
+ hfs_global_shared_lock_release(hfsmp);
+ return (0);
}
- MALLOC_ZONE(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK);
- bzero((caddr_t)hp, sizeof(struct hfsnode));
- hp->h_nodeflags |= IN_ALLOCATING;
- lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0);
- H_FORKTYPE(hp) = forkType;
- rl_init(&hp->h_invalidranges);
+ if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p) == 0) {
+ error = cat_create(hfsmp, &hfsmp->hfs_privdir_desc,
+ &hfsmp->hfs_privdir_attr, &out_desc);
- /*
- * There were several blocking points since we first
- * checked the hash. Now that we're through blocking,
- * check the hash again in case we're racing for the
- * same hnode.
- */
- vp = hfs_vhashget(dev, catInfo->nodeData.cnd_nodeID, forkType);
- if (vp != NULL) {
- /* We lost the race, use the winner's vnode */
- FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE);
- *vpp = vp;
- UBCINFOCHECK("hfs_vcreate", vp);
- return (0);
- }
-
- /*
- * Insert the hfsnode into the hash queue, also if meta exists
- * add to sibling list and return the meta address
- */
- fm = NULL;
- if (SIBLING_FORKTYPE(forkType))
- hfs_vhashins_sibling(dev, catInfo->nodeData.cnd_nodeID, hp, &fm);
- else
- hfs_vhashins(dev, catInfo->nodeData.cnd_nodeID, hp);
-
- /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
- if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &vp))) {
- hfs_vhashrem(hp);
- if (hp->h_nodeflags & IN_WANT) {
- hp->h_nodeflags &= ~IN_WANT;
- wakeup(hp);
- }
- FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE);
- *vpp = NULL;
- return (retval);
- }
- hp->h_vp = vp;
- vp->v_data = hp;
-
- hp->h_nodeflags &= ~IN_ALLOCATING;
- if (hp->h_nodeflags & IN_WANT) {
- hp->h_nodeflags &= ~IN_WANT;
- wakeup((caddr_t)hp);
- }
-
- /*
- * If needed allocate and init the object meta data:
- */
- if (fm == NULL) {
- /* Allocate it....remember we can do a context switch here */
- MALLOC_ZONE(fm, struct hfsfilemeta *, sizeof(struct hfsfilemeta), M_HFSFMETA, M_WAITOK);
- bzero(fm, sizeof(struct hfsfilemeta));
-
- /* Fill it in */
- /*
- * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO
- * accessable lists, we do not assign it until later,
- * this helps to make sure we do not use a half initiated meta
- */
-
- /* Init the sibling list if needed */
- if (SIBLING_FORKTYPE(forkType)) {
- simple_lock_init(&fm->h_siblinglock);
- CIRCLEQ_INIT(&fm->h_siblinghead);
- CIRCLEQ_INSERT_HEAD(&fm->h_siblinghead, hp, h_sibling);
- };
-
- fm->h_dev = dev;
- CopyCatalogToObjectMeta(catInfo, vp, fm);
-
- /*
- * the vnode is finally alive, with the exception of the FCB below,
- * It is finally locked and ready for its debutante ball
- */
- hp->h_meta = fm;
- };
- fm->h_usecount++;
-
- /*
- * Init the File Control Block.
- */
- CopyCatalogToFCB(catInfo, vp);
-
- /*
- * Finish vnode initialization.
- * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last.
- *
- * At this point the vnode should be locked and fully allocated. And ready to be used
- * or accessed. (though having it locked prevents most of this, it
- * can still be accessed through lists and hashs).
- */
- vp->v_type = IFTOVT(hp->h_meta->h_mode);
- if ((vp->v_type == VREG)
- && (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp))) {
- ubc_info_init(vp);
- }
-
- /*
- * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
- * Note that the underlying vnode may have changed.
- */
- if ((retval = hfs_vinit(mp, hfs_specop_p, hfs_fifoop_p, &vp))) {
- vput(vp);
- *vpp = NULL;
- return (retval);
+ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
}
- /*
- * Finish inode initialization now that aliasing has been resolved.
- */
- hp->h_meta->h_devvp = hfsmp->hfs_devvp;
- VREF(hp->h_meta->h_devvp);
-
- *vpp = vp;
- return 0;
-}
-
-void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm)
-{
- ExtendedVCB *vcb = VTOVCB(vp);
- struct mount *mp = VTOVFS(vp);
- Boolean isHFSPlus, isDirectory;
- ushort finderFlags;
- ushort filetype;
-
- DBG_ASSERT (fm != NULL);
- DBG_ASSERT (fm->h_namelen == 0);
- DBG_ASSERT (fm->h_namePtr == 0);
+ cat_postflight(hfsmp, &cookie, p);
- DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo->nodeData.cnm_nameptr, catalogInfo->nodeData.cnd_nodeID));
-
- isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
- isDirectory = (catalogInfo->nodeData.cnd_type == kCatalogFolderNode);
- finderFlags = SWAP_BE16 (((struct FInfo *)(&catalogInfo->nodeData.cnd_finderInfo))->fdFlags);
-
- /* Copy over the dirid, and hint */
- fm->h_nodeID = catalogInfo->nodeData.cnd_nodeID;
- fm->h_dirID = catalogInfo->nodeData.cnm_parID;
- fm->h_hint = catalogInfo->hint;
-
- /* Copy over the name */
- hfs_name_CatToMeta(&catalogInfo->nodeData, fm);
-
-
- /* get dates in BSD format */
- fm->h_mtime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
- fm->h_crtime = to_bsd_time(catalogInfo->nodeData.cnd_createDate);
- fm->h_butime = to_bsd_time(catalogInfo->nodeData.cnd_backupDate);
- if (isHFSPlus) {
- fm->h_atime = to_bsd_time(catalogInfo->nodeData.cnd_accessDate);
- fm->h_ctime = to_bsd_time(catalogInfo->nodeData.cnd_attributeModDate);
- }
- else {
- fm->h_atime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
- fm->h_ctime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
- }
-
- /* Now the rest */
- if (isHFSPlus && (catalogInfo->nodeData.cnd_mode & IFMT)) {
- fm->h_uid = catalogInfo->nodeData.cnd_ownerID;
- fm->h_gid = catalogInfo->nodeData.cnd_groupID;
- fm->h_pflags = catalogInfo->nodeData.cnd_ownerFlags |
- (catalogInfo->nodeData.cnd_adminFlags << 16);
- fm->h_mode = (mode_t)catalogInfo->nodeData.cnd_mode;
-#if 1
- if (fm->h_uid == 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
- fm->h_uid = UNKNOWNUID;
- fm->h_metaflags |= IN_CHANGE;
- vcb->vcbFlags |= kHFS_DamagedVolume; /* Trigger fsck on next mount */
- };
- if (fm->h_gid == 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
- fm->h_gid = UNKNOWNGID;
- fm->h_metaflags |= IN_CHANGE;
- vcb->vcbFlags |= kHFS_DamagedVolume; /* Trigger fsck on next mount */
- };
-#endif
- filetype = fm->h_mode & IFMT;
- if (filetype == IFCHR || filetype == IFBLK)
- fm->h_rdev = catalogInfo->nodeData.cnd_rawDevice;
- else {
- fm->h_rdev = 0;
-#if HFS_HARDLINKS
- if (catalogInfo->nodeData.cnd_type == kCatalogFileNode &&
- catalogInfo->nodeData.cnd_linkCount > 0) {
- fm->h_nlink = catalogInfo->nodeData.cnd_linkCount;
- fm->h_indnodeno = catalogInfo->nodeData.cnd_iNodeNumCopy;
- fm->h_metaflags |= IN_DATANODE;
- }
-#endif
- }
-
- 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.
- */
- fm->h_metaflags |= IN_UNSETACCESS;
- fm->h_uid = VTOHFS(vp)->hfs_uid;
- fm->h_gid = VTOHFS(vp)->hfs_gid;
-#if OVERRIDE_UNKNOWN_PERMISSIONS
- /* Default access is full read/write/execute: */
- /* XXX won't this smash IFCHR, IFBLK and IFLNK (for no-follow lookups)? */
- fm->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */
- fm->h_rdev = 0;
-
- /* ... but no more than that permitted by the mount point's: */
- if (isDirectory) {
- fm->h_mode &= VTOHFS(vp)->hfs_dir_mask;
- }
- else {
- fm->h_mode &= VTOHFS(vp)->hfs_file_mask;
- }
-
- if(isDirectory)
- fm->h_mode |= IFDIR;
- else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */
- fm->h_mode |= IFLNK;
- else
- fm->h_mode |= IFREG;
-#endif
- };
- } else {
- /*
- * Set the permissions as determined by the mount auguments
- * but keep in account if the file or folder is hfs locked
- */
- fm->h_metaflags |= IN_UNSETACCESS;
- fm->h_uid = VTOHFS(vp)->hfs_uid;
- fm->h_gid = VTOHFS(vp)->hfs_gid;
- fm->h_pflags = 0; /* No valid pflags on disk (IMMUTABLE is synced from lock flag later) */
- fm->h_rdev = 0; /* No valid rdev on disk */
- /* Default access is full read/write/execute: */
- fm->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */
-
- /* ... but no more than that permitted by the mount point's: */
- if (isDirectory) {
- fm->h_mode &= VTOHFS(vp)->hfs_dir_mask;
- }
- else {
- fm->h_mode &= VTOHFS(vp)->hfs_file_mask;
- }
-
- if(isDirectory)
- fm->h_mode |= IFDIR;
- else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */
- fm->h_mode |= IFLNK;
- else
- fm->h_mode |= IFREG;
- };
-
- /* Make sure that there is no nodeType/mode mismatch */
- if (isDirectory && ((fm->h_mode & IFMT) != IFDIR)) {
- fm->h_mode &= ~IFMT; /* Clear the bad bits */
- fm->h_mode |= IFDIR; /* Set the proper one */
- };
-
- /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
- if (!isDirectory) {
- if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask) {
- /* The file's supposed to be locked:
- Make sure at least one of the IMMUTABLE bits is set: */
- if ((fm->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0) {
- fm->h_pflags |= UF_IMMUTABLE; /* Set the user-changable IMMUTABLE bit */
- };
- } else {
- /* The file's supposed to be unlocked: */
- fm->h_pflags &= ~(SF_IMMUTABLE | UF_IMMUTABLE);
- };
- };
-
- if (isDirectory) {
- fm->h_nlink = 2 + catalogInfo->nodeData.cnd_valence;
- fm->h_size = (2 * sizeof(hfsdotentry)) +
- (catalogInfo->nodeData.cnd_valence * AVERAGE_HFSDIRENTRY_SIZE);
- if (fm->h_size < MAX_HFSDIRENTRY_SIZE)
- fm->h_size = MAX_HFSDIRENTRY_SIZE;
- } else {
- fm->h_size = (off_t)vcb->blockSize *
- (off_t)(catalogInfo->nodeData.cnd_rsrcfork.totalBlocks +
- catalogInfo->nodeData.cnd_datafork.totalBlocks);
- }
-}
-
-
-void CopyCatalogToFCB(struct hfsCatalogInfo *catalogInfo, struct vnode *vp)
-{
- FCB *fcb = VTOFCB(vp);
- ExtendedVCB *vcb = VTOVCB(vp);
- Boolean isHFSPlus, isDirectory, isResource;
- HFSPlusExtentDescriptor *extents;
- UInt8 forkType;
-
- DBG_ASSERT (vp != NULL);
- DBG_ASSERT (fcb != NULL);
- DBG_ASSERT (vcb != NULL);
- DBG_ASSERT (VTOH(vp) != NULL);
-
- forkType = H_FORKTYPE(VTOH(vp));
- isResource = (forkType == kRsrcFork);
- isDirectory = (catalogInfo->nodeData.cnd_type == kCatalogFolderNode);
- isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
-
- /* Init the fcb */
- fcb->fcbFlags = catalogInfo->nodeData.cnd_flags;
-
- if (forkType != kDirectory) {
- fcb->fcbFlags &= kHFSFileLockedMask; /* Clear resource, dirty bits */
- if (fcb->fcbFlags != 0) /* if clear, its not locked, then.. */
- fcb->fcbFlags = fcbFileLockedMask; /* duplicate the bit for later use */
-
- fcb->fcbClmpSize = vcb->vcbClpSiz; /*XXX why not use the one in catalogInfo? */
-
- if (isResource)
- extents = catalogInfo->nodeData.cnd_rsrcfork.extents;
- else
- extents = catalogInfo->nodeData.cnd_datafork.extents;
-
- /* Copy the extents to their correct location: */
- bcopy (extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
-
- if (isResource) {
- fcb->fcbEOF = catalogInfo->nodeData.cnd_rsrcfork.logicalSize;
- fcb->fcbPLen = (off_t)((off_t)catalogInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
- fcb->fcbFlags |= fcbResourceMask;
- } else {
- fcb->fcbEOF = catalogInfo->nodeData.cnd_datafork.logicalSize;
- fcb->fcbPLen = (off_t)((off_t)catalogInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize);
- };
- };
-
-
-}
-
-int hasOverflowExtents(struct hfsnode *hp)
-{
- ExtendedVCB *vcb = HTOVCB(hp);
- FCB *fcb = HTOFCB(hp);
- u_long blocks;
-
- if (vcb->vcbSigWord == kHFSPlusSigWord)
- {
-
- if (fcb->fcbExtents[7].blockCount == 0)
- return false;
-
- blocks = fcb->fcbExtents[0].blockCount +
- fcb->fcbExtents[1].blockCount +
- fcb->fcbExtents[2].blockCount +
- fcb->fcbExtents[3].blockCount +
- fcb->fcbExtents[4].blockCount +
- fcb->fcbExtents[5].blockCount +
- fcb->fcbExtents[6].blockCount +
- fcb->fcbExtents[7].blockCount;
- }
- else
- {
- if (fcb->fcbExtents[2].blockCount == 0)
- return false;
-
- blocks = fcb->fcbExtents[0].blockCount +
- fcb->fcbExtents[1].blockCount +
- fcb->fcbExtents[2].blockCount;
- }
-
- return ((fcb->fcbPLen / vcb->blockSize) > blocks);
-}
-
-
-int hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p)
-{
- ExtendedVCB *vcb;
- struct vnode *vp = NULL;
- int numOfLockedBuffs;
- int retval = 0;
-
- vcb = HFSTOVCB(hfsmp);
-
- DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb->vcbVRefNum, fileID,
- ((flags & LK_TYPE_MASK) == LK_RELEASE ? "RELEASE" : ""),
- ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE ? "EXCLUSIVE" : ""),
- ((flags & LK_TYPE_MASK) == LK_SHARED ? "SHARED" : "") ));
-
-
- switch (fileID)
- {
- case kHFSExtentsFileID:
- vp = vcb->extentsRefNum;
- break;
-
- case kHFSCatalogFileID:
- vp = vcb->catalogRefNum;
- break;
-
- case kHFSAllocationFileID:
- /* bitmap is covered by Extents B-tree locking */
- /* FALL THROUGH */
- default:
- panic("hfs_lockmetafile: invalid fileID");
- }
-
- if (vp != NULL) {
-
- /* Release, if necesary any locked buffer caches */
- if ((flags & LK_TYPE_MASK) == LK_RELEASE) {
- struct timeval tv = time;
- u_int32_t lastfsync = tv.tv_sec;
-
- (void) BTGetLastSync(VTOFCB(vp), &lastfsync);
-
- numOfLockedBuffs = count_lock_queue();
- if ((numOfLockedBuffs > kMaxLockedMetaBuffers) || ((numOfLockedBuffs>1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) {
- DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp)),
- numOfLockedBuffs, (tv.tv_sec - lastfsync)));
- hfs_fsync_transaction(vp);
- };
- };
-
- retval = lockmgr(&VTOH(vp)->h_lock, flags, &vp->v_interlock, p);
- };
-
- return retval;
-}
-
-
-/*
- * There are three ways to qualify for ownership rights on an object:
- *
- * 1. (a) Your UID matches the UID of the vnode
- * (b) The object in question is owned by "unknown" and your UID matches the console user's UID
- * 2. (a) Permissions on the filesystem are being ignored and your UID matches the replacement UID
- * (b) Permissions on the filesystem are being ignored and the replacement UID is "unknown" and
- * your UID matches the console user UID
- * 3. You are root
- *
- */
-int hfs_owner_rights(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean invokesuperuserstatus) {
- return ((cred->cr_uid == VTOH(vp)->h_meta->h_uid) || /* [1a] */
- ((VTOH(vp)->h_meta->h_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */
- ((VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */
- ((cred->cr_uid == VTOHFS(vp)->hfs_uid) || /* [2a] */
- ((VTOHFS(vp)->hfs_uid == UNKNOWNUID) && (cred->cr_uid == console_user)))) || /* [2b] */
- (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) ? 0 : EPERM;
-}
-
-
-
-int hfs_catalogentry_owner_rights(uid_t obj_uid, struct mount *mp, struct ucred *cred, struct proc *p, Boolean invokesuperuserstatus) {
- return ((cred->cr_uid == obj_uid) || /* [1a] */
- ((obj_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */
- ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */
- ((cred->cr_uid == VFSTOHFS(mp)->hfs_uid) || /* [2a] */
- ((VFSTOHFS(mp)->hfs_uid == UNKNOWNUID) && (cred->cr_uid == console_user)))) || /* [2b] */
- (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) ? 0 : EPERM;
-}
-
-
+ if (error) {
+ if (hfsmp->jnl) {
+ journal_end_transaction(hfsmp->jnl);
+ }
+ hfs_global_shared_lock_release(hfsmp);
-void CopyVNodeToCatalogNode (struct vnode *vp, struct CatalogNodeData *nodeData)
-{
- ExtendedVCB *vcb;
- FCB *fcb;
- struct hfsnode *hp;
- Boolean isHFSPlus, isResource;
- HFSPlusExtentDescriptor *extents;
- off_t fileReadLimit;
-
- hp = VTOH(vp);
- vcb = HTOVCB(hp);
- fcb = HTOFCB(hp);
- isResource = (H_FORKTYPE(hp) == kRsrcFork);
- isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
-
- /* date and time of last fork modification */
- if (hp->h_meta->h_mtime != 0)
- nodeData->cnd_contentModDate = to_hfs_time(hp->h_meta->h_mtime);
-
- if (isHFSPlus) {
- /* Make sure that there is no nodeType/mode mismatch */
- if ((nodeData->cnd_type == kCatalogFolderNode)
- && ((hp->h_meta->h_mode & IFMT) != IFDIR)) {
-
- DBG_ASSERT((hp->h_meta->h_mode & IFMT) == IFDIR);
- hp->h_meta->h_mode &= ~IFMT; /* Clear the bad bits */
- hp->h_meta->h_mode |= IFDIR; /* Set the proper one */
- };
- /* date and time of last modification (any kind) */
- if (hp->h_meta->h_ctime != 0)
- nodeData->cnd_attributeModDate = to_hfs_time(hp->h_meta->h_ctime);
- /* date and time of last access (MacOS X only) */
- if (hp->h_meta->h_atime != 0)
- nodeData->cnd_accessDate = to_hfs_time(hp->h_meta->h_atime);
- /* hfs_setattr can change the create date */
- if (hp->h_meta->h_crtime != 0)
- nodeData->cnd_createDate = to_hfs_time(hp->h_meta->h_crtime);
- if (! (hp->h_meta->h_metaflags & IN_UNSETACCESS)) {
- nodeData->cnd_adminFlags = hp->h_meta->h_pflags >> 16;
- nodeData->cnd_ownerFlags = hp->h_meta->h_pflags & 0x000000FF;
- nodeData->cnd_mode = hp->h_meta->h_mode;
- nodeData->cnd_ownerID = hp->h_meta->h_uid;
- nodeData->cnd_groupID = hp->h_meta->h_gid;
- }
- };
-
- /* the rest only applies to files */
- if (nodeData->cnd_type == kCatalogFileNode) {
- if (hp->h_meta->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
- /* The file is locked: set the locked bit in the catalog. */
- nodeData->cnd_flags |= kHFSFileLockedMask;
- } else {
- /* The file is unlocked: make sure the locked bit in the catalog is clear. */
- nodeData->cnd_flags &= ~kHFSFileLockedMask;
- };
- if (CIRCLEQ_EMPTY(&hp->h_invalidranges)) {
- fileReadLimit = fcb->fcbEOF;
- } else {
- fileReadLimit = CIRCLEQ_FIRST(&hp->h_invalidranges)->rl_start;
- };
- if (isResource) {
- extents = nodeData->cnd_rsrcfork.extents;
- nodeData->cnd_rsrcfork.logicalSize = fileReadLimit;
- nodeData->cnd_rsrcfork.totalBlocks = fcb->fcbPLen / vcb->blockSize;
- } else {
- extents = nodeData->cnd_datafork.extents;
- nodeData->cnd_datafork.logicalSize = fileReadLimit;
- nodeData->cnd_datafork.totalBlocks = fcb->fcbPLen / vcb->blockSize;
- };
-
- bcopy ( fcb->fcbExtents, extents, sizeof(HFSPlusExtentRecord));
-
- if ((vp->v_type == VBLK) || (vp->v_type == VCHR))
- nodeData->cnd_rawDevice = hp->h_meta->h_rdev;
- else if (hp->h_meta->h_metaflags & IN_DATANODE)
- nodeData->cnd_linkCount = hp->h_meta->h_nlink;
-
- if (vp->v_type == VLNK) {
- ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdType = SWAP_BE32 (kSymLinkFileType);
- ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdCreator = SWAP_BE32 (kSymLinkCreator);
-
- /* Set this up as an alias */
- #if SUPPORTS_MAC_ALIASES
- ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdFlags |= SWAP_BE16 (kIsAlias);
- #endif
- }
+ return (0);
}
- }
-
-
-/*********************************************************************
-
- Sets the name in the filemeta structure
-
- XXX Does not preflight if changing from one size to another
- XXX Currently not protected from context switching
-
-*********************************************************************/
-
-void hfs_set_metaname(char *name, struct hfsfilemeta *fm, struct hfsmount *hfsmp)
-{
-int namelen = strlen(name);
-char *tname, *fname;
-
-#if HFS_DIAGNOSTIC
- DBG_ASSERT(name != NULL);
- DBG_ASSERT(fm != NULL);
- if (fm->h_namePtr) {
- DBG_ASSERT(fm->h_namelen == strlen(fm->h_namePtr));
- if (strlen(fm->h_namePtr) > MAXHFSVNODELEN)
- DBG_ASSERT(fm->h_metaflags & IN_LONGNAME);
- };
- if (fm->h_metaflags & IN_LONGNAME) {
- DBG_ASSERT(fm->h_namePtr != (char *)fm->h_fileName);
- DBG_ASSERT(fm->h_namePtr != NULL);
- };
-#endif //HFS_DIAGNOSTIC
-
- /*
- * Details that have to be dealt with:
- * 1. No name is allocated. fm->h_namePtr should be NULL
- * 2. A name is being changed and:
- * a. it was in static space and now cannot fit
- * b. It was malloc'd and now will fit in the static
- * c. It did and will fit in the static
- * This could be a little smarter:
- * - Dont re'malloc if the new name is smaller (but then wasting memory)
- * - If its a longname but the same size, we still free and malloc
- * -
- */
-
- /* Allocate the new memory */
- if (namelen > MAXHFSVNODELEN) {
- /*
- * Notice the we ALWAYS allocate, even if the new is less then the old,
- * or even if they are the SAME
- */
- MALLOC(tname, char *, namelen+1, M_TEMP, M_WAITOK);
+ hfsmp->hfs_privdir_desc.cd_hint = out_desc.cd_hint;
+ hfsmp->hfs_privdir_desc.cd_cnid = out_desc.cd_cnid;
+ hfsmp->hfs_privdir_attr.ca_fileid = out_desc.cd_cnid;
+ hfsmp->hfs_metadata_createdate = vcb->vcbCrDate;
+
+ if (VFS_ROOT(HFSTOVFS(hfsmp), &dvp) == 0) {
+ dcp = VTOC(dvp);
+ dcp->c_childhint = out_desc.cd_hint;
+ dcp->c_nlink++;
+ dcp->c_entries++;
+ dcp->c_flag |= C_CHANGE | C_UPDATE;
+ tv = time;
+ (void) VOP_UPDATE(dvp, &tv, &tv, 0);
+ vput(dvp);
}
- else
- tname = fm->h_fileName;
-
- simple_lock(&hfsmp->hfs_renamelock);
-
- /* Check to see if there is something to free, if yes, remember it */
- if (fm->h_metaflags & IN_LONGNAME)
- fname = fm->h_namePtr;
- else
- fname = NULL;
-
- /* Set the flag */
- if (namelen > MAXHFSVNODELEN) {
- fm->h_metaflags |= IN_LONGNAME;
- }
- else {
- fm->h_metaflags &= ~IN_LONGNAME;
- };
-
- /* Now copy it over */
- bcopy(name, tname, namelen+1);
-
- fm->h_namePtr = tname;
- fm->h_namelen = namelen;
-
- simple_unlock(&hfsmp->hfs_renamelock);
-
- /* Lastly, free the old, if set */
- if (fname != NULL)
- FREE(fname, M_TEMP);
-
-}
-
-void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm)
-{
-char *fname;
-
-#if HFS_DIAGNOSTIC
- DBG_ASSERT(nodeData != NULL);
- DBG_ASSERT(fm != NULL);
- if (fm->h_namePtr) {
- DBG_ASSERT(fm->h_namelen == strlen(fm->h_namePtr));
- if (strlen(fm->h_namePtr) > MAXHFSVNODELEN)
- DBG_ASSERT(fm->h_metaflags & IN_LONGNAME);
- };
- if (fm->h_metaflags & IN_LONGNAME) {
- DBG_ASSERT(fm->h_namePtr != (char *)fm->h_fileName);
- DBG_ASSERT(fm->h_namePtr != NULL);
- };
-
- DBG_ASSERT(nodeData->cnm_nameptr != NULL);
-
- if (nodeData->cnm_length) {
- DBG_ASSERT(strlen(nodeData->cnm_nameptr) == nodeData->cnm_length);
- }
-
- if (nodeData->cnm_length > MAXHFSVNODELEN)
- { DBG_ASSERT(nodeData->cnm_nameptr != nodeData->cnm_namespace); }
- else if (nodeData->cnm_nameptr)
- { DBG_ASSERT(nodeData->cnm_nameptr == nodeData->cnm_namespace); }
-
-#endif //HFS_DIAGNOSTIC
-
-
- /* Check to see if there is something to free, if yes, remember it */
- if (fm->h_metaflags & IN_LONGNAME)
- fname = fm->h_namePtr;
- else
- fname = NULL;
-
- /* Set the flag */
- if (nodeData->cnm_length > MAXHFSVNODELEN) {
- fm->h_metaflags |= IN_LONGNAME;
- } else {
- fm->h_metaflags &= ~IN_LONGNAME;
- };
-
- /* Copy over the name */
- if (nodeData->cnm_nameptr == nodeData->cnm_namespace) {
- bcopy(nodeData->cnm_namespace, fm->h_fileName, nodeData->cnm_length+1);
- fm->h_namePtr = fm->h_fileName;
+ hfs_volupdate(hfsmp, VOL_MKDIR, 1);
+ if (hfsmp->jnl) {
+ journal_end_transaction(hfsmp->jnl);
}
- else {
- fm->h_namePtr = nodeData->cnm_nameptr;
- }
-
- fm->h_namelen = nodeData->cnm_length;
-
- nodeData->cnm_flags |= kCatNameIsConsumed;
- nodeData->cnm_flags &= ~kCatNameIsAllocated;
- nodeData->cnm_length = 0;
- nodeData->cnm_nameptr = (char *)0;
- nodeData->cnm_namespace[0] = 0;
-
- /* Lastly, free the old, if set */
- if (fname != NULL)
- FREE(fname, M_TEMP);
-}
-
-
-
-unsigned long DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, mode_t obj_mode, struct mount *mp, struct ucred *cred, struct proc *p) {
- register gid_t *gp;
- unsigned long permissions;
- int i;
-
- /* User id 0 (root) always gets access. */
- if (cred->cr_uid == 0) {
- permissions = R_OK | W_OK | X_OK;
- goto Exit;
- };
-
- /* Otherwise, check the owner. */
- if (hfs_catalogentry_owner_rights(obj_uid, mp, cred, p, false) == 0) {
- permissions = ((unsigned long)obj_mode & S_IRWXU) >> 6;
- goto Exit;
- }
-
- /* Otherwise, check the groups. */
- if (! (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)) {
- for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) {
- if (obj_gid == *gp) {
- permissions = ((unsigned long)obj_mode & S_IRWXG) >> 3;
- goto Exit;
- }
- };
- };
-
- /* Otherwise, settle for 'others' access. */
- permissions = (unsigned long)obj_mode & S_IRWXO;
+ hfs_global_shared_lock_release(hfsmp);
-Exit:
- return permissions;
-}
-
-
-
-int AttributeBlockSize(struct attrlist *attrlist) {
- int size;
- attrgroup_t a;
-
-#if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
- ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \
- ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
- ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
- ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \
- ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) != ATTR_CMN_VALIDMASK)
-#error AttributeBlockSize: Missing bits in common mask computation!
-#endif
- DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0);
-
-#if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
- ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
- ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \
- ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \
- ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) != ATTR_VOL_VALIDMASK)
-#error AttributeBlockSize: Missing bits in volume mask computation!
-#endif
- DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0);
-
-#if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) != ATTR_DIR_VALIDMASK)
-#error AttributeBlockSize: Missing bits in directory mask computation!
-#endif
- DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0);
-#if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
- ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \
- ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
- ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK)
-#error AttributeBlockSize: Missing bits in file mask computation!
-#endif
- DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0);
-
-#if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
-#error AttributeBlockSize: Missing bits in fork mask computation!
-#endif
- DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0);
-
- size = 0;
-
- if ((a = attrlist->commonattr) != 0) {
- if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference);
- if (a & ATTR_CMN_DEVID) size += sizeof(dev_t);
- if (a & ATTR_CMN_FSID) size += sizeof(fsid_t);
- if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t);
- if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t);
- if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t);
- if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t);
- if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t);
- if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t);
- if (a & ATTR_CMN_CRTIME) size += sizeof(struct timespec);
- if (a & ATTR_CMN_MODTIME) size += sizeof(struct timespec);
- if (a & ATTR_CMN_CHGTIME) size += sizeof(struct timespec);
- if (a & ATTR_CMN_ACCTIME) size += sizeof(struct timespec);
- if (a & ATTR_CMN_BKUPTIME) size += sizeof(struct timespec);
- if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(UInt8);
- if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t);
- if (a & ATTR_CMN_GRPID) size += sizeof(gid_t);
- if (a & ATTR_CMN_ACCESSMASK) size += sizeof(u_long);
- if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(u_long);
- if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference);
- if (a & ATTR_CMN_FLAGS) size += sizeof(u_long);
- if (a & ATTR_CMN_USERACCESS) size += sizeof(u_long);
- };
- if ((a = attrlist->volattr) != 0) {
- if (a & ATTR_VOL_FSTYPE) size += sizeof(u_long);
- if (a & ATTR_VOL_SIGNATURE) size += sizeof(u_long);
- if (a & ATTR_VOL_SIZE) size += sizeof(off_t);
- if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t);
- if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t);
- if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t);
- if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t);
- if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(u_long);
- if (a & ATTR_VOL_OBJCOUNT) size += sizeof(u_long);
- if (a & ATTR_VOL_FILECOUNT) size += sizeof(u_long);
- if (a & ATTR_VOL_DIRCOUNT) size += sizeof(u_long);
- if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(u_long);
- if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference);
- if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference);
- if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(u_long);
- if (a & ATTR_VOL_MOUNTEDDEVICE) size += sizeof(struct attrreference);
- if (a & ATTR_VOL_ENCODINGSUSED) size += sizeof(unsigned long long);
- if (a & ATTR_VOL_CAPABILITIES) size += sizeof(vol_capabilities_attr_t);
- if (a & ATTR_VOL_ATTRIBUTES) size += sizeof(vol_attributes_attr_t);
- };
- if ((a = attrlist->dirattr) != 0) {
- if (a & ATTR_DIR_LINKCOUNT) size += sizeof(u_long);
- if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(u_long);
- if (a & ATTR_DIR_MOUNTSTATUS) size += sizeof(u_long);
- };
- if ((a = attrlist->fileattr) != 0) {
- if (a & ATTR_FILE_LINKCOUNT) size += sizeof(u_long);
- if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t);
- if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t);
- if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(size_t);
- if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(off_t);
- if (a & ATTR_FILE_DEVTYPE) size += sizeof(u_long);
- if (a & ATTR_FILE_FILETYPE) size += sizeof(u_long);
- if (a & ATTR_FILE_FORKCOUNT) size += sizeof(u_long);
- if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference);
- if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t);
- if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t);
- if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord);
- if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t);
- if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t);
- if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord);
- };
- if ((a = attrlist->forkattr) != 0) {
- if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t);
- if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t);
- };
-
- return size;
-}
-
-
-
-char* FindMountpointName(struct mount *mp) {
- size_t namelength = strlen(mp->mnt_stat.f_mntonname);
- int foundchars = 0;
- char *c;
-
- if (namelength == 0) return NULL;
-
- /* Look backwards through the name string, looking for the first slash
- encountered (which must precede the last part of the pathname)
- */
- for (c = mp->mnt_stat.f_mntonname + namelength - 1; namelength > 0; --c, --namelength) {
- if (*c != '/') {
- foundchars = 1;
- } else if (foundchars) {
- return (c + 1);
- };
- };
-
- return mp->mnt_stat.f_mntonname;
-}
-
-
-
-void PackObjectName(struct vnode *vp,
- char *name,
- size_t namelen,
- void **attrbufptrptr,
- void **varbufptrptr) {
- char *mpname;
- size_t mpnamelen;
- u_long attrlength;
-
- /* The name of an object may be incorrect for the root of a mounted filesystem
- because it may be mounted on a different directory name than the name of the
- volume (such as "blah-1". For the root directory, it's best to return the
- last element of the location where the volume's mounted:
- */
- if ((vp->v_flag & VROOT) && (mpname = FindMountpointName(vp->v_mount))) {
- mpnamelen = strlen(mpname);
-
- /* Trim off any trailing slashes: */
- while ((mpnamelen > 0) && (mpname[mpnamelen-1] == '/')) {
- --mpnamelen;
- };
-
- /* If there's anything left, use it instead of the volume's name */
- if (mpnamelen > 0) {
- name = mpname;
- namelen = mpnamelen;
- };
- };
-
- attrlength = namelen + 1;
- ((struct attrreference *)(*attrbufptrptr))->attr_dataoffset = (char *)(*varbufptrptr) - (char *)(*attrbufptrptr);
- ((struct attrreference *)(*attrbufptrptr))->attr_length = attrlength;
- (void) strncpy((unsigned char *)(*varbufptrptr), name, attrlength);
-
- /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
- (char *)(*varbufptrptr) += attrlength + ((4 - (attrlength & 3)) & 3);
- ++((struct attrreference *)(*attrbufptrptr));
-}
+ cat_releasedesc(&out_desc);
-
-
-void PackVolCommonAttributes(struct attrlist *alist,
- struct vnode *root_vp,
- struct hfsCatalogInfo *root_catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- void *attrbufptr;
- void *varbufptr;
- attrgroup_t a;
- struct hfsnode *root_hp = VTOH(root_vp);
- struct mount *mp = VTOVFS(root_vp);
- struct hfsmount *hfsmp = VTOHFS(root_vp);
- ExtendedVCB *vcb = HFSTOVCB(hfsmp);
- u_long attrlength;
-
- attrbufptr = *attrbufptrptr;
- varbufptr = *varbufptrptr;
-
- if ((a = alist->commonattr) != 0) {
- if (a & ATTR_CMN_NAME) {
- PackObjectName(root_vp, H_NAME(root_hp), root_hp->h_meta->h_namelen, &attrbufptr, &varbufptr);
- };
- if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
- if (a & ATTR_CMN_FSID) {
- *((fsid_t *)attrbufptr) = mp->mnt_stat.f_fsid;
- ++((fsid_t *)attrbufptr);
- };
- if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = 0;
- if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
- if (a & ATTR_CMN_OBJID) {
- ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- if (a & ATTR_CMN_OBJPERMANENTID) {
- ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- if (a & ATTR_CMN_PAROBJID) {
- ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- VCB_LOCK(vcb);
- if (a & ATTR_CMN_SCRIPT) *((text_encoding_t *)attrbufptr)++ = vcb->volumeNameEncodingHint;
- /* NOTE: all VCB dates are in Mac OS time */
- if (a & ATTR_CMN_CRTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbCrDate);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_MODTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_CHGTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_ACCTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_BKUPTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbVolBkUp);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_FNDRINFO) {
- bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo));
- (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
- };
- VCB_UNLOCK(vcb);
- if (a & ATTR_CMN_OWNERID) {
- if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
- *((uid_t *)attrbufptr)++ =
- (VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid;
- } else {
- *((uid_t *)attrbufptr)++ =
- (root_hp->h_meta->h_uid == UNKNOWNUID) ? console_user : root_hp->h_meta->h_uid;
- };
- };
- if (a & ATTR_CMN_GRPID) {
- if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
- *((gid_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_gid;
- } else {
- *((gid_t *)attrbufptr)++ = root_hp->h_meta->h_gid;
- };
- };
- if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)root_hp->h_meta->h_mode;
- if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
- if (a & ATTR_CMN_NAMEDATTRLIST) {
- attrlength = 0;
- ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
- ((struct attrreference *)attrbufptr)->attr_length = attrlength;
-
- /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
- (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
- ++((struct attrreference *)attrbufptr);
- };
- if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = root_hp->h_meta->h_pflags;
- if (a & ATTR_CMN_USERACCESS) {
- if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
- *((u_long *)attrbufptr)++ =
- DerivePermissionSummary((VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid,
- VTOHFS(root_vp)->hfs_gid,
- root_hp->h_meta->h_mode,
- VTOVFS(root_vp),
- current_proc()->p_ucred,
- current_proc());
- } else {
- *((u_long *)attrbufptr)++ =
- DerivePermissionSummary((root_hp->h_meta->h_uid == UNKNOWNUID) ? console_user : root_hp->h_meta->h_uid,
- root_hp->h_meta->h_gid,
- root_hp->h_meta->h_mode,
- VTOVFS(root_vp),
- current_proc()->p_ucred,
- current_proc());
- };
- };
- };
-
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
+ return (out_desc.cd_cnid);
}
-
-
-void PackVolAttributeBlock(struct attrlist *alist,
- struct vnode *root_vp,
- struct hfsCatalogInfo *root_catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- void *attrbufptr;
- void *varbufptr;
- attrgroup_t a;
- struct mount *mp = VTOVFS(root_vp);
- struct hfsmount *hfsmp = VTOHFS(root_vp);
- ExtendedVCB *vcb = HFSTOVCB(hfsmp);
- u_long attrlength;
-
- attrbufptr = *attrbufptrptr;
- varbufptr = *varbufptrptr;
-
- if ((a = alist->volattr) != 0) {
- VCB_LOCK(vcb);
- if (a & ATTR_VOL_FSTYPE) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_vfc->vfc_typenum;
- if (a & ATTR_VOL_SIGNATURE) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbSigWord;
- if (a & ATTR_VOL_SIZE) *((off_t *)attrbufptr)++ = (off_t)vcb->totalBlocks * (off_t)vcb->blockSize;
- if (a & ATTR_VOL_SPACEFREE) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize;
- if (a & ATTR_VOL_SPACEAVAIL) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize;
- if (a & ATTR_VOL_MINALLOCATION) *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize;
- if (a & ATTR_VOL_ALLOCATIONCLUMP) *((off_t *)attrbufptr)++ = (off_t)(vcb->vcbClpSiz);
- if (a & ATTR_VOL_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = (u_long)hfsmp->hfs_logBlockSize;
- if (a & ATTR_VOL_OBJCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt + (u_long)vcb->vcbDirCnt;
- if (a & ATTR_VOL_FILECOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt;
- if (a & ATTR_VOL_DIRCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbDirCnt;
- if (a & ATTR_VOL_MAXOBJCOUNT) *((u_long *)attrbufptr)++ = 0xFFFFFFFF;
- if (a & ATTR_VOL_MOUNTPOINT) {
- ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
- ((struct attrreference *)attrbufptr)->attr_length = strlen(mp->mnt_stat.f_mntonname) + 1;
- attrlength = ((struct attrreference *)attrbufptr)->attr_length;
- attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
- (void) bcopy(mp->mnt_stat.f_mntonname, varbufptr, attrlength);
-
- /* Advance beyond the space just allocated: */
- (char *)varbufptr += attrlength;
- ++((struct attrreference *)attrbufptr);
- };
- if (a & ATTR_VOL_NAME) {
- ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
- ((struct attrreference *)attrbufptr)->attr_length = VTOH(root_vp)->h_meta->h_namelen + 1;
- attrlength = ((struct attrreference *)attrbufptr)->attr_length;
- attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
- bcopy(H_NAME(VTOH(root_vp)), varbufptr, attrlength);
-
- /* Advance beyond the space just allocated: */
- (char *)varbufptr += attrlength;
- ++((struct attrreference *)attrbufptr);
- };
- if (a & ATTR_VOL_MOUNTFLAGS) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_flag;
- if (a & ATTR_VOL_MOUNTEDDEVICE) {
- ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
- ((struct attrreference *)attrbufptr)->attr_length = strlen(mp->mnt_stat.f_mntfromname) + 1;
- attrlength = ((struct attrreference *)attrbufptr)->attr_length;
- attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
- (void) bcopy(mp->mnt_stat.f_mntfromname, varbufptr, attrlength);
-
- /* Advance beyond the space just allocated: */
- (char *)varbufptr += attrlength;
- ++((struct attrreference *)attrbufptr);
- };
- if (a & ATTR_VOL_ENCODINGSUSED) *((unsigned long long *)attrbufptr)++ = (unsigned long long)vcb->encodingsBitmap;
- if (a & ATTR_VOL_CAPABILITIES) {
- if (vcb->vcbSigWord == kHFSPlusSigWord) {
- ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_FORMAT] =
- VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS;
- } else { /* Plain HFS */
- ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_FORMAT] =
- VOL_CAP_FMT_PERSISTENTOBJECTIDS;
- }
- ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_INTERFACES] =
- VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | VOL_CAP_INT_READDIRATTR;
- ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
- ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
-
- ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_FORMAT] =
- VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS;
- ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_INTERFACES] =
- VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | VOL_CAP_INT_READDIRATTR;
- ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_RESERVED1] = 0;
- ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_RESERVED2] = 0;
-
- ++((vol_capabilities_attr_t *)attrbufptr);
- };
- if (a & ATTR_VOL_ATTRIBUTES) {
- ((vol_attributes_attr_t *)attrbufptr)->validattr.commonattr = ATTR_CMN_VALIDMASK;
- ((vol_attributes_attr_t *)attrbufptr)->validattr.volattr = ATTR_VOL_VALIDMASK;
- ((vol_attributes_attr_t *)attrbufptr)->validattr.dirattr = ATTR_DIR_VALIDMASK;
- ((vol_attributes_attr_t *)attrbufptr)->validattr.fileattr = ATTR_FILE_VALIDMASK;
- ((vol_attributes_attr_t *)attrbufptr)->validattr.forkattr = ATTR_FORK_VALIDMASK;
-
- ((vol_attributes_attr_t *)attrbufptr)->nativeattr.commonattr = ATTR_CMN_VALIDMASK;
- ((vol_attributes_attr_t *)attrbufptr)->nativeattr.volattr = ATTR_VOL_VALIDMASK;
- ((vol_attributes_attr_t *)attrbufptr)->nativeattr.dirattr = ATTR_DIR_VALIDMASK;
- ((vol_attributes_attr_t *)attrbufptr)->nativeattr.fileattr = ATTR_FILE_VALIDMASK;
- ((vol_attributes_attr_t *)attrbufptr)->nativeattr.forkattr = ATTR_FORK_VALIDMASK;
-
- ++((vol_attributes_attr_t *)attrbufptr);
- };
- VCB_UNLOCK(vcb);
- };
+__private_extern__
+u_long
+GetFileInfo(ExtendedVCB *vcb, u_int32_t dirid, char *name,
+ struct cat_attr *fattr, struct cat_fork *forkinfo)
+{
+ struct hfsmount * hfsmp;
+ struct vnode * dvp = NULL;
+ struct cnode * dcp = NULL;
+ struct FndrDirInfo * fndrinfo;
+ struct cat_desc jdesc;
+ struct timeval tv;
+ int error;
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
-}
-
-
+ if (vcb->vcbSigWord != kHFSPlusSigWord)
+ return (0);
+ hfsmp = VCBTOHFS(vcb);
-void PackVolumeInfo(struct attrlist *alist,
- struct vnode *root_vp,
- struct hfsCatalogInfo *root_catinfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
+ memset(&jdesc, 0, sizeof(struct cat_desc));
+ jdesc.cd_parentcnid = kRootDirID;
+ jdesc.cd_nameptr = name;
+ jdesc.cd_namelen = strlen(name);
- PackVolCommonAttributes(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr);
- PackVolAttributeBlock(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr);
-};
+ /* Lock catalog b-tree */
+ error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, current_proc());
+ if (error)
+ return (0);
-// Pack the common attribute contents of an objects hfsCatalogInfo
-void PackCommonCatalogInfoAttributeBlock(struct attrlist *alist,
- struct vnode *root_vp,
- struct hfsCatalogInfo *catalogInfo,
- void **attrbufptrptr,
- void **varbufptrptr )
-{
- struct hfsnode *hp;
- void *attrbufptr;
- void *varbufptr;
- attrgroup_t a;
- u_long attrlength;
- Boolean isHFSPlus;
-
- hp = VTOH(root_vp);
- attrbufptr = *attrbufptrptr;
- varbufptr = *varbufptrptr;
- isHFSPlus = (VTOVCB(root_vp)->vcbSigWord == kHFSPlusSigWord);
-
- if ((a = alist->commonattr) != 0)
- {
- if (a & ATTR_CMN_NAME)
- {
- attrlength = strlen(catalogInfo->nodeData.cnm_nameptr) + 1;
- ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
- ((struct attrreference *)attrbufptr)->attr_length = attrlength;
- (void) strncpy((unsigned char *)varbufptr,
- catalogInfo->nodeData.cnm_nameptr, attrlength);
-
- /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
- (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
- ++((struct attrreference *)attrbufptr);
- };
- if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = H_DEV(hp);
- if (a & ATTR_CMN_FSID) {
- *((fsid_t *)attrbufptr) = VTOVFS(root_vp)->mnt_stat.f_fsid;
- ++((fsid_t *)attrbufptr);
- };
- if (a & ATTR_CMN_OBJTYPE)
- {
- switch (catalogInfo->nodeData.cnd_type) {
- case kCatalogFolderNode:
- *((fsobj_type_t *)attrbufptr)++ = VDIR;
- break;
+ error = cat_lookup(hfsmp, &jdesc, 0, NULL, fattr, forkinfo);
- case kCatalogFileNode:
- /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
- if ((HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) &&
- (catalogInfo->nodeData.cnd_mode & IFMT)) {
- *((fsobj_type_t *)attrbufptr)++ =
- IFTOVT((mode_t)catalogInfo->nodeData.cnd_mode);
- } else {
- *((fsobj_type_t *)attrbufptr)++ = VREG;
- };
- break;
-
- default:
- *((fsobj_type_t *)attrbufptr)++ = VNON;
- break;
- };
- }
- if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = root_vp->v_tag;
- if (a & ATTR_CMN_OBJID) {
- u_int32_t cnid;
-
- /* For hard links use the link's cnid */
- if (catalogInfo->nodeData.cnd_iNodeNumCopy != 0)
- cnid = catalogInfo->nodeData.cnd_linkCNID;
- else
- cnid = catalogInfo->nodeData.cnd_nodeID;
- ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- if (a & ATTR_CMN_OBJPERMANENTID) {
- u_int32_t cnid;
-
- /* For hard links use the link's cnid */
- if (catalogInfo->nodeData.cnd_iNodeNumCopy != 0)
- cnid = catalogInfo->nodeData.cnd_linkCNID;
- else
- cnid = catalogInfo->nodeData.cnd_nodeID;
- ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- if (a & ATTR_CMN_PAROBJID)
- {
- ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.cnm_parID;
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- if (a & ATTR_CMN_SCRIPT)
- {
- if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) {
- *((text_encoding_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_textEncoding;
- } else {
- *((text_encoding_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_encoding;
- }
- };
- if (a & ATTR_CMN_CRTIME)
- {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_createDate);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_MODTIME)
- {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_CHGTIME)
- {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_attributeModDate);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_ACCTIME)
- {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_accessDate);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_BKUPTIME)
- {
- ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_backupDate);
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_FNDRINFO)
- {
- bcopy (&catalogInfo->nodeData.cnd_finderInfo, attrbufptr, sizeof(catalogInfo->nodeData.cnd_finderInfo));
- (char *)attrbufptr += sizeof(catalogInfo->nodeData.cnd_finderInfo);
- };
- if (a & ATTR_CMN_OWNERID) {
- if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) ||
- ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) {
- *((uid_t *)attrbufptr)++ =
- (VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid;
- } else {
- *((uid_t *)attrbufptr)++ =
- (catalogInfo->nodeData.cnd_ownerID == UNKNOWNUID) ? console_user : catalogInfo->nodeData.cnd_ownerID;
- };
- }
- if (a & ATTR_CMN_GRPID) {
- if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) ||
- ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) {
- *((gid_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_gid;
- } else {
- *((gid_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_groupID;
- };
- }
- if (a & ATTR_CMN_ACCESSMASK) {
- if (((catalogInfo->nodeData.cnd_mode & IFMT) == 0)
-#if OVERRIDE_UNKNOWN_PERMISSIONS
- || (VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS)
-#endif
- ) {
- switch (catalogInfo->nodeData.cnd_type) {
- case kCatalogFileNode:
- /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
- *((u_long *)attrbufptr)++ = (u_long)(IFREG | (ACCESSPERMS & (u_long)(VTOHFS(root_vp)->hfs_file_mask)));
- break;
-
- case kCatalogFolderNode:
- *((u_long *)attrbufptr)++ = (u_long)(IFDIR | (ACCESSPERMS & (u_long)(VTOHFS(root_vp)->hfs_dir_mask)));
- break;
-
- default:
- *((u_long *)attrbufptr)++ = (u_long)((catalogInfo->nodeData.cnd_mode & IFMT) |
- VTOHFS(root_vp)->hfs_dir_mask);
- };
- } else {
- *((u_long *)attrbufptr)++ =
- (u_long)catalogInfo->nodeData.cnd_mode;
- };
- }
- if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
- if (a & ATTR_CMN_NAMEDATTRLIST)
- {
- attrlength = 0;
- ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
- ((struct attrreference *)attrbufptr)->attr_length = attrlength;
-
- /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
- (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
- ++((struct attrreference *)attrbufptr);
- };
- if (a & ATTR_CMN_FLAGS) {
- u_long flags;
-
- if (catalogInfo->nodeData.cnd_mode & IFMT)
- flags = catalogInfo->nodeData.cnd_ownerFlags |
- catalogInfo->nodeData.cnd_adminFlags << 16;
- else
- flags = 0;
-
- if (catalogInfo->nodeData.cnd_type == kCatalogFileNode) {
- if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask)
- flags |= UF_IMMUTABLE;
- else
- flags &= ~UF_IMMUTABLE;
- };
- *((u_long *)attrbufptr)++ = flags;
- };
- if (a & ATTR_CMN_USERACCESS) {
- if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) ||
- ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) {
- *((u_long *)attrbufptr)++ =
- DerivePermissionSummary((VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid,
- VTOHFS(root_vp)->hfs_gid,
-#if OVERRIDE_UNKNOWN_PERMISSIONS
- (catalogInfo->nodeData.cnd_type == kCatalogFileNode) ? VTOHFS(root_vp)->hfs_file_mask : VTOHFS(root_vp)->hfs_dir_mask,
-#else
- (catalogInfo->nodeData.cnd_mode & IFMT) ?
- (u_long)catalogInfo->nodeData.cnd_mode :
- ((catalogInfo->nodeData.cnd_type == kCatalogFileNode) ?
- VTOHFS(root_vp)->hfs_file_mask :
- VTOHFS(root_vp)->hfs_dir_mask),
-#endif
- VTOVFS(root_vp),
- current_proc()->p_ucred,
- current_proc());
- } else {
- *((u_long *)attrbufptr)++ =
- DerivePermissionSummary((catalogInfo->nodeData.cnd_ownerID == UNKNOWNUID) ? console_user : catalogInfo->nodeData.cnd_ownerID,
- catalogInfo->nodeData.cnd_groupID,
- (mode_t)catalogInfo->nodeData.cnd_mode,
- VTOVFS(root_vp),
- current_proc()->p_ucred,
- current_proc());
- };
- };
- };
-
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
-}
-
-
-void PackCommonAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- struct hfsnode *hp;
- void *attrbufptr;
- void *varbufptr;
- attrgroup_t a;
- u_long attrlength;
-
- hp = VTOH(vp);
-
- attrbufptr = *attrbufptrptr;
- varbufptr = *varbufptrptr;
-
- if ((a = alist->commonattr) != 0) {
- if (a & ATTR_CMN_NAME) {
- PackObjectName(vp, H_NAME(hp), hp->h_meta->h_namelen, &attrbufptr, &varbufptr);
- };
- if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = H_DEV(hp);
- if (a & ATTR_CMN_FSID) {
- *((fsid_t *)attrbufptr) = VTOVFS(vp)->mnt_stat.f_fsid;
- ++((fsid_t *)attrbufptr);
- };
- if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = vp->v_type;
- if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = vp->v_tag;
- if (a & ATTR_CMN_OBJID) {
- u_int32_t cnid;
-
- /* For hard links use the link's cnid */
- if (hp->h_meta->h_metaflags & IN_DATANODE)
- cnid = catInfo->nodeData.cnd_linkCNID;
- else
- cnid = H_FILEID(hp);
- ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- if (a & ATTR_CMN_OBJPERMANENTID) {
- u_int32_t cnid;
-
- /* For hard links use the link's cnid */
- if (hp->h_meta->h_metaflags & IN_DATANODE)
- cnid = catInfo->nodeData.cnd_linkCNID;
- else
- cnid = H_FILEID(hp);
- ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- if (a & ATTR_CMN_PAROBJID) {
- ((fsobj_id_t *)attrbufptr)->fid_objno = H_DIRID(hp);
- ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
- ++((fsobj_id_t *)attrbufptr);
- };
- if (a & ATTR_CMN_SCRIPT)
- {
- if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) {
- *((text_encoding_t *)attrbufptr)++ = catInfo->nodeData.cnd_textEncoding;
- } else {
- *((text_encoding_t *)attrbufptr)++ = VTOHFS(vp)->hfs_encoding;
- }
- };
- if (a & ATTR_CMN_CRTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_crtime;
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_MODTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_mtime;
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_CHGTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_ctime;
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_ACCTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_atime;
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_BKUPTIME) {
- ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_butime;
- ((struct timespec *)attrbufptr)->tv_nsec = 0;
- ++((struct timespec *)attrbufptr);
- };
- if (a & ATTR_CMN_FNDRINFO) {
- bcopy (&catInfo->nodeData.cnd_finderInfo, attrbufptr, sizeof(catInfo->nodeData.cnd_finderInfo));
- (char *)attrbufptr += sizeof(catInfo->nodeData.cnd_finderInfo);
- };
- if (a & ATTR_CMN_OWNERID) {
- if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
- *((uid_t *)attrbufptr)++ =
- (VTOHFS(vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(vp)->hfs_uid;
- } else {
- *((uid_t *)attrbufptr)++ =
- (hp->h_meta->h_uid == UNKNOWNUID) ? console_user : hp->h_meta->h_uid;
- }
- };
- if (a & ATTR_CMN_GRPID) {
- if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
- *((gid_t *)attrbufptr)++ = VTOHFS(vp)->hfs_gid;
- } else {
- *((gid_t *)attrbufptr)++ = hp->h_meta->h_gid;
- };
- };
- if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)hp->h_meta->h_mode;
- if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
- if (a & ATTR_CMN_NAMEDATTRLIST) {
- attrlength = 0;
- ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
- ((struct attrreference *)attrbufptr)->attr_length = attrlength;
-
- /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
- (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
- ++((struct attrreference *)attrbufptr);
- };
- if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = hp->h_meta->h_pflags;
- if (a & ATTR_CMN_USERACCESS) {
- if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
- *((u_long *)attrbufptr)++ =
- DerivePermissionSummary((VTOHFS(vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(vp)->hfs_uid,
- VTOHFS(vp)->hfs_gid,
- hp->h_meta->h_mode,
- VTOVFS(vp),
- current_proc()->p_ucred,
- current_proc());
- } else {
- *((u_long *)attrbufptr)++ =
- DerivePermissionSummary((hp->h_meta->h_uid == UNKNOWNUID) ? console_user : hp->h_meta->h_uid,
- hp->h_meta->h_gid,
- hp->h_meta->h_mode,
- VTOVFS(vp),
- current_proc()->p_ucred,
- current_proc());
- };
- };
- };
-
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
-}
-
-
-// Pack the directory attributes given hfsCatalogInfo
-void PackCatalogInfoDirAttributeBlock( struct attrlist *alist, struct vnode *vp,
- struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr )
-{
- void *attrbufptr;
- attrgroup_t a;
- u_long valence;
-
- attrbufptr = *attrbufptrptr;
- a = alist->dirattr;
-
- if ( (catInfo->nodeData.cnd_type == kCatalogFolderNode) && (a != 0) ) {
- valence = catInfo->nodeData.cnd_valence;
- if ((catInfo->nodeData.cnm_parID == kRootParID) &&
- (VTOHFS(vp)->hfs_private_metadata_dir != 0)) {
- --valence; /* hide private dir */
- }
- /* The 'link count' is faked */
- if (a & ATTR_DIR_LINKCOUNT)
- *((u_long *)attrbufptr)++ = 2 + valence;
- if (a & ATTR_DIR_ENTRYCOUNT)
- *((u_long *)attrbufptr)++ = valence;
- if (a & ATTR_DIR_MOUNTSTATUS)
- *((u_long *)attrbufptr)++ = 0;
- };
-
- *attrbufptrptr = attrbufptr;
-}
-
-
-void PackDirAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- void *attrbufptr;
- attrgroup_t a;
- u_long valence;
-
- attrbufptr = *attrbufptrptr;
-
- a = alist->dirattr;
- if ((vp->v_type == VDIR) && (a != 0)) {
- valence = catInfo->nodeData.cnd_valence;
- if ((catInfo->nodeData.cnm_parID == kRootParID) &&
- (VTOHFS(vp)->hfs_private_metadata_dir != 0)) {
- --valence; /* hide private dir */
- }
-
- /* The 'link count' is faked */
- if (a & ATTR_DIR_LINKCOUNT)
- *((u_long *)attrbufptr)++ = 2 + valence;
- if (a & ATTR_DIR_ENTRYCOUNT)
- *((u_long *)attrbufptr)++ = valence;
- if (a & ATTR_DIR_MOUNTSTATUS) {
- if (vp->v_mountedhere) {
- *((u_long *)attrbufptr)++ = DIR_MNTSTATUS_MNTPOINT;
- } else {
- *((u_long *)attrbufptr)++ = 0;
- };
- };
- };
-
- *attrbufptrptr = attrbufptr;
-}
-
-
-
-// Pack the file attributes from the hfsCatalogInfo for the file.
-void PackCatalogInfoFileAttributeBlock( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr )
-{
- void *attrbufptr;
- void *varbufptr;
- attrgroup_t a;
- u_long attrlength;
- ExtendedVCB *vcb = VTOVCB(root_vp);
-
- attrbufptr = *attrbufptrptr;
- varbufptr = *varbufptrptr;
-
- a = alist->fileattr;
- if ( (catInfo->nodeData.cnd_type == kCatalogFileNode) && (a != 0) )
- {
-#if HFS_HARDLINKS
- if (a & ATTR_FILE_LINKCOUNT) {
- u_long linkcnt = catInfo->nodeData.cnd_linkCount;
-
- if (linkcnt < 1)
- linkcnt = 1;
- *((u_long *)attrbufptr)++ = linkcnt;
- }
-#else
- if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1;
-#endif
- if (a & ATTR_FILE_TOTALSIZE) {
- *((off_t *)attrbufptr)++ =
- (off_t)catInfo->nodeData.cnd_datafork.logicalSize +
- (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
- }
- if (a & ATTR_FILE_ALLOCSIZE) {
- *((off_t *)attrbufptr)++ =
- (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize) +
- (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
- }
- if (a & ATTR_FILE_IOBLOCKSIZE) {
- *((u_long *)attrbufptr)++ = (u_long)(VTOHFS(root_vp)->hfs_logBlockSize);
- }
- if (a & ATTR_FILE_CLUMPSIZE) {
- *((u_long *)attrbufptr)++ = vcb->vcbClpSiz;
- }
- if (a & ATTR_FILE_DEVTYPE) {
- u_long rawdev;
- u_short filetype;
-
- filetype = (catInfo->nodeData.cnd_mode & IFMT);
- if (filetype == IFCHR || filetype == IFBLK)
- rawdev = (u_long)catInfo->nodeData.cnd_rawDevice;
- else
- rawdev = 0;
-
- *((u_long *)attrbufptr)++ = rawdev;
- }
- if (a & ATTR_FILE_FILETYPE) {
- *((u_long *)attrbufptr)++ = 0; /* XXX PPD */
- }
- if (a & ATTR_FILE_FORKCOUNT) {
- *((u_long *)attrbufptr)++ = 2; /* XXX PPD */
- }
- if (a & ATTR_FILE_FORKLIST) {
- attrlength = 0;
- ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
- ((struct attrreference *)attrbufptr)->attr_length = attrlength;
-
- /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
- (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
- ++((struct attrreference *)attrbufptr);
- };
- if (a & ATTR_FILE_DATALENGTH) {
- *((off_t *)attrbufptr)++ =
- (off_t)catInfo->nodeData.cnd_datafork.logicalSize;
- }
- if (a & ATTR_FILE_DATAALLOCSIZE) {
- *((off_t *)attrbufptr)++ =
- (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize);
- }
- if (a & ATTR_FILE_DATAEXTENTS) {
- bcopy(&catInfo->nodeData.cnd_datafork.extents, attrbufptr, sizeof(extentrecord));
- (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
- };
- if (a & ATTR_FILE_RSRCLENGTH) {
- *((off_t *)attrbufptr)++ =
- (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
- }
- if (a & ATTR_FILE_RSRCALLOCSIZE) {
- *((off_t *)attrbufptr)++ =
- (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
- }
- if (a & ATTR_FILE_RSRCEXTENTS) {
- bcopy(&catInfo->nodeData.cnd_rsrcfork.extents, attrbufptr, sizeof(extentrecord));
- (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
- };
- };
-
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
-}
-
-
-void PackFileAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- struct hfsnode *hp = VTOH(vp);
- FCB *fcb = HTOFCB(hp);
- ExtendedVCB *vcb = HTOVCB(hp);
- Boolean isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
- void *attrbufptr = *attrbufptrptr;
- void *varbufptr = *varbufptrptr;
- attrgroup_t a = alist->fileattr;
- u_long attrlength;
-
- if (a != 0) {
-#if HFS_HARDLINKS
- if (a & ATTR_FILE_LINKCOUNT) {
- u_long linkcnt = catInfo->nodeData.cnd_linkCount;
-
- if (linkcnt < 1)
- linkcnt = 1;
- *((u_long *)attrbufptr)++ = linkcnt;
- }
-#else
- if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1;
-#endif
- if (a & ATTR_FILE_TOTALSIZE) {
- *((off_t *)attrbufptr)++ =
- (off_t)catInfo->nodeData.cnd_datafork.logicalSize +
- (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
- }
- if (a & ATTR_FILE_ALLOCSIZE) {
- switch (H_FORKTYPE(hp)) {
- case kDataFork:
- *((off_t *)attrbufptr)++ =
- (off_t)fcb->fcbPLen +
- (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
- break;
- case kRsrcFork:
- *((off_t *)attrbufptr)++ =
- (off_t)fcb->fcbPLen +
- (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize);
- break;
- default:
- *((off_t *)attrbufptr)++ =
- (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize) +
- (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
- };
- };
- if (a & ATTR_FILE_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = GetLogicalBlockSize(vp);
- if (a & ATTR_FILE_CLUMPSIZE) *((u_long *)attrbufptr)++ = fcb->fcbClmpSize;
- if (a & ATTR_FILE_DEVTYPE) {
- u_long rawdev;
-
- if ((vp->v_type == VBLK) || (vp->v_type == VCHR))
- rawdev = (u_long)catInfo->nodeData.cnd_rawDevice;
- else
- rawdev = 0;
- *((u_long *)attrbufptr)++ = rawdev;
- }
- if (a & ATTR_FILE_FILETYPE) *((u_long *)attrbufptr)++ = 0; /* XXX PPD */
- if (a & ATTR_FILE_FORKCOUNT) *((u_long *)attrbufptr)++ = 2; /* XXX PPD */
- if (a & ATTR_FILE_FORKLIST) {
- attrlength = 0;
- ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
- ((struct attrreference *)attrbufptr)->attr_length = attrlength;
-
- /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
- (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
- ++((struct attrreference *)attrbufptr);
- };
- if (H_FORKTYPE(hp) == kDataFork) {
- if (a & ATTR_FILE_DATALENGTH)
- *((off_t *)attrbufptr)++ = fcb->fcbEOF;
- if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen;
- if (a & ATTR_FILE_DATAEXTENTS) {
- bcopy ( fcb->fcbExtents, attrbufptr, sizeof(extentrecord));
- (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
- };
- } else {
- if (a & ATTR_FILE_DATALENGTH) {
- *((off_t *)attrbufptr)++ =
- (off_t)catInfo->nodeData.cnd_datafork.logicalSize;
- }
- if (a & ATTR_FILE_DATAALLOCSIZE) {
- *((off_t *)attrbufptr)++ =
- (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize);
- }
- if (a & ATTR_FILE_DATAEXTENTS) {
- bcopy(&catInfo->nodeData.cnd_datafork.extents, attrbufptr, sizeof(extentrecord));
- (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
- };
- };
- if (H_FORKTYPE(hp) == kRsrcFork) {
- if (a & ATTR_FILE_RSRCLENGTH)
- *((off_t *)attrbufptr)++ = fcb->fcbEOF;
- if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen;
- if (a & ATTR_FILE_RSRCEXTENTS) {
- bcopy ( fcb->fcbExtents, attrbufptr, sizeof(extentrecord));
- (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
- };
- } else {
- if (a & ATTR_FILE_RSRCLENGTH) {
- *((off_t *)attrbufptr)++ =
- (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
- }
- if (a & ATTR_FILE_RSRCALLOCSIZE) {
- *((off_t *)attrbufptr)++ =
- (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
- }
- if (a & ATTR_FILE_RSRCEXTENTS) {
- bcopy(&catInfo->nodeData.cnd_rsrcfork.extents, attrbufptr, sizeof(extentrecord));
- (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
- };
- };
- };
-
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
-}
-
-#if 0
-void PackForkAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- /* XXX PPD TBC */
-}
-#endif
-
-
-// This routine takes catInfo, and alist, as inputs and packs it into an attribute block.
-void PackCatalogInfoAttributeBlock ( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr)
-{
- //XXX Preflight that alist only contains bits with fields in catInfo
-
- PackCommonCatalogInfoAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
-
- switch ( catInfo->nodeData.cnd_type )
- {
- case kCatalogFolderNode:
- PackCatalogInfoDirAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
- break;
-
- case kCatalogFileNode:
- PackCatalogInfoFileAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
- break;
-
- default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */
- /* XXX PPD - Panic? */
- break;
- }
-}
-
-
-
-void PackAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr)
-{
- if (alist->volattr != 0) {
- DBG_ASSERT((vp->v_flag & VROOT) != 0);
- PackVolumeInfo(alist,vp, catInfo, attrbufptrptr, varbufptrptr);
- } else {
- PackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
-
- switch (vp->v_type) {
- case VDIR:
- PackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
- break;
-
- case VREG:
- case VLNK:
- PackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
- break;
-
- /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
- not being handled...
- */
- default:
- /* XXX PPD - Panic? */
- break;
- };
- };
-};
-
-
-
-void UnpackVolumeAttributeBlock(struct attrlist *alist,
- struct vnode *root_vp,
- ExtendedVCB *vcb,
- void **attrbufptrptr,
- void **varbufptrptr) {
- void *attrbufptr = *attrbufptrptr;
- attrgroup_t a;
-
- if ((alist->commonattr == 0) && (alist->volattr == 0)) {
- return; /* Get out without dirtying the VCB */
- };
-
- VCB_LOCK(vcb);
-
- a = alist->commonattr;
-
- if (a & ATTR_CMN_SCRIPT) {
- vcb->volumeNameEncodingHint = (u_int32_t)*(((text_encoding_t *)attrbufptr)++);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_SCRIPT;
-#endif
- };
- if (a & ATTR_CMN_CRTIME) {
- vcb->vcbCrDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
- /* Need to update the local time also */
- vcb->localCreateDate = UTCToLocal(vcb->vcbCrDate);
- ++((struct timespec *)attrbufptr);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_CRTIME;
-#endif
- };
- if (a & ATTR_CMN_MODTIME) {
- vcb->vcbLsMod = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
- ++((struct timespec *)attrbufptr);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_MODTIME;
-#endif
- };
- if (a & ATTR_CMN_BKUPTIME) {
- vcb->vcbVolBkUp = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
- ++((struct timespec *)attrbufptr);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_BKUPTIME;
-#endif
- };
- if (a & ATTR_CMN_FNDRINFO) {
- bcopy (attrbufptr, &vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo));
- (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_FNDRINFO;
-#endif
- };
-
- DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */
-
- a = alist->volattr & ~ATTR_VOL_INFO;
- if (a & ATTR_VOL_NAME) {
- copystr(((char *)attrbufptr) + *((u_long *)attrbufptr), vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
- (char *)attrbufptr += sizeof(struct attrreference);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_VOL_NAME;
-#endif
- };
-
- DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */
-
- vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty
-
- VCB_UNLOCK(vcb);
-}
-
-
-void UnpackCommonAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- struct hfsnode *hp = VTOH(vp);
- void *attrbufptr;
- attrgroup_t a;
-
- attrbufptr = *attrbufptrptr;
-
- DBG_ASSERT(catInfo != NULL);
-
- a = alist->commonattr;
- if (a & ATTR_CMN_SCRIPT) {
- catInfo->nodeData.cnd_textEncoding = (u_int32_t)*((text_encoding_t *)attrbufptr)++;
- UpdateVolumeEncodings(VTOVCB(vp), catInfo->nodeData.cnd_textEncoding); /* Update the volume encoding */
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_SCRIPT;
-#endif
- };
- if (a & ATTR_CMN_CRTIME) {
- catInfo->nodeData.cnd_createDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
- VTOH(vp)->h_meta->h_crtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
- ++((struct timespec *)attrbufptr);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_CRTIME;
-#endif
- };
- if (a & ATTR_CMN_MODTIME) {
- catInfo->nodeData.cnd_contentModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
- VTOH(vp)->h_meta->h_mtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
- ++((struct timespec *)attrbufptr);
- hp->h_nodeflags &= ~IN_UPDATE;
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_MODTIME;
-#endif
- };
- if (a & ATTR_CMN_CHGTIME) {
- catInfo->nodeData.cnd_attributeModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
- VTOH(vp)->h_meta->h_ctime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
- ++((struct timespec *)attrbufptr);
- hp->h_nodeflags &= ~IN_CHANGE;
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_CHGTIME;
-#endif
- };
- if (a & ATTR_CMN_ACCTIME) {
- catInfo->nodeData.cnd_accessDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
- VTOH(vp)->h_meta->h_atime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
- ++((struct timespec *)attrbufptr);
- hp->h_nodeflags &= ~IN_ACCESS;
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_ACCTIME;
-#endif
- };
- if (a & ATTR_CMN_BKUPTIME) {
- catInfo->nodeData.cnd_backupDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
- VTOH(vp)->h_meta->h_butime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
- ++((struct timespec *)attrbufptr);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_BKUPTIME;
-#endif
- };
- if (a & ATTR_CMN_FNDRINFO) {
- bcopy (attrbufptr, &catInfo->nodeData.cnd_finderInfo, sizeof(catInfo->nodeData.cnd_finderInfo));
- (char *)attrbufptr += sizeof(catInfo->nodeData.cnd_finderInfo);
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_FNDRINFO;
-#endif
- };
- if (a & ATTR_CMN_OWNERID) {
- if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
- u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++;
- if (uid != (uid_t)VNOVAL)
- hp->h_meta->h_uid = uid; /* catalog will get updated by hfs_chown() */
- }
- else {
- ((uid_t *)attrbufptr)++;
- }
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_OWNERID;
-#endif
- };
- if (a & ATTR_CMN_GRPID) {
- u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++;
- if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
- if (gid != (gid_t)VNOVAL)
- hp->h_meta->h_gid = gid; /* catalog will get updated by hfs_chown() */
- };
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_GRPID;
-#endif
- };
- if (a & ATTR_CMN_ACCESSMASK) {
- u_int16_t mode = (u_int16_t)*((u_long *)attrbufptr)++;
- if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
- if (mode != (mode_t)VNOVAL) {
- hp->h_meta->h_mode &= ~ALLPERMS;
- hp->h_meta->h_mode |= (mode & ALLPERMS); /* catalog will get updated by hfs_chmod() */
- }
- };
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_ACCESSMASK;
-#endif
- };
- if (a & ATTR_CMN_FLAGS) {
- u_long flags = *((u_long *)attrbufptr)++;
- /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE
- flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */
- if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) ||
- ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && ((flags & ~IMMUTABLE) == 0))) {
- if (flags != (u_long)VNOVAL) {
- hp->h_meta->h_pflags = flags; /* catalog will get updated by hfs_chflags */
- };
- };
-#if HFS_DIAGNOSTIC
- a &= ~ATTR_CMN_FLAGS;
-#endif
- };
-
-#if HFS_DIAGNOSTIC
- if (a != 0) {
- DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a));
- };
-#endif
-
- *attrbufptrptr = attrbufptr;
-// *varbufptrptr = varbufptr;
-}
-
-
-
-#if 0
-void UnpackDirAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- void *attrbufptr;
- void *varbufptr;
- attrgroup_t a;
- u_long attrlength;
-
- attrbufptr = *attrbufptrptr;
- varbufptr = *varbufptrptr;
-
- /* XXX PPD TBC */
-
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
-}
-#endif
-
-
-
-#if 0
-void UnpackFileAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- void *attrbufptr;
- void *varbufptr;
- attrgroup_t a;
- u_long attrlength;
-
- attrbufptr = *attrbufptrptr;
- varbufptr = *varbufptrptr;
-
- /* XXX PPD TBC */
-
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
-}
-#endif
-
-
-
-#if 0
-void UnpackForkAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
- void *attrbufptr;
- void *varbufptr;
- attrgroup_t a;
- u_long attrlength;
-
- attrbufptr = *attrbufptrptr;
- varbufptr = *varbufptrptr;
-
- /* XXX PPD TBC */
-
- *attrbufptrptr = attrbufptr;
- *varbufptrptr = varbufptr;
-}
-#endif
-
-
-
-void UnpackAttributeBlock(struct attrlist *alist,
- struct vnode *vp,
- struct hfsCatalogInfo *catInfo,
- void **attrbufptrptr,
- void **varbufptrptr) {
-
-
- if (alist->volattr != 0) {
- UnpackVolumeAttributeBlock(alist, vp, VTOVCB(vp), attrbufptrptr, varbufptrptr);
- return;
- };
-
- /* We're dealing with a vnode object here: */
- UnpackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
-
-#if 0
- switch (vp->v_type) {
- case VDIR:
- UnpackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
- break;
-
- case VREG:
- /* case VCPLX: */ /* XXX PPD TBC */
- UnpackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
- break;
-
- case VFORK:
- UnpackForkAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
- break;
-
- /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
- not being handled...
- */
- default:
- /* XXX PPD - Panic? */
- break;
- };
-#endif
-
-};
-
-
-unsigned long BestBlockSizeFit(unsigned long allocationBlockSize,
- unsigned long blockSizeLimit,
- unsigned long baseMultiple) {
- /*
- Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
- specified limit but still an even multiple of the baseMultiple.
- */
- int baseBlockCount, blockCount;
- unsigned long trialBlockSize;
-
- if (allocationBlockSize % baseMultiple != 0) {
- /*
- Whoops: the allocation blocks aren't even multiples of the specified base:
- no amount of dividing them into even parts will be a multiple, either then!
- */
- return 512; /* Hope for the best */
- };
-
- /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
- from being handled as two 6K logical blocks instead of 3 4K logical blocks.
- Even though the former (the result of the loop below) is the larger allocation
- block size, the latter is more efficient: */
- if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE;
-
- /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
- baseBlockCount = allocationBlockSize / baseMultiple; /* Now guaranteed to be an even multiple */
-
- for (blockCount = baseBlockCount; blockCount > 0; --blockCount) {
- trialBlockSize = blockCount * baseMultiple;
- if (allocationBlockSize % trialBlockSize == 0) { /* An even multiple? */
- if ((trialBlockSize <= blockSizeLimit) &&
- (trialBlockSize % baseMultiple == 0)) {
- return trialBlockSize;
- };
- };
- };
+ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc());
- /* Note: we should never get here, since blockCount = 1 should always work,
- but this is nice and safe and makes the compiler happy, too ... */
- return 512;
+ if (error == 0) {
+ return (fattr->ca_fileid);
+ } else if (hfsmp->hfs_flags & HFS_READ_ONLY) {
+ return (0);
+ }
}
/*
- * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
- * of an active vnode is translated to a move/rename so the file appears
- * deleted. The destination folder for these move/renames is setup here
- * and a reference to it is place in hfsmp->hfs_private_metadata_dir.
+ * On Journaled HFS, there can be orphaned files. These
+ * are files that were unlinked while busy. If the volume
+ * was not cleanly unmounted then some of these files may
+ * have persisted and need to be removed.
*/
-u_long
-FindMetaDataDirectory(ExtendedVCB *vcb)
+__private_extern__
+void
+hfs_remove_orphans(struct hfsmount * hfsmp)
{
- char namep[32];
- hfsCatalogInfo catInfo;
- HFSCatalogNodeID dirID;
- u_int32_t metadata_createdate;
- int retval;
-
- if (vcb->vcbSigWord != kHFSPlusSigWord)
- return (0);
+ struct BTreeIterator * iterator = NULL;
+ struct FSBufferDescriptor btdata;
+ struct HFSPlusCatalogFile filerec;
+ struct HFSPlusCatalogKey * keyp;
+ struct proc *p = current_proc();
+ FCB *fcb;
+ ExtendedVCB *vcb;
+ char filename[32];
+ char tempname[32];
+ size_t namelen;
+ cat_cookie_t cookie = {0};
+ int catlock = 0;
+ int catreserve = 0;
+ int started_tr = 0;
+ int shared_lock = 0;
+ int result;
+
+ if (hfsmp->hfs_flags & HFS_CLEANED_ORPHANS)
+ return;
- dirID = 0;
- metadata_createdate = 0;
- strncpy(namep, HFSPLUS_PRIVATE_DIR, sizeof(namep));
- INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName);
- catInfo.hint = kNoHint;
-
- /* lock catalog b-tree */
- retval = hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_SHARED, current_proc());
- if (retval) goto Err_Exit;
-
- if (hfs_getcatalog(vcb, kRootDirID, namep, -1, &catInfo) == 0) {
- dirID = catInfo.nodeData.cnd_nodeID;
- metadata_createdate = catInfo.nodeData.cnd_createDate;
- } else if (VCBTOHFS(vcb)->hfs_fs_ronly == 0) {
- if (CreateCatalogNode(vcb, kRootDirID, namep, kCatalogFolderNode, &dirID, &catInfo.hint, 0) == 0) {
- catInfo.hint = kNoHint;
- if (hfs_getcatalog(vcb, kRootDirID, namep, -1, &catInfo) == 0) {
-
- /* create date is later used for validation */
- catInfo.nodeData.cnd_createDate = vcb->vcbCrDate;
- metadata_createdate = catInfo.nodeData.cnd_createDate;
-
- /* directory with no permissions owned by root */
- catInfo.nodeData.cnd_mode = IFDIR;
- catInfo.nodeData.cnd_adminFlags = (SF_IMMUTABLE >> 16);
-
- /* hidden and off the desktop view */
- ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frLocation.v = SWAP_BE16 (22460);
- ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frLocation.h = SWAP_BE16 (22460);
- ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frFlags |= SWAP_BE16 (kIsInvisible + kNameLocked);
-
- (void) UpdateCatalogNode(vcb, kRootDirID, namep, catInfo.hint, &catInfo.nodeData);
+ vcb = HFSTOVCB(hfsmp);
+ fcb = VTOF(vcb->catalogRefNum);
+
+ btdata.bufferAddress = &filerec;
+ btdata.itemSize = sizeof(filerec);
+ btdata.itemCount = 1;
+
+ MALLOC(iterator, struct BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
+ bzero(iterator, sizeof(*iterator));
+ keyp = (HFSPlusCatalogKey*)&iterator->key;
+ keyp->parentID = hfsmp->hfs_privdir_desc.cd_cnid;
+
+ result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
+ if (result)
+ goto exit;
+ /*
+ * Position the iterator at the folder thread record.
+ * (i.e. one record before first child)
+ */
+ result = BTSearchRecord(fcb, iterator, NULL, NULL, iterator);
+
+ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
+ if (result)
+ goto exit;
+
+ /* Visit all the children in the HFS+ private directory. */
+ for (;;) {
+ result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
+ if (result)
+ goto exit;
+
+ result = BTIterateRecord(fcb, kBTreeNextRecord, iterator, &btdata, NULL);
+
+ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
+ if (result)
+ break;
+
+ if (keyp->parentID != hfsmp->hfs_privdir_desc.cd_cnid)
+ break;
+ if (filerec.recordType != kHFSPlusFileRecord)
+ continue;
+
+ (void) utf8_encodestr(keyp->nodeName.unicode, keyp->nodeName.length * 2,
+ filename, &namelen, sizeof(filename), 0, 0);
+
+ (void) sprintf(tempname, "%s%d", HFS_DELETE_PREFIX, filerec.fileID);
+
+ /*
+ * Delete all files named "tempxxx", where
+ * xxx is the file's cnid in decimal.
+ *
+ */
+ if (bcmp(tempname, filename, namelen) == 0) {
+ struct filefork dfork = {0};
+ struct filefork rfork = {0};
+ struct cnode cnode = {0};
+
+ // XXXdbg
+ hfs_global_shared_lock_acquire(hfsmp);
+ shared_lock = 1;
+ if (hfsmp->jnl) {
+ if (journal_start_transaction(hfsmp->jnl) != 0) {
+ goto exit;
+ }
+ started_tr = 1;
}
- }
- }
+
+ /*
+ * Reserve some space in the Catalog file.
+ */
+ if (cat_preflight(hfsmp, CAT_DELETE, &cookie, p) != 0) {
+ goto exit;
+ }
+ catreserve = 1;
- /* unlock catalog b-tree */
- (void) hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_RELEASE, current_proc());
-
- VCBTOHFS(vcb)->hfs_metadata_createdate = metadata_createdate;
-Err_Exit:
- CLEAN_CATALOGDATA(&catInfo.nodeData);
+ /* Lock catalog b-tree */
+ if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID,
+ LK_EXCLUSIVE, p) != 0) {
+ goto exit;
+ }
+ catlock = 1;
+
+ /* Build a fake cnode */
+ cat_convertattr(hfsmp, (CatalogRecord *)&filerec, &cnode.c_attr,
+ &dfork.ff_data, &rfork.ff_data);
+ cnode.c_desc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid;
+ cnode.c_desc.cd_nameptr = filename;
+ cnode.c_desc.cd_namelen = namelen;
+ cnode.c_desc.cd_cnid = cnode.c_attr.ca_fileid;
+ cnode.c_blocks = dfork.ff_blocks + rfork.ff_blocks;
+
+ /* Position iterator at previous entry */
+ if (BTIterateRecord(fcb, kBTreePrevRecord, iterator,
+ NULL, NULL) != 0) {
+ break;
+ }
- return dirID;
-}
+ /* Truncate the file to zero (both forks) */
+ if (dfork.ff_blocks > 0) {
+ u_int64_t fsize;
+
+ dfork.ff_cp = &cnode;
+ cnode.c_datafork = &dfork;
+ cnode.c_rsrcfork = NULL;
+ fsize = (u_int64_t)dfork.ff_blocks * (u_int64_t)HFSTOVCB(hfsmp)->blockSize;
+ while (fsize > 0) {
+ if (fsize > HFS_BIGFILE_SIZE) {
+ fsize -= HFS_BIGFILE_SIZE;
+ } else {
+ fsize = 0;
+ }
+
+ if (TruncateFileC(vcb, (FCB*)&dfork, fsize, false) != 0) {
+ printf("error truncting data fork!\n");
+ break;
+ }
+
+ //
+ // if we're iteratively truncating this file down,
+ // then end the transaction and start a new one so
+ // that no one transaction gets too big.
+ //
+ if (fsize > 0 && started_tr) {
+ journal_end_transaction(hfsmp->jnl);
+ if (journal_start_transaction(hfsmp->jnl) != 0) {
+ started_tr = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (rfork.ff_blocks > 0) {
+ rfork.ff_cp = &cnode;
+ cnode.c_datafork = NULL;
+ cnode.c_rsrcfork = &rfork;
+ if (TruncateFileC(vcb, (FCB*)&rfork, 0, false) != 0) {
+ printf("error truncting rsrc fork!\n");
+ break;
+ }
+ }
+ /* Remove the file record from the Catalog */
+ if (cat_delete(hfsmp, &cnode.c_desc, &cnode.c_attr) != 0) {
+ printf("error deleting cat rec!\n");
+ break;
+ }
+
+ /* Update parent and volume counts */
+ hfsmp->hfs_privdir_attr.ca_entries--;
+ (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc,
+ &hfsmp->hfs_privdir_attr, NULL, NULL);
+ hfs_volupdate(hfsmp, VOL_RMFILE, 0);
+
+ /* Drop locks and end the transaction */
+ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
+ cat_postflight(hfsmp, &cookie, p);
+ catlock = catreserve = 0;
+ if (started_tr) {
+ journal_end_transaction(hfsmp->jnl);
+ started_tr = 0;
+ }
+ hfs_global_shared_lock_release(hfsmp);
+ shared_lock = 0;
-static void
-RemovedMetaDataDirectory(ExtendedVCB *vcb)
-{
- char name[32];
- hfsCatalogInfo catInfo;
- int retval;
+ } /* end if */
+ } /* end for */
- strncpy(name, HFSPLUS_PRIVATE_DIR, sizeof(name));
- INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName);
-
- /* lock catalog b-tree */
- retval = hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_SHARED, current_proc());
- if (retval) goto Err_Exit;
-
- /* If the HFSPLUSMETADATAFOLDER exists then delete it. */
- retval = GetCatalogNode(vcb, kRootDirID, name, strlen(name), kNoHint,
- &catInfo.nodeData, &catInfo.hint);
- if (retval == 0 && (catInfo.nodeData.cnd_type == kCatalogFolderNode)) {
- (void) DeleteCatalogNode(vcb, kRootDirID, name, catInfo.hint);
- printf("hfs_mount: removed \"%s\" from hfs volume \"%s\"\n", name, vcb->vcbVN);
+exit:
+ if (catlock) {
+ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
+ }
+ if (catreserve) {
+ cat_postflight(hfsmp, &cookie, p);
+ }
+ if (started_tr) {
+ journal_end_transaction(hfsmp->jnl);
+ }
+ if (shared_lock) {
+ hfs_global_shared_lock_release(hfsmp);
}
- /* unlock catalog b-tree */
- (void) hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_RELEASE, current_proc());
-
-Err_Exit:
- CLEAN_CATALOGDATA(&catInfo.nodeData);
+ FREE(iterator, M_TEMP);
+ hfsmp->hfs_flags |= HFS_CLEANED_ORPHANS;
}
+
/*
* This will return the correct logical block size for a given vnode.
* For most files, it is the allocation block size, for meta data like
logBlockSize = VTOHFS(vp)->hfs_logBlockSize;
if (vp->v_flag & VSYSTEM) {
- if (VTOH(vp)->fcbBTCBPtr != NULL) {
+ if (VTOF(vp)->fcbBTCBPtr != NULL) {
BTreeInfoRec bTreeInfo;
/*
* it in the first place??
*/
- (void) BTGetInformation (VTOFCB(vp), kBTreeInfoVersion, &bTreeInfo);
+ (void) BTGetInformation (VTOF(vp), kBTreeInfoVersion, &bTreeInfo);
logBlockSize = bTreeInfo.nodeSize;
- } else if (H_FILEID(VTOH(vp)) == kHFSAllocationFileID) {
+ } else if (VTOC(vp)->c_fileid == kHFSAllocationFileID) {
logBlockSize = VTOVCB(vp)->vcbVBMIOSize;
}
}
return logBlockSize;
}
+__private_extern__
+u_int32_t
+hfs_freeblks(struct hfsmount * hfsmp, int wantreserve)
+{
+ struct vcb_t *vcb = HFSTOVCB(hfsmp);
+ u_int32_t freeblks;
+
+ freeblks = vcb->freeBlocks;
+ if (wantreserve) {
+ if (freeblks > vcb->reserveBlocks)
+ freeblks -= vcb->reserveBlocks;
+ else
+ freeblks = 0;
+ }
+ if (freeblks > vcb->loanedBlocks)
+ freeblks -= vcb->loanedBlocks;
+ else
+ freeblks = 0;
+
+#ifdef HFS_SPARSE_DEV
+ /*
+ * When the underlying device is sparse, check the
+ * available space on the backing store volume.
+ */
+ if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) && hfsmp->hfs_backingfs_rootvp) {
+ struct statfs statbuf; /* 272 bytes */
+ u_int32_t vfreeblks;
+ u_int32_t loanedblks;
+ struct mount * backingfs_mp;
+
+ backingfs_mp = hfsmp->hfs_backingfs_rootvp->v_mount;
+
+ if (VFS_STATFS(backingfs_mp, &statbuf, current_proc()) == 0) {
+ vfreeblks = statbuf.f_bavail;
+ /* Normalize block count if needed. */
+ if (statbuf.f_bsize != vcb->blockSize) {
+ vfreeblks = ((u_int64_t)vfreeblks * (u_int64_t)statbuf.f_bsize) / vcb->blockSize;
+ }
+ if (vfreeblks > hfsmp->hfs_sparsebandblks)
+ vfreeblks -= hfsmp->hfs_sparsebandblks;
+ else
+ vfreeblks = 0;
+
+ /* Take into account any delayed allocations. */
+ loanedblks = 2 * vcb->loanedBlocks;
+ if (vfreeblks > loanedblks)
+ vfreeblks -= loanedblks;
+ else
+ vfreeblks = 0;
+
+ freeblks = MIN(vfreeblks, freeblks);
+ }
+ }
+#endif /* HFS_SPARSE_DEV */
+
+ return (freeblks);
+}
+
/*
* Map HFS Common errors (negative) to BSD error codes (positive).
* Positive errors (ie BSD errors) are passed through unchanged.
*/
short MacToVFSError(OSErr err)
{
- if (err >= 0) {
- if (err > 0) {
- DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err));
- };
- return err;
- };
+ if (err >= 0)
+ return err;
- if (err != 0) {
- DBG_ERR(("MacToVFSError: mapping error code %d...\n", err));
- };
-
switch (err) {
- case dirFulErr: /* -33 */
- case dskFulErr: /* -34 */
- case btNoSpaceAvail: /* -32733 */
- case fxOvFlErr: /* -32750 */
- return ENOSPC; /* +28 */
-
- case btBadNode: /* -32731 */
- case ioErr: /* -36 */
- return EIO; /* +5 */
-
- case mFulErr: /* -41 */
- case memFullErr: /* -108 */
- return ENOMEM; /* +12 */
-
- case tmfoErr: /* -42 */
- /* Consider EMFILE (Too many open files, 24)? */
- return ENFILE; /* +23 */
-
- case nsvErr: /* -35 */
- case fnfErr: /* -43 */
- case dirNFErr: /* -120 */
- case fidNotFound: /* -1300 */
- return ENOENT; /* +2 */
-
- case wPrErr: /* -44 */
- case vLckdErr: /* -46 */
- case fsDSIntErr: /* -127 */
- return EROFS; /* +30 */
-
- case opWrErr: /* -49 */
- case fLckdErr: /* -45 */
- return EACCES; /* +13 */
-
- case permErr: /* -54 */
- case wrPermErr: /* -61 */
- return EPERM; /* +1 */
-
- case fBsyErr: /* -47 */
- return EBUSY; /* +16 */
-
- case dupFNErr: /* -48 */
- case fidExists: /* -1301 */
- case cmExists: /* -32718 */
- case btExists: /* -32734 */
- return EEXIST; /* +17 */
-
- case rfNumErr: /* -51 */
- return EBADF; /* +9 */
-
- case notAFileErr: /* -1302 */
- return EISDIR; /* +21 */
-
- case cmNotFound: /* -32719 */
- case btNotFound: /* -32735 */
- return ENOENT; /* 28 */
-
- case cmNotEmpty: /* -32717 */
- return ENOTEMPTY; /* 66 */
-
- case cmFThdDirErr: /* -32714 */
- return EISDIR; /* 21 */
-
- case fxRangeErr: /* -32751 */
- return EIO; /* 5 */
-
- case bdNamErr: /* -37 */
- return ENAMETOOLONG; /* 63 */
-
- case fnOpnErr: /* -38 */
- case eofErr: /* -39 */
- case posErr: /* -40 */
- case paramErr: /* -50 */
- case badMDBErr: /* -60 */
- case badMovErr: /* -122 */
- case sameFileErr: /* -1306 */
- case badFidErr: /* -1307 */
- case fileBoundsErr: /* -1309 */
- return EINVAL; /* +22 */
-
- case fsBTBadNodeSize:
+ case dskFulErr: /* -34 */
+ case btNoSpaceAvail: /* -32733 */
+ return ENOSPC;
+ case fxOvFlErr: /* -32750 */
+ return EOVERFLOW;
+
+ case btBadNode: /* -32731 */
+ return EBADF;
+
+ case memFullErr: /* -108 */
+ return ENOMEM; /* +12 */
+
+ case cmExists: /* -32718 */
+ case btExists: /* -32734 */
+ return EEXIST; /* +17 */
+
+ case cmNotFound: /* -32719 */
+ case btNotFound: /* -32735 */
+ return ENOENT; /* 28 */
+
+ case cmNotEmpty: /* -32717 */
+ return ENOTEMPTY; /* 66 */
+
+ case cmFThdDirErr: /* -32714 */
+ return EISDIR; /* 21 */
+
+ case fxRangeErr: /* -32751 */
+ return ERANGE;
+
+ case bdNamErr: /* -37 */
+ return ENAMETOOLONG; /* 63 */
+
+ case paramErr: /* -50 */
+ case fileBoundsErr: /* -1309 */
+ return EINVAL; /* +22 */
+
+ case fsBTBadNodeSize:
return ENXIO;
- default:
- DBG_UTILS(("Unmapped MacOS error: %d\n", err));
- return EIO; /* +5 */
+
+ default:
+ return EIO; /* +5 */
}
}
/*
- * All of our debugging functions
+ * Get the directory entry name hint for a given index.
+ * The directory cnode (dcp) must be locked.
*/
+__private_extern__
+char *
+hfs_getnamehint(struct cnode *dcp, int index)
+{
+ struct hfs_index *entry;
+ void *self;
+
+ if (index > 0) {
+ self = current_act();
+ SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) {
+ if ((entry->hi_index == index)
+ && (entry->hi_thread == self))
+ return (entry->hi_name);
+ }
+ }
-#if HFS_DIAGNOSTIC
+ return (NULL);
+}
-void debug_vn_status (char* introStr, struct vnode *vn)
+/*
+ * Save a directory entry name hint for a given index.
+ * The directory cnode (dcp) must be locked.
+ */
+__private_extern__
+void
+hfs_savenamehint(struct cnode *dcp, int index, const char * namehint)
{
- DBG_VOP(("%s:\t",introStr));
- if (vn != NULL)
- {
- if (vn->v_tag != VT_HFS)
- {
- DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn));
- }
- else if(vn->v_tag==VT_HFS && (vn->v_data==NULL || VTOH((vn))->h_valid != HFS_VNODE_MAGIC))
- {
- DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n"));
- }
- else
- {
- DBG_VOP(("r: %d & ", vn->v_usecount));
- if (lockstatus(&VTOH(vn)->h_lock))
- {
- DBG_VOP_CONT(("is L\n"));
- }
- else
- {
- DBG_VOP_CONT(("is U\n"));
- }
- }
- }
- else
- {
- DBG_VOP(("vnode is NULL\n"));
- };
+ struct hfs_index *entry;
+ int len;
+
+ if (index > 0) {
+ len = strlen(namehint);
+ MALLOC(entry, struct hfs_index *, len + sizeof(struct hfs_index),
+ M_TEMP, M_WAITOK);
+ entry->hi_index = index;
+ entry->hi_thread = current_act();
+ bcopy(namehint, entry->hi_name, len + 1);
+ SLIST_INSERT_HEAD(&dcp->c_indexlist, entry, hi_link);
+ }
}
-void debug_vn_print (char* introStr, struct vnode *vn)
+/*
+ * Release the directory entry name hint for a given index.
+ * The directory cnode (dcp) must be locked.
+ */
+__private_extern__
+void
+hfs_relnamehint(struct cnode *dcp, int index)
{
-// DBG_FUNC_NAME("DBG_VN_PRINT");
- DBG_ASSERT (vn != NULL);
- DBG_VFS(("%s: ",introStr));
- DBG_VFS_CONT(("vnode: 0x%x is a ", (uint)vn));
- switch (vn->v_tag)
- {
- case VT_UFS:
- DBG_VFS_CONT(("%s","UFS"));
- break;
- case VT_HFS:
- DBG_VFS_CONT(("%s","HFS"));
- break;
- default:
- DBG_VFS_CONT(("%s","UNKNOWN"));
- break;
- }
-
- DBG_VFS_CONT((" vnode\n"));
- if (vn->v_tag==VT_HFS)
- {
- if (vn->v_data==NULL)
- {
- DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n"));
- }
- else
- {
- DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn)), H_FILEID(VTOH(vn))));
- }
- }
- else
- DBG_VFS((" "));
-
- DBG_VFS_CONT(("Refcount: %d\n", vn->v_usecount));
- if (VOP_ISLOCKED(vn))
- {
- DBG_VFS((" The vnode is locked\n"));
- }
- else
- {
- DBG_VFS((" The vnode is not locked\n"));
- }
+ struct hfs_index *entry;
+ void *self;
+
+ if (index > 0) {
+ self = current_act();
+ SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) {
+ if ((entry->hi_index == index)
+ && (entry->hi_thread == self)) {
+ SLIST_REMOVE(&dcp->c_indexlist, entry, hfs_index,
+ hi_link);
+ FREE(entry, M_TEMP);
+ break;
+ }
+ }
+ }
}
-void debug_rename_test_locks (char* introStr,
- struct vnode *fvp,
- struct vnode *fdvp,
- struct vnode *tvp,
- struct vnode *tdvp,
- int fstatus,
- int fdstatus,
- int tstatus,
- int tdstatus
-)
+/*
+ * Release all directory entry name hints.
+ */
+__private_extern__
+void
+hfs_relnamehints(struct cnode *dcp)
{
- DBG_VOP(("\t%s: ", introStr));
- if (fvp) {if(lockstatus(&VTOH(fvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
- if (fdvp) {if(lockstatus(&VTOH(fdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
- if (tvp) {if(lockstatus(&VTOH(tvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
- if (tdvp) {if(lockstatus(&VTOH(tdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
- DBG_VFS_CONT(("\n"));
-
- if (fvp) {
- if (lockstatus(&VTOH(fvp)->h_lock)) {
- if (fstatus==VOPDBG_UNLOCKED) {
- DBG_VOP(("\tfvp should be NOT LOCKED and it is\n"));
- }
- } else if (fstatus == VOPDBG_LOCKED) {
- DBG_VOP(("\tfvp should be LOCKED and it isnt\n"));
- }
- }
-
- if (fdvp) {
- if (lockstatus(&VTOH(fdvp)->h_lock)) {
- if (fdstatus==VOPDBG_UNLOCKED) {
- DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n"));
- }
- } else if (fdstatus == VOPDBG_LOCKED) {
- DBG_VOP(("\tfdvp should be LOCKED and it isnt\n"));
- }
- }
-
- if (tvp) {
- if (lockstatus(&VTOH(tvp)->h_lock)) {
- if (tstatus==VOPDBG_UNLOCKED) {
- DBG_VOP(("\ttvp should be NOT LOCKED and it is\n"));
- }
- } else if (tstatus == VOPDBG_LOCKED) {
- DBG_VOP(("\ttvp should be LOCKED and it isnt\n"));
- }
- }
-
- if (tdvp) {
- if (lockstatus(&VTOH(tdvp)->h_lock)) {
- if (tdstatus==VOPDBG_UNLOCKED) {
- DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n"));
- }
- } else if (tdstatus == VOPDBG_LOCKED) {
- DBG_VOP(("\ttdvp should be LOCKED and it isnt\n"));
-
- }
- }
-
+ struct hfs_index *entry;
+ struct hfs_index *next;
+
+ if (!SLIST_EMPTY(&dcp->c_indexlist)) {
+ for(entry = SLIST_FIRST(&dcp->c_indexlist);
+ entry != NULL;
+ entry = next) {
+ next = SLIST_NEXT(entry, hi_link);
+ SLIST_REMOVE(&dcp->c_indexlist, entry, hfs_index, hi_link);
+ FREE(entry, M_TEMP);
+ }
+ }
}
-#endif /* HFS_DIAGNOSTIC */
-#if HFS_DIAGNOSTIC
-void debug_check_buffersizes(struct vnode *vp, struct hfsnode *hp, struct buf *bp) {
- DBG_ASSERT(bp->b_validoff == 0);
- DBG_ASSERT(bp->b_dirtyoff == 0);
- DBG_ASSERT((bp->b_bcount == HTOHFS(hp)->hfs_logBlockSize) ||
- ((bp->b_bcount % 512 == 0) &&
- (bp->b_validend > 0) &&
- (bp->b_dirtyend > 0) &&
- (bp->b_bcount < HTOHFS(hp)->hfs_logBlockSize)));
-
- if (bp->b_validend == 0) {
- DBG_ASSERT(bp->b_dirtyend == 0);
- } else {
- DBG_ASSERT(bp->b_validend == bp->b_bcount);
- DBG_ASSERT(bp->b_dirtyend <= bp->b_bcount);
- };
+/*
+ * Perform a case-insensitive compare of two UTF-8 filenames.
+ *
+ * Returns 0 if the strings match.
+ */
+__private_extern__
+int
+hfs_namecmp(const char *str1, size_t len1, const char *str2, size_t len2)
+{
+ u_int16_t *ustr1, *ustr2;
+ size_t ulen1, ulen2;
+ size_t maxbytes;
+ int cmp = -1;
+
+ if (len1 != len2)
+ return (cmp);
+
+ maxbytes = kHFSPlusMaxFileNameChars << 1;
+ MALLOC(ustr1, u_int16_t *, maxbytes << 1, M_TEMP, M_WAITOK);
+ ustr2 = ustr1 + (maxbytes >> 1);
+
+ if (utf8_decodestr(str1, len1, ustr1, &ulen1, maxbytes, ':', 0) != 0)
+ goto out;
+ if (utf8_decodestr(str2, len2, ustr2, &ulen2, maxbytes, ':', 0) != 0)
+ goto out;
+
+ cmp = FastUnicodeCompare(ustr1, ulen1>>1, ustr2, ulen2>>1);
+out:
+ FREE(ustr1, M_TEMP);
+ return (cmp);
}
-void debug_check_blocksizes(struct vnode *vp) {
- struct hfsnode *hp = VTOH(vp);
- struct buf *bp;
+__private_extern__
+int
+hfs_early_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
+ void *_args, int embeddedOffset, int mdb_offset,
+ HFSMasterDirectoryBlock *mdbp, struct ucred *cred)
+{
+ JournalInfoBlock *jibp;
+ struct buf *jinfo_bp, *bp;
+ int sectors_per_fsblock, arg_flags=0, arg_tbufsz=0;
+ int retval, blksize = hfsmp->hfs_phys_block_size;
+ struct vnode *devvp;
+ struct hfs_mount_args *args = _args;
+
+ devvp = hfsmp->hfs_devvp;
+
+ if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS)) {
+ arg_flags = args->journal_flags;
+ arg_tbufsz = args->journal_tbuffer_size;
+ }
+
+ sectors_per_fsblock = SWAP_BE32(vhp->blockSize) / blksize;
+
+ retval = meta_bread(devvp,
+ embeddedOffset/blksize +
+ (SWAP_BE32(vhp->journalInfoBlock)*sectors_per_fsblock),
+ SWAP_BE32(vhp->blockSize), cred, &jinfo_bp);
+ if (retval)
+ return retval;
+
+ jibp = (JournalInfoBlock *)jinfo_bp->b_data;
+ jibp->flags = SWAP_BE32(jibp->flags);
+ jibp->offset = SWAP_BE64(jibp->offset);
+ jibp->size = SWAP_BE64(jibp->size);
+
+ if (jibp->flags & kJIJournalInFSMask) {
+ hfsmp->jvp = hfsmp->hfs_devvp;
+ } else {
+ printf("hfs: journal not stored in fs! don't know what to do.\n");
+ brelse(jinfo_bp);
+ return EINVAL;
+ }
+
+ // save this off for the hack-y check in hfs_remove()
+ hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize);
+ hfsmp->jnl_size = jibp->size;
+
+ if (jibp->flags & kJIJournalNeedInitMask) {
+ printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
+ jibp->offset + (off_t)embeddedOffset, jibp->size);
+ hfsmp->jnl = journal_create(hfsmp->jvp,
+ jibp->offset + (off_t)embeddedOffset,
+ jibp->size,
+ devvp,
+ blksize,
+ arg_flags,
+ arg_tbufsz,
+ hfs_sync_metadata, hfsmp->hfs_mp);
+
+ // no need to start a transaction here... if this were to fail
+ // we'd just re-init it on the next mount.
+ jibp->flags &= ~kJIJournalNeedInitMask;
+ jibp->flags = SWAP_BE32(jibp->flags);
+ jibp->offset = SWAP_BE64(jibp->offset);
+ jibp->size = SWAP_BE64(jibp->size);
+ bwrite(jinfo_bp);
+ jinfo_bp = NULL;
+ jibp = NULL;
+ } else {
+ //printf("hfs: Opening the journal (joffset 0x%llx sz 0x%llx vhp_blksize %d)...\n",
+ // jibp->offset + (off_t)embeddedOffset,
+ // jibp->size, SWAP_BE32(vhp->blockSize));
+
+ hfsmp->jnl = journal_open(hfsmp->jvp,
+ jibp->offset + (off_t)embeddedOffset,
+ jibp->size,
+ devvp,
+ blksize,
+ arg_flags,
+ arg_tbufsz,
+ hfs_sync_metadata, hfsmp->hfs_mp);
+
+ brelse(jinfo_bp);
+ jinfo_bp = NULL;
+ jibp = NULL;
+
+ if (hfsmp->jnl && mdbp) {
+ // reload the mdb because it could have changed
+ // if the journal had to be replayed.
+ if (mdb_offset == 0) {
+ mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
+ }
+ retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp);
+ if (retval) {
+ brelse(bp);
+ printf("hfs: failed to reload the mdb after opening the journal (retval %d)!\n",
+ retval);
+ return retval;
+ }
+ bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512);
+ brelse(bp);
+ bp = NULL;
+ }
+ }
- if (vp->v_flag & VSYSTEM) return;
- for (bp = vp->v_cleanblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) {
- debug_check_buffersizes(vp, hp, bp);
- };
+ //printf("journal @ 0x%x\n", hfsmp->jnl);
+
+ // if we expected the journal to be there and we couldn't
+ // create it or open it then we have to bail out.
+ if (hfsmp->jnl == NULL) {
+ printf("hfs: early jnl init: failed to open/create the journal (retval %d).\n", retval);
+ return EINVAL;
+ }
- for (bp = vp->v_dirtyblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) {
- debug_check_buffersizes(vp, hp, bp);
- };
+ return 0;
}
-void debug_check_catalogdata(struct CatalogNodeData *cat) {
- if (cat->cnm_nameptr == NULL) {
- DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0);
+//
+// This function will go and re-locate the .journal_info_block and
+// the .journal files in case they moved (which can happen if you
+// run Norton SpeedDisk). If we fail to find either file we just
+// disable journaling for this volume and return. We turn off the
+// journaling bit in the vcb and assume it will get written to disk
+// later (if it doesn't on the next mount we'd do the same thing
+// again which is harmless). If we disable journaling we don't
+// return an error so that the volume is still mountable.
+//
+// If the info we find for the .journal_info_block and .journal files
+// isn't what we had stored, we re-set our cached info and proceed
+// with opening the journal normally.
+//
+static int
+hfs_late_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, void *_args)
+{
+ JournalInfoBlock *jibp;
+ struct buf *jinfo_bp, *bp;
+ int sectors_per_fsblock, arg_flags=0, arg_tbufsz=0;
+ int retval, need_flush = 0, write_jibp = 0;
+ struct vnode *devvp;
+ struct cat_attr jib_attr, jattr;
+ struct cat_fork jib_fork, jfork;
+ ExtendedVCB *vcb;
+ u_long fid;
+ struct hfs_mount_args *args = _args;
+
+ devvp = hfsmp->hfs_devvp;
+ vcb = HFSTOVCB(hfsmp);
+
+ if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS)) {
+ if (args->journal_disable) {
+ return 0;
+ }
+
+ arg_flags = args->journal_flags;
+ arg_tbufsz = args->journal_tbuffer_size;
+ }
+
+ fid = GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jib_attr, &jib_fork);
+ if (fid == 0 || jib_fork.cf_extents[0].startBlock == 0 || jib_fork.cf_size == 0) {
+ printf("hfs: can't find the .journal_info_block! disabling journaling (start: %d).\n",
+ jib_fork.cf_extents[0].startBlock);
+ vcb->vcbAtrb &= ~kHFSVolumeJournaledMask;
+ return 0;
}
- else if (cat->cnm_nameptr == cat->cnm_namespace) {
- DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0);
- }
- else {
- DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == kCatNameIsAllocated);
- }
-
- if (cat->cnm_nameptr) {
- DBG_ASSERT(strlen(cat->cnm_nameptr) == cat->cnm_length);
+ hfsmp->hfs_jnlinfoblkid = fid;
+
+ // make sure the journal_info_block begins where we think it should.
+ if (SWAP_BE32(vhp->journalInfoBlock) != jib_fork.cf_extents[0].startBlock) {
+ printf("hfs: The journal_info_block moved (was: %d; is: %d). Fixing up\n",
+ SWAP_BE32(vhp->journalInfoBlock), jib_fork.cf_extents[0].startBlock);
+
+ vcb->vcbJinfoBlock = jib_fork.cf_extents[0].startBlock;
+ vhp->journalInfoBlock = SWAP_BE32(jib_fork.cf_extents[0].startBlock);
}
-
- if (cat->cnm_flags & kCatNameIsConsumed) {
- DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0);
- }
- if (cat->cnm_flags & kCatNameNoCopyName) {
- DBG_ASSERT((cat->cnm_flags & (kCatNameIsAllocated|kCatNameIsConsumed|kCatNameIsMangled)) == 0);
- DBG_ASSERT(cat->cnm_length == 0);
- DBG_ASSERT(cat->cnm_nameptr == 0);
- DBG_ASSERT(strlen(cat->cnm_namespace) == 0);
- }
-}
+ sectors_per_fsblock = SWAP_BE32(vhp->blockSize) / hfsmp->hfs_phys_block_size;
+ retval = meta_bread(devvp,
+ vcb->hfsPlusIOPosOffset / hfsmp->hfs_phys_block_size +
+ (SWAP_BE32(vhp->journalInfoBlock)*sectors_per_fsblock),
+ SWAP_BE32(vhp->blockSize), NOCRED, &jinfo_bp);
+ if (retval) {
+ printf("hfs: can't read journal info block. disabling journaling.\n");
+ vcb->vcbAtrb &= ~kHFSVolumeJournaledMask;
+ return 0;
+ }
+
+ jibp = (JournalInfoBlock *)jinfo_bp->b_data;
+ jibp->flags = SWAP_BE32(jibp->flags);
+ jibp->offset = SWAP_BE64(jibp->offset);
+ jibp->size = SWAP_BE64(jibp->size);
+
+ fid = GetFileInfo(vcb, kRootDirID, ".journal", &jattr, &jfork);
+ if (fid == 0 || jfork.cf_extents[0].startBlock == 0 || jfork.cf_size == 0) {
+ printf("hfs: can't find the journal file! disabling journaling (start: %d)\n",
+ jfork.cf_extents[0].startBlock);
+ brelse(jinfo_bp);
+ vcb->vcbAtrb &= ~kHFSVolumeJournaledMask;
+ return 0;
+ }
+ hfsmp->hfs_jnlfileid = fid;
-extern void hfs_vhash_dbg(struct hfsnode *hp);
+ // make sure the journal file begins where we think it should.
+ if ((jibp->offset / (u_int64_t)vcb->blockSize) != jfork.cf_extents[0].startBlock) {
+ printf("hfs: The journal file moved (was: %lld; is: %d). Fixing up\n",
+ (jibp->offset / (u_int64_t)vcb->blockSize), jfork.cf_extents[0].startBlock);
-/* Checks the valicity of a hfs vnode */
-void debug_check_vnode(struct vnode *vp, int stage) {
- struct hfsnode *hp;
- u_long size;
- int i;
+ jibp->offset = (u_int64_t)jfork.cf_extents[0].startBlock * (u_int64_t)vcb->blockSize;
+ write_jibp = 1;
+ }
- /* vcb stuff */
- if (VTOHFS(vp)->hfs_mount_flags & kHFSBootVolumeInconsistentMask)
- DEBUG_BREAK_MSG(("Volume is damaged!"));
+ // check the size of the journal file.
+ if (jibp->size != (u_int64_t)jfork.cf_extents[0].blockCount*vcb->blockSize) {
+ printf("hfs: The journal file changed size! (was %lld; is %lld). Fixing up.\n",
+ jibp->size, (u_int64_t)jfork.cf_extents[0].blockCount*vcb->blockSize);
+
+ jibp->size = (u_int64_t)jfork.cf_extents[0].blockCount * vcb->blockSize;
+ write_jibp = 1;
+ }
- /* vnode stuff */
- if (vp==NULL)
- DEBUG_BREAK_MSG(("Null vnode"));
- if (vp->v_tag != VT_HFS)
- DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp->v_tag));
- if (vp->v_data==NULL)
- DEBUG_BREAK_MSG(("v_data is NULL"));
-
- /* hfsnode stuff */
- hp = VTOH(vp);
- if (hp->h_valid != HFS_VNODE_MAGIC)
- DEBUG_BREAK_MSG(("Bad Formed HFS node"));
- if (hp->h_vp==NULL || hp->h_vp!=vp)
- DEBUG_BREAK_MSG(("Bad hfsnode vnode pte"));
- if (hp->h_meta == NULL)
- DEBUG_BREAK_MSG(("Bad hfsnode meta ptr"));
- switch (H_FORKTYPE(hp)) {
- case kDataFork:
- case kRsrcFork:
- if ((hp->h_meta->h_siblinghead.cqh_first == NULL) || (hp->h_meta->h_siblinghead.cqh_last == NULL))
- DEBUG_BREAK_MSG(("Null sibling header"));
- if ((hp->h_sibling.cqe_next==NULL) || (hp->h_sibling.cqe_prev==NULL))
- DEBUG_BREAK_MSG(("Null sibling list"));
- if (hp->h_meta->h_usecount<1 || hp->h_meta->h_usecount>2)
- DEBUG_BREAK_MSG(("Bad sibling usecount"));
- break;
- case kDirectory:
- case kSysFile:
- if ((hp->h_meta->h_siblinghead.cqh_first != NULL) || (hp->h_meta->h_siblinghead.cqh_last != NULL))
- DEBUG_BREAK_MSG(("Non Null sibling header"));
- if ((hp->h_sibling.cqe_next!=NULL) || (hp->h_sibling.cqe_prev!=NULL))
- DEBUG_BREAK_MSG(("Null sibling list"));
- if (hp->h_meta->h_usecount!=1)
- DEBUG_BREAK_MSG(("Bad usecount"));
-
- break;
- default:
- DEBUG_BREAK_MSG(("Bad hfsnode fork type"));
- }
-
- /* hfsmeta stuff */
- if (hp->h_meta->h_devvp == NULL)
- DEBUG_BREAK_MSG(("Bad hfsnode dev vnode"));
- if (H_DEV(hp) == 0)
- DEBUG_BREAK_MSG(("Bad dev id"));
- if (H_FILEID(hp) == 0)
- DEBUG_BREAK_MSG(("Bad file id"));
-
- if (((hp->h_meta->h_metaflags & IN_DATANODE)==0) && (H_DIRID(hp) == 0) && (H_FILEID(hp) != 1))
- DEBUG_BREAK_MSG(("Bad dir id"));
-
- if (hp->h_meta->h_namePtr == NULL && hp->h_meta->h_namelen!=0)
- DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0"));
- if (hp->h_meta->h_namePtr != NULL && strlen(hp->h_meta->h_namePtr) != hp->h_meta->h_namelen)
- DEBUG_BREAK_MSG(("Bad hfs meta h_namelen"));
+ if (jibp->flags & kJIJournalInFSMask) {
+ hfsmp->jvp = hfsmp->hfs_devvp;
+ } else {
+ printf("hfs: journal not stored in fs! don't know what to do.\n");
+ brelse(jinfo_bp);
+ return EINVAL;
+ }
+
+ // save this off for the hack-y check in hfs_remove()
+ hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize);
+ hfsmp->jnl_size = jibp->size;
+
+ if (jibp->flags & kJIJournalNeedInitMask) {
+ printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
+ jibp->offset + (off_t)vcb->hfsPlusIOPosOffset, jibp->size);
+ hfsmp->jnl = journal_create(hfsmp->jvp,
+ jibp->offset + (off_t)vcb->hfsPlusIOPosOffset,
+ jibp->size,
+ devvp,
+ hfsmp->hfs_phys_block_size,
+ arg_flags,
+ arg_tbufsz,
+ hfs_sync_metadata, hfsmp->hfs_mp);
+
+ // no need to start a transaction here... if this were to fail
+ // we'd just re-init it on the next mount.
+ jibp->flags &= ~kJIJournalNeedInitMask;
+ write_jibp = 1;
+
+ } else {
+ //
+ // if we weren't the last person to mount this volume
+ // then we need to throw away the journal because it
+ // is likely that someone else mucked with the disk.
+ // if the journal is empty this is no big deal. if the
+ // disk is dirty this prevents us from replaying the
+ // journal over top of changes that someone else made.
+ //
+ arg_flags |= JOURNAL_RESET;
+
+ //printf("hfs: Opening the journal (joffset 0x%llx sz 0x%llx vhp_blksize %d)...\n",
+ // jibp->offset + (off_t)vcb->hfsPlusIOPosOffset,
+ // jibp->size, SWAP_BE32(vhp->blockSize));
+
+ hfsmp->jnl = journal_open(hfsmp->jvp,
+ jibp->offset + (off_t)vcb->hfsPlusIOPosOffset,
+ jibp->size,
+ devvp,
+ hfsmp->hfs_phys_block_size,
+ arg_flags,
+ arg_tbufsz,
+ hfs_sync_metadata, hfsmp->hfs_mp);
+ }
+
+
+ if (write_jibp) {
+ jibp->flags = SWAP_BE32(jibp->flags);
+ jibp->offset = SWAP_BE64(jibp->offset);
+ jibp->size = SWAP_BE64(jibp->size);
- /* Check the hash */
- hfs_vhash_dbg(hp);
+ bwrite(jinfo_bp);
+ } else {
+ brelse(jinfo_bp);
+ }
+ jinfo_bp = NULL;
+ jibp = NULL;
- /* Check to see if we want to compare with the disk */
- if (stage > 200) {
- int retval;
- hfsCatalogInfo catInfo;
+ //printf("journal @ 0x%x\n", hfsmp->jnl);
+
+ // if we expected the journal to be there and we couldn't
+ // create it or open it then we have to bail out.
+ if (hfsmp->jnl == NULL) {
+ printf("hfs: late jnl init: failed to open/create the journal (retval %d).\n", retval);
+ return EINVAL;
+ }
- INIT_CATALOGDATA(&catInfo.nodeData, 0);
- catInfo.hint = 0;
+ return 0;
+}
- if (hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, current_proc()))
- return;
+/*
+ * Calculate the allocation zone for metadata.
+ *
+ * This zone includes the following:
+ * Allocation Bitmap file
+ * Overflow Extents file
+ * Journal file
+ * Quota files
+ * Clustered Hot files
+ * Catalog file
+ *
+ * METADATA ALLOCATION ZONE
+ * ____________________________________________________________________________
+ * | | | | | | |
+ * | BM | JF | OEF | CATALOG |---> | HOT FILES |
+ * |____|____|_____|_______________|______________________________|___________|
+ *
+ * <------------------------------- N * 128 MB ------------------------------->
+ *
+ */
+#define GIGABYTE (u_int64_t)(1024*1024*1024)
- if (hfs_getcatalog(VTOVCB(vp), H_DIRID(hp), hp->h_meta->h_namePtr, hp->h_meta->h_namelen, &catInfo))
- DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record"));
+#define OVERFLOW_DEFAULT_SIZE (4*1024*1024)
+#define OVERFLOW_MAXIMUM_SIZE (128*1024*1024)
+#define JOURNAL_DEFAULT_SIZE (8*1024*1024)
+#define JOURNAL_MAXIMUM_SIZE (512*1024*1024)
+#define HOTBAND_MINIMUM_SIZE (10*1024*1024)
+#define HOTBAND_MAXIMUM_SIZE (512*1024*1024)
- (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, current_proc());
+static void
+hfs_metadatazone_init(struct hfsmount *hfsmp)
+{
+ ExtendedVCB *vcb;
+ struct BTreeInfoRec btinfo;
+ u_int64_t fs_size;
+ u_int64_t zonesize;
+ u_int64_t temp;
+ u_int64_t filesize;
+ u_int32_t blk;
+ int items;
- if (H_FILEID(hp) != catInfo.nodeData.cnd_nodeID)
- DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch"));
- if (H_DIRID(hp) != catInfo.nodeData.cnm_parID)
- DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch"));
- if (strcmp(hp->h_meta->h_namePtr, catInfo.nodeData.cnm_nameptr) != 0)
- DEBUG_BREAK_MSG(("hfsnode catalog name mismatch"));
- /* Check dates too??? */
+ vcb = HFSTOVCB(hfsmp);
+ fs_size = (u_int64_t)vcb->blockSize * (u_int64_t)vcb->totalBlocks;
- CLEAN_CATALOGDATA(&catInfo.nodeData);
+ /*
+ * For volumes less than 10 GB, don't bother.
+ */
+ if (fs_size < ((u_int64_t)10 * GIGABYTE))
+ return;
+ /*
+ * Skip non-journaled volumes as well.
+ */
+ if (hfsmp->jnl == NULL)
+ return;
- }
+ /*
+ * Start with allocation bitmap (a fixed size).
+ */
+ zonesize = roundup(vcb->totalBlocks / 8, vcb->vcbVBMIOSize);
+ /*
+ * Overflow Extents file gets 4 MB per 100 GB.
+ */
+ items = fs_size / ((u_int64_t)100 * GIGABYTE);
+ filesize = (u_int64_t)(items + 1) * OVERFLOW_DEFAULT_SIZE;
+ if (filesize > OVERFLOW_MAXIMUM_SIZE)
+ filesize = OVERFLOW_MAXIMUM_SIZE;
+ zonesize += filesize;
+ hfsmp->hfs_overflow_maxblks = filesize / vcb->blockSize;
- /* Check Extents */
- {
- for(i = 0, size = 0; i < kHFSPlusExtentDensity; i++)
- {
- size += hp->fcbExtents[i].blockCount;
- }
+ /*
+ * Plan for at least 8 MB of journal for each
+ * 100 GB of disk space (up to a 512 MB).
+ */
+ items = fs_size / ((u_int64_t)100 * GIGABYTE);
+ filesize = (u_int64_t)(items + 1) * JOURNAL_DEFAULT_SIZE;
+ if (filesize > JOURNAL_MAXIMUM_SIZE)
+ filesize = JOURNAL_MAXIMUM_SIZE;
+ zonesize += filesize;
- if (hp->fcbEOF > hp->fcbPLen)
- DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF"));
+ /*
+ * Catalog file gets 10 MB per 1 GB.
+ *
+ * How about considering the current catalog size (used nodes * node size)
+ * and the current file data size to help estimate the required
+ * catalog size.
+ */
+ filesize = MIN((fs_size / 1024) * 10, GIGABYTE);
+ hfsmp->hfs_catalog_maxblks = filesize / vcb->blockSize;
+ zonesize += filesize;
- if (hp->fcbExtents[kHFSPlusExtentDensity-1].blockCount == 0) {
- if ((off_t)size * (off_t)VTOVCB(vp)->blockSize != hp->fcbPLen)
- DEBUG_BREAK_MSG(("fcbPLen does not match extents"));
- } else {
- if ( hp->fcbPLen < (off_t)size * (off_t)VTOVCB(vp)->blockSize)
- DEBUG_BREAK_MSG(("fcbPLen is smaller than extents"));
+ /*
+ * Add space for hot file region.
+ *
+ * ...for now, use 5 MB per 1 GB (0.5 %)
+ */
+ filesize = (fs_size / 1024) * 5;
+ if (filesize > HOTBAND_MAXIMUM_SIZE)
+ filesize = HOTBAND_MAXIMUM_SIZE;
+ else if (filesize < HOTBAND_MINIMUM_SIZE)
+ filesize = HOTBAND_MINIMUM_SIZE;
+ /*
+ * Calculate user quota file requirements.
+ */
+ items = QF_USERS_PER_GB * (fs_size / GIGABYTE);
+ if (items < QF_MIN_USERS)
+ items = QF_MIN_USERS;
+ else if (items > QF_MAX_USERS)
+ items = QF_MAX_USERS;
+ if (!powerof2(items)) {
+ int x = items;
+ items = 4;
+ while (x>>1 != 1) {
+ x = x >> 1;
+ items = items << 1;
+ }
}
- for(i = 0; i < kHFSPlusExtentDensity; i++)
- {
- if (hp->fcbExtents[i].blockCount == 0 || hp->fcbExtents[i].startBlock == 0)
- break;
- }
- if ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && i > kHFSExtentDensity)
- DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS"));
- if (i > kHFSPlusExtentDensity) {
- for(; i < kHFSPlusExtentDensity; i++)
- {
- if (hp->fcbExtents[i].blockCount != 0 || hp->fcbExtents[i].startBlock != 0)
- DEBUG_BREAK_MSG(("Illegal value in extents"));
- }
- }
+ filesize += (items + 1) * sizeof(struct dqblk);
+ /*
+ * Calculate group quota file requirements.
+ *
+ */
+ items = QF_GROUPS_PER_GB * (fs_size / GIGABYTE);
+ if (items < QF_MIN_GROUPS)
+ items = QF_MIN_GROUPS;
+ else if (items > QF_MAX_GROUPS)
+ items = QF_MAX_GROUPS;
+ if (!powerof2(items)) {
+ int x = items;
+ items = 4;
+ while (x>>1 != 1) {
+ x = x >> 1;
+ items = items << 1;
+ }
}
+ filesize += (items + 1) * sizeof(struct dqblk);
+ hfsmp->hfs_hotfile_maxblks = filesize / vcb->blockSize;
+ zonesize += filesize;
-
- /* BTree stuff */
- if (0 && vp->v_flag & VSYSTEM) {
- BTreeInfoRec info;
-
- BTGetInformation(hp, 0, &info);
- if (hp->fcbBTCBPtr == NULL)
- DEBUG_BREAK_MSG(("Null fcbBTCBPtr"));
- if (H_HINT(hp) == 0)
- DEBUG_BREAK_MSG(("hint is 0"));
- if (H_HINT(hp) > info.numNodes)
- DEBUG_BREAK_MSG(("hint > numNodes"));
- }
+ /*
+ * Round up entire zone to a bitmap block's worth.
+ * The extra space goes to the catalog file and hot file area.
+ */
+ temp = zonesize;
+ zonesize = roundup(zonesize, vcb->vcbVBMIOSize * 8 * vcb->blockSize);
+ temp = zonesize - temp; /* temp has extra space */
+ filesize += temp / 3;
+ hfsmp->hfs_catalog_maxblks += (temp - (temp / 3)) / vcb->blockSize;
+
+ /* Convert to allocation blocks. */
+ blk = zonesize / vcb->blockSize;
+
+ /* The default metadata zone location is at the start of volume. */
+ hfsmp->hfs_metazone_start = 1;
+ hfsmp->hfs_metazone_end = blk - 1;
+
+ /* The default hotfile area is at the end of the zone. */
+ hfsmp->hfs_hotfile_start = blk - (filesize / vcb->blockSize);
+ hfsmp->hfs_hotfile_end = hfsmp->hfs_metazone_end;
+ hfsmp->hfs_hotfile_freeblks = hfs_hotfile_freeblocks(hfsmp);
+#if 0
+ printf("HFS: metadata zone is %d to %d\n", hfsmp->hfs_metazone_start, hfsmp->hfs_metazone_end);
+ printf("HFS: hot file band is %d to %d\n", hfsmp->hfs_hotfile_start, hfsmp->hfs_hotfile_end);
+ printf("HFS: hot file band free blocks = %d\n", hfsmp->hfs_hotfile_freeblks);
+#endif
+ hfsmp->hfs_flags |= HFS_METADATA_ZONE;
+}
+
+
+static u_int32_t
+hfs_hotfile_freeblocks(struct hfsmount *hfsmp)
+{
+ ExtendedVCB *vcb = HFSTOVCB(hfsmp);
+ int freeblocks;
+
+ freeblocks = MetaZoneFreeBlocks(vcb);
+ /* Minus Extents overflow file reserve. */
+ freeblocks -=
+ hfsmp->hfs_overflow_maxblks - VTOF(vcb->extentsRefNum)->ff_blocks;
+ /* Minus catalog file reserve. */
+ freeblocks -=
+ hfsmp->hfs_catalog_maxblks - VTOF(vcb->catalogRefNum)->ff_blocks;
+ if (freeblocks < 0)
+ freeblocks = 0;
+
+ return MIN(freeblocks, hfsmp->hfs_hotfile_maxblks);
+}
+
+/*
+ * Determine if a file is a "virtual" metadata file.
+ * This includes journal and quota files.
+ */
+__private_extern__
+int
+hfs_virtualmetafile(struct cnode *cp)
+{
+ char * filename;
+
+
+ if (cp->c_parentcnid != kHFSRootFolderID)
+ return (0);
+ filename = cp->c_desc.cd_nameptr;
+ if (filename == NULL)
+ return (0);
+
+ if ((strcmp(filename, ".journal") == 0) ||
+ (strcmp(filename, ".journal_info_block") == 0) ||
+ (strcmp(filename, ".quota.user") == 0) ||
+ (strcmp(filename, ".quota.group") == 0) ||
+ (strcmp(filename, ".hotfiles.btree") == 0))
+ return (1);
+
+ return (0);
}
-#endif /* HFS_DIAGNOSTIC */