Source to bsd/hfs/hfs_vfsutils.c
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @[email protected]
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. 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 1.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.apple.com/publicsource 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."
*
* @[email protected]
*/
/* @(#)hfs_vfsutils.c 4.0
*
* (c) 1997-1999 Apple Computer, Inc. All Rights Reserved
*
* hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS.
*
* Change History (most recent first):
*
* 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.
* 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/fcntl.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/attr.h>
#include <sys/mount.h>
#include <libkern/libkern.h>
#include <mach/machine/simple_lock.h>
#include <mach/vm_param.h>
#include <kern/mapfs.h>
#include "hfs.h"
#include "hfs_dbg.h"
#include "hfscommon/headers/system/MacOSTypes.h"
#include "hfscommon/headers/system/MacOSStubs.h"
#include "hfscommon/headers/FileMgrInternal.h"
#include "hfscommon/headers/BTreesPrivate.h"
#include "hfscommon/headers/system/HFSUnicodeWrappers.h"
#define SUPPORTS_MAC_ALIASES 0
#define kMaxSecsForFsync 5
#define BYPASSBLOCKINGOPTIMIZATION 0
extern int (**hfs_vnodeop_p)();
extern int count_lock_queue __P((void));
OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb );
Boolean IsARamDiskDriver( void );
UInt16 DivUp( UInt32 byteRun, UInt32 blockSize );
extern struct tm *localtime __P((const time_t *));
extern time_t mktime __P((struct tm *));
int memcmp __P((const void *,const void *, size_t));
extern UInt16 CountRootFiles(ExtendedVCB *vcb);
extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
static int InitMetaFileVNode(struct vnode *vp, u_long eof, u_long clumpSize, void *extents,
HFSCatalogNodeID fileID, void * keyCompareProc);
static void ReleaseMetaFileVNode(struct vnode *vp);
//*******************************************************************************
// Routine: hfs_MountHFSVolume
//
//
//*******************************************************************************
OSErr hfs_MountHFSVolume( register struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb, struct proc *p)
{
ExtendedVCB *vcb = HFSTOVCB(hfsmp);
struct vnode *tmpvnode;
OSErr err;
DBG_FUNC_NAME("hfs_MountHFSVolume");
DBG_PRINT_FUNC_NAME();
if (hfsmp == nil || mdb == nil) /* exit if bad paramater */
return (EINVAL);
err = ValidMasterDirectoryBlock( mdb ); /* make sure this is an HFS disk */
if (err)
return MacToVFSError(err);
/*
* The MDB seems OK: transfer info from it into VCB
* Note - the VCB starts out clear (all zeros)
*
* vcbSigWord is the start of duplicate mdb/vcb info.
* copy all fields in mdb till the drVN field
*/
DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev);
bcopy( mdb, &(vcb->vcbSigWord), (Size)(&(mdb->drVN)) - (Size)mdb );
/*
* Copy the drVN field, which is a Pascal String to the vcb, which is a cstring
*/
bcopy( &mdb->drVN[1], vcb->vcbVN, mdb->drVN[0]);
vcb->vcbVN[mdb->drVN[0]] = '\0';
// Initialize our dirID/nodePtr cache associated with this volume.
err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
ReturnIfError( err );
/*
* Some fields like vcbNmAlBlks, vcbAlBlkSiz, and vcbFreeBks are just
* around for API compatability and the HFS/HFS Plus code uses new
* ExtendedVCB fields.
* note: vcbNmAlBlks * vcbAlBlkSiz still gives correct volume size
*/
vcb->totalBlocks = vcb->vcbNmAlBlks;
vcb->freeBlocks = vcb->vcbFreeBks;
vcb->blockSize = vcb->vcbAlBlkSiz;
hfsmp->hfs_log_block_size = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
// XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
if ( IsARamDiskDriver() )
{
vcb->vcbAtrb |= kHFSVolumeNoCacheRequiredMask; // yes: mark VCB as a RAM Disk
}
//-- copy all fields in mdb between drXTFlSize & drVolBkUp
bcopy( &(mdb->drVolBkUp), &(vcb->vcbVolBkUp), (Size)&(mdb->drXTFlSize) - (Size)&(mdb->drVolBkUp) ); // 66 bytes
vcb->vcbXTAlBlks = DivUp( mdb->drXTFlSize, vcb->blockSize ); // Pick up PEOF of extent B*-Tree
vcb->vcbCTAlBlks = DivUp( mdb->drCTFlSize, vcb->blockSize ); // Pick up PEOF of catalog B*-Tree
vcb->nextAllocation = mdb->drAllocPtr;
vcb->vcbAllocPtr = 0; // Restart the roving allocation ptr
vcb->vcbWrCnt++; // Compensate for write of MDB on last flush
VCB_LOCK_INIT(vcb);
/*
* Set up Extents B-tree vnode...
*/
err = GetInitializedVNode(hfsmp, &tmpvnode);
if (err) goto MtVolErr;
err = InitMetaFileVNode(tmpvnode, mdb->drXTFlSize, vcb->vcbXTClpSiz, &mdb->drXTExtRec,
kHFSExtentsFileID, CompareExtentKeys);
if (err) goto MtVolErr;
/*
* Set up Catalog B-tree vnode...
*/
err = GetInitializedVNode(hfsmp, &tmpvnode);
if (err) goto MtVolErr;
err = InitMetaFileVNode(tmpvnode, mdb->drCTFlSize, vcb->vcbCTClpSiz, &mdb->drCTExtRec,
kHFSCatalogFileID, CompareCatalogKeys);
if (err) goto MtVolErr;
if ( !(vcb->vcbAtrb & (short)kHFSVolumeUnmountedMask) )
{
UInt32 consistencyStatus;
vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; // From now until _Unmount (clear the bit)
DBG_VFS(("hfs_MountHFSVolume: calling MountCheck...\n"));
err = MountCheck(vcb, &consistencyStatus);
DBG_VFS(("hfs_MountHFSVolume: MountCheck returned %d and %08lx\n",err, consistencyStatus));
if ( err ) goto MtChkErr;
}
else
{
vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; // From now until _Unmount (clear the bit)
}
/*
* all done with b-trees so we can unlock now...
*/
VOP_UNLOCK(vcb->catalogRefNum, 0, p);
VOP_UNLOCK(vcb->extentsRefNum, 0, p);
err = noErr;
if ( err == noErr )
{
if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
{
MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
}
}
goto CmdDone;
MtChkErr:;
InvalidateCatalogCache( vcb );
err = EBADF;
//-- Release any resources allocated so far before exiting with an error:
MtVolErr:;
ReleaseMetaFileVNode(vcb->catalogRefNum);
ReleaseMetaFileVNode(vcb->extentsRefNum);
CmdDone:;
return( err );
}
//*******************************************************************************
// Routine: hfs_MountHFSPlusVolume
//
//
//*******************************************************************************
OSErr hfs_MountHFSPlusVolume( register struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, u_long embBlkOffset, struct proc *p)
{
register ExtendedVCB *vcb;
HFSPlusForkData *fdp;
struct vnode *tmpvnode;
OSErr retval;
if (hfsmp == nil || vhp == nil) /* exit if bad paramater */
return (EINVAL);
DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n", vhp->signature, vhp->version, vhp->blockSize));
retval = ValidVolumeHeader(vhp); /* make sure this is an HFS Plus disk */
if (retval)
return MacToVFSError(retval);
/*
* 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 = vhp->signature;
vcb->vcbCrDate = vhp->createDate; // NOTE: local time, not GMT!
vcb->vcbLsMod = UTCToLocal(vhp->modifyDate);
vcb->vcbAtrb = (UInt16) vhp->attributes; // VCB only uses lower 16 bits
vcb->vcbClpSiz = vhp->rsrcClumpSize;
vcb->vcbNxtCNID = vhp->nextCatalogID;
vcb->vcbVolBkUp = UTCToLocal(vhp->backupDate);
vcb->vcbWrCnt = vhp->writeCount;
vcb->vcbXTClpSiz = vhp->extentsFile.clumpSize;
vcb->vcbCTClpSiz = vhp->catalogFile.clumpSize;
vcb->vcbFilCnt = vhp->fileCount;
vcb->vcbDirCnt = vhp->folderCount;
/* copy 32 bytes of Finder info */
bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));
/*
* vcbFreeBks is the number of free bytes divided by the (HFS compatible) allocation block size. Since the
* number of free bytes could overflow a UInt32, we actually divide both free bytes and allocation block size by
* 512 before doing the division. This prevents intermediate values from overflowing until the volume size is
* 2 TB. It's OK to divide by 512 since HFS Plus requires allocation blocks to be a multiple of 512.
*/
HFSBlocksFromTotalSectors( (vhp->blockSize / 512) * vhp->totalBlocks, &vcb->vcbAlBlkSiz, &vcb->vcbNmAlBlks );
vcb->vcbFreeBks = (vhp->freeBlocks * (vhp->blockSize / 512)) / (vcb->vcbAlBlkSiz / 512);
vcb->vcbAlBlSt = 0; /* hfs+ allocation blocks start at first block of volume */
vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */
VCB_LOCK_INIT(vcb);
/* Now fill in the Extended VCB info */
vcb->nextAllocation = vhp->nextAllocation;
vcb->totalBlocks = vhp->totalBlocks;
vcb->freeBlocks = vhp->freeBlocks;
vcb->blockSize = vhp->blockSize;
vcb->allocationsClumpSize = vhp->allocationFile.clumpSize;
vcb->attributesClumpSize = vhp->attributesFile.clumpSize;
vcb->checkedDate = vhp->checkedDate;
vcb->encodingsBitmap = vhp->encodingsBitmap;
vcb->vcbAlBlSt = embBlkOffset;
vcb->hfsPlusIOPosOffset = embBlkOffset * 512;
/* Update the logical block size in the mount struct (currently set up from the wrapper MDB)
using the new blocksize value: */
hfsmp->hfs_log_block_size = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
// 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!!!!
if ( IsARamDiskDriver() )
vcb->vcbAtrb |= kHFSVolumeNoCacheRequiredMask; // yes: mark VCB as a RAM Disk
// Initialize our dirID/nodePtr cache associated with this volume.
retval = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
if (retval != noErr) goto ErrorExit;
/*
* Set up Extents B-tree vnode...
*/
retval = GetInitializedVNode(hfsmp, &tmpvnode);
if (retval) goto ErrorExit;
fdp = &vhp->extentsFile;
retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize.lo, fdp->clumpSize, &fdp->extents,
kHFSExtentsFileID, CompareExtentKeysPlus);
if (retval) goto ErrorExit;
/*
* Set up Catalog B-tree vnode...
*/
retval = GetInitializedVNode(hfsmp, &tmpvnode);
if (retval) goto ErrorExit;
fdp = &vhp->catalogFile;
retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize.lo, fdp->clumpSize, &fdp->extents,
kHFSCatalogFileID, CompareExtendedCatalogKeys);
if (retval) goto ErrorExit;
/*
* Set up Allocation file vnode...
*/
retval = GetInitializedVNode(hfsmp, &tmpvnode);
if (retval) goto ErrorExit;
VTOH(tmpvnode)->h_meta->h_logBlockSize = kHFSBlockSize; /* XXX does Allocation use GetBlock? */
VTOH(tmpvnode)->h_meta->h_physBlkPerLogBlk = 1;
fdp = &vhp->allocationFile;
retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize.lo, fdp->clumpSize, &fdp->extents,
kHFSAllocationFileID, NULL);
if (retval) goto ErrorExit;
/*
* Set up Attribute B-tree vnode (optional)...
*/
if (vhp->attributesFile.logicalSize.lo > 0) {
retval = GetInitializedVNode(hfsmp, &tmpvnode);
if (retval) goto ErrorExit;
fdp = &vhp->attributesFile;
retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize.lo, fdp->clumpSize, &fdp->extents,
kHFSAttributesFileID, CompareAttributeKeys);
if (retval) goto ErrorExit;
}
/*
* Now that Catalog file is open...
* get the root file count
* get the volume name from the catalog
*/
vcb->vcbNmFls = CountRootFiles(vcb); /* set up root file count */
DBG_VFS(("hfs_MountHFSPlusVolume: root file count was %d\n", vcb->vcbNmFls));
retval = MacToVFSError( GetVolumeNameFromCatalog(vcb) );
if (retval != noErr) goto ErrorExit;
/*
* if volume was not cleanly unmounted then do a consistency check
*/
if ( !(vcb->vcbAtrb & (short)kHFSVolumeUnmountedMask) )
{
UInt32 consistencyStatus;
vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; // From now until _Unmount (clear the bit)
DBG_VFS(("hfs_MountHFSPlusVolume: calling MountCheck...\n"));
retval = MacToVFSError( MountCheck(vcb, &consistencyStatus) );
DBG_VFS(("hfs_MountHFSPlusVolume: MountCheck returned %d and %08lx\n",retval, consistencyStatus));
if (retval) goto ErrorExit;
}
else
{
vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; // From now until _Unmount (clear the bit)
}
/*
* all done with metadata files so we can unlock now...
*/
if (vcb->attributesRefNum != NULL)
VOP_UNLOCK(vcb->attributesRefNum, 0, p);
VOP_UNLOCK(vcb->allocationsRefNum, 0, p);
VOP_UNLOCK(vcb->catalogRefNum, 0, p);
VOP_UNLOCK(vcb->extentsRefNum, 0, p);
if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
{
MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
}
DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval));
return (0);
ErrorExit:
/*
* A fatal error occured and the volume cannot be mounted
* release any resources that we aquired...
*/
DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval));
InvalidateCatalogCache(vcb);
ReleaseMetaFileVNode(vcb->allocationsRefNum);
ReleaseMetaFileVNode(vcb->attributesRefNum);
ReleaseMetaFileVNode(vcb->catalogRefNum);
ReleaseMetaFileVNode(vcb->extentsRefNum);
return (retval);
}
/*
* ReleaseMetaFileVNode
*
* vp L - -
*/
static void ReleaseMetaFileVNode(struct vnode *vp)
{
if (vp)
{
FCB *fcb = VTOFCB(vp);
if (fcb->fcbBTCBPtr != NULL)
(void) BTClosePath(fcb); /* ignore errors since there is only one path open */
/* 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, u_long eof, u_long clumpSize, void *extents,
HFSCatalogNodeID fileID, void * keyCompareProc)
{
FCB *fcb;
ExtendedVCB *vcb;
int result = 0;
DBG_ASSERT(vp != NULL);
DBG_ASSERT(vp->v_data != NULL);
DBG_ASSERT(VTOH(vp)->h_xfcb->fcb_vp == vp);
vcb = VTOVCB(vp);
fcb = VTOFCB(vp);
switch (fileID)
{
case kHFSExtentsFileID:
vcb->extentsRefNum = vp;
break;
case kHFSCatalogFileID:
vcb->catalogRefNum = vp;
break;
case kHFSAttributesFileID:
vcb->attributesRefNum = vp;
break;
case kHFSAllocationFileID:
vcb->allocationsRefNum = vp;
VTOH(vp)->h_meta->h_logBlockSize = kHFSBlockSize;
VTOH(vp)->h_meta->h_physBlkPerLogBlk = 1;
break;
default:
panic("InitMetaFileVNode: invalid fileID!");
}
fcb->fcbVPtr = vcb;
fcb->fcbEOF = eof;
fcb->fcbPLen = eof;
fcb->fcbClmpSize = clumpSize;
fcb->fcbFlNm = fileID;
H_FILEID(VTOH(vp)) = fileID;
H_FORKTYPE(VTOH(vp)) = kSysFile;
if (vcb->vcbSigWord == kHFSPlusSigWord) {
ExtendedFCB *xfcb;
xfcb = &(((struct vfsFCB *)(fcb))->fcb_extFCB); //XXX use a macro instead?!
bcopy(extents, xfcb->extents, sizeof(HFSPlusExtentRecord));
}
else {
bcopy(extents, fcb->fcbExtRec, sizeof(HFSExtentRecord));
}
/*
* Lock the hfsnode and insert the hfsnode into the hash queue:
*/
hfs_vhashins(VTOH(vp));
vp->v_flag |= VSYSTEM; /* tag our metadata files (used by vflush call) */
if (keyCompareProc != NULL) {
result = BTOpenPath(fcb,
(KeyCompareProcPtr) keyCompareProc,
GetBTreeBlock,
ReleaseBTreeBlock,
ExtendBTreeFile,
SetBTreeBlockSize);
result = MacToVFSError(result);
}
return (result);
}
/*************************************************************
*
* Unmounts a hfs volume.
* At this point vflush() has been called (to dump all non-metadata files)
*
*************************************************************/
short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p)
{
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 (vcb->vcbSigWord == kHFSPlusSigWord) {
(void) hfs_metafilelocking(hfsmp, kHFSAttributesFileID, LK_EXCLUSIVE, p);
ReleaseMetaFileVNode(vcb->allocationsRefNum);
ReleaseMetaFileVNode(vcb->attributesRefNum);
}
ReleaseMetaFileVNode(vcb->catalogRefNum);
ReleaseMetaFileVNode(vcb->extentsRefNum);
return (retval);
}
/*
* Performs a lookup on the given dirID, name. Returns the catalog info
*/
/* XXX SER catInfo points to a hint, why do we need to pass one in ? */
short hfsLookup (ExtendedVCB *vcb, UInt32 parentDirID, char *name, short len, UInt32 hint, hfsCatalogInfo *catInfo)
{
char tmpname[NAME_MAX + 1]; /* UUU */
OSErr result;
if (len != -1 ) {
bcopy(name, tmpname, len);
tmpname[len] = '\0';
result = GetCatalogNode(vcb, parentDirID, tmpname, hint, &catInfo->spec, &catInfo->nodeData, &catInfo->hint);
} else
result = GetCatalogNode(vcb, parentDirID, name, hint, &catInfo->spec, &catInfo->nodeData, &catInfo->hint);
if (result)
DBG_ERR(("on Lookup, GetCatalogNode returned: %d: dirid: %ld name: %s\n", result, parentDirID, name));
return MacToVFSError(result);
}
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? */
/*
* 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);
if (result)
DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result, parentDirID, name));
return MacToVFSError(result);
}
short hfsMoveRename (ExtendedVCB *vcb, UInt32 oldDirID, char *oldName, UInt32 newDirID, char *newName, UInt32 *hint)
{
OSErr result = noErr;
result = MoveRenameCatalogNode(vcb, oldDirID,oldName, *hint, newDirID, newName, hint);
if (result)
DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result, newDirID, newName));
return MacToVFSError(result);
}
/* XXX SER pass back the hint so other people can use it */
short hfsCreate(ExtendedVCB *vcb, UInt32 dirID, char *name, int mode)
{
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;
result = CreateCatalogNode (vcb, dirID, name, type, &catalogNodeID, &catalogHint);
return MacToVFSError(result);
}
short hfsCreateFileID (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, UInt32 catalogHint, UInt32 *fileIDPtr)
{
return MacToVFSError(CreateFileIDRef(vcb, parentDirID, name, catalogHint, fileIDPtr));
}
/************************************************************************/
/* hfsGet - Returns a vnode derived from hfs */
/* */
/************************************************************************/
short hfsGet( ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, struct vnode *dvp, struct vnode **vpp)
{
struct hfsnode *hp;
struct vnode *vp;
struct vnode *cp;
struct hfsmount *hfsmp;
struct hfsfilemeta *fm;
struct mount *mp;
struct vfsFCB *xfcb;
dev_t dev;
int retval;
DBG_ASSERT(vcb != NULL);
DBG_ASSERT(catInfo != NULL);
DBG_ASSERT(vpp != NULL);
hfsmp = VCBTOHFS(vcb);
mp = HFSTOVFS(hfsmp);
dev = hfsmp->hfs_raw_dev;
DBG_UTILS(("\thfsGet: On '%s' with forktype of %d, nodeType of 0x%08lX\n", catInfo->spec.name, forkType, (unsigned long)catInfo->nodeData.nodeType));
/* Must malloc() here, since getnewvnode() can sleep */
MALLOC(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK);
bzero((caddr_t)hp, sizeof(struct hfsnode));
lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0);
/* getnewvnode() does a VREF() on the vnode */
/* Allocate a new vnode. */
if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &vp))) {
*vpp = NULL;
goto Err_Exit;
}
hp->h_vp = vp; /* Make HFSTOV work */
hp->h_dev = hfsmp->hfs_raw_dev;
vp->v_data = hp; /* Make VTOH work */
H_FILEID(hp) = catInfo->nodeData.nodeID;
H_FORKTYPE(hp) = forkType;
/*
* Lock the hfsnode and insert the hfsnode into the hash queue:
* NOTE: THIS IS DANGEROUS IN CASES WHERE WE NEED TO BACK OUT OF THE CREATION?
*/
hfs_vhashins(hp);
hp->h_valid = HFS_VNODE_MAGIC;
/*
* Allocate and init the right data structs:
*/
xfcb = NULL;
if (catInfo->nodeData.nodeType == kCatalogFolderNode)
{
/* Just allocate the data */
MALLOC(fm, struct hfsfilemeta *, sizeof(struct hfsfilemeta), M_HFSNODE, M_WAITOK);
bzero(fm, sizeof(struct hfsfilemeta));
MALLOC(xfcb, struct vfsFCB *, sizeof(struct vfsFCB), M_HFSNODE, M_WAITOK);
bzero(xfcb, sizeof(struct vfsFCB));
fm->h_logBlockSize = hfsmp->hfs_log_block_size;
fm->h_physBlkPerLogBlk = fm->h_logBlockSize/kHFSBlockSize;
}
else
{
if (forkType==kDirCmplx)
{
/* Just allocate the meta part */
MALLOC(fm, struct hfsfilemeta *, sizeof(struct hfsfilemeta), M_HFSNODE, M_WAITOK);
bzero(fm, sizeof(struct hfsfilemeta));
lockinit(&fm->h_fmetalock, PINOD, "hfsfilemeta", 0, 0);
fm->h_logBlockSize = hfsmp->hfs_log_block_size;
fm->h_physBlkPerLogBlk = fm->h_logBlockSize/kHFSBlockSize;
}
else
{
Boolean unlockPar = false;
/* Get the complex vnode, creating it if none existed */
if (dvp->v_type == VCPLX) {
cp = dvp;
}
else {
cp = hfs_vhashget(hp->h_dev, H_FILEID(hp), kDirCmplx);
unlockPar = TRUE;
}
if (cp == NULL)
{
if ((retval = hfsGet(vcb, catInfo, kDirCmplx, NULL, &cp)))
{
/* Couldn't get a complex node: back out of this vnode's creation
since an hfs vnode can't stand alone: */
vp->v_flag |= VSYSTEM; /* Prevent hfs_lock et al. from going for meta lock... */
VPUT(vp);
goto Err_Exit;
};
unlockPar = TRUE;
}
fm = VTOH(cp)->h_meta;
DBG_ASSERT(fm);
/* Increment the usecount, to make sure it doesnt go away on us */
fm->h_usecount++;
lockmgr(&fm->h_fmetalock, LK_EXCLUSIVE, (struct slock *)0, CURRENT_PROC);
hp->h_relative = cp;
if (forkType == kDataFork) /* Init downlink */
VTOH(cp)->h_relative = vp;
if (fm->h_fork == NULL)
fm->h_fork = vp;
else {
hp->h_sibling = fm->h_fork;
VTOH(fm->h_fork)->h_sibling = vp;
}
/* Increment the complex usecount, to make sure it doesnt go inactive on us */
VREF(cp);
if (unlockPar)
VPUT(cp);
}
MALLOC(xfcb, struct vfsFCB *, sizeof(struct vfsFCB), M_HFSNODE, M_WAITOK);
bzero(xfcb, sizeof(struct vfsFCB));
}
hp->h_xfcb = xfcb;
hp->h_meta = fm;
/*
* Finish filling in the record
*/
if (xfcb) {
xfcb->fcb_vp = vp; /* Make FCBTOV work */
}
/*
* Copy the Catalog info to the new macnode
*/
CopyCatalogToHFSNode(catInfo, hp);
/* Lets do some testing here */
DBG_ASSERT(hp->h_meta);
DBG_ASSERT(VTOH(vp)==hp);
DBG_ASSERT(HTOV(hp)==vp);
if (hp->h_xfcb) {
DBG_ASSERT(VTOH(vp)->h_xfcb->fcb_vp == vp);
DBG_ASSERT(FCBTOV(&hp->h_xfcb->fcb_fcb) == vp);
DBG_ASSERT(FCBTOH(&hp->h_xfcb->fcb_fcb) == hp);
DBG_ASSERT(&hp->h_xfcb->fcb_fcb == VTOFCB(vp));
DBG_ASSERT(&hp->h_xfcb->fcb_fcb == HTOFCB(hp));
DBG_ASSERT(VTOVCB(vp) == FCBTOVCB(&hp->h_xfcb->fcb_fcb));
}
if (hp->h_sibling) {
DBG_ASSERT(VTOH(hp->h_sibling)->h_sibling == vp);
DBG_ASSERT(VTOH(hp->h_sibling)->h_relative == hp->h_relative);
DBG_ASSERT(VTOH(hp->h_sibling)->h_meta == hp->h_meta);
}
if (H_FORKTYPE(hp) == kDirCmplx) {
DBG_ASSERT(hp->h_meta->h_usecount==0);
}
else {
DBG_ASSERT(hp->h_meta->h_usecount>0 && hp->h_meta->h_usecount<=2);
}
/*
* Finish inode initialization now that aliasing has been resolved.
*/
hp->h_devvp = hfsmp->hfs_devvp;
VREF(hp->h_devvp);
*vpp = vp;
return 0;
Err_Exit:;
FREE (hp, M_HFSNODE);
*vpp = NULL;
return (retval);
}
int hasOverflowExtents(struct hfsnode *hp)
{
ExtendedVCB *vcb = HTOVCB(hp);
FCB *fcb = HTOFCB(hp);
u_long blocks;
if (vcb->vcbSigWord == kHFSPlusSigWord)
{
ExtendedFCB *xfcb;
xfcb = GetParallelFCB(HTOV(hp));
if (xfcb->extents[7].blockCount == 0)
return false;
blocks = xfcb->extents[0].blockCount +
xfcb->extents[1].blockCount +
xfcb->extents[2].blockCount +
xfcb->extents[3].blockCount +
xfcb->extents[4].blockCount +
xfcb->extents[5].blockCount +
xfcb->extents[6].blockCount +
xfcb->extents[7].blockCount;
}
else
{
if (fcb->fcbExtRec[2].blockCount == 0)
return false;
blocks = fcb->fcbExtRec[0].blockCount +
fcb->fcbExtRec[1].blockCount +
fcb->fcbExtRec[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;
struct timeval tv;
int numOfLockedBuffs;
int retval = 0;
vcb = HFSTOVCB(hfsmp);
DBG_VFS((" hfs_metafilelocking: vol: %d, file: %ld %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" : "") ));
/*kprintf("file: %ld flags: 0x%x %s%s%s\n",fileID, flags,
((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 kHFSAttributesFileID:
if (vcb->vcbSigWord == kHFSPlusSigWord) {
vp = vcb->attributesRefNum;
break;
}
// fall through for hfs...
case kHFSAllocationFileID:
// bitmap is covered by Extents B-tree locking
default:
panic("hfs_lockmetafile: invalid fileID");
}
/*kprintf("\tBefore: %d\n", lockstatus(&VTOH(vp)->h_lock));
*/
if (vp != NULL) {
/* Release, if necesary any locked buffer caches */
if (flags & LK_RELEASE) {
numOfLockedBuffs = count_lock_queue();
tv = time;
if ((numOfLockedBuffs > 32) || ((numOfLockedBuffs>1) && ((tv.tv_sec - VTOH(vp)->h_lastfsync) > kMaxSecsForFsync))) {
// kprintf("Synching meta deta...locked buffers = %d, fsync gap = %ld\n", numOfLockedBuffs, (tv.tv_sec - VTOH(vp)->h_lastfsync));
VOP_FSYNC(vp, NOCRED, MNT_NOWAIT, p);
};
};
retval = lockmgr(&VTOH(vp)->h_lock, flags, &vp->v_interlock, p);
};
return retval;
}
void CopyVNodeToCatalogNode (struct vnode *vp, struct CatalogNodeData *nodeData)
{
ExtendedVCB *vcb;
FCB *fcb;
struct hfsnode *hp;
Boolean isHFSPlus, isResource;
HFSPlusExtentDescriptor *extents, *parellextents;
ExtendedFCB *extendedFCB;
hp = VTOH(vp);
vcb = HTOVCB(hp);
fcb = HTOFCB(hp);
isResource = (H_FORKTYPE(hp) == kRsrcFork);
isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
nodeData->contentModDate = to_hfs_time(hp->h_meta->h_mtime); /* date and time of last fork modification */
DBG_ASSERT(fcb->fcbFlNm == H_FILEID(hp));
if (isHFSPlus) {
nodeData->attributeModDate = to_hfs_time(hp->h_meta->h_ctime); /* date and time of last modification (any kind) */
nodeData->accessDate = to_hfs_time(hp->h_meta->h_atime); /* date and time of last access (Rhapsody only) */
if (! (hp->h_meta->h_nodeflags & IN_UNSETACCESS)) {
/* This is a tricky stuff-job: the pflags longword has two bytes of significance and they're
combined with the mode field to yield a 32-bit permissions field as follows:
+------------------------------------+
hp->h_meta->h_pflags: |XXXXXXXX| A |XXXXXXXX| B |
+------------------------------------+
|
V
+------------------------------------+
permissions: | A | B | mode |
+------------------------------------+
*/
nodeData->permissions.permissions = (((hp->h_meta->h_pflags << 8) & 0xFF000000) | /* A */
((hp->h_meta->h_pflags << 16) & 0x00FF0000) | /* B */
(hp->h_meta->h_mode & 0x0000FFFF));
nodeData->permissions.ownerID = hp->h_meta->h_uid;
nodeData->permissions.groupID = hp->h_meta->h_gid;
nodeData->permissions.specialDevice = hp->h_meta->h_rdev;
};
};
/* the rest only applies to files */
if (nodeData->nodeType == kCatalogFileNode) {
if (hp->h_meta->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
/* The file is locked: set the locked bit in the catalog. */
nodeData->nodeFlags |= kHFSFileLockedMask;
} else {
/* The file is unlocked: make sure the locked bit in the catalog is clear. */
nodeData->nodeFlags &= ~kHFSFileLockedMask;
};
if (isResource) {
extents = nodeData->rsrcExtents;
nodeData->rsrcLogicalSize = fcb->fcbEOF;
nodeData->rsrcPhysicalSize = fcb->fcbPLen;
} else {
extents = nodeData->dataExtents;
nodeData->dataLogicalSize = fcb->fcbEOF;
nodeData->dataPhysicalSize = fcb->fcbPLen;
};
/* Copy the extents from their correct location */
if ( ! isHFSPlus) {
/* HFS, Copy the extents from the FCB part */
int i;
for (i = 0; i < kHFSExtentDensity; ++i) {
extents[i].startBlock = (UInt16) (fcb->fcbExtRec[i].startBlock);
extents[i].blockCount = (UInt16) (fcb->fcbExtRec[i].blockCount);
}
} else {
/* HFSPlus, Copy the extents from the parallel extents */
extendedFCB = GetParallelFCB (HTOV(hp));
parellextents = extendedFCB->extents;
bcopy ( parellextents, extents, sizeof(HFSPlusExtentRecord));
};
if (vp->v_type == VLNK) {
((struct FInfo *)(&nodeData->finderInfo))->fdType = kSymLinkFileType;
((struct FInfo *)(&nodeData->finderInfo))->fdCreator = kSymLinkCreator;
/* Set this up as an alias */
#if SUPPORTS_MAC_ALIASES
((struct FInfo *)(&nodeData->finderInfo))->fdFlags |= kIsAlias;
#endif
}
}
}
void MapFileOffset(struct hfsnode *hp,
off_t filePosition,
daddr_t *logBlockNumber,
long *blockSize,
long *blockOffset) {
off_t extentOffset = filePosition;
daddr_t precedingBlockCount;
unsigned long logicalBlockSize = 0;
unsigned long spaceRemaining;
DBG_IO(("MapFileOffset: hp = 0x%08lX, vp = 0x%08lX ('%s'):\n", (u_long)hp, (u_long)HTOV(hp), H_NAME(hp)));
// DBG_IO(("\tfilePosition 0x%08lX", (u_long)filePosition));
if (filePosition < hp->h_optimizedblocksizelimit) {
int extent;
precedingBlockCount = 0;
for (extent = 0; extent < LOGBLOCKMAPENTRIES; ++extent) {
if ((hp->h_logicalblocktable[extent].logicalBlockCount > 0) &&
(extentOffset < hp->h_logicalblocktable[extent].extentLength)) {
logicalBlockSize = MAXLOGBLOCKSIZE;
spaceRemaining = hp->h_logicalblocktable[extent].extentLength - ((extentOffset / logicalBlockSize) * logicalBlockSize);
*blockSize = MIN(logicalBlockSize, spaceRemaining);
// DBG_IO(("\tUsing entry #%d: preceding blocks = 0x%X, position = 0x%8lX:\n",
// extent, precedingBlockCount, (u_long)extentOffset));
break;
};
precedingBlockCount += hp->h_logicalblocktable[extent].logicalBlockCount;
extentOffset -= hp->h_logicalblocktable[extent].extentLength;
};
DBG_ASSERT(logicalBlockSize > 0);
} else {
// DBG_IO(("\tUsing h_uniformblocksizestart = 0x%X and h_optimizedblocksizelimit = 0x%lX:\n",
// hp->h_uniformblocksizestart, (u_long)hp->h_optimizedblocksizelimit));
precedingBlockCount = hp->h_uniformblocksizestart;
extentOffset -= hp->h_optimizedblocksizelimit;
logicalBlockSize = hp->h_meta->h_logBlockSize;
*blockSize = logicalBlockSize;
};
*logBlockNumber = precedingBlockCount + (extentOffset / logicalBlockSize);
*blockOffset = extentOffset % logicalBlockSize;
DBG_IO(("\tfilePosition 0x%08lX -> logBlockNo = 0x%X, blockSize = 0x%lX, blockOffset = 0x%lX.\n",
(u_long)filePosition,
*logBlockNumber,
*blockSize,
*blockOffset));
}
long LogicalBlockSize(struct hfsnode *hp, daddr_t logicalBlockNumber) {
if (logicalBlockNumber < hp->h_uniformblocksizestart) {
off_t fragmentOffset = 0;
int extent;
for (extent = 0; extent < LOGBLOCKMAPENTRIES; ++extent) {
if ((hp->h_logicalblocktable[extent].logicalBlockCount > 0) &&
(logicalBlockNumber < hp->h_logicalblocktable[extent].logicalBlockCount)) {
// *filePosition = fragmentOffset + (logicalBlockNumber * MAXLOGBLOCKSIZE);
return MIN(MAXLOGBLOCKSIZE, hp->h_logicalblocktable[extent].extentLength - (logicalBlockNumber * MAXLOGBLOCKSIZE));
};
logicalBlockNumber -= hp->h_logicalblocktable[extent].logicalBlockCount;
fragmentOffset += hp->h_logicalblocktable[extent].extentLength;
};
} else {
// *filePosition = hp->h_optimizedblocksizelimit + ((logicalBlockNumber - hp->h_uniformblocksizestart) * hp->h_meta->h_logBlockSize);
return hp->h_meta->h_logBlockSize;
};
DBG_ASSERT(0 /* cannot be reached */);
return 0;
};
void UpdateBlockMappingTableEntry(struct hfsnode *hp, int index, daddr_t firstFragmentBlockNumber, long newFragmentLength) {
// off_t currentFragmentLength;
/* Compute the number of logical blocks, rounding up to include any small trailing fragments: */
hp->h_logicalblocktable[index].logicalBlockCount = (newFragmentLength + MAXLOGBLOCKSIZE - 1) / MAXLOGBLOCKSIZE;
DBG_IO(("\tblocktable[%d]: length = 0x%lX, # blocks = 0x%lX.\n",
index,
newFragmentLength,
(u_long)hp->h_logicalblocktable[index].logicalBlockCount));
#if 0
currentFragmentLength = hp->h_logicalblocktable[index].extentLength;
if ((newFragmentLength > currentFragmentLength) && (currentFragmentLength > 0)) {
daddr_t currentLastBlockNumber;
long currentLastBlockSize;
long newLastBlockSize;
struct buf *bp;
int retval;
currentLastBlockNumber = firstFragmentBlockNumber + (currentFragmentLength / MAXLOGBLOCKSIZE);
currentLastBlockSize = currentFragmentLength % MAXLOGBLOCKSIZE;
if (currentLastBlockSize > 0) {
newLastBlockSize = MIN(MAXLOGBLOCKSIZE,
newFragmentLength -
((currentLastBlockNumber - firstFragmentBlockNumber) * MAXLOGBLOCKSIZE));
if (newLastBlockSize != currentLastBlockSize) {
DBG_IO(("\t\t(Adjusting block 0x%lX from 0x%lX to 0x%lX...)\n",
(unsigned long)currentLastBlockNumber,
currentLastBlockSize,
newLastBlockSize));
retval = bread(HTOV(hp), currentLastBlockNumber, currentLastBlockSize, NOCRED, &bp);
if (retval == 0) {
bexpand(bp, newLastBlockSize, NULL, RELEASE_BUFFER);
} else {
DBG_IO(("\t\terror (%d.) acquiring block 0x%lX; bp = 0x%08lX\n",
retval,
(unsigned long)currentLastBlockNumber,
(unsigned long)bp));
if (bp) brelse(bp);
};
};
};
};
#endif
hp->h_logicalblocktable[index].extentLength = newFragmentLength;
}
void UpdateBlockMappingTable(struct hfsnode *hp)
{
ExtendedVCB *vcb = HTOVCB(hp);
FCB *fcb = HTOFCB(hp);
ExtendedFCB *extendedFCB;
Boolean isHFSPlus;
HFSPlusExtentDescriptor *parellextents;
off_t rangeMappedSoFar;
u_long logicalBlocksMappedSoFar;
int i;
off_t newFragmentLength;
isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
DBG_IO(("UpdateBlockMappingTable: hp = 0x%08lX, vp = 0x%08lX ('%s'):\n", (u_long)hp, (u_long)HTOV(hp), H_NAME(hp)));
if (H_FORKTYPE(hp) != kDirCmplx) {
rangeMappedSoFar = 0;
logicalBlocksMappedSoFar = 0;
if ( ! isHFSPlus) {
DBG_ASSERT(kHFSExtentDensity <= LOGBLOCKMAPENTRIES);
for (i = 0; i < kHFSExtentDensity; ++i) {
newFragmentLength = fcb->fcbExtRec[i].blockCount * vcb->blockSize;
UpdateBlockMappingTableEntry(hp, i, logicalBlocksMappedSoFar, newFragmentLength);
rangeMappedSoFar += newFragmentLength;
logicalBlocksMappedSoFar += hp->h_logicalblocktable[i].logicalBlockCount;
}
/* Zero out any remaining entries: */
for (i = kHFSExtentDensity; i < LOGBLOCKMAPENTRIES; ++i) {
hp->h_logicalblocktable[i].extentLength = 0;
};
#if DIAGNOSTIC
if (rangeMappedSoFar < fcb->fcbPLen) DBG_ASSERT(hp->h_logicalblocktable[kHFSExtentDensity-1].extentLength > 0);
#endif
} else {
extendedFCB = GetParallelFCB (FCBTOV(fcb));
parellextents = extendedFCB->extents;
for (i = 0; i < kHFSPlusExtentDensity; ++i) {
newFragmentLength = parellextents[i].blockCount * vcb->blockSize;
UpdateBlockMappingTableEntry(hp, i, logicalBlocksMappedSoFar, newFragmentLength);
rangeMappedSoFar += newFragmentLength;
logicalBlocksMappedSoFar += hp->h_logicalblocktable[i].logicalBlockCount;
}
/* No need to zero out the remaining entries [there are none]: */
DBG_ASSERT(LOGBLOCKMAPENTRIES <= kHFSPlusExtentDensity);
#if DIAGNOSTIC
if (rangeMappedSoFar < fcb->fcbPLen) DBG_ASSERT(hp->h_logicalblocktable[kHFSPlusExtentDensity-1].extentLength > 0);
#endif
};
hp->h_optimizedblocksizelimit = rangeMappedSoFar;
hp->h_uniformblocksizestart = logicalBlocksMappedSoFar;
DBG_IO(("\th_optimizedblocksizelimit = 0x%lX, h_uniformblocksizestart = 0x%lX.\n",
(u_long)hp->h_optimizedblocksizelimit, (u_long)hp->h_uniformblocksizestart));
#if BYPASSBLOCKINGOPTIMIZATION
hp->h_optimizedblocksizelimit = 0;
hp->h_uniformblocksizestart = 0;
#endif
};
}
void CopyCatalogToHFSNode(struct hfsCatalogInfo *catalogInfo, struct hfsnode *hp)
{
FCB *fcb;
ExtendedVCB *vcb = HTOVCB(hp);
Boolean isHFSPlus, isDirectory, isResource;
HFSPlusExtentDescriptor *extents, *parellextents;
ExtendedFCB *extendedFCB;
ushort finderFlags;
UInt8 forkType;
DBG_ASSERT (hp != NULL);
DBG_ASSERT (hp->h_valid == HFS_VNODE_MAGIC);
DBG_ASSERT (hp->h_meta != NULL);
DBG_UTILS(("\tCopying to vnode Ox%08lX: name:%s, type:%d, nodeid:%ld\n", (unsigned long)HTOV(hp), catalogInfo->spec.name, H_FORKTYPE(hp), catalogInfo->nodeData.nodeID));
forkType = H_FORKTYPE(hp);
isResource = (forkType == kRsrcFork);
isDirectory = (catalogInfo->nodeData.nodeType == kCatalogFolderNode);
isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
finderFlags = ((struct FInfo *)(&catalogInfo->nodeData.finderInfo))->fdFlags;
DBG_UTILS(("\t\t forkType:%d, isResource:%d, isDirectory:%d, isHFSPlus:%d\n", forkType, isResource, isDirectory, isHFSPlus));
/* Copy over the name if NOT set yet */
if (H_NAME(hp) == NULL) {
hp->h_meta->h_namelen = strlen(catalogInfo->spec.name);
if (hp->h_meta->h_namelen <= MAXHFSVNODELEN) {
H_NAME(hp) = hp->h_meta->h_fileName;
}
else {
MALLOC(H_NAME(hp), char *, hp->h_meta->h_namelen+1, M_HFSNODE, M_WAITOK);
hp->h_meta->h_nodeflags |= IN_LONGNAME;
};
bcopy(catalogInfo->spec.name, H_NAME(hp), hp->h_meta->h_namelen+1);
}
else {
DBG_ASSERT (hp->h_meta->h_namelen == strlen(catalogInfo->spec.name));
DBG_ASSERT (strcmp(H_NAME(hp), catalogInfo->spec.name) == 0);
};
/* Copy over the dirid, and hint */
H_FILEID(hp) = catalogInfo->nodeData.nodeID;
H_DIRID(hp) = catalogInfo->spec.parID;
H_HINT(hp) = catalogInfo->hint;
if (hp->h_xfcb != NULL) {
/* Init the fcb */
fcb = HTOFCB(hp);
fcb->fcbVPtr = vcb;
fcb->fcbFlNm = catalogInfo->nodeData.nodeID;
fcb->fcbFlags = catalogInfo->nodeData.nodeFlags;
if (forkType != kDirCmplx) {
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.rsrcExtents;
else
extents = catalogInfo->nodeData.dataExtents;
/* Copy the extents to their correct location: */
if ( ! isHFSPlus) {
int i;
for (i = 0; i < kHFSExtentDensity; ++i) {
fcb->fcbExtRec[i].startBlock = (UInt32) (extents[i].startBlock);
fcb->fcbExtRec[i].blockCount = (UInt32) (extents[i].blockCount);
}
} else {
/* HFSPlus, Copy the extents to the parallel extents */
extendedFCB = GetParallelFCB (FCBTOV(fcb));
parellextents = extendedFCB->extents;
bcopy (extents, parellextents, sizeof(HFSPlusExtentRecord));
};
UpdateBlockMappingTable(hp);
/* the valence field is overloaded to flag files over 2 gig */
/* since we are working with a single fork, isolate it flags <why?> */
/* secondFlags = catalogInfo->nodeData.valence; */
if (isResource) {
fcb->fcbEOF = catalogInfo->nodeData.rsrcLogicalSize;
fcb->fcbPLen = catalogInfo->nodeData.rsrcPhysicalSize;
fcb->fcbFlags |= fcbResourceMask;
} else {
fcb->fcbEOF = catalogInfo->nodeData.dataLogicalSize;
fcb->fcbPLen = catalogInfo->nodeData.dataPhysicalSize;
};
};
};
hp->h_meta->h_mtime = to_bsd_time(catalogInfo->nodeData.contentModDate); /* UNIX-format mod date in seconds */
hp->h_meta->h_crtime = to_bsd_time(catalogInfo->nodeData.createDate); /* UNIX-format creation date in secs. */
hp->h_meta->h_butime = to_bsd_time(catalogInfo->nodeData.backupDate); /* UNIX-format backup date in secs. */
if (isHFSPlus) {
hp->h_meta->h_atime = to_bsd_time(catalogInfo->nodeData.accessDate); /* UNIX-format mod date in seconds */
hp->h_meta->h_ctime = to_bsd_time(catalogInfo->nodeData.attributeModDate); /* UNIX-format status change date */
}
else {
hp->h_meta->h_atime = to_bsd_time(catalogInfo->nodeData.contentModDate); /* UNIX-format mod date in seconds */
hp->h_meta->h_ctime = to_bsd_time(catalogInfo->nodeData.contentModDate); /* UNIX-format status change date */
}
/* Now the rest */
if (isHFSPlus && (catalogInfo->nodeData.permissions.permissions & IFMT)) {
hp->h_meta->h_uid = catalogInfo->nodeData.permissions.ownerID;
hp->h_meta->h_gid = catalogInfo->nodeData.permissions.groupID;
/* The 32-bit permissions field is unpacked to yield the two significant bytes of flags and the
mode as follows:
+------------------------------------+
permissions: | A | B | mode |
+------------------------------------+
|
V
+------------------------------------+
hp->h_meta->h_pflags: |XXXXXXXX| A |XXXXXXXX| B |
+------------------------------------+
*/
hp->h_meta->h_pflags = (((catalogInfo->nodeData.permissions.permissions & 0xFF000000) >> 8) | /* A */
((catalogInfo->nodeData.permissions.permissions & 0x00FF0000) >> 16)); /* B */
hp->h_meta->h_mode = (mode_t)(catalogInfo->nodeData.permissions.permissions & 0x0000FFFF);
hp->h_meta->h_rdev = catalogInfo->nodeData.permissions.specialDevice;
} else {
/*
* Set the permissions as determined by the mount auguments
* but keep in account if the file or folder is hfs locked
*/
hp->h_meta->h_nodeflags |= IN_UNSETACCESS;
hp->h_meta->h_uid = HTOHFS(hp)->hfs_uid;
hp->h_meta->h_gid = HTOHFS(hp)->hfs_gid;
/* Default access is full read/write/execute: */
hp->h_meta->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */
/* ... but no more than that permitted by the mount point's: */
if (isDirectory) {
hp->h_meta->h_mode &= HTOHFS(hp)->hfs_dir_mask;
}
else {
hp->h_meta->h_mode &= HTOHFS(hp)->hfs_file_mask;
}
if(isDirectory)
hp->h_meta->h_mode |= IFDIR;
else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */
hp->h_meta->h_mode |= IFLNK;
else
hp->h_meta->h_mode |= IFREG;
};
/* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
if (!isDirectory) {
if (catalogInfo->nodeData.nodeFlags & kHFSFileLockedMask) {
/* The file's supposed to be locked:
Make sure at least one of the IMMUTABLE bits is set: */
if ((hp->h_meta->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0) {
hp->h_meta->h_pflags |= UF_IMMUTABLE; /* Set the user-changable IMMUTABLE bit */
};
} else {
/* The file's supposed to be unlocked: */
hp->h_meta->h_pflags &= ~(SF_IMMUTABLE | UF_IMMUTABLE);
};
};
if (isDirectory)
hp->h_size = sizeof (hfsdirentry) * (catalogInfo->nodeData.valence + 2);
else
hp->h_size = catalogInfo->nodeData.rsrcPhysicalSize + catalogInfo->nodeData.dataPhysicalSize;
/* finish up some vnode stuff */
/* Set the root flag if necesary */
switch (hp->h_meta->h_mode & IFMT) {
case IFDIR:
HTOV(hp)->v_type = VDIR;
if (H_FILEID(hp) == kRootDirID)
HTOV(hp)->v_flag |= VROOT;
break;
case IFREG:
if (forkType == kDirCmplx)
HTOV(hp)->v_type = VCPLX;
else
HTOV(hp)->v_type = VREG;
break;
case IFLNK:
if (forkType == kDirCmplx)
HTOV(hp)->v_type = VCPLX;
else
HTOV(hp)->v_type = VLNK;
break;
default:
DBG_ASSERT(false);
HTOV(hp)->v_type = VBAD;
};
}
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_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_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_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 = 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 = attrlist->dirattr) != 0) {
if (a & ATTR_DIR_LINKCOUNT) size += sizeof(u_long);
if (a & ATTR_DIR_ENTRYCOUNT) 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;
}
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);
struct ExtendedVCB *vcb = HFSTOVCB(hfsmp);
u_long attrlength;
attrbufptr = *attrbufptrptr;
varbufptr = *varbufptrptr;
if ((a = alist->commonattr) != 0) {
if (a & ATTR_CMN_NAME) {
attrlength = root_hp->h_meta->h_namelen+1;
((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr;
((struct attrreference *)attrbufptr)->attr_length = attrlength;
(void) strncpy((unsigned char *)varbufptr, H_NAME(root_hp), attrlength);
/* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
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;
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 local Mac OS time */
if (a & ATTR_CMN_CRTIME) {
/*
* HFS Plus stores the volume create date in *local*
* time in the volume header. So don't use the create
* date from the vcb. Use the root's crtime instead.
*/
if (vcb->vcbSigWord == kHFSPlusSigWord) {
((struct timespec *)attrbufptr)->tv_sec = root_hp->h_meta->h_crtime;
} else {
((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));
attrbufptr += sizeof(vcb->vcbFndrInfo);
};
VCB_UNLOCK(vcb);
if (a & ATTR_CMN_OWNERID) *((uid_t *)attrbufptr)++ = root_hp->h_meta->h_uid;
if (a & ATTR_CMN_GRPID) *((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: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = root_hp->h_meta->h_pflags;
};
*attrbufptrptr = attrbufptr;
*varbufptrptr = varbufptr;
}
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);
struct 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->allocationsClumpSize;
if (a & ATTR_VOL_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = (u_long)hfsmp->hfs_log_block_size;
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) {
attrlength = strlen(hfsmp->hfs_mountpoint) + 1;
((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr;
((struct attrreference *)attrbufptr)->attr_length = attrlength;
(void) strcpy((unsigned char *)varbufptr, hfsmp->hfs_mountpoint);
/* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (a & ATTR_VOL_NAME) {
attrlength = VTOH(root_vp)->h_meta->h_namelen + 1;
((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr;
((struct attrreference *)attrbufptr)->attr_length = attrlength;
strncpy((char *)varbufptr, H_NAME(VTOH(root_vp)), attrlength);
/* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (a & ATTR_VOL_MOUNTFLAGS) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_flag;
VCB_UNLOCK(vcb);
};
*attrbufptrptr = attrbufptr;
*varbufptrptr = varbufptr;
}
void PackVolumeInfo(struct attrlist *alist,
struct vnode *root_vp,
struct hfsCatalogInfo *root_catinfo,
void **attrbufptrptr,
void **varbufptrptr) {
PackVolCommonAttributes(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr);
PackVolAttributeBlock(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr);
};
// 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;
hp = VTOH(root_vp);
attrbufptr = *attrbufptrptr;
varbufptr = *varbufptrptr;
if ((a = alist->commonattr) != 0)
{
if (a & ATTR_CMN_NAME)
{
attrlength = strlen(catalogInfo->spec.name) + 1;
((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr;
((struct attrreference *)attrbufptr)->attr_length = attrlength;
(void) strncpy((unsigned char *)varbufptr, (unsigned char *) &(catalogInfo->spec.name), attrlength);
// ((char *) varbufptr)[attrlength-1] = 0; // Now it's a C string
/* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hp->h_dev;
if (a & ATTR_CMN_FSID) *((fsid_t *)attrbufptr)++ = VTOVFS(root_vp)->mnt_stat.f_fsid;
if (a & ATTR_CMN_OBJTYPE)
{
if ( catalogInfo->nodeData.nodeType == kCatalogFolderNode )
*((fsobj_type_t *)attrbufptr)++ = VDIR;
else //XXX could be more robust in object type handling
*((fsobj_type_t *)attrbufptr)++ = VREG;
}
if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = root_vp->v_tag;
if (a & ATTR_CMN_OBJID)
{
((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.nodeID; // H_FILEID(hp);
((fsobj_id_t *)attrbufptr)->fid_generation = 0;
++((fsobj_id_t *)attrbufptr);
};
if (a & ATTR_CMN_OBJPERMANENTID)
{
((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.nodeID; // H_FILEID(hp);
((fsobj_id_t *)attrbufptr)->fid_generation = 0;
++((fsobj_id_t *)attrbufptr);
};
if (a & ATTR_CMN_PAROBJID)
{
((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->spec.parID; // 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)++ = catalogInfo->nodeData.textEncoding;
} else {
*((text_encoding_t *)attrbufptr)++ = 0;
}
};
if (a & ATTR_CMN_CRTIME)
{
((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.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.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.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.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.backupDate);
((struct timespec *)attrbufptr)->tv_nsec = 0;
++((struct timespec *)attrbufptr);
};
if (a & ATTR_CMN_FNDRINFO)
{
bcopy (&catalogInfo->nodeData.finderInfo, attrbufptr, sizeof(catalogInfo->nodeData.finderInfo));
attrbufptr += sizeof(catalogInfo->nodeData.finderInfo);
bcopy (&catalogInfo->nodeData.extFinderInfo, attrbufptr, sizeof(catalogInfo->nodeData.extFinderInfo));
attrbufptr += sizeof(catalogInfo->nodeData.extFinderInfo);
};
if (a & ATTR_CMN_OWNERID) *((uid_t *)attrbufptr)++ = catalogInfo->nodeData.permissions.ownerID;
if (a & ATTR_CMN_GRPID) *((gid_t *)attrbufptr)++ = catalogInfo->nodeData.permissions.groupID;
if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)(mode_t)(catalogInfo->nodeData.permissions.permissions & 0x0000FFFF);
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: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = (u_long)((((catalogInfo->nodeData.permissions.permissions & 0xFFFF0000) >> 8) & 0x00FF0000) |
(((catalogInfo->nodeData.permissions.permissions & 0xFFFF0000) >> 24) & 0x000000FF));
};
*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) {
attrlength = hp->h_meta->h_namelen + 1;
((struct attrreference *)attrbufptr)->attr_dataoffset = varbufptr - attrbufptr;
((struct attrreference *)attrbufptr)->attr_length = attrlength;
(void) strncpy((unsigned char *)varbufptr, H_NAME(hp), attrlength);
/* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hp->h_dev;
if (a & ATTR_CMN_FSID) *((fsid_t *)attrbufptr)++ = VTOVFS(vp)->mnt_stat.f_fsid;
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) {
((fsobj_id_t *)attrbufptr)->fid_objno = H_FILEID(hp);
((fsobj_id_t *)attrbufptr)->fid_generation = 0;
++((fsobj_id_t *)attrbufptr);
};
if (a & ATTR_CMN_OBJPERMANENTID) {
((fsobj_id_t *)attrbufptr)->fid_objno = H_FILEID(hp);
((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.textEncoding;
} else {
*((text_encoding_t *)attrbufptr)++ = 0;
}
};
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.finderInfo, attrbufptr, sizeof(catInfo->nodeData.finderInfo));
attrbufptr += sizeof(catInfo->nodeData.finderInfo);
bcopy (&catInfo->nodeData.extFinderInfo, attrbufptr, sizeof(catInfo->nodeData.extFinderInfo));
attrbufptr += sizeof(catInfo->nodeData.extFinderInfo);
};
if (a & ATTR_CMN_OWNERID) *((uid_t *)attrbufptr)++ = hp->h_meta->h_uid;
if (a & ATTR_CMN_GRPID) *((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: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = hp->h_meta->h_pflags;
};
*attrbufptrptr = attrbufptr;
*varbufptrptr = varbufptr;
}
// Pack the directory attributes given hfsCatalogInfo
void PackCatalogInfoDirAttributeBlock( struct attrlist *alist, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr )
{
void *attrbufptr;
attrgroup_t a;
attrbufptr = *attrbufptrptr;
a = alist->dirattr;
if ( (catInfo->nodeData.nodeType == kCatalogFolderNode) && (a != 0) )
{
/* The 'link count' is faked as 1 (the parent entry and "."). In reality it would include at least an additional link for the ".." in each subdirectory. */
if (a & ATTR_DIR_LINKCOUNT) *((u_long *)attrbufptr)++ = 2;
if (a & ATTR_DIR_ENTRYCOUNT) *((u_long *)attrbufptr)++ = catInfo->nodeData.valence;
};
*attrbufptrptr = attrbufptr;
}
void PackDirAttributeBlock(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;
a = alist->dirattr;
if ((vp->v_type == VDIR) && (a != 0)) {
/* The 'link count' is faked as 1 (the parent entry and "."). In reality it would include at least
an additional link for the ".." in each subdirectory. */
if (a & ATTR_DIR_LINKCOUNT) *((u_long *)attrbufptr)++ = 2;
if (a & ATTR_DIR_ENTRYCOUNT) *((u_long *)attrbufptr)++ = catInfo->nodeData.valence;
};
*attrbufptrptr = attrbufptr;
// *varbufptrptr = varbufptr;
}
// Pack the file attributes from the hfsCatalogInfo for the file.
void PackCatalogInfoFileAttributeBlock( struct attrlist *alist, struct hfsCatalogInfo *catInfo, struct vnode *root_vp, 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.nodeType == kCatalogFileNode) && (a != 0) )
{
if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1; /* There ARE no hard links... */
if (a & ATTR_FILE_TOTALSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataLogicalSize + (off_t)catInfo->nodeData.rsrcLogicalSize;
if (a & ATTR_FILE_ALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataPhysicalSize + (off_t)catInfo->nodeData.rsrcPhysicalSize;
if (a & ATTR_FILE_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = (u_long)(VTOHFS(root_vp)->hfs_log_block_size);
if (a & ATTR_FILE_CLUMPSIZE) *((u_long *)attrbufptr)++ = vcb->vcbClpSiz; //XXX Yikes, this is just the vcb clump size
if (a & ATTR_FILE_DEVTYPE) *((u_long *)attrbufptr)++ = (u_long)catInfo->nodeData.permissions.specialDevice;
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: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (a & ATTR_FILE_DATALENGTH) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataLogicalSize;
if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataPhysicalSize;
if (a & ATTR_FILE_DATAEXTENTS)
{
bcopy(&catInfo->nodeData.dataExtents, attrbufptr, sizeof(extentrecord));
attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
};
if (a & ATTR_FILE_RSRCLENGTH) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.rsrcLogicalSize;
if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.rsrcPhysicalSize;
if (a & ATTR_FILE_RSRCEXTENTS)
{
bcopy(&catInfo->nodeData.rsrcExtents, attrbufptr, sizeof(extentrecord));
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);
ExtendedFCB *extendedFCB;
HFSPlusExtentDescriptor *parellextents;
ExtendedVCB *vcb = HTOVCB(hp);
Boolean isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
void *attrbufptr = *attrbufptrptr;
void *varbufptr = *varbufptrptr;
attrgroup_t a = alist->fileattr;
u_long attrlength;
if ((vp->v_type == VREG) && (a != 0)) {
if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1; /* There ARE no hard links... */
if (a & ATTR_FILE_TOTALSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataLogicalSize +
(off_t)catInfo->nodeData.rsrcLogicalSize;
if (a & ATTR_FILE_ALLOCSIZE) {
switch (H_FORKTYPE(hp)) {
case kDataFork:
*((off_t *)attrbufptr)++ = (off_t)fcb->fcbPLen + (off_t)catInfo->nodeData.rsrcPhysicalSize;
case kRsrcFork:
*((off_t *)attrbufptr)++ = (off_t)fcb->fcbPLen + (off_t)catInfo->nodeData.dataPhysicalSize;
default:
*((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataPhysicalSize +
(off_t)catInfo->nodeData.rsrcPhysicalSize;
};
};
if (a & ATTR_FILE_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = hp->h_meta->h_logBlockSize;
if (a & ATTR_FILE_CLUMPSIZE) *((u_long *)attrbufptr)++ = fcb->fcbClmpSize;
if (a & ATTR_FILE_DEVTYPE) *((u_long *)attrbufptr)++ = (u_long)catInfo->nodeData.permissions.specialDevice;
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: */
varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
++((struct attrreference *)attrbufptr);
};
if (H_FORKTYPE(hp) == kDataFork) {
if (a & ATTR_FILE_DATALENGTH)
#if MACH_NBC
if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped &&
(!vp->v_vm_info->filesize)) {
*((off_t *)attrbufptr)++ = vp->v_vm_info->vnode_size;
}
else
#endif /* MACH_NBC */
*((off_t *)attrbufptr)++ = fcb->fcbEOF;
if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen;
if (a & ATTR_FILE_DATAEXTENTS) {
if ( ! isHFSPlus) {
/* HFS, Copy the extents from the FCB part */
int i;
HFSPlusExtentRecord extents;
for (i = 0; i < kHFSExtentDensity; ++i) {
extents[i].startBlock = (UInt16) (fcb->fcbExtRec[i].startBlock);
extents[i].blockCount = (UInt16) (fcb->fcbExtRec[i].blockCount);
};
bcopy ( extents, attrbufptr, sizeof(extentrecord));
} else {
/* HFSPlus, Copy the extents from the parallel extents */
extendedFCB = GetParallelFCB (HTOV(hp));
parellextents = extendedFCB->extents;
bcopy ( parellextents, attrbufptr, sizeof(extentrecord));
};
attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
};
} else {
if (a & ATTR_FILE_DATALENGTH) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataLogicalSize;
if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.dataPhysicalSize;
if (a & ATTR_FILE_DATAEXTENTS) {
bcopy(&catInfo->nodeData.dataExtents, attrbufptr, sizeof(extentrecord));
attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
};
};
if (H_FORKTYPE(hp) == kRsrcFork) {
if (a & ATTR_FILE_RSRCLENGTH)
#if MACH_NBC
if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped &&
(!vp->v_vm_info->filesize)) {
*((off_t *)attrbufptr)++ = vp->v_vm_info->vnode_size;
}
else
#endif /* MACH_NBC */
*((off_t *)attrbufptr)++ = fcb->fcbEOF;
if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen;
if (a & ATTR_FILE_RSRCEXTENTS) {
if ( ! isHFSPlus) {
/* HFS, Copy the extents from the FCB part */
int i;
HFSPlusExtentRecord extents;
for (i = 0; i < kHFSExtentDensity; ++i) {
extents[i].startBlock = (UInt16) (fcb->fcbExtRec[i].startBlock);
extents[i].blockCount = (UInt16) (fcb->fcbExtRec[i].blockCount);
};
bcopy ( extents, attrbufptr, sizeof(extentrecord));
} else {
/* HFSPlus, Copy the extents from the parallel extents */
extendedFCB = GetParallelFCB (HTOV(hp));
parellextents = extendedFCB->extents;
bcopy ( parellextents, attrbufptr, sizeof(extentrecord));
};
attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
};
} else {
if (a & ATTR_FILE_RSRCLENGTH) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.rsrcLogicalSize;
if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = (off_t)catInfo->nodeData.rsrcPhysicalSize;
if (a & ATTR_FILE_RSRCEXTENTS) {
bcopy(&catInfo->nodeData.rsrcExtents, attrbufptr, sizeof(extentrecord));
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.nodeType )
{
case kCatalogFolderNode:
PackCatalogInfoDirAttributeBlock( alist, catInfo, attrbufptrptr, varbufptrptr );
break;
case kCatalogFileNode:
PackCatalogInfoFileAttributeBlock( alist, catInfo, root_vp, 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) {
// DBG_FUNC_NAME("PackAttributeBlock");
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 VCPLX: */ /* XXX PPD TBC */
PackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
break;
#if 0 /* XXX PPD TBC */
case VFORK:
PackForkAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
break;
#endif
/* 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;
text_encoding_t nameEncoding;
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) {
/* XXX PPD No use for this info right now... */
nameEncoding = *(((text_encoding_t *)attrbufptr)++);
#if DIAGNOSTIC
a &= ~ATTR_CMN_SCRIPT;
#endif
};
if (a & ATTR_CMN_CRTIME) {
/*
* HFS Plus stores the volume create date in *local*
* time in the volume header. So don't set the create
* date in the vcb. Set the root's crtime instead.
*/
if (vcb->vcbSigWord == kHFSPlusSigWord) {
VTOH(root_vp)->h_meta->h_crtime =
(UInt32)((struct timespec *)attrbufptr)->tv_sec;
} else {
vcb->vcbCrDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
}
++((struct timespec *)attrbufptr);
#if 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 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 DIAGNOSTIC
a &= ~ATTR_CMN_BKUPTIME;
#endif
};
if (a & ATTR_CMN_FNDRINFO) {
bcopy (attrbufptr, &vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo));
attrbufptr += sizeof(vcb->vcbFndrInfo);
#if 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);
attrbufptr += sizeof(struct attrreference);
#if 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) {
/* XXX PPD No use for this info right now... */
++((text_encoding_t *)attrbufptr);
#if DIAGNOSTIC
a &= ~ATTR_CMN_SCRIPT;
#endif
};
if (a & ATTR_CMN_CRTIME) {
catInfo->nodeData.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 DIAGNOSTIC
a &= ~ATTR_CMN_CRTIME;
#endif
};
if (a & ATTR_CMN_MODTIME) {
catInfo->nodeData.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);
#if DIAGNOSTIC
a &= ~ATTR_CMN_MODTIME;
#endif
};
if (a & ATTR_CMN_CHGTIME) {
catInfo->nodeData.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);
#if DIAGNOSTIC
a &= ~ATTR_CMN_CHGTIME;
#endif
};
if (a & ATTR_CMN_ACCTIME) {
catInfo->nodeData.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);
#if DIAGNOSTIC
a &= ~ATTR_CMN_ACCTIME;
#endif
};
if (a & ATTR_CMN_BKUPTIME) {
catInfo->nodeData.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 DIAGNOSTIC
a &= ~ATTR_CMN_BKUPTIME;
#endif
};
if (a & ATTR_CMN_FNDRINFO) {
bcopy (attrbufptr, &catInfo->nodeData.finderInfo, sizeof(catInfo->nodeData.finderInfo));
attrbufptr += sizeof(catInfo->nodeData.finderInfo);
bcopy (attrbufptr, &catInfo->nodeData.extFinderInfo, sizeof(catInfo->nodeData.extFinderInfo));
attrbufptr += sizeof(catInfo->nodeData.extFinderInfo);
#if 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 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 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 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 DIAGNOSTIC
a &= ~ATTR_CMN_FLAGS;
#endif
};
#if 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;
};
};
};
/* 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;
}
/*
* 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) {
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 badMDBErr: /* -60 */
case fnOpnErr: /* -38 */
return EBADF; /* +9 */
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 eofErr: /* -39 */
case posErr: /* -40 */
case paramErr: /* -50 */
case badMovErr: /* -122 */
case sameFileErr: /* -1306 */
case badFidErr: /* -1307 */
case fileBoundsErr: /* -1309 */
return EINVAL; /* +22 */
default:
DBG_UTILS(("Unmapped MacOS error: %d\n", err));
return EIO; /* +5 */
}
}
/*
* All of our debugging functions
*/
#if DIAGNOSTIC
void debug_vn_status (char* introStr, struct vnode *vn)
{
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"));
};
}
void debug_vn_print (char* introStr, struct vnode *vn)
{
// 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"));
}
}
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
)
{
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"));
}
}
}
#endif /* DIAGNOSTIC */
#if 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);
if (bp->b_lblkno < hp->h_uniformblocksizestart) {
DBG_ASSERT((bp->b_bcount == MAXLOGBLOCKSIZE) ||
(bp->b_bcount == LogicalBlockSize(hp, bp->b_lblkno)) ||
((bp->b_bcount % 512 == 0) &&
(bp->b_validend > 0) &&
(bp->b_dirtyend >= 0) && /* Could be partial block due to file growth */
(bp->b_bcount < LogicalBlockSize(hp, bp->b_lblkno))));
} else {
DBG_ASSERT((bp->b_bcount == hp->h_meta->h_logBlockSize) ||
((bp->b_bcount % 512 == 0) &&
(bp->b_validend > 0) &&
(bp->b_dirtyend > 0) &&
(bp->b_bcount < hp->h_meta->h_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);
};
if ((bp->b_lblkno == 0x21) || (bp->b_lblkno == 0x22)) DBG_ASSERT((hp->h_uniformblocksizestart > 0x21) || (bp->b_bcount != MAXLOGBLOCKSIZE));
}
void debug_check_blocksizes(struct vnode *vp) {
struct hfsnode *hp = VTOH(vp);
struct buf *bp;
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);
};
for (bp = vp->v_dirtyblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) {
debug_check_buffersizes(vp, hp, bp);
};
}
#endif /* DIAGNOSTIC */