]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_btreeio.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_btreeio.c
index 6889834193e70c4eba700013d110880dce5b95a3..3c19d78e2c9eb1a27587ac0dfdd5db60d73c8a9e 100644 (file)
@@ -85,36 +85,57 @@ OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions option
     if (retval == E_NONE) {
         block->blockHeader = bp;
         block->buffer = (char *)buf_dataptr(bp);
+       block->blockNum = buf_lblkno(bp);
         block->blockReadFromDisk = (buf_fromcache(bp) == 0);   /* not found in cache ==> came from disk */
 
                // XXXdbg 
                block->isModified = 0;
 
-#if BYTE_ORDER == LITTLE_ENDIAN
-        /* Endian swap B-Tree node (only if it's a valid block) */
+        /* Check and endian swap B-Tree node (only if it's a valid block) */
         if (!(options & kGetEmptyBlock)) {
             /* This happens when we first open the b-tree, we might not have all the node data on hand */
             if ((((BTNodeDescriptor *)block->buffer)->kind == kBTHeaderNode) &&
                 (((BTHeaderRec *)((char *)block->buffer + 14))->nodeSize != buf_count(bp)) &&
                 (SWAP_BE16 (((BTHeaderRec *)((char *)block->buffer + 14))->nodeSize) != buf_count(bp))) {
 
-                /* Don't swap the descriptors at all, we don't care (this block will be invalidated) */
-                SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), VTOC(vp)->c_fileid, 3);
-
-            /* The node needs swapping */
+                /*
+                 * Don't swap the node descriptor, record offsets, or other records.
+                 * This record will be invalidated and re-read with the correct node
+                 * size once the B-tree control block is set up with the node size
+                 * from the header record.
+                 */
+                retval = hfs_swap_BTNode (block, vp, kSwapBTNodeHeaderRecordOnly);
+
+                       } else if (block->blockReadFromDisk) {
+               /*
+                * The node was just read from disk, so always swap/check it.
+                * This is necessary on big endian since the test below won't trigger.
+                */
+                retval = hfs_swap_BTNode (block, vp, kSwapBTNodeBigToHost);
             } else if (*((UInt16 *)((char *)block->buffer + (block->blockSize - sizeof (UInt16)))) == 0x0e00) {
-                SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), VTOC(vp)->c_fileid, 0);
-#if 0
-            /* The node is not already in native byte order, hence corrupt */
-            } else if (*((UInt16 *)((char *)block->buffer + (block->blockSize - sizeof (UInt16)))) != 0x000e) {
-                panic ("%s Corrupt B-Tree node detected!\n", "GetBTreeBlock:");
-#endif
+                               /*
+                                * The node was left in the cache in non-native order, so swap it.
+                                * This only happens on little endian, after the node is written
+                                * back to disk.
+                                */
+                retval = hfs_swap_BTNode (block, vp, kSwapBTNodeBigToHost);
             }
+            
+               /*
+                * If we got an error, then the node is only partially swapped.
+                * We mark the buffer invalid so that the next attempt to get the
+                * node will read it and attempt to swap again, and will notice
+                * the error again.  If we didn't do this, the next attempt to get
+                * the node might use the partially swapped node as-is.
+                */
+            if (retval)
+                               buf_markinvalid(bp);
         }
-#endif
-    } else {
+    }
+    
+    if (retval) {
        if (bp)
-               buf_brelse(bp);
+                       buf_brelse(bp);
         block->blockHeader = NULL;
         block->buffer = NULL;
     }
@@ -146,20 +167,22 @@ void ModifyBlockStart(FileReference vp, BlockDescPtr blockPtr)
 static int
 btree_journal_modify_block_end(struct hfsmount *hfsmp, struct buf *bp)
 {
-#if BYTE_ORDER == LITTLE_ENDIAN
+       int retval;
     struct vnode *vp = buf_vnode(bp);
     BlockDescriptor block;
                                    
     /* Prepare the block pointer */
     block.blockHeader = bp;
     block.buffer = (char *)buf_dataptr(bp);
+    block.blockNum = buf_lblkno(bp);
     /* not found in cache ==> came from disk */
     block.blockReadFromDisk = (buf_fromcache(bp) == 0);
     block.blockSize = buf_count(bp);
 
     // XXXdbg have to swap the data before it goes in the journal
-    SWAP_BT_NODE (&block, ISHFSPLUS (VTOVCB(vp)), VTOC(vp)->c_fileid, 1);
-#endif
+    retval = hfs_swap_BTNode (&block, vp, kSwapBTNodeHostToBig);
+    if (retval)
+       panic("btree_journal_modify_block_end: about to write corrupt node!\n");
 
     return journal_modify_block_end(hfsmp->jnl, bp);
 }
@@ -266,6 +289,8 @@ exit:
 }
 
 
+#define HFS_CLUMP_ADJ_LIMIT  (200*1024*1024)
+
 __private_extern__
 OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF)
 {
@@ -298,7 +323,13 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF)
        }
 
        vcb = VTOVCB(vp);
-       
+
+       /* Take past growth into account when extending the catalog file. */
+       if ((VTOC(vp)->c_fileid == kHFSCatalogFileID) &&
+           (bytesToAdd / vcb->blockSize) < filePtr->fcbExtents[0].blockCount) {
+                       bytesToAdd = filePtr->fcbExtents[0].blockCount * (UInt64)vcb->blockSize;
+                       bytesToAdd = MIN(bytesToAdd, HFS_CLUMP_ADJ_LIMIT);
+       }
        /*
         * The Extents B-tree can't have overflow extents. ExtendFileC will
         * return an error if an attempt is made to extend the Extents B-tree