X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0b4c1975fb5e4eccf1012a35081f7e7799b81046..04b8595b18b1b41ac7a206e4b3d51a635f8413d7:/bsd/hfs/hfscommon/Misc/FileExtentMapping.c diff --git a/bsd/hfs/hfscommon/Misc/FileExtentMapping.c b/bsd/hfs/hfscommon/Misc/FileExtentMapping.c index 5d037026b..018a8701e 100644 --- a/bsd/hfs/hfscommon/Misc/FileExtentMapping.c +++ b/bsd/hfs/hfscommon/Misc/FileExtentMapping.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2013 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -97,7 +97,9 @@ Internal Routines: and was in the extents file, then delete the record instead. */ +#if CONFIG_HFS_STD static const int64_t kTwoGigabytes = 0x80000000LL; +#endif enum { @@ -108,9 +110,11 @@ enum }; +#if CONFIG_HFS_STD static OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents); +#endif static OSErr FindExtentRecord( const ExtendedVCB *vcb, @@ -180,7 +184,8 @@ static OSErr TruncateExtents( static OSErr UpdateExtentRecord ( ExtendedVCB *vcb, - FCB *fcb, + FCB *fcb, + int deleted, const HFSPlusExtentKey *extentFileKey, const HFSPlusExtentRecord extentData, u_int32_t extentBTreeHint); @@ -224,7 +229,7 @@ static OSErr FindExtentRecord( u_int32_t *foundHint) { FCB * fcb; - BTreeIterator btIterator; + struct BTreeIterator *btIterator = NULL; FSBufferDescriptor btRecord; OSErr err; u_int16_t btRecordSize; @@ -233,14 +238,60 @@ static OSErr FindExtentRecord( if (foundHint) *foundHint = 0; fcb = GetFileControlBlock(vcb->extentsRefNum); - - bzero(&btIterator, sizeof(btIterator)); - if (vcb->vcbSigWord == kHFSSigWord) { + MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); + if (btIterator == NULL) { + return memFullErr; // translates to ENOMEM + } + bzero(btIterator, sizeof(*btIterator)); + + /* HFS Plus / HFSX */ + if (vcb->vcbSigWord != kHFSSigWord) { + HFSPlusExtentKey * extentKeyPtr; + HFSPlusExtentRecord extentData; + + extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key; + extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; + extentKeyPtr->forkType = forkType; + extentKeyPtr->pad = 0; + extentKeyPtr->fileID = fileID; + extentKeyPtr->startBlock = startBlock; + + btRecord.bufferAddress = &extentData; + btRecord.itemSize = sizeof(HFSPlusExtentRecord); + btRecord.itemCount = 1; + + err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator); + + if (err == btNotFound && allowPrevious) { + err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize); + + // A previous record may not exist, so just return btNotFound (like we would if + // it was for the wrong file/fork). + if (err == (OSErr) fsBTStartOfIterationErr) //¥¥ fsBTStartOfIterationErr is type unsigned long + err = btNotFound; + + if (err == noErr) { + // Found a previous record. Does it belong to the same fork of the same file? + if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType) + err = btNotFound; + } + } + + if (err == noErr) { + // Copy the found key back for the caller + if (foundKey) + BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); + // Copy the found data back for the caller + BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord)); + } + } +#if CONFIG_HFS_STD + else { HFSExtentKey * extentKeyPtr; HFSExtentRecord extentData; - extentKeyPtr = (HFSExtentKey*) &btIterator.key; + extentKeyPtr = (HFSExtentKey*) &btIterator->key; extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength; extentKeyPtr->forkType = forkType; extentKeyPtr->fileID = fileID; @@ -250,10 +301,10 @@ static OSErr FindExtentRecord( btRecord.itemSize = sizeof(HFSExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator); + err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator); if (err == btNotFound && allowPrevious) { - err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize); + err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize); // A previous record may not exist, so just return btNotFound (like we would if // it was for the wrong file/fork). @@ -293,49 +344,12 @@ static OSErr FindExtentRecord( } } } - else { // HFS Plus volume - HFSPlusExtentKey * extentKeyPtr; - HFSPlusExtentRecord extentData; - - extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key; - extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; - extentKeyPtr->forkType = forkType; - extentKeyPtr->pad = 0; - extentKeyPtr->fileID = fileID; - extentKeyPtr->startBlock = startBlock; - - btRecord.bufferAddress = &extentData; - btRecord.itemSize = sizeof(HFSPlusExtentRecord); - btRecord.itemCount = 1; - - err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator); - - if (err == btNotFound && allowPrevious) { - err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize); - - // A previous record may not exist, so just return btNotFound (like we would if - // it was for the wrong file/fork). - if (err == (OSErr) fsBTStartOfIterationErr) //¥¥ fsBTStartOfIterationErr is type unsigned long - err = btNotFound; - - if (err == noErr) { - // Found a previous record. Does it belong to the same fork of the same file? - if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType) - err = btNotFound; - } - } - - if (err == noErr) { - // Copy the found key back for the caller - if (foundKey) - BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); - // Copy the found data back for the caller - BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord)); - } - } +#endif if (foundHint) - *foundHint = btIterator.hint.nodeNum; + *foundHint = btIterator->hint.nodeNum; + + FREE(btIterator, M_TEMP); return err; } @@ -347,7 +361,7 @@ static OSErr CreateExtentRecord( HFSPlusExtentRecord extents, u_int32_t *hint) { - BTreeIterator btIterator; + struct BTreeIterator *btIterator = NULL; FSBufferDescriptor btRecord; u_int16_t btRecordSize; int lockflags; @@ -356,7 +370,11 @@ static OSErr CreateExtentRecord( err = noErr; *hint = 0; - bzero(&btIterator, sizeof(btIterator)); + MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); + if (btIterator == NULL) { + return memFullErr; // translates to ENOMEM + } + bzero(btIterator, sizeof(*btIterator)); /* * The lock taken by callers of ExtendFileC is speculative and @@ -367,7 +385,18 @@ static OSErr CreateExtentRecord( */ lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK); - if (vcb->vcbSigWord == kHFSSigWord) { + /* HFS+/HFSX */ + if (vcb->vcbSigWord != kHFSSigWord) { + btRecordSize = sizeof(HFSPlusExtentRecord); + btRecord.bufferAddress = extents; + btRecord.itemSize = btRecordSize; + btRecord.itemCount = 1; + + BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey)); + } +#if CONFIG_HFS_STD + else { + /* HFS Standard */ HFSExtentKey * keyPtr; HFSExtentRecord data; @@ -376,7 +405,7 @@ static OSErr CreateExtentRecord( btRecord.itemSize = btRecordSize; btRecord.itemCount = 1; - keyPtr = (HFSExtentKey*) &btIterator.key; + keyPtr = (HFSExtentKey*) &btIterator->key; keyPtr->keyLength = kHFSExtentKeyMaximumLength; keyPtr->forkType = key->forkType; keyPtr->fileID = key->fileID; @@ -384,25 +413,19 @@ static OSErr CreateExtentRecord( err = HFSPlusToHFSExtents(extents, data); } - else { // HFS Plus volume - btRecordSize = sizeof(HFSPlusExtentRecord); - btRecord.bufferAddress = extents; - btRecord.itemSize = btRecordSize; - btRecord.itemCount = 1; - - BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey)); - } +#endif if (err == noErr) - err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize); + err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator, &btRecord, btRecordSize); if (err == noErr) - *hint = btIterator.hint.nodeNum; + *hint = btIterator->hint.nodeNum; (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum)); hfs_systemfile_unlock(vcb, lockflags); - + + FREE (btIterator, M_TEMP); return err; } @@ -413,36 +436,46 @@ static OSErr DeleteExtentRecord( u_int32_t fileID, u_int32_t startBlock) { - BTreeIterator btIterator; + struct BTreeIterator *btIterator = NULL; OSErr err; err = noErr; - bzero(&btIterator, sizeof(btIterator)); + MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); + if (btIterator == NULL) { + return memFullErr; // translates to ENOMEM + } + bzero(btIterator, sizeof(*btIterator)); - if (vcb->vcbSigWord == kHFSSigWord) { - HFSExtentKey * keyPtr; + /* HFS+ / HFSX */ + if (vcb->vcbSigWord != kHFSSigWord) { // HFS Plus volume + HFSPlusExtentKey * keyPtr; - keyPtr = (HFSExtentKey*) &btIterator.key; - keyPtr->keyLength = kHFSExtentKeyMaximumLength; + keyPtr = (HFSPlusExtentKey*) &btIterator->key; + keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; keyPtr->forkType = forkType; + keyPtr->pad = 0; keyPtr->fileID = fileID; keyPtr->startBlock = startBlock; } - else { // HFS Plus volume - HFSPlusExtentKey * keyPtr; +#if CONFIG_HFS_STD + else { + /* HFS standard */ + HFSExtentKey * keyPtr; - keyPtr = (HFSPlusExtentKey*) &btIterator.key; - keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; + keyPtr = (HFSExtentKey*) &btIterator->key; + keyPtr->keyLength = kHFSExtentKeyMaximumLength; keyPtr->forkType = forkType; - keyPtr->pad = 0; keyPtr->fileID = fileID; keyPtr->startBlock = startBlock; } +#endif - err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator); + err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator); (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum)); + + FREE(btIterator, M_TEMP); return err; } @@ -456,7 +489,6 @@ static OSErr DeleteExtentRecord( // //_________________________________________________________________________________ -__private_extern__ OSErr MapFileBlockC ( ExtendedVCB *vcb, // volume that file resides on FCB *fcb, // FCB of file @@ -529,10 +561,19 @@ OSErr MapFileBlockC ( if (availableBytes) { tmpOff = dataEnd - offset; - if (tmpOff > (off_t)(numberOfBytes)) + /* + * Disallow negative runs. + */ + if (tmpOff <= 0) { + return EINVAL; + } + + if (tmpOff > (off_t)(numberOfBytes)) { *availableBytes = numberOfBytes; // more there than they asked for, so pin the output - else + } + else { *availableBytes = tmpOff; + } } return noErr; @@ -682,7 +723,6 @@ static OSErr DeallocateFork( // Function: Flushes the extent file for a specified volume //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -__private_extern__ OSErr FlushExtentFile( ExtendedVCB *vcb ) { FCB * fcb; @@ -710,6 +750,7 @@ OSErr FlushExtentFile( ExtendedVCB *vcb ) } +#if CONFIG_HFS_STD //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ // Routine: CompareExtentKeys // @@ -771,7 +812,7 @@ int32_t CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *tr return( result ); } - +#endif //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ @@ -842,7 +883,6 @@ int32_t CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusE * Used by hfs_extendfs to extend the volume allocation bitmap file. * */ -__private_extern__ int AddFileExtent(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockCount) { @@ -896,7 +936,7 @@ AddFileExtent(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockC */ foundData[foundIndex].startBlock = startBlock; foundData[foundIndex].blockCount = blockCount; - error = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint); + error = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint); } (void) FlushExtentFile(vcb); @@ -912,7 +952,6 @@ AddFileExtent(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockC // //_________________________________________________________________________________ -__private_extern__ OSErr ExtendFileC ( ExtendedVCB *vcb, // volume that file resides on FCB *fcb, // FCB of file to truncate @@ -936,6 +975,7 @@ OSErr ExtendFileC ( Boolean wantContig; Boolean useMetaZone; Boolean needsFlush; + int allowFlushTxns; u_int32_t actualStartBlock; u_int32_t actualNumBlocks; u_int32_t numExtentsPerRecord; @@ -943,8 +983,8 @@ OSErr ExtendFileC ( int64_t availbytes; int64_t peof; u_int32_t prevblocks; - - + struct hfsmount *hfsmp = (struct hfsmount*)vcb; + allowFlushTxns = 0; needsFlush = false; *actualBytesAdded = 0; volumeBlockSize = vcb->blockSize; @@ -952,20 +992,22 @@ OSErr ExtendFileC ( forceContig = ((flags & kEFContigMask) != 0); prevblocks = fcb->ff_blocks; - if (vcb->vcbSigWord == kHFSPlusSigWord) + if (vcb->vcbSigWord != kHFSSigWord) { numExtentsPerRecord = kHFSPlusExtentDensity; - else + } +#if CONFIG_HFS_STD + else { + /* HFS Standard */ numExtentsPerRecord = kHFSExtentDensity; - // - // Make sure the request and new PEOF are less than 2GB if HFS. - // - if (vcb->vcbSigWord == kHFSSigWord) { + /* Make sure the request and new PEOF are less than 2GB if HFS std*/ if (bytesToAdd >= kTwoGigabytes) - goto Overflow; + goto HFS_Std_Overflow; if ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) - goto Overflow; + goto HFS_Std_Overflow; } +#endif + // // Determine how many blocks need to be allocated. // Round up the number of desired bytes to add. @@ -980,9 +1022,9 @@ OSErr ExtendFileC ( && (vcb->vcbSigWord == kHFSPlusSigWord) && (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC) && (blocksToAdd < hfs_freeblks(VCBTOHFS(vcb), 1))) { - HFS_MOUNT_LOCK(vcb, TRUE); + hfs_lock_mount (hfsmp); vcb->loanedBlocks += blocksToAdd; - HFS_MOUNT_UNLOCK(vcb, TRUE); + hfs_unlock_mount(hfsmp); fcb->ff_unallocblocks += blocksToAdd; FTOC(fcb)->c_blocks += blocksToAdd; @@ -1005,9 +1047,9 @@ OSErr ExtendFileC ( fcb->ff_blocks -= loanedBlocks; fcb->ff_unallocblocks = 0; - HFS_MOUNT_LOCK(vcb, TRUE); + hfs_lock_mount(hfsmp); vcb->loanedBlocks -= loanedBlocks; - HFS_MOUNT_UNLOCK(vcb, TRUE); + hfs_unlock_mount(hfsmp); } // @@ -1024,18 +1066,20 @@ OSErr ExtendFileC ( maximumBytes = bytesToAdd; } +#if CONFIG_HFS_STD // // Compute new physical EOF, rounded up to a multiple of a block. // if ( (vcb->vcbSigWord == kHFSSigWord) && // Too big? ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) ) { if (allOrNothing) // Yes, must they have it all? - goto Overflow; // Yes, can't have it + goto HFS_Std_Overflow; // Yes, can't have it else { --blocksToAdd; // No, give give 'em one block less bytesToAdd -= volumeBlockSize; } } +#endif // // If allocation is all-or-nothing, make sure there are @@ -1087,23 +1131,48 @@ OSErr ExtendFileC ( * should only be aggressive with re-using once-allocated pieces * if we're not dealing with system files. If we're trying to operate * on behalf of a system file, we need the maximum contiguous amount - * possible. + * possible. For non-system files we favor locality and fragmentation over + * contiguity as it can result in fewer blocks being needed from the underlying + * filesystem that the sparse image resides upon. */ err = noErr; if ( (vcb->hfs_flags & HFS_HAS_SPARSE_DEVICE) - && (fcb->ff_cp->c_fileid >= kHFSFirstUserCatalogNodeID) - && (flags & kEFMetadataMask) == 0) { - if (vcb->hfs_flags & HFS_DID_CONTIG_SCAN) { - wantContig = false; - } else { - // we only want to do this once to scan the bitmap to - // fill in the vcbFreeExt table of free blocks - vcb->hfs_flags |= HFS_DID_CONTIG_SCAN; - wantContig = true; + && (fcb->ff_cp->c_fileid >= kHFSFirstUserCatalogNodeID) + && (flags & kEFMetadataMask) == 0) { + /* + * We want locality over contiguity so by default we set wantContig to + * false unless we hit one of the circumstances below. + */ + wantContig = false; + if (hfs_isrbtree_active(VCBTOHFS(vcb))) { + /* + * If the red-black tree is acive, we can always find a suitable contiguous + * chunk. So if the user specifically requests contiguous files, we should + * honor that no matter what kind of device it is. + */ + if (forceContig) { + wantContig = true; + } } - } else { + else { + /* + * If the red-black tree is not active, then only set wantContig to true + * if we have never done a contig scan on the device, which would populate + * the free extent cache. Note that the caller may explicitly unset the + * DID_CONTIG_SCAN bit in order to force us to vend a contiguous extent here + * if the caller wants to get a contiguous chunk. + */ + if ((vcb->hfs_flags & HFS_DID_CONTIG_SCAN) == 0) { + vcb->hfs_flags |= HFS_DID_CONTIG_SCAN; + wantContig = true; + } + } + } + else { wantContig = true; } + + useMetaZone = flags & kEFMetadataMask; do { if (blockHint != 0) @@ -1120,23 +1189,45 @@ OSErr ExtendFileC ( if (availbytes <= 0) { err = dskFulErr; } else { - if (wantContig && (availbytes < bytesToAdd)) + if (wantContig && (availbytes < bytesToAdd)) { err = dskFulErr; + } else { + uint32_t ba_flags = 0; + + if (wantContig) { + ba_flags |= HFS_ALLOC_FORCECONTIG; + } + if (useMetaZone) { + ba_flags |= HFS_ALLOC_METAZONE; + } + if (allowFlushTxns) { + ba_flags |= HFS_ALLOC_FLUSHTXN; + } + err = BlockAllocate( vcb, startBlock, howmany(MIN(bytesToAdd, availbytes), volumeBlockSize), howmany(MIN(maximumBytes, availbytes), volumeBlockSize), - (wantContig ? HFS_ALLOC_FORCECONTIG : 0) | - (useMetaZone ? HFS_ALLOC_METAZONE : 0), + ba_flags, &actualStartBlock, &actualNumBlocks); } } if (err == dskFulErr) { - if (forceContig) - break; // AllocContig failed because not enough contiguous space + if (forceContig) { + if (allowFlushTxns == 0) { + /* If we're forcing contiguity, re-try but allow plucking from recently freed regions */ + allowFlushTxns = 1; + wantContig = 1; + err = noErr; + continue; + } + else { + break; // AllocContig failed because not enough contiguous space + } + } if (wantContig) { // Couldn't get one big chunk, so get whatever we can. err = noErr; @@ -1145,12 +1236,21 @@ OSErr ExtendFileC ( } if (actualNumBlocks != 0) err = noErr; + if (useMetaZone == 0) { /* Couldn't get anything so dip into metadat zone */ err = noErr; useMetaZone = 1; continue; } + + /* If we couldn't find what we needed without flushing the journal, then go ahead and do it now */ + if (allowFlushTxns == 0) { + allowFlushTxns = 1; + err = noErr; + continue; + } + } if (err == noErr) { if (actualNumBlocks != 0) { @@ -1163,7 +1263,7 @@ OSErr ExtendFileC ( if ((actualStartBlock == startBlock) && (blockHint == 0)) { // We grew the file's last extent, so just adjust the number of blocks. foundData[foundIndex].blockCount += actualNumBlocks; - err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint); + err = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint); if (err != noErr) break; } else { @@ -1217,7 +1317,7 @@ OSErr ExtendFileC ( // Add a new extent into this record and update. foundData[foundIndex].startBlock = actualStartBlock; foundData[foundIndex].blockCount = actualNumBlocks; - err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint); + err = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint); if (err != noErr) break; } } @@ -1254,10 +1354,10 @@ Exit: /* Keep the roving allocator out of the metadata zone. */ if (vcb->nextAllocation >= VCBTOHFS(vcb)->hfs_metazone_start && vcb->nextAllocation <= VCBTOHFS(vcb)->hfs_metazone_end) { - HFS_MOUNT_LOCK(vcb, TRUE); + hfs_lock_mount (hfsmp); HFS_UPDATE_NEXT_ALLOCATION(vcb, VCBTOHFS(vcb)->hfs_metazone_end + 1); MarkVCBDirty(vcb); - HFS_MOUNT_UNLOCK(vcb, TRUE); + hfs_unlock_mount(hfsmp); } } if (prevblocks < fcb->ff_blocks) { @@ -1271,9 +1371,11 @@ Exit: return err; -Overflow: +#if CONFIG_HFS_STD +HFS_Std_Overflow: err = fileBoundsErr; goto ErrorExit; +#endif } @@ -1289,12 +1391,15 @@ Overflow: // //_________________________________________________________________________________ -__private_extern__ OSErr TruncateFileC ( ExtendedVCB *vcb, // volume that file resides on FCB *fcb, // FCB of file to truncate int64_t peof, // new physical size for file + int deleted, // if nonzero, the file's catalog record has already been deleted. + int rsrc, // does this represent a resource fork or not? + uint32_t fileid, // the fileid of the file we're manipulating. Boolean truncateToExtent) // if true, truncate to end of extent containing newPEOF + { OSErr err; u_int32_t nextBlock; // next file allocation block to consider @@ -1314,16 +1419,20 @@ OSErr TruncateFileC ( recordDeleted = false; - if (vcb->vcbSigWord == kHFSPlusSigWord) + if (vcb->vcbSigWord == kHFSPlusSigWord) { numExtentsPerRecord = kHFSPlusExtentDensity; - else + } + else { numExtentsPerRecord = kHFSExtentDensity; - - if (FORK_IS_RSRC(fcb)) + } + + if (rsrc) { forkType = kResourceForkType; - else + } + else { forkType = kDataForkType; - + } + temp64 = fcb->ff_blocks; physNumBlocks = (u_int32_t)temp64; @@ -1334,6 +1443,8 @@ OSErr TruncateFileC ( // nextBlock = howmany(peof, vcb->blockSize); // number of allocation blocks to remain in file peof = (int64_t)((int64_t)nextBlock * (int64_t)vcb->blockSize); // number of bytes in those blocks + +#if CONFIG_HFS_STD if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= kTwoGigabytes)) { #if DEBUG_BUILD DebugStr("HFS: Trying to truncate a file to 2GB or more"); @@ -1341,6 +1452,7 @@ OSErr TruncateFileC ( err = fileBoundsErr; goto ErrorExit; } +#endif // // Update FCB's length @@ -1349,13 +1461,21 @@ OSErr TruncateFileC ( * XXX Any errors could cause ff_blocks and c_blocks to get out of sync... */ numBlocks = peof / vcb->blockSize; - FTOC(fcb)->c_blocks -= (fcb->ff_blocks - numBlocks); + if (!deleted) { + FTOC(fcb)->c_blocks -= (fcb->ff_blocks - numBlocks); + } fcb->ff_blocks = numBlocks; - + // this catalog entry is modified and *must* get forced // to disk when hfs_update() is called - FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE; - + if (!deleted) { + /* + * If the file is already C_NOEXISTS, then the catalog record + * has been removed from disk already. We wouldn't need to force + * another update + */ + FTOC(fcb)->c_flag |= (C_MODIFIED | C_FORCEUPDATE); + } // // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate // all storage). @@ -1364,7 +1484,7 @@ OSErr TruncateFileC ( int i; // Deallocate all the extents for this fork - err = DeallocateFork(vcb, FTOC(fcb)->c_fileid, forkType, fcb->fcbExtents, &recordDeleted); + err = DeallocateFork(vcb, fileid, forkType, fcb->fcbExtents, &recordDeleted); if (err != noErr) goto ErrorExit; // got some error, so return it // Update the catalog extent record (making sure it's zeroed out) @@ -1440,7 +1560,7 @@ OSErr TruncateFileC ( // record (in the FCB, or extents file). // if (extentChanged) { - err = UpdateExtentRecord(vcb, fcb, &key, extentRecord, hint); + err = UpdateExtentRecord(vcb, fcb, deleted, &key, extentRecord, hint); if (err != noErr) goto ErrorExit; } @@ -1450,7 +1570,7 @@ OSErr TruncateFileC ( // blocks. // if (nextBlock < physNumBlocks) - err = TruncateExtents(vcb, forkType, FTOC(fcb)->c_fileid, nextBlock, &recordDeleted); + err = TruncateExtents(vcb, forkType, fileid, nextBlock, &recordDeleted); Done: ErrorExit: @@ -1465,7 +1585,6 @@ ErrorExit: * HFS Plus only * */ -__private_extern__ OSErr HeadTruncateFile ( ExtendedVCB *vcb, FCB *fcb, @@ -1641,7 +1760,8 @@ static OSErr SearchExtentRecord( { OSErr err = noErr; u_int32_t extentIndex; - u_int32_t numberOfExtents; + /* Set it to the HFS std value */ + u_int32_t numberOfExtents = kHFSExtentDensity; u_int32_t numAllocationBlocks; Boolean foundExtent; @@ -1649,10 +1769,10 @@ static OSErr SearchExtentRecord( *noMoreExtents = false; foundExtent = false; - if (vcb->vcbSigWord == kHFSPlusSigWord) + /* Override numberOfExtents for HFS+/HFSX */ + if (vcb->vcbSigWord != kHFSSigWord) { numberOfExtents = kHFSPlusExtentDensity; - else - numberOfExtents = kHFSExtentDensity; + } for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex ) { @@ -1824,6 +1944,7 @@ Exit: // // Input: vcb - the volume containing the extents // fcb - the file that owns the extents +// deleted - whether or not the file is already deleted // extentFileKey - pointer to extent key record (xkr) // If the key length is 0, then the extents are actually part // of the catalog record, stored in the FCB. @@ -1834,21 +1955,21 @@ Exit: // (other) = error from BTree //============================================================================ -static OSErr UpdateExtentRecord ( - ExtendedVCB *vcb, - FCB *fcb, - const HFSPlusExtentKey *extentFileKey, - const HFSPlusExtentRecord extentData, - u_int32_t extentBTreeHint) +static OSErr UpdateExtentRecord (ExtendedVCB *vcb, FCB *fcb, int deleted, + const HFSPlusExtentKey *extentFileKey, + const HFSPlusExtentRecord extentData, + u_int32_t extentBTreeHint) { OSErr err = noErr; if (extentFileKey->keyLength == 0) { // keyLength == 0 means the FCB's extent record BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); - FTOC(fcb)->c_flag |= C_MODIFIED; + if (!deleted) { + FTOC(fcb)->c_flag |= C_MODIFIED; + } } else { - BTreeIterator btIterator; + struct BTreeIterator *btIterator = NULL; FSBufferDescriptor btRecord; u_int16_t btRecordSize; FCB * btFCB; @@ -1858,8 +1979,12 @@ static OSErr UpdateExtentRecord ( // Need to find and change a record in Extents BTree // btFCB = GetFileControlBlock(vcb->extentsRefNum); - - bzero(&btIterator, sizeof(btIterator)); + + MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); + if (btIterator == NULL) { + return memFullErr; // translates to ENOMEM + } + bzero(btIterator, sizeof(*btIterator)); /* * The lock taken by callers of ExtendFileC/TruncateFileC is @@ -1870,53 +1995,61 @@ static OSErr UpdateExtentRecord ( */ lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK); - if (vcb->vcbSigWord == kHFSSigWord) { + /* HFS+/HFSX */ + if (vcb->vcbSigWord != kHFSSigWord) { // HFS Plus volume + HFSPlusExtentRecord foundData; // The extent data actually found + + BlockMoveData(extentFileKey, &btIterator->key, sizeof(HFSPlusExtentKey)); + + btIterator->hint.index = 0; + btIterator->hint.nodeNum = extentBTreeHint; + + btRecord.bufferAddress = &foundData; + btRecord.itemSize = sizeof(HFSPlusExtentRecord); + btRecord.itemCount = 1; + + err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator); + + if (err == noErr) { + BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord)); + err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize); + } + (void) BTFlushPath(btFCB); + } +#if CONFIG_HFS_STD + else { + /* HFS Standard */ HFSExtentKey * key; // Actual extent key used on disk in HFS HFSExtentRecord foundData; // The extent data actually found - key = (HFSExtentKey*) &btIterator.key; + key = (HFSExtentKey*) &btIterator->key; key->keyLength = kHFSExtentKeyMaximumLength; key->forkType = extentFileKey->forkType; key->fileID = extentFileKey->fileID; key->startBlock = extentFileKey->startBlock; - btIterator.hint.index = 0; - btIterator.hint.nodeNum = extentBTreeHint; + btIterator->hint.index = 0; + btIterator->hint.nodeNum = extentBTreeHint; btRecord.bufferAddress = &foundData; btRecord.itemSize = sizeof(HFSExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(btFCB, &btIterator, &btRecord, &btRecordSize, &btIterator); - + err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator); + if (err == noErr) err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData); if (err == noErr) - err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize); + err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize); (void) BTFlushPath(btFCB); - } - else { // HFS Plus volume - HFSPlusExtentRecord foundData; // The extent data actually found - - BlockMoveData(extentFileKey, &btIterator.key, sizeof(HFSPlusExtentKey)); - - btIterator.hint.index = 0; - btIterator.hint.nodeNum = extentBTreeHint; - btRecord.bufferAddress = &foundData; - btRecord.itemSize = sizeof(HFSPlusExtentRecord); - btRecord.itemCount = 1; - - err = BTSearchRecord(btFCB, &btIterator, &btRecord, &btRecordSize, &btIterator); - - if (err == noErr) { - BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord)); - err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize); - } - (void) BTFlushPath(btFCB); } +#endif + hfs_systemfile_unlock(vcb, lockflags); + + FREE(btIterator, M_TEMP); } return err; @@ -1924,7 +2057,7 @@ static OSErr UpdateExtentRecord ( - +#if CONFIG_HFS_STD static OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents) @@ -1950,7 +2083,7 @@ static OSErr HFSPlusToHFSExtents( return err; } - +#endif @@ -2013,7 +2146,6 @@ static Boolean ExtentsAreIntegral( // Called by BTOpenPath during volume mount //_________________________________________________________________________________ -__private_extern__ Boolean NodesAreContiguous( ExtendedVCB *vcb, FCB *fcb,