]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfscommon/Misc/FileExtentMapping.c
xnu-344.12.2.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / FileExtentMapping.c
index b294edd9ada7c28ab253a7502d32a4e0fd7af9b1..6831d79c0c8898162afa9045fd8ecca1d4aef086 100644 (file)
@@ -495,6 +495,12 @@ static OSErr CreateExtentRecord(
        
        err = noErr;
        *hint = 0;
+
+       // XXXdbg - preflight that there's enough space
+       err = BTCheckFreeSpace(GetFileControlBlock(vcb->extentsRefNum));
+       if (err)
+               return err;
+
        MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
        bzero(btIterator, sizeof(*btIterator));
        
@@ -530,6 +536,8 @@ static OSErr CreateExtentRecord(
        if (err == noErr)
                *hint = btIterator->hint.nodeNum;
 
+       (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
+       
        FREE(btIterator, M_TEMP);       
        return err;
 }
@@ -545,6 +553,12 @@ OSErr DeleteExtentRecord(
        OSErr                           err;
        
        err = noErr;
+
+       // XXXdbg - preflight that there's enough space
+       err = BTCheckFreeSpace(GetFileControlBlock(vcb->extentsRefNum));
+       if (err)
+               return err;
+
        MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
        bzero(btIterator, sizeof(*btIterator));
        
@@ -569,7 +583,8 @@ OSErr DeleteExtentRecord(
        }
 
        err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator);
-
+       (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
+       
        FREE(btIterator, M_TEMP);       
        return err;
 }
@@ -1730,6 +1745,12 @@ static OSErr UpdateExtentRecord (
                //      Need to find and change a record in Extents BTree
                //
                btFCB = GetFileControlBlock(vcb->extentsRefNum);
+
+               // XXXdbg - preflight that there's enough space
+               err = BTCheckFreeSpace(btFCB);
+               if (err)
+                       return err;
+
                MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
                bzero(btIterator, sizeof(*btIterator));
 
@@ -1757,6 +1778,7 @@ static OSErr UpdateExtentRecord (
 
                        if (err == noErr)
                                err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
+                       (void) BTFlushPath(btFCB);
                }
                else {          //      HFS Plus volume
                        HFSPlusExtentRecord     foundData;              // The extent data actually found
@@ -1776,6 +1798,7 @@ static OSErr UpdateExtentRecord (
                                BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
                                err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
                        }
+                       (void) BTFlushPath(btFCB);
                }
                FREE(btIterator, M_TEMP);       
        }
@@ -1887,3 +1910,58 @@ static Boolean ExtentsAreIntegral(
        
        return true;
 }
+
+
+//_________________________________________________________________________________
+//
+// Routine:            NodesAreContiguous
+//
+// Purpose:            Ensure that all b-tree nodes are contiguous on disk
+//                             Called by BTOpenPath during volume mount
+//_________________________________________________________________________________
+
+Boolean NodesAreContiguous(
+       ExtendedVCB     *vcb,
+       FCB                     *fcb,
+       UInt32          nodeSize)
+{
+       UInt32                          mask;
+       UInt32                          startBlock;
+       UInt32                          blocksChecked;
+       UInt32                          hint;
+       HFSPlusExtentKey        key;
+       HFSPlusExtentRecord     extents;
+       OSErr                           result;
+       Boolean                         lastExtentReached;
+       
+
+       if (vcb->blockSize >= nodeSize)
+               return TRUE;
+
+       mask = (nodeSize / vcb->blockSize) - 1;
+
+       // check the local extents
+       (void) GetFCBExtentRecord(fcb, extents);
+       if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
+               return FALSE;
+
+       if (lastExtentReached || (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= fcb->ff_size)
+               return TRUE;
+
+       startBlock = blocksChecked;
+
+       // check the overflow extents (if any)
+       while ( !lastExtentReached )
+       {
+               result = FindExtentRecord(vcb, kDataForkType, fcb->ff_cp->c_fileid, startBlock, FALSE, &key, extents, &hint);
+               if (result) break;
+
+               if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
+                       return FALSE;
+
+               startBlock += blocksChecked;
+       }
+
+       return TRUE;
+}
+