2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include "../../hfs.h"
31 #include "../../hfs_format.h"
32 #include "../../hfs_endian.h"
34 #include "../headers/FileMgrInternal.h"
35 #include "../headers/BTreesInternal.h"
37 #include <sys/malloc.h>
40 ============================================================
41 Public (Exported) Routines:
42 ============================================================
44 ExtendFileC Allocate more space to a given file.
47 Compare two extents file keys (a search key and a trial
48 key). Used by the BTree manager when searching for,
49 adding, or deleting keys in the extents file of an HFS
53 Compare two extents file keys (a search key and a trial
54 key). Used by the BTree manager when searching for,
55 adding, or deleting keys in the extents file of an HFS+
58 MapFileBlockC Convert (map) an offset within a given file into a
59 physical disk address.
61 TruncateFileC Truncates the disk space allocated to a file. The file
62 space is truncated to a specified new physical EOF, rounded
63 up to the next allocation block boundry. There is an option
64 to truncate to the end of the extent containing the new EOF.
67 Flush the extents file for a given volume.
72 ============================================================
74 ============================================================
76 Search the extents BTree for a particular extent record.
78 Search the FCB and extents file for an extent record that
79 contains a given file position (in bytes).
81 Search a given extent record to see if it contains a given
82 file position (in bytes). Used by SearchExtentFile.
84 Deallocate all allocation blocks in all extents of an extent
87 Deallocate blocks and delete extent records for all allocation
88 blocks beyond a certain point in a file. The starting point
89 must be the first file allocation block for some extent record
92 Deallocate all allocation blocks belonging to a given fork.
94 If the extent record came from the extents file, write out
95 the updated record; otherwise, copy the updated record into
96 the FCB resident extent record. If the record has no extents,
97 and was in the extents file, then delete the record instead.
100 static const int64_t kTwoGigabytes
= 0x80000000LL
;
105 kResourceForkType
= 0xFF,
111 static OSErr
HFSPlusToHFSExtents(
112 const HFSPlusExtentRecord oldExtents
,
113 HFSExtentRecord newExtents
);
115 static OSErr
FindExtentRecord(
116 const ExtendedVCB
*vcb
,
119 u_int32_t startBlock
,
120 Boolean allowPrevious
,
121 HFSPlusExtentKey
*foundKey
,
122 HFSPlusExtentRecord foundData
,
123 u_int32_t
*foundHint
);
125 static OSErr
DeleteExtentRecord(
126 const ExtendedVCB
*vcb
,
129 u_int32_t startBlock
);
131 static OSErr
CreateExtentRecord(
133 HFSPlusExtentKey
*key
,
134 HFSPlusExtentRecord extents
,
138 static OSErr
GetFCBExtentRecord(
140 HFSPlusExtentRecord extents
);
142 static OSErr
SearchExtentFile(
145 int64_t filePosition
,
146 HFSPlusExtentKey
*foundExtentKey
,
147 HFSPlusExtentRecord foundExtentData
,
148 u_int32_t
*foundExtentDataIndex
,
149 u_int32_t
*extentBTreeHint
,
150 u_int32_t
*endingFABNPlusOne
);
152 static OSErr
SearchExtentRecord(
154 u_int32_t searchFABN
,
155 const HFSPlusExtentRecord extentData
,
156 u_int32_t extentDataStartFABN
,
157 u_int32_t
*foundExtentDataOffset
,
158 u_int32_t
*endingFABNPlusOne
,
159 Boolean
*noMoreExtents
);
161 static OSErr
ReleaseExtents(
163 const HFSPlusExtentRecord extentRecord
,
164 u_int32_t
*numReleasedAllocationBlocks
,
165 Boolean
*releasedLastExtent
);
167 static OSErr
DeallocateFork(
169 HFSCatalogNodeID fileID
,
171 HFSPlusExtentRecord catalogExtents
,
172 Boolean
* recordDeleted
);
174 static OSErr
TruncateExtents(
178 u_int32_t startBlock
,
179 Boolean
* recordDeleted
);
181 static OSErr
UpdateExtentRecord (
184 const HFSPlusExtentKey
*extentFileKey
,
185 const HFSPlusExtentRecord extentData
,
186 u_int32_t extentBTreeHint
);
188 static Boolean
ExtentsAreIntegral(
189 const HFSPlusExtentRecord extentRecord
,
191 u_int32_t
*blocksChecked
,
192 Boolean
*checkedLastExtent
);
194 //_________________________________________________________________________________
196 // Routine: FindExtentRecord
198 // Purpose: Search the extents BTree for an extent record matching the given
199 // FileID, fork, and starting file allocation block number.
202 // vcb Volume to search
203 // forkType 0 = data fork, -1 = resource fork
204 // fileID File's FileID (CatalogNodeID)
205 // startBlock Starting file allocation block number
206 // allowPrevious If the desired record isn't found and this flag is set,
207 // then see if the previous record belongs to the same fork.
208 // If so, then return it.
211 // foundKey The key data for the record actually found
212 // foundData The extent record actually found (NOTE: on an HFS volume, the
213 // fourth entry will be zeroes.
214 // foundHint The BTree hint to find the node again
215 //_________________________________________________________________________________
216 static OSErr
FindExtentRecord(
217 const ExtendedVCB
*vcb
,
220 u_int32_t startBlock
,
221 Boolean allowPrevious
,
222 HFSPlusExtentKey
*foundKey
,
223 HFSPlusExtentRecord foundData
,
224 u_int32_t
*foundHint
)
227 BTreeIterator
*btIterator
;
228 FSBufferDescriptor btRecord
;
230 u_int16_t btRecordSize
;
235 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
237 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
238 bzero(btIterator
, sizeof(*btIterator
));
240 if (vcb
->vcbSigWord
== kHFSSigWord
) {
241 HFSExtentKey
* extentKeyPtr
;
242 HFSExtentRecord extentData
;
244 extentKeyPtr
= (HFSExtentKey
*) &btIterator
->key
;
245 extentKeyPtr
->keyLength
= kHFSExtentKeyMaximumLength
;
246 extentKeyPtr
->forkType
= forkType
;
247 extentKeyPtr
->fileID
= fileID
;
248 extentKeyPtr
->startBlock
= startBlock
;
250 btRecord
.bufferAddress
= &extentData
;
251 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
252 btRecord
.itemCount
= 1;
254 err
= BTSearchRecord(fcb
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
256 if (err
== btNotFound
&& allowPrevious
) {
257 err
= BTIterateRecord(fcb
, kBTreePrevRecord
, btIterator
, &btRecord
, &btRecordSize
);
259 // A previous record may not exist, so just return btNotFound (like we would if
260 // it was for the wrong file/fork).
261 if (err
== (OSErr
) fsBTStartOfIterationErr
) //¥¥ fsBTStartOfIterationErr is type unsigned long
265 // Found a previous record. Does it belong to the same fork of the same file?
266 if (extentKeyPtr
->fileID
!= fileID
|| extentKeyPtr
->forkType
!= forkType
)
274 // Copy the found key back for the caller
276 foundKey
->keyLength
= kHFSPlusExtentKeyMaximumLength
;
277 foundKey
->forkType
= extentKeyPtr
->forkType
;
279 foundKey
->fileID
= extentKeyPtr
->fileID
;
280 foundKey
->startBlock
= extentKeyPtr
->startBlock
;
282 // Copy the found data back for the caller
283 foundData
[0].startBlock
= extentData
[0].startBlock
;
284 foundData
[0].blockCount
= extentData
[0].blockCount
;
285 foundData
[1].startBlock
= extentData
[1].startBlock
;
286 foundData
[1].blockCount
= extentData
[1].blockCount
;
287 foundData
[2].startBlock
= extentData
[2].startBlock
;
288 foundData
[2].blockCount
= extentData
[2].blockCount
;
290 for (i
= 3; i
< kHFSPlusExtentDensity
; ++i
)
292 foundData
[i
].startBlock
= 0;
293 foundData
[i
].blockCount
= 0;
297 else { // HFS Plus volume
298 HFSPlusExtentKey
* extentKeyPtr
;
299 HFSPlusExtentRecord extentData
;
301 extentKeyPtr
= (HFSPlusExtentKey
*) &btIterator
->key
;
302 extentKeyPtr
->keyLength
= kHFSPlusExtentKeyMaximumLength
;
303 extentKeyPtr
->forkType
= forkType
;
304 extentKeyPtr
->pad
= 0;
305 extentKeyPtr
->fileID
= fileID
;
306 extentKeyPtr
->startBlock
= startBlock
;
308 btRecord
.bufferAddress
= &extentData
;
309 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
310 btRecord
.itemCount
= 1;
312 err
= BTSearchRecord(fcb
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
314 if (err
== btNotFound
&& allowPrevious
) {
315 err
= BTIterateRecord(fcb
, kBTreePrevRecord
, btIterator
, &btRecord
, &btRecordSize
);
317 // A previous record may not exist, so just return btNotFound (like we would if
318 // it was for the wrong file/fork).
319 if (err
== (OSErr
) fsBTStartOfIterationErr
) //¥¥ fsBTStartOfIterationErr is type unsigned long
323 // Found a previous record. Does it belong to the same fork of the same file?
324 if (extentKeyPtr
->fileID
!= fileID
|| extentKeyPtr
->forkType
!= forkType
)
330 // Copy the found key back for the caller
332 BlockMoveData(extentKeyPtr
, foundKey
, sizeof(HFSPlusExtentKey
));
333 // Copy the found data back for the caller
334 BlockMoveData(&extentData
, foundData
, sizeof(HFSPlusExtentRecord
));
339 *foundHint
= btIterator
->hint
.nodeNum
;
340 FREE(btIterator
, M_TEMP
);
346 static OSErr
CreateExtentRecord(
348 HFSPlusExtentKey
*key
,
349 HFSPlusExtentRecord extents
,
352 BTreeIterator
* btIterator
;
353 FSBufferDescriptor btRecord
;
354 u_int16_t btRecordSize
;
361 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
362 bzero(btIterator
, sizeof(*btIterator
));
365 * The lock taken by callers of ExtendFileC is speculative and
366 * only occurs when the file already has overflow extents. So
367 * We need to make sure we have the lock here. The extents
368 * btree lock can be nested (its recursive) so we always take
371 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
373 if (vcb
->vcbSigWord
== kHFSSigWord
) {
374 HFSExtentKey
* keyPtr
;
375 HFSExtentRecord data
;
377 btRecordSize
= sizeof(HFSExtentRecord
);
378 btRecord
.bufferAddress
= &data
;
379 btRecord
.itemSize
= btRecordSize
;
380 btRecord
.itemCount
= 1;
382 keyPtr
= (HFSExtentKey
*) &btIterator
->key
;
383 keyPtr
->keyLength
= kHFSExtentKeyMaximumLength
;
384 keyPtr
->forkType
= key
->forkType
;
385 keyPtr
->fileID
= key
->fileID
;
386 keyPtr
->startBlock
= key
->startBlock
;
388 err
= HFSPlusToHFSExtents(extents
, data
);
390 else { // HFS Plus volume
391 btRecordSize
= sizeof(HFSPlusExtentRecord
);
392 btRecord
.bufferAddress
= extents
;
393 btRecord
.itemSize
= btRecordSize
;
394 btRecord
.itemCount
= 1;
396 BlockMoveData(key
, &btIterator
->key
, sizeof(HFSPlusExtentKey
));
400 err
= BTInsertRecord(GetFileControlBlock(vcb
->extentsRefNum
), btIterator
, &btRecord
, btRecordSize
);
403 *hint
= btIterator
->hint
.nodeNum
;
405 (void) BTFlushPath(GetFileControlBlock(vcb
->extentsRefNum
));
407 hfs_systemfile_unlock(vcb
, lockflags
);
409 FREE(btIterator
, M_TEMP
);
414 static OSErr
DeleteExtentRecord(
415 const ExtendedVCB
*vcb
,
418 u_int32_t startBlock
)
420 BTreeIterator
* btIterator
;
425 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
426 bzero(btIterator
, sizeof(*btIterator
));
428 if (vcb
->vcbSigWord
== kHFSSigWord
) {
429 HFSExtentKey
* keyPtr
;
431 keyPtr
= (HFSExtentKey
*) &btIterator
->key
;
432 keyPtr
->keyLength
= kHFSExtentKeyMaximumLength
;
433 keyPtr
->forkType
= forkType
;
434 keyPtr
->fileID
= fileID
;
435 keyPtr
->startBlock
= startBlock
;
437 else { // HFS Plus volume
438 HFSPlusExtentKey
* keyPtr
;
440 keyPtr
= (HFSPlusExtentKey
*) &btIterator
->key
;
441 keyPtr
->keyLength
= kHFSPlusExtentKeyMaximumLength
;
442 keyPtr
->forkType
= forkType
;
444 keyPtr
->fileID
= fileID
;
445 keyPtr
->startBlock
= startBlock
;
448 err
= BTDeleteRecord(GetFileControlBlock(vcb
->extentsRefNum
), btIterator
);
449 (void) BTFlushPath(GetFileControlBlock(vcb
->extentsRefNum
));
451 FREE(btIterator
, M_TEMP
);
457 //_________________________________________________________________________________
459 // Routine: MapFileBlock
461 // Function: Maps a file position into a physical disk address.
463 //_________________________________________________________________________________
466 OSErr
MapFileBlockC (
467 ExtendedVCB
*vcb
, // volume that file resides on
468 FCB
*fcb
, // FCB of file
469 size_t numberOfBytes
, // number of contiguous bytes desired
470 off_t offset
, // starting offset within file (in bytes)
471 daddr64_t
*startSector
, // first sector (NOT an allocation block)
472 size_t *availableBytes
) // number of contiguous bytes (up to numberOfBytes)
475 u_int32_t allocBlockSize
; // Size of the volume's allocation block
476 u_int32_t sectorSize
;
477 HFSPlusExtentKey foundKey
;
478 HFSPlusExtentRecord foundData
;
479 u_int32_t foundIndex
;
481 u_int32_t firstFABN
; // file allocation block of first block in found extent
482 u_int32_t nextFABN
; // file allocation block of block after end of found extent
483 off_t dataEnd
; // (offset) end of range that is contiguous
484 u_int32_t sectorsPerBlock
; // Number of sectors per allocation block
485 u_int32_t startBlock
; // volume allocation block corresponding to firstFABN
489 allocBlockSize
= vcb
->blockSize
;
490 sectorSize
= VCBTOHFS(vcb
)->hfs_phys_block_size
;
492 err
= SearchExtentFile(vcb
, fcb
, offset
, &foundKey
, foundData
, &foundIndex
, &hint
, &nextFABN
);
494 startBlock
= foundData
[foundIndex
].startBlock
;
495 firstFABN
= nextFABN
- foundData
[foundIndex
].blockCount
;
504 // Determine the end of the available space. It will either be the end of the extent,
505 // or the file's PEOF, whichever is smaller.
507 dataEnd
= (off_t
)((off_t
)(nextFABN
) * (off_t
)(allocBlockSize
)); // Assume valid data through end of this extent
508 if (((off_t
)fcb
->ff_blocks
* (off_t
)allocBlockSize
) < dataEnd
) // Is PEOF shorter?
509 dataEnd
= (off_t
)fcb
->ff_blocks
* (off_t
)allocBlockSize
; // Yes, so only map up to PEOF
511 // Compute the number of sectors in an allocation block
512 sectorsPerBlock
= allocBlockSize
/ sectorSize
; // sectors per allocation block
515 // Compute the absolute sector number that contains the offset of the given file
516 // offset in sectors from start of the extent +
517 // offset in sectors from start of allocation block space
519 temp
= (daddr64_t
)((offset
- (off_t
)((off_t
)(firstFABN
) * (off_t
)(allocBlockSize
)))/sectorSize
);
520 temp
+= (daddr64_t
)startBlock
* (daddr64_t
)sectorsPerBlock
;
522 /* Add in any volume offsets */
523 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
524 temp
+= vcb
->hfsPlusIOPosOffset
/ sectorSize
;
526 temp
+= vcb
->vcbAlBlSt
;
528 // Return the desired sector for file position "offset"
532 // Determine the number of contiguous bytes until the end of the extent
533 // (or the amount they asked for, whichever comes first).
537 tmpOff
= dataEnd
- offset
;
538 if (tmpOff
> (off_t
)(numberOfBytes
))
539 *availableBytes
= numberOfBytes
; // more there than they asked for, so pin the output
541 *availableBytes
= tmpOff
;
548 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
549 // Routine: ReleaseExtents
551 // Function: Release the extents of a single extent data record.
552 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
554 static OSErr
ReleaseExtents(
556 const HFSPlusExtentRecord extentRecord
,
557 u_int32_t
*numReleasedAllocationBlocks
,
558 Boolean
*releasedLastExtent
)
560 u_int32_t extentIndex
;
561 u_int32_t numberOfExtents
;
564 *numReleasedAllocationBlocks
= 0;
565 *releasedLastExtent
= false;
567 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
568 numberOfExtents
= kHFSPlusExtentDensity
;
570 numberOfExtents
= kHFSExtentDensity
;
572 for( extentIndex
= 0; extentIndex
< numberOfExtents
; extentIndex
++)
574 u_int32_t numAllocationBlocks
;
576 // Loop over the extent record and release the blocks associated with each extent.
578 numAllocationBlocks
= extentRecord
[extentIndex
].blockCount
;
579 if ( numAllocationBlocks
== 0 )
581 *releasedLastExtent
= true;
585 err
= BlockDeallocate( vcb
, extentRecord
[extentIndex
].startBlock
, numAllocationBlocks
);
589 *numReleasedAllocationBlocks
+= numAllocationBlocks
; // bump FABN to beg of next extent
597 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
598 // Routine: TruncateExtents
600 // Purpose: Delete extent records whose starting file allocation block number
601 // is greater than or equal to a given starting block number. The
602 // allocation blocks represented by the extents are deallocated.
605 // vcb Volume to operate on
606 // fileID Which file to operate on
607 // startBlock Starting file allocation block number for first extent
609 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
611 static OSErr
TruncateExtents(
615 u_int32_t startBlock
,
616 Boolean
* recordDeleted
)
619 u_int32_t numberExtentsReleased
;
620 Boolean releasedLastExtent
;
622 HFSPlusExtentKey key
;
623 HFSPlusExtentRecord extents
;
627 * The lock taken by callers of TruncateFileC is speculative and
628 * only occurs when the file already has overflow extents. So
629 * We need to make sure we have the lock here. The extents
630 * btree lock can be nested (its recursive) so we always take
633 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
636 err
= FindExtentRecord(vcb
, forkType
, fileID
, startBlock
, false, &key
, extents
, &hint
);
638 if (err
== btNotFound
)
643 err
= ReleaseExtents( vcb
, extents
, &numberExtentsReleased
, &releasedLastExtent
);
644 if (err
!= noErr
) break;
646 err
= DeleteExtentRecord(vcb
, forkType
, fileID
, startBlock
);
647 if (err
!= noErr
) break;
649 *recordDeleted
= true;
650 startBlock
+= numberExtentsReleased
;
652 hfs_systemfile_unlock(vcb
, lockflags
);
659 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
660 // Routine: DeallocateFork
662 // Function: De-allocates all disk space allocated to a specified fork.
663 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
665 static OSErr
DeallocateFork(
667 HFSCatalogNodeID fileID
,
669 HFSPlusExtentRecord catalogExtents
,
670 Boolean
* recordDeleted
) /* true if a record was deleted */
673 u_int32_t numReleasedAllocationBlocks
;
674 Boolean releasedLastExtent
;
676 // Release the catalog extents
677 err
= ReleaseExtents( vcb
, catalogExtents
, &numReleasedAllocationBlocks
, &releasedLastExtent
);
678 // Release the extra extents, if present
679 if (err
== noErr
&& !releasedLastExtent
)
680 err
= TruncateExtents(vcb
, forkType
, fileID
, numReleasedAllocationBlocks
, recordDeleted
);
685 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
686 // Routine: FlushExtentFile
688 // Function: Flushes the extent file for a specified volume
689 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
692 OSErr
FlushExtentFile( ExtendedVCB
*vcb
)
698 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
700 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
701 err
= BTFlushPath(fcb
);
702 hfs_systemfile_unlock(vcb
, lockflags
);
706 // If the FCB for the extent "file" is dirty, mark the VCB as dirty.
708 if (FTOC(fcb
)->c_flag
& C_MODIFIED
)
711 // err = FlushVolumeControlBlock( vcb );
719 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
720 // Routine: CompareExtentKeys
722 // Function: Compares two extent file keys (a search key and a trial key) for
724 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
727 int32_t CompareExtentKeys( const HFSExtentKey
*searchKey
, const HFSExtentKey
*trialKey
)
729 int32_t result
; // ± 1
732 if (searchKey
->keyLength
!= kHFSExtentKeyMaximumLength
)
733 DebugStr("\pHFS: search Key is wrong length");
734 if (trialKey
->keyLength
!= kHFSExtentKeyMaximumLength
)
735 DebugStr("\pHFS: trial Key is wrong length");
738 result
= -1; // assume searchKey < trialKey
740 if (searchKey
->fileID
== trialKey
->fileID
) {
742 // FileNum's are equal; compare fork types
744 if (searchKey
->forkType
== trialKey
->forkType
) {
746 // Fork types are equal; compare allocation block number
748 if (searchKey
->startBlock
== trialKey
->startBlock
) {
750 // Everything is equal
756 // Allocation block numbers differ; determine sign
758 if (searchKey
->startBlock
> trialKey
->startBlock
)
764 // Fork types differ; determine sign
766 if (searchKey
->forkType
> trialKey
->forkType
)
772 // FileNums differ; determine sign
774 if (searchKey
->fileID
> trialKey
->fileID
)
783 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
784 // Routine: CompareExtentKeysPlus
786 // Function: Compares two extent file keys (a search key and a trial key) for
788 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
791 int32_t CompareExtentKeysPlus( const HFSPlusExtentKey
*searchKey
, const HFSPlusExtentKey
*trialKey
)
793 int32_t result
; // ± 1
796 if (searchKey
->keyLength
!= kHFSPlusExtentKeyMaximumLength
)
797 DebugStr("\pHFS: search Key is wrong length");
798 if (trialKey
->keyLength
!= kHFSPlusExtentKeyMaximumLength
)
799 DebugStr("\pHFS: trial Key is wrong length");
802 result
= -1; // assume searchKey < trialKey
804 if (searchKey
->fileID
== trialKey
->fileID
) {
806 // FileNum's are equal; compare fork types
808 if (searchKey
->forkType
== trialKey
->forkType
) {
810 // Fork types are equal; compare allocation block number
812 if (searchKey
->startBlock
== trialKey
->startBlock
) {
814 // Everything is equal
820 // Allocation block numbers differ; determine sign
822 if (searchKey
->startBlock
> trialKey
->startBlock
)
828 // Fork types differ; determine sign
830 if (searchKey
->forkType
> trialKey
->forkType
)
836 // FileNums differ; determine sign
838 if (searchKey
->fileID
> trialKey
->fileID
)
846 * Add a file extent to a file.
848 * Used by hfs_extendfs to extend the volume allocation bitmap file.
853 AddFileExtent(ExtendedVCB
*vcb
, FCB
*fcb
, u_int32_t startBlock
, u_int32_t blockCount
)
855 HFSPlusExtentKey foundKey
;
856 HFSPlusExtentRecord foundData
;
857 u_int32_t foundIndex
;
864 peof
= (int64_t)(fcb
->ff_blocks
+ blockCount
) * (int64_t)vcb
->blockSize
;
866 error
= SearchExtentFile(vcb
, fcb
, peof
-1, &foundKey
, foundData
, &foundIndex
, &hint
, &nextBlock
);
867 if (error
!= fxRangeErr
)
871 * Add new extent. See if there is room in the current record.
873 if (foundData
[foundIndex
].blockCount
!= 0)
875 if (foundIndex
== kHFSPlusExtentDensity
) {
877 * Existing record is full so create a new one.
879 foundKey
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
880 foundKey
.forkType
= kDataForkType
;
882 foundKey
.fileID
= FTOC(fcb
)->c_fileid
;
883 foundKey
.startBlock
= nextBlock
;
885 foundData
[0].startBlock
= startBlock
;
886 foundData
[0].blockCount
= blockCount
;
888 /* zero out remaining extents. */
889 for (i
= 1; i
< kHFSPlusExtentDensity
; ++i
) {
890 foundData
[i
].startBlock
= 0;
891 foundData
[i
].blockCount
= 0;
896 error
= CreateExtentRecord(vcb
, &foundKey
, foundData
, &hint
);
897 if (error
== fxOvFlErr
)
901 * Add a new extent into existing record.
903 foundData
[foundIndex
].startBlock
= startBlock
;
904 foundData
[foundIndex
].blockCount
= blockCount
;
905 error
= UpdateExtentRecord(vcb
, fcb
, &foundKey
, foundData
, hint
);
907 (void) FlushExtentFile(vcb
);
913 //_________________________________________________________________________________
915 // Routine: Extendfile
917 // Function: Extends the disk space allocated to a file.
919 //_________________________________________________________________________________
923 ExtendedVCB
*vcb
, // volume that file resides on
924 FCB
*fcb
, // FCB of file to truncate
925 int64_t bytesToAdd
, // number of bytes to allocate
926 u_int32_t blockHint
, // desired starting allocation block
927 u_int32_t flags
, // EFContig and/or EFAll
928 int64_t *actualBytesAdded
) // number of bytes actually allocated
931 u_int32_t volumeBlockSize
;
933 int64_t bytesThisExtent
;
934 HFSPlusExtentKey foundKey
;
935 HFSPlusExtentRecord foundData
;
936 u_int32_t foundIndex
;
939 u_int32_t startBlock
;
940 Boolean allOrNothing
;
945 u_int32_t actualStartBlock
;
946 u_int32_t actualNumBlocks
;
947 u_int32_t numExtentsPerRecord
;
948 int64_t maximumBytes
;
951 u_int32_t prevblocks
;
955 *actualBytesAdded
= 0;
956 volumeBlockSize
= vcb
->blockSize
;
957 allOrNothing
= ((flags
& kEFAllMask
) != 0);
958 forceContig
= ((flags
& kEFContigMask
) != 0);
959 prevblocks
= fcb
->ff_blocks
;
961 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
962 numExtentsPerRecord
= kHFSPlusExtentDensity
;
964 numExtentsPerRecord
= kHFSExtentDensity
;
967 // Make sure the request and new PEOF are less than 2GB if HFS.
969 if (vcb
->vcbSigWord
== kHFSSigWord
) {
970 if (bytesToAdd
>= kTwoGigabytes
)
972 if ((((int64_t)fcb
->ff_blocks
* (int64_t)volumeBlockSize
) + bytesToAdd
) >= kTwoGigabytes
)
976 // Determine how many blocks need to be allocated.
977 // Round up the number of desired bytes to add.
979 blocksToAdd
= howmany(bytesToAdd
, volumeBlockSize
);
980 bytesToAdd
= (int64_t)((int64_t)blocksToAdd
* (int64_t)volumeBlockSize
);
983 * For deferred allocations just reserve the blocks.
985 if ((flags
& kEFDeferMask
)
986 && (vcb
->vcbSigWord
== kHFSPlusSigWord
)
987 && (bytesToAdd
< (int64_t)HFS_MAX_DEFERED_ALLOC
)
988 && (blocksToAdd
< hfs_freeblks(VCBTOHFS(vcb
), 1))) {
989 HFS_MOUNT_LOCK(vcb
, TRUE
);
990 vcb
->loanedBlocks
+= blocksToAdd
;
991 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
993 fcb
->ff_unallocblocks
+= blocksToAdd
;
994 FTOC(fcb
)->c_blocks
+= blocksToAdd
;
995 fcb
->ff_blocks
+= blocksToAdd
;
997 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
998 *actualBytesAdded
= bytesToAdd
;
1002 * Give back any unallocated blocks before doing real allocations.
1004 if (fcb
->ff_unallocblocks
> 0) {
1005 u_int32_t loanedBlocks
;
1007 loanedBlocks
= fcb
->ff_unallocblocks
;
1008 blocksToAdd
+= loanedBlocks
;
1009 bytesToAdd
= (int64_t)blocksToAdd
* (int64_t)volumeBlockSize
;
1010 FTOC(fcb
)->c_blocks
-= loanedBlocks
;
1011 fcb
->ff_blocks
-= loanedBlocks
;
1012 fcb
->ff_unallocblocks
= 0;
1014 HFS_MOUNT_LOCK(vcb
, TRUE
);
1015 vcb
->loanedBlocks
-= loanedBlocks
;
1016 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
1020 // If the file's clump size is larger than the allocation block size,
1021 // then set the maximum number of bytes to the requested number of bytes
1022 // rounded up to a multiple of the clump size.
1024 if ((vcb
->vcbClpSiz
> (int32_t)volumeBlockSize
)
1025 && (bytesToAdd
< (int64_t)HFS_MAX_DEFERED_ALLOC
)
1026 && (flags
& kEFNoClumpMask
) == 0) {
1027 maximumBytes
= (int64_t)howmany(bytesToAdd
, vcb
->vcbClpSiz
);
1028 maximumBytes
*= vcb
->vcbClpSiz
;
1030 maximumBytes
= bytesToAdd
;
1034 // Compute new physical EOF, rounded up to a multiple of a block.
1036 if ( (vcb
->vcbSigWord
== kHFSSigWord
) && // Too big?
1037 ((((int64_t)fcb
->ff_blocks
* (int64_t)volumeBlockSize
) + bytesToAdd
) >= kTwoGigabytes
) ) {
1038 if (allOrNothing
) // Yes, must they have it all?
1039 goto Overflow
; // Yes, can't have it
1041 --blocksToAdd
; // No, give give 'em one block less
1042 bytesToAdd
-= volumeBlockSize
;
1047 // If allocation is all-or-nothing, make sure there are
1048 // enough free blocks on the volume (quick test).
1051 (blocksToAdd
> hfs_freeblks(VCBTOHFS(vcb
), flags
& kEFReserveMask
))) {
1057 // See if there are already enough blocks allocated to the file.
1059 peof
= ((int64_t)fcb
->ff_blocks
* (int64_t)volumeBlockSize
) + bytesToAdd
; // potential new PEOF
1060 err
= SearchExtentFile(vcb
, fcb
, peof
-1, &foundKey
, foundData
, &foundIndex
, &hint
, &nextBlock
);
1062 // Enough blocks are already allocated. Just update the FCB to reflect the new length.
1063 fcb
->ff_blocks
= peof
/ volumeBlockSize
;
1064 FTOC(fcb
)->c_blocks
+= (bytesToAdd
/ volumeBlockSize
);
1065 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1068 if (err
!= fxRangeErr
) // Any real error?
1069 goto ErrorExit
; // Yes, so exit immediately
1072 // Adjust the PEOF to the end of the last extent.
1074 peof
= (int64_t)((int64_t)nextBlock
* (int64_t)volumeBlockSize
); // currently allocated PEOF
1075 bytesThisExtent
= (int64_t)(nextBlock
- fcb
->ff_blocks
) * (int64_t)volumeBlockSize
;
1076 if (bytesThisExtent
!= 0) {
1077 fcb
->ff_blocks
= nextBlock
;
1078 FTOC(fcb
)->c_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1079 FTOC(fcb
)->c_flag
|= C_MODIFIED
;
1080 bytesToAdd
-= bytesThisExtent
;
1084 // Allocate some more space.
1086 // First try a contiguous allocation (of the whole amount).
1087 // If that fails, get whatever we can.
1088 // If forceContig, then take whatever we got
1089 // else, keep getting bits and pieces (non-contig)
1092 useMetaZone
= flags
& kEFMetadataMask
;
1093 vcb
->vcbFreeExtCnt
= 0; /* For now, force rebuild of free extent list */
1096 startBlock
= blockHint
;
1098 startBlock
= foundData
[foundIndex
].startBlock
+ foundData
[foundIndex
].blockCount
;
1100 actualNumBlocks
= 0;
1101 actualStartBlock
= 0;
1103 /* Find number of free blocks based on reserved block flag option */
1104 availbytes
= (int64_t)hfs_freeblks(VCBTOHFS(vcb
), flags
& kEFReserveMask
) *
1105 (int64_t)volumeBlockSize
;
1106 if (availbytes
<= 0) {
1109 if (wantContig
&& (availbytes
< bytesToAdd
))
1112 err
= BlockAllocate(
1115 howmany(MIN(bytesToAdd
, availbytes
), volumeBlockSize
),
1116 howmany(MIN(maximumBytes
, availbytes
), volumeBlockSize
),
1123 if (err
== dskFulErr
) {
1125 break; // AllocContig failed because not enough contiguous space
1127 // Couldn't get one big chunk, so get whatever we can.
1132 if (actualNumBlocks
!= 0)
1134 if (useMetaZone
== 0) {
1135 /* Couldn't get anything so dip into metadat zone */
1142 if (actualNumBlocks
!= 0) {
1143 // this catalog entry *must* get forced to disk when
1144 // hfs_update() is called
1145 FTOC(fcb
)->c_flag
|= C_FORCEUPDATE
;
1148 // Add the new extent to the existing extent record, or create a new one.
1149 if ((actualStartBlock
== startBlock
) && (blockHint
== 0)) {
1150 // We grew the file's last extent, so just adjust the number of blocks.
1151 foundData
[foundIndex
].blockCount
+= actualNumBlocks
;
1152 err
= UpdateExtentRecord(vcb
, fcb
, &foundKey
, foundData
, hint
);
1153 if (err
!= noErr
) break;
1158 // Need to add a new extent. See if there is room in the current record.
1159 if (foundData
[foundIndex
].blockCount
!= 0) // Is current extent free to use?
1160 ++foundIndex
; // No, so use the next one.
1161 if (foundIndex
== numExtentsPerRecord
) {
1162 // This record is full. Need to create a new one.
1163 if (FTOC(fcb
)->c_fileid
== kHFSExtentsFileID
) {
1164 (void) BlockDeallocate(vcb
, actualStartBlock
, actualNumBlocks
);
1165 err
= dskFulErr
; // Oops. Can't extend extents file past first record.
1169 foundKey
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
1170 if (FORK_IS_RSRC(fcb
))
1171 foundKey
.forkType
= kResourceForkType
;
1173 foundKey
.forkType
= kDataForkType
;
1175 foundKey
.fileID
= FTOC(fcb
)->c_fileid
;
1176 foundKey
.startBlock
= nextBlock
;
1178 foundData
[0].startBlock
= actualStartBlock
;
1179 foundData
[0].blockCount
= actualNumBlocks
;
1181 // zero out remaining extents...
1182 for (i
= 1; i
< kHFSPlusExtentDensity
; ++i
)
1184 foundData
[i
].startBlock
= 0;
1185 foundData
[i
].blockCount
= 0;
1190 err
= CreateExtentRecord(vcb
, &foundKey
, foundData
, &hint
);
1191 if (err
== fxOvFlErr
) {
1192 // We couldn't create an extent record because extents B-tree
1193 // couldn't grow. Dellocate the extent just allocated and
1194 // return a disk full error.
1195 (void) BlockDeallocate(vcb
, actualStartBlock
, actualNumBlocks
);
1198 if (err
!= noErr
) break;
1200 needsFlush
= true; // We need to update the B-tree header
1203 // Add a new extent into this record and update.
1204 foundData
[foundIndex
].startBlock
= actualStartBlock
;
1205 foundData
[foundIndex
].blockCount
= actualNumBlocks
;
1206 err
= UpdateExtentRecord(vcb
, fcb
, &foundKey
, foundData
, hint
);
1207 if (err
!= noErr
) break;
1211 // Figure out how many bytes were actually allocated.
1212 // NOTE: BlockAllocate could have allocated more than we asked for.
1213 // Don't set the PEOF beyond what our client asked for.
1214 nextBlock
+= actualNumBlocks
;
1215 bytesThisExtent
= (int64_t)((int64_t)actualNumBlocks
* (int64_t)volumeBlockSize
);
1216 if (bytesThisExtent
> bytesToAdd
) {
1220 bytesToAdd
-= bytesThisExtent
;
1221 maximumBytes
-= bytesThisExtent
;
1223 fcb
->ff_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1224 FTOC(fcb
)->c_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1225 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1227 // If contiguous allocation was requested, then we've already got one contiguous
1228 // chunk. If we didn't get all we wanted, then adjust the error to disk full.
1230 if (bytesToAdd
!= 0)
1232 break; // We've already got everything that's contiguous
1235 } while (err
== noErr
&& bytesToAdd
);
1239 if (VCBTOHFS(vcb
)->hfs_flags
& HFS_METADATA_ZONE
) {
1240 /* Keep the roving allocator out of the metadata zone. */
1241 if (vcb
->nextAllocation
>= VCBTOHFS(vcb
)->hfs_metazone_start
&&
1242 vcb
->nextAllocation
<= VCBTOHFS(vcb
)->hfs_metazone_end
) {
1243 HFS_MOUNT_LOCK(vcb
, TRUE
);
1244 HFS_UPDATE_NEXT_ALLOCATION(vcb
, VCBTOHFS(vcb
)->hfs_metazone_end
+ 1);
1246 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
1249 if (prevblocks
< fcb
->ff_blocks
) {
1250 *actualBytesAdded
= (int64_t)(fcb
->ff_blocks
- prevblocks
) * (int64_t)volumeBlockSize
;
1252 *actualBytesAdded
= 0;
1256 (void) FlushExtentFile(vcb
);
1261 err
= fileBoundsErr
;
1267 //_________________________________________________________________________________
1269 // Routine: TruncateFileC
1271 // Function: Truncates the disk space allocated to a file. The file space is
1272 // truncated to a specified new PEOF rounded up to the next allocation
1273 // block boundry. If the 'TFTrunExt' option is specified, the file is
1274 // truncated to the end of the extent containing the new PEOF.
1276 //_________________________________________________________________________________
1279 OSErr
TruncateFileC (
1280 ExtendedVCB
*vcb
, // volume that file resides on
1281 FCB
*fcb
, // FCB of file to truncate
1282 int64_t peof
, // new physical size for file
1283 Boolean truncateToExtent
) // if true, truncate to end of extent containing newPEOF
1286 u_int32_t nextBlock
; // next file allocation block to consider
1287 u_int32_t startBlock
; // Physical (volume) allocation block number of start of a range
1288 u_int32_t physNumBlocks
; // Number of allocation blocks in file (according to PEOF)
1289 u_int32_t numBlocks
;
1290 HFSPlusExtentKey key
; // key for current extent record; key->keyLength == 0 if FCB's extent record
1291 u_int32_t hint
; // BTree hint corresponding to key
1292 HFSPlusExtentRecord extentRecord
;
1293 u_int32_t extentIndex
;
1294 u_int32_t extentNextBlock
;
1295 u_int32_t numExtentsPerRecord
;
1298 Boolean extentChanged
; // true if we actually changed an extent
1299 Boolean recordDeleted
; // true if an extent record got deleted
1301 recordDeleted
= false;
1303 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1304 numExtentsPerRecord
= kHFSPlusExtentDensity
;
1306 numExtentsPerRecord
= kHFSExtentDensity
;
1308 if (FORK_IS_RSRC(fcb
))
1309 forkType
= kResourceForkType
;
1311 forkType
= kDataForkType
;
1313 temp64
= fcb
->ff_blocks
;
1314 physNumBlocks
= (u_int32_t
)temp64
;
1317 // Round newPEOF up to a multiple of the allocation block size. If new size is
1318 // two gigabytes or more, then round down by one allocation block (??? really?
1319 // shouldn't that be an error?).
1321 nextBlock
= howmany(peof
, vcb
->blockSize
); // number of allocation blocks to remain in file
1322 peof
= (int64_t)((int64_t)nextBlock
* (int64_t)vcb
->blockSize
); // number of bytes in those blocks
1323 if ((vcb
->vcbSigWord
== kHFSSigWord
) && (peof
>= kTwoGigabytes
)) {
1325 DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
1327 err
= fileBoundsErr
;
1332 // Update FCB's length
1335 * XXX Any errors could cause ff_blocks and c_blocks to get out of sync...
1337 numBlocks
= peof
/ vcb
->blockSize
;
1338 FTOC(fcb
)->c_blocks
-= (fcb
->ff_blocks
- numBlocks
);
1339 fcb
->ff_blocks
= numBlocks
;
1341 // this catalog entry is modified and *must* get forced
1342 // to disk when hfs_update() is called
1343 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1346 // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
1352 // Deallocate all the extents for this fork
1353 err
= DeallocateFork(vcb
, FTOC(fcb
)->c_fileid
, forkType
, fcb
->fcbExtents
, &recordDeleted
);
1354 if (err
!= noErr
) goto ErrorExit
; // got some error, so return it
1356 // Update the catalog extent record (making sure it's zeroed out)
1358 for (i
=0; i
< kHFSPlusExtentDensity
; i
++) {
1359 fcb
->fcbExtents
[i
].startBlock
= 0;
1360 fcb
->fcbExtents
[i
].blockCount
= 0;
1367 // Find the extent containing byte (peof-1). This is the last extent we'll keep.
1368 // (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only
1369 // keep up through peof). The search will tell us how many allocation blocks exist
1370 // in the found extent plus all previous extents.
1372 err
= SearchExtentFile(vcb
, fcb
, peof
-1, &key
, extentRecord
, &extentIndex
, &hint
, &extentNextBlock
);
1373 if (err
!= noErr
) goto ErrorExit
;
1375 extentChanged
= false; // haven't changed the extent yet
1377 if (!truncateToExtent
) {
1379 // Shorten this extent. It may be the case that the entire extent gets
1382 numBlocks
= extentNextBlock
- nextBlock
; // How many blocks in this extent to free up
1383 if (numBlocks
!= 0) {
1384 // Compute first volume allocation block to free
1385 startBlock
= extentRecord
[extentIndex
].startBlock
+ extentRecord
[extentIndex
].blockCount
- numBlocks
;
1386 // Free the blocks in bitmap
1387 err
= BlockDeallocate(vcb
, startBlock
, numBlocks
);
1388 if (err
!= noErr
) goto ErrorExit
;
1389 // Adjust length of this extent
1390 extentRecord
[extentIndex
].blockCount
-= numBlocks
;
1391 // If extent is empty, set start block to 0
1392 if (extentRecord
[extentIndex
].blockCount
== 0)
1393 extentRecord
[extentIndex
].startBlock
= 0;
1394 // Remember that we changed the extent record
1395 extentChanged
= true;
1400 // Now move to the next extent in the record, and set up the file allocation block number
1402 nextBlock
= extentNextBlock
; // Next file allocation block to free
1403 ++extentIndex
; // Its index within the extent record
1406 // Release all following extents in this extent record. Update the record.
1408 while (extentIndex
< numExtentsPerRecord
&& extentRecord
[extentIndex
].blockCount
!= 0) {
1409 numBlocks
= extentRecord
[extentIndex
].blockCount
;
1410 // Deallocate this extent
1411 err
= BlockDeallocate(vcb
, extentRecord
[extentIndex
].startBlock
, numBlocks
);
1412 if (err
!= noErr
) goto ErrorExit
;
1413 // Update next file allocation block number
1414 nextBlock
+= numBlocks
;
1415 // Zero out start and length of this extent to delete it from record
1416 extentRecord
[extentIndex
].startBlock
= 0;
1417 extentRecord
[extentIndex
].blockCount
= 0;
1418 // Remember that we changed an extent
1419 extentChanged
= true;
1420 // Move to next extent in record
1425 // If any of the extents in the current record were changed, then update that
1426 // record (in the FCB, or extents file).
1428 if (extentChanged
) {
1429 err
= UpdateExtentRecord(vcb
, fcb
, &key
, extentRecord
, hint
);
1430 if (err
!= noErr
) goto ErrorExit
;
1434 // If there are any following allocation blocks, then we need
1435 // to seach for their extent records and delete those allocation
1438 if (nextBlock
< physNumBlocks
)
1439 err
= TruncateExtents(vcb
, forkType
, FTOC(fcb
)->c_fileid
, nextBlock
, &recordDeleted
);
1444 (void) FlushExtentFile(vcb
);
1455 OSErr
HeadTruncateFile (
1460 HFSPlusExtentRecord extents
;
1461 HFSPlusExtentRecord tailExtents
;
1462 HFSCatalogNodeID fileID
;
1466 u_int32_t blksfreed
;
1472 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
1475 forkType
= FORK_IS_RSRC(fcb
) ? kResourceForkType
: kDataForkType
;
1476 fileID
= FTOC(fcb
)->c_fileid
;
1477 bzero(tailExtents
, sizeof(tailExtents
));
1483 * Process catalog resident extents
1485 for (i
= 0, j
= 0; i
< kHFSPlusExtentDensity
; ++i
) {
1486 blkcnt
= fcb
->fcbExtents
[i
].blockCount
;
1488 break; /* end of extents */
1490 if (blksfreed
< headblks
) {
1491 error
= BlockDeallocate(vcb
, fcb
->fcbExtents
[i
].startBlock
, blkcnt
);
1493 * Any errors after the first BlockDeallocate
1494 * must be ignored so we can put the file in
1499 goto ErrorExit
; /* uh oh */
1502 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1503 FTOC(fcb
)->c_desc
.cd_nameptr
? (const char *)FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1507 blksfreed
+= blkcnt
;
1508 fcb
->fcbExtents
[i
].startBlock
= 0;
1509 fcb
->fcbExtents
[i
].blockCount
= 0;
1511 tailExtents
[j
].startBlock
= fcb
->fcbExtents
[i
].startBlock
;
1512 tailExtents
[j
].blockCount
= blkcnt
;
1521 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1524 * Process overflow extents
1529 error
= FindExtentRecord(vcb
, forkType
, fileID
, startblk
, false, NULL
, extents
, NULL
);
1532 * Any errors after the first BlockDeallocate
1533 * must be ignored so we can put the file in
1536 if (error
!= btNotFound
)
1537 printf("HeadTruncateFile: problems finding extents %s (%d)\n",
1538 FTOC(fcb
)->c_desc
.cd_nameptr
? (const char *)FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1543 for(i
= 0, extblks
= 0; i
< kHFSPlusExtentDensity
; ++i
) {
1544 blkcnt
= extents
[i
].blockCount
;
1546 break; /* end of extents */
1548 if (blksfreed
< headblks
) {
1549 error
= BlockDeallocate(vcb
, extents
[i
].startBlock
, blkcnt
);
1551 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1552 FTOC(fcb
)->c_desc
.cd_nameptr
? (const char *)FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1555 blksfreed
+= blkcnt
;
1557 tailExtents
[j
].startBlock
= extents
[i
].startBlock
;
1558 tailExtents
[j
].blockCount
= blkcnt
;
1564 error
= DeleteExtentRecord(vcb
, forkType
, fileID
, startblk
);
1566 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1567 FTOC(fcb
)->c_desc
.cd_nameptr
? (const char *)FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1572 break; /* all done */
1574 startblk
+= extblks
;
1576 hfs_systemfile_unlock(vcb
, lockflags
);
1580 bcopy(tailExtents
, fcb
->fcbExtents
, sizeof(tailExtents
));
1581 blkcnt
= fcb
->ff_blocks
- headblks
;
1582 FTOC(fcb
)->c_blocks
-= headblks
;
1583 fcb
->ff_blocks
= blkcnt
;
1585 FTOC(fcb
)->c_flag
|= C_FORCEUPDATE
;
1586 FTOC(fcb
)->c_touch_chgtime
= TRUE
;
1588 (void) FlushExtentFile(vcb
);
1592 return MacToVFSError(error
);
1597 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1598 // Routine: SearchExtentRecord (was XRSearch)
1600 // Function: Searches extent record for the extent mapping a given file
1601 // allocation block number (FABN).
1603 // Input: searchFABN - desired FABN
1604 // extentData - pointer to extent data record (xdr)
1605 // extentDataStartFABN - beginning FABN for extent record
1607 // Output: foundExtentDataOffset - offset to extent entry within xdr
1608 // result = noErr, offset to extent mapping desired FABN
1609 // result = FXRangeErr, offset to last extent in record
1610 // endingFABNPlusOne - ending FABN +1
1611 // noMoreExtents - True if the extent was not found, and the
1612 // extent record was not full (so don't bother
1613 // looking in subsequent records); false otherwise.
1615 // Result: noErr = ok
1616 // FXRangeErr = desired FABN > last mapped FABN in record
1617 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1619 static OSErr
SearchExtentRecord(
1621 u_int32_t searchFABN
,
1622 const HFSPlusExtentRecord extentData
,
1623 u_int32_t extentDataStartFABN
,
1624 u_int32_t
*foundExtentIndex
,
1625 u_int32_t
*endingFABNPlusOne
,
1626 Boolean
*noMoreExtents
)
1629 u_int32_t extentIndex
;
1630 u_int32_t numberOfExtents
;
1631 u_int32_t numAllocationBlocks
;
1632 Boolean foundExtent
;
1634 *endingFABNPlusOne
= extentDataStartFABN
;
1635 *noMoreExtents
= false;
1636 foundExtent
= false;
1638 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1639 numberOfExtents
= kHFSPlusExtentDensity
;
1641 numberOfExtents
= kHFSExtentDensity
;
1643 for( extentIndex
= 0; extentIndex
< numberOfExtents
; ++extentIndex
)
1646 // Loop over the extent record and find the search FABN.
1648 numAllocationBlocks
= extentData
[extentIndex
].blockCount
;
1649 if ( numAllocationBlocks
== 0 )
1654 *endingFABNPlusOne
+= numAllocationBlocks
;
1656 if( searchFABN
< *endingFABNPlusOne
)
1658 // Found the extent.
1666 // Found the extent. Note the extent offset
1667 *foundExtentIndex
= extentIndex
;
1671 // Did not find the extent. Set foundExtentDataOffset accordingly
1672 if( extentIndex
> 0 )
1674 *foundExtentIndex
= extentIndex
- 1;
1678 *foundExtentIndex
= 0;
1681 // If we found an empty extent, then set noMoreExtents.
1682 if (extentIndex
< numberOfExtents
)
1683 *noMoreExtents
= true;
1685 // Finally, return an error to the caller
1692 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1693 // Routine: SearchExtentFile (was XFSearch)
1695 // Function: Searches extent file (including the FCB resident extent record)
1696 // for the extent mapping a given file position.
1698 // Input: vcb - VCB pointer
1699 // fcb - FCB pointer
1700 // filePosition - file position (byte address)
1702 // Output: foundExtentKey - extent key record (xkr)
1703 // If extent was found in the FCB's resident extent record,
1704 // then foundExtentKey->keyLength will be set to 0.
1705 // foundExtentData - extent data record(xdr)
1706 // foundExtentIndex - index to extent entry in xdr
1707 // result = 0, offset to extent mapping desired FABN
1708 // result = FXRangeErr, offset to last extent in record
1709 // (i.e., kNumExtentsPerRecord-1)
1710 // extentBTreeHint - BTree hint for extent record
1711 // kNoHint = Resident extent record
1712 // endingFABNPlusOne - ending FABN +1
1715 // noErr Found an extent that contains the given file position
1716 // FXRangeErr Given position is beyond the last allocated extent
1717 // (other) (some other internal I/O error)
1718 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1720 static OSErr
SearchExtentFile(
1723 int64_t filePosition
,
1724 HFSPlusExtentKey
*foundExtentKey
,
1725 HFSPlusExtentRecord foundExtentData
,
1726 u_int32_t
*foundExtentIndex
,
1727 u_int32_t
*extentBTreeHint
,
1728 u_int32_t
*endingFABNPlusOne
)
1731 u_int32_t filePositionBlock
;
1733 Boolean noMoreExtents
;
1736 temp64
= filePosition
/ (int64_t)vcb
->blockSize
;
1737 filePositionBlock
= (u_int32_t
)temp64
;
1739 bcopy ( fcb
->fcbExtents
, foundExtentData
, sizeof(HFSPlusExtentRecord
));
1741 // Search the resident FCB first.
1742 err
= SearchExtentRecord( vcb
, filePositionBlock
, foundExtentData
, 0,
1743 foundExtentIndex
, endingFABNPlusOne
, &noMoreExtents
);
1745 if( err
== noErr
) {
1746 // Found the extent. Set results accordingly
1747 *extentBTreeHint
= kNoHint
; // no hint, because not in the BTree
1748 foundExtentKey
->keyLength
= 0; // 0 = the FCB itself
1753 // Didn't find extent in FCB. If FCB's extent record wasn't full, there's no point
1754 // in searching the extents file. Note that SearchExtentRecord left us pointing at
1755 // the last valid extent (or the first one, if none were valid). This means we need
1756 // to fill in the hint and key outputs, just like the "if" statement above.
1757 if ( noMoreExtents
) {
1758 *extentBTreeHint
= kNoHint
; // no hint, because not in the BTree
1759 foundExtentKey
->keyLength
= 0; // 0 = the FCB itself
1760 err
= fxRangeErr
; // There are no more extents, so must be beyond PEOF
1765 // Find the desired record, or the previous record if it is the same fork
1767 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1769 err
= FindExtentRecord(vcb
, FORK_IS_RSRC(fcb
) ? kResourceForkType
: kDataForkType
,
1770 FTOC(fcb
)->c_fileid
, filePositionBlock
, true, foundExtentKey
, foundExtentData
, extentBTreeHint
);
1771 hfs_systemfile_unlock(vcb
, lockflags
);
1773 if (err
== btNotFound
) {
1775 // If we get here, the desired position is beyond the extents in the FCB, and there are no extents
1776 // in the extents file. Return the FCB's extents and a range error.
1778 *extentBTreeHint
= kNoHint
;
1779 foundExtentKey
->keyLength
= 0;
1780 err
= GetFCBExtentRecord(fcb
, foundExtentData
);
1781 // Note: foundExtentIndex and endingFABNPlusOne have already been set as a result of the very
1782 // first SearchExtentRecord call in this function (when searching in the FCB's extents, and
1783 // we got a range error).
1789 // If we get here, there was either a BTree error, or we found an appropriate record.
1790 // If we found a record, then search it for the correct index into the extents.
1793 // Find appropriate index into extent record
1794 err
= SearchExtentRecord(vcb
, filePositionBlock
, foundExtentData
, foundExtentKey
->startBlock
,
1795 foundExtentIndex
, endingFABNPlusOne
, &noMoreExtents
);
1804 //============================================================================
1805 // Routine: UpdateExtentRecord
1807 // Function: Write new extent data to an existing extent record with a given key.
1808 // If all of the extents are empty, and the extent record is in the
1809 // extents file, then the record is deleted.
1811 // Input: vcb - the volume containing the extents
1812 // fcb - the file that owns the extents
1813 // extentFileKey - pointer to extent key record (xkr)
1814 // If the key length is 0, then the extents are actually part
1815 // of the catalog record, stored in the FCB.
1816 // extentData - pointer to extent data record (xdr)
1817 // extentBTreeHint - hint for given key, or kNoHint
1819 // Result: noErr = ok
1820 // (other) = error from BTree
1821 //============================================================================
1823 static OSErr
UpdateExtentRecord (
1826 const HFSPlusExtentKey
*extentFileKey
,
1827 const HFSPlusExtentRecord extentData
,
1828 u_int32_t extentBTreeHint
)
1832 if (extentFileKey
->keyLength
== 0) { // keyLength == 0 means the FCB's extent record
1833 BlockMoveData(extentData
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
1834 FTOC(fcb
)->c_flag
|= C_MODIFIED
;
1837 BTreeIterator
* btIterator
;
1838 FSBufferDescriptor btRecord
;
1839 u_int16_t btRecordSize
;
1844 // Need to find and change a record in Extents BTree
1846 btFCB
= GetFileControlBlock(vcb
->extentsRefNum
);
1848 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
1849 bzero(btIterator
, sizeof(*btIterator
));
1852 * The lock taken by callers of ExtendFileC/TruncateFileC is
1853 * speculative and only occurs when the file already has
1854 * overflow extents. So we need to make sure we have the lock
1855 * here. The extents btree lock can be nested (its recursive)
1856 * so we always take it here.
1858 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1860 if (vcb
->vcbSigWord
== kHFSSigWord
) {
1861 HFSExtentKey
* key
; // Actual extent key used on disk in HFS
1862 HFSExtentRecord foundData
; // The extent data actually found
1864 key
= (HFSExtentKey
*) &btIterator
->key
;
1865 key
->keyLength
= kHFSExtentKeyMaximumLength
;
1866 key
->forkType
= extentFileKey
->forkType
;
1867 key
->fileID
= extentFileKey
->fileID
;
1868 key
->startBlock
= extentFileKey
->startBlock
;
1870 btIterator
->hint
.index
= 0;
1871 btIterator
->hint
.nodeNum
= extentBTreeHint
;
1873 btRecord
.bufferAddress
= &foundData
;
1874 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
1875 btRecord
.itemCount
= 1;
1877 err
= BTSearchRecord(btFCB
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
1880 err
= HFSPlusToHFSExtents(extentData
, (HFSExtentDescriptor
*)&foundData
);
1883 err
= BTReplaceRecord(btFCB
, btIterator
, &btRecord
, btRecordSize
);
1884 (void) BTFlushPath(btFCB
);
1886 else { // HFS Plus volume
1887 HFSPlusExtentRecord foundData
; // The extent data actually found
1889 BlockMoveData(extentFileKey
, &btIterator
->key
, sizeof(HFSPlusExtentKey
));
1891 btIterator
->hint
.index
= 0;
1892 btIterator
->hint
.nodeNum
= extentBTreeHint
;
1894 btRecord
.bufferAddress
= &foundData
;
1895 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
1896 btRecord
.itemCount
= 1;
1898 err
= BTSearchRecord(btFCB
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
1901 BlockMoveData(extentData
, &foundData
, sizeof(HFSPlusExtentRecord
));
1902 err
= BTReplaceRecord(btFCB
, btIterator
, &btRecord
, btRecordSize
);
1904 (void) BTFlushPath(btFCB
);
1906 hfs_systemfile_unlock(vcb
, lockflags
);
1907 FREE(btIterator
, M_TEMP
);
1916 static OSErr
HFSPlusToHFSExtents(
1917 const HFSPlusExtentRecord oldExtents
,
1918 HFSExtentRecord newExtents
)
1924 // copy the first 3 extents
1925 newExtents
[0].startBlock
= oldExtents
[0].startBlock
;
1926 newExtents
[0].blockCount
= oldExtents
[0].blockCount
;
1927 newExtents
[1].startBlock
= oldExtents
[1].startBlock
;
1928 newExtents
[1].blockCount
= oldExtents
[1].blockCount
;
1929 newExtents
[2].startBlock
= oldExtents
[2].startBlock
;
1930 newExtents
[2].blockCount
= oldExtents
[2].blockCount
;
1933 if (oldExtents
[3].startBlock
|| oldExtents
[3].blockCount
) {
1934 DebugStr("\pExtentRecord with > 3 extents is invalid for HFS");
1945 static OSErr
GetFCBExtentRecord(
1947 HFSPlusExtentRecord extents
)
1950 BlockMoveData(fcb
->fcbExtents
, extents
, sizeof(HFSPlusExtentRecord
));
1956 //_________________________________________________________________________________
1958 // Routine: ExtentsAreIntegral
1960 // Purpose: Ensure that each extent can hold an integral number of nodes
1961 // Called by the NodesAreContiguous function
1962 //_________________________________________________________________________________
1964 static Boolean
ExtentsAreIntegral(
1965 const HFSPlusExtentRecord extentRecord
,
1967 u_int32_t
*blocksChecked
,
1968 Boolean
*checkedLastExtent
)
1971 u_int32_t extentIndex
;
1974 *checkedLastExtent
= false;
1976 for(extentIndex
= 0; extentIndex
< kHFSPlusExtentDensity
; extentIndex
++)
1978 blocks
= extentRecord
[extentIndex
].blockCount
;
1982 *checkedLastExtent
= true;
1986 *blocksChecked
+= blocks
;
1996 //_________________________________________________________________________________
1998 // Routine: NodesAreContiguous
2000 // Purpose: Ensure that all b-tree nodes are contiguous on disk
2001 // Called by BTOpenPath during volume mount
2002 //_________________________________________________________________________________
2005 Boolean
NodesAreContiguous(
2011 u_int32_t startBlock
;
2012 u_int32_t blocksChecked
;
2014 HFSPlusExtentKey key
;
2015 HFSPlusExtentRecord extents
;
2017 Boolean lastExtentReached
;
2021 if (vcb
->blockSize
>= nodeSize
)
2024 mask
= (nodeSize
/ vcb
->blockSize
) - 1;
2026 // check the local extents
2027 (void) GetFCBExtentRecord(fcb
, extents
);
2028 if ( !ExtentsAreIntegral(extents
, mask
, &blocksChecked
, &lastExtentReached
) )
2031 if ( lastExtentReached
||
2032 (int64_t)((int64_t)blocksChecked
* (int64_t)vcb
->blockSize
) >= (int64_t)fcb
->ff_size
)
2035 startBlock
= blocksChecked
;
2037 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
2039 // check the overflow extents (if any)
2040 while ( !lastExtentReached
)
2042 result
= FindExtentRecord(vcb
, kDataForkType
, fcb
->ff_cp
->c_fileid
, startBlock
, FALSE
, &key
, extents
, &hint
);
2045 if ( !ExtentsAreIntegral(extents
, mask
, &blocksChecked
, &lastExtentReached
) ) {
2046 hfs_systemfile_unlock(vcb
, lockflags
);
2049 startBlock
+= blocksChecked
;
2051 hfs_systemfile_unlock(vcb
, lockflags
);