X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/91447636331957f3d9b5ca5b508f07c526b0074d..c0fea4742e91338fffdcf79f86a7c1d5e2b97eb1:/bsd/hfs/hfs_btreeio.c diff --git a/bsd/hfs/hfs_btreeio.c b/bsd/hfs/hfs_btreeio.c index 688983419..3c19d78e2 100644 --- a/bsd/hfs/hfs_btreeio.c +++ b/bsd/hfs/hfs_btreeio.c @@ -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