2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
32 #include "../../hfs.h"
33 #include "../../hfs_format.h"
34 #include "../../hfs_endian.h"
36 #include "../headers/FileMgrInternal.h"
37 #include "../headers/BTreesInternal.h"
39 #include <sys/malloc.h>
42 ============================================================
43 Public (Exported) Routines:
44 ============================================================
46 ExtendFileC Allocate more space to a given file.
49 Compare two extents file keys (a search key and a trial
50 key). Used by the BTree manager when searching for,
51 adding, or deleting keys in the extents file of an HFS
55 Compare two extents file keys (a search key and a trial
56 key). Used by the BTree manager when searching for,
57 adding, or deleting keys in the extents file of an HFS+
60 MapFileBlockC Convert (map) an offset within a given file into a
61 physical disk address.
63 TruncateFileC Truncates the disk space allocated to a file. The file
64 space is truncated to a specified new physical EOF, rounded
65 up to the next allocation block boundry. There is an option
66 to truncate to the end of the extent containing the new EOF.
69 Flush the extents file for a given volume.
74 ============================================================
76 ============================================================
78 Search the extents BTree for a particular extent record.
80 Search the FCB and extents file for an extent record that
81 contains a given file position (in bytes).
83 Search a given extent record to see if it contains a given
84 file position (in bytes). Used by SearchExtentFile.
86 Deallocate all allocation blocks in all extents of an extent
89 Deallocate blocks and delete extent records for all allocation
90 blocks beyond a certain point in a file. The starting point
91 must be the first file allocation block for some extent record
94 Deallocate all allocation blocks belonging to a given fork.
96 If the extent record came from the extents file, write out
97 the updated record; otherwise, copy the updated record into
98 the FCB resident extent record. If the record has no extents,
99 and was in the extents file, then delete the record instead.
102 static const SInt64 kTwoGigabytes
= 0x80000000LL
;
107 kResourceForkType
= 0xFF,
113 static OSErr
HFSPlusToHFSExtents(
114 const HFSPlusExtentRecord oldExtents
,
115 HFSExtentRecord newExtents
);
117 static OSErr
FindExtentRecord(
118 const ExtendedVCB
*vcb
,
122 Boolean allowPrevious
,
123 HFSPlusExtentKey
*foundKey
,
124 HFSPlusExtentRecord foundData
,
127 static OSErr
DeleteExtentRecord(
128 const ExtendedVCB
*vcb
,
133 static OSErr
CreateExtentRecord(
135 HFSPlusExtentKey
*key
,
136 HFSPlusExtentRecord extents
,
140 static OSErr
GetFCBExtentRecord(
142 HFSPlusExtentRecord extents
);
144 static OSErr
SearchExtentFile(
148 HFSPlusExtentKey
*foundExtentKey
,
149 HFSPlusExtentRecord foundExtentData
,
150 UInt32
*foundExtentDataIndex
,
151 UInt32
*extentBTreeHint
,
152 UInt32
*endingFABNPlusOne
);
154 static OSErr
SearchExtentRecord(
157 const HFSPlusExtentRecord extentData
,
158 UInt32 extentDataStartFABN
,
159 UInt32
*foundExtentDataOffset
,
160 UInt32
*endingFABNPlusOne
,
161 Boolean
*noMoreExtents
);
163 static OSErr
ReleaseExtents(
165 const HFSPlusExtentRecord extentRecord
,
166 UInt32
*numReleasedAllocationBlocks
,
167 Boolean
*releasedLastExtent
);
169 static OSErr
DeallocateFork(
171 HFSCatalogNodeID fileID
,
173 HFSPlusExtentRecord catalogExtents
,
174 Boolean
* recordDeleted
);
176 static OSErr
TruncateExtents(
181 Boolean
* recordDeleted
);
183 static OSErr
UpdateExtentRecord (
186 const HFSPlusExtentKey
*extentFileKey
,
187 const HFSPlusExtentRecord extentData
,
188 UInt32 extentBTreeHint
);
190 static Boolean
ExtentsAreIntegral(
191 const HFSPlusExtentRecord extentRecord
,
193 UInt32
*blocksChecked
,
194 Boolean
*checkedLastExtent
);
196 //_________________________________________________________________________________
198 // Routine: FindExtentRecord
200 // Purpose: Search the extents BTree for an extent record matching the given
201 // FileID, fork, and starting file allocation block number.
204 // vcb Volume to search
205 // forkType 0 = data fork, -1 = resource fork
206 // fileID File's FileID (CatalogNodeID)
207 // startBlock Starting file allocation block number
208 // allowPrevious If the desired record isn't found and this flag is set,
209 // then see if the previous record belongs to the same fork.
210 // If so, then return it.
213 // foundKey The key data for the record actually found
214 // foundData The extent record actually found (NOTE: on an HFS volume, the
215 // fourth entry will be zeroes.
216 // foundHint The BTree hint to find the node again
217 //_________________________________________________________________________________
218 static OSErr
FindExtentRecord(
219 const ExtendedVCB
*vcb
,
223 Boolean allowPrevious
,
224 HFSPlusExtentKey
*foundKey
,
225 HFSPlusExtentRecord foundData
,
229 BTreeIterator
*btIterator
;
230 FSBufferDescriptor btRecord
;
237 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
239 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
240 bzero(btIterator
, sizeof(*btIterator
));
242 if (vcb
->vcbSigWord
== kHFSSigWord
) {
243 HFSExtentKey
* extentKeyPtr
;
244 HFSExtentRecord extentData
;
246 extentKeyPtr
= (HFSExtentKey
*) &btIterator
->key
;
247 extentKeyPtr
->keyLength
= kHFSExtentKeyMaximumLength
;
248 extentKeyPtr
->forkType
= forkType
;
249 extentKeyPtr
->fileID
= fileID
;
250 extentKeyPtr
->startBlock
= startBlock
;
252 btRecord
.bufferAddress
= &extentData
;
253 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
254 btRecord
.itemCount
= 1;
256 err
= BTSearchRecord(fcb
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
258 if (err
== btNotFound
&& allowPrevious
) {
259 err
= BTIterateRecord(fcb
, kBTreePrevRecord
, btIterator
, &btRecord
, &btRecordSize
);
261 // A previous record may not exist, so just return btNotFound (like we would if
262 // it was for the wrong file/fork).
263 if (err
== (OSErr
) fsBTStartOfIterationErr
) //¥¥ fsBTStartOfIterationErr is type unsigned long
267 // Found a previous record. Does it belong to the same fork of the same file?
268 if (extentKeyPtr
->fileID
!= fileID
|| extentKeyPtr
->forkType
!= forkType
)
276 // Copy the found key back for the caller
278 foundKey
->keyLength
= kHFSPlusExtentKeyMaximumLength
;
279 foundKey
->forkType
= extentKeyPtr
->forkType
;
281 foundKey
->fileID
= extentKeyPtr
->fileID
;
282 foundKey
->startBlock
= extentKeyPtr
->startBlock
;
284 // Copy the found data back for the caller
285 foundData
[0].startBlock
= extentData
[0].startBlock
;
286 foundData
[0].blockCount
= extentData
[0].blockCount
;
287 foundData
[1].startBlock
= extentData
[1].startBlock
;
288 foundData
[1].blockCount
= extentData
[1].blockCount
;
289 foundData
[2].startBlock
= extentData
[2].startBlock
;
290 foundData
[2].blockCount
= extentData
[2].blockCount
;
292 for (i
= 3; i
< kHFSPlusExtentDensity
; ++i
)
294 foundData
[i
].startBlock
= 0;
295 foundData
[i
].blockCount
= 0;
299 else { // HFS Plus volume
300 HFSPlusExtentKey
* extentKeyPtr
;
301 HFSPlusExtentRecord extentData
;
303 extentKeyPtr
= (HFSPlusExtentKey
*) &btIterator
->key
;
304 extentKeyPtr
->keyLength
= kHFSPlusExtentKeyMaximumLength
;
305 extentKeyPtr
->forkType
= forkType
;
306 extentKeyPtr
->pad
= 0;
307 extentKeyPtr
->fileID
= fileID
;
308 extentKeyPtr
->startBlock
= startBlock
;
310 btRecord
.bufferAddress
= &extentData
;
311 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
312 btRecord
.itemCount
= 1;
314 err
= BTSearchRecord(fcb
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
316 if (err
== btNotFound
&& allowPrevious
) {
317 err
= BTIterateRecord(fcb
, kBTreePrevRecord
, btIterator
, &btRecord
, &btRecordSize
);
319 // A previous record may not exist, so just return btNotFound (like we would if
320 // it was for the wrong file/fork).
321 if (err
== (OSErr
) fsBTStartOfIterationErr
) //¥¥ fsBTStartOfIterationErr is type unsigned long
325 // Found a previous record. Does it belong to the same fork of the same file?
326 if (extentKeyPtr
->fileID
!= fileID
|| extentKeyPtr
->forkType
!= forkType
)
332 // Copy the found key back for the caller
334 BlockMoveData(extentKeyPtr
, foundKey
, sizeof(HFSPlusExtentKey
));
335 // Copy the found data back for the caller
336 BlockMoveData(&extentData
, foundData
, sizeof(HFSPlusExtentRecord
));
341 *foundHint
= btIterator
->hint
.nodeNum
;
342 FREE(btIterator
, M_TEMP
);
348 static OSErr
CreateExtentRecord(
350 HFSPlusExtentKey
*key
,
351 HFSPlusExtentRecord extents
,
354 BTreeIterator
* btIterator
;
355 FSBufferDescriptor btRecord
;
363 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
364 bzero(btIterator
, sizeof(*btIterator
));
367 * The lock taken by callers of ExtendFileC is speculative and
368 * only occurs when the file already has overflow extents. So
369 * We need to make sure we have the lock here. The extents
370 * btree lock can be nested (its recursive) so we always take
373 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
375 if (vcb
->vcbSigWord
== kHFSSigWord
) {
376 HFSExtentKey
* keyPtr
;
377 HFSExtentRecord data
;
379 btRecordSize
= sizeof(HFSExtentRecord
);
380 btRecord
.bufferAddress
= &data
;
381 btRecord
.itemSize
= btRecordSize
;
382 btRecord
.itemCount
= 1;
384 keyPtr
= (HFSExtentKey
*) &btIterator
->key
;
385 keyPtr
->keyLength
= kHFSExtentKeyMaximumLength
;
386 keyPtr
->forkType
= key
->forkType
;
387 keyPtr
->fileID
= key
->fileID
;
388 keyPtr
->startBlock
= key
->startBlock
;
390 err
= HFSPlusToHFSExtents(extents
, data
);
392 else { // HFS Plus volume
393 btRecordSize
= sizeof(HFSPlusExtentRecord
);
394 btRecord
.bufferAddress
= extents
;
395 btRecord
.itemSize
= btRecordSize
;
396 btRecord
.itemCount
= 1;
398 BlockMoveData(key
, &btIterator
->key
, sizeof(HFSPlusExtentKey
));
402 err
= BTInsertRecord(GetFileControlBlock(vcb
->extentsRefNum
), btIterator
, &btRecord
, btRecordSize
);
405 *hint
= btIterator
->hint
.nodeNum
;
407 (void) BTFlushPath(GetFileControlBlock(vcb
->extentsRefNum
));
409 hfs_systemfile_unlock(vcb
, lockflags
);
411 FREE(btIterator
, M_TEMP
);
416 static OSErr
DeleteExtentRecord(
417 const ExtendedVCB
*vcb
,
422 BTreeIterator
* btIterator
;
427 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
428 bzero(btIterator
, sizeof(*btIterator
));
430 if (vcb
->vcbSigWord
== kHFSSigWord
) {
431 HFSExtentKey
* keyPtr
;
433 keyPtr
= (HFSExtentKey
*) &btIterator
->key
;
434 keyPtr
->keyLength
= kHFSExtentKeyMaximumLength
;
435 keyPtr
->forkType
= forkType
;
436 keyPtr
->fileID
= fileID
;
437 keyPtr
->startBlock
= startBlock
;
439 else { // HFS Plus volume
440 HFSPlusExtentKey
* keyPtr
;
442 keyPtr
= (HFSPlusExtentKey
*) &btIterator
->key
;
443 keyPtr
->keyLength
= kHFSPlusExtentKeyMaximumLength
;
444 keyPtr
->forkType
= forkType
;
446 keyPtr
->fileID
= fileID
;
447 keyPtr
->startBlock
= startBlock
;
450 err
= BTDeleteRecord(GetFileControlBlock(vcb
->extentsRefNum
), btIterator
);
451 (void) BTFlushPath(GetFileControlBlock(vcb
->extentsRefNum
));
453 FREE(btIterator
, M_TEMP
);
459 //_________________________________________________________________________________
461 // Routine: MapFileBlock
463 // Function: Maps a file position into a physical disk address.
465 //_________________________________________________________________________________
468 OSErr
MapFileBlockC (
469 ExtendedVCB
*vcb
, // volume that file resides on
470 FCB
*fcb
, // FCB of file
471 size_t numberOfBytes
, // number of contiguous bytes desired
472 off_t offset
, // starting offset within file (in bytes)
473 daddr64_t
*startSector
, // first sector (NOT an allocation block)
474 size_t *availableBytes
) // number of contiguous bytes (up to numberOfBytes)
477 UInt32 allocBlockSize
; // Size of the volume's allocation block
479 HFSPlusExtentKey foundKey
;
480 HFSPlusExtentRecord foundData
;
483 UInt32 firstFABN
; // file allocation block of first block in found extent
484 UInt32 nextFABN
; // file allocation block of block after end of found extent
485 off_t dataEnd
; // (offset) end of range that is contiguous
486 UInt32 sectorsPerBlock
; // Number of sectors per allocation block
487 UInt32 startBlock
; // volume allocation block corresponding to firstFABN
491 allocBlockSize
= vcb
->blockSize
;
492 sectorSize
= VCBTOHFS(vcb
)->hfs_phys_block_size
;
494 err
= SearchExtentFile(vcb
, fcb
, offset
, &foundKey
, foundData
, &foundIndex
, &hint
, &nextFABN
);
496 startBlock
= foundData
[foundIndex
].startBlock
;
497 firstFABN
= nextFABN
- foundData
[foundIndex
].blockCount
;
506 // Determine the end of the available space. It will either be the end of the extent,
507 // or the file's PEOF, whichever is smaller.
509 dataEnd
= (off_t
)((off_t
)(nextFABN
) * (off_t
)(allocBlockSize
)); // Assume valid data through end of this extent
510 if (((off_t
)fcb
->ff_blocks
* (off_t
)allocBlockSize
) < dataEnd
) // Is PEOF shorter?
511 dataEnd
= (off_t
)fcb
->ff_blocks
* (off_t
)allocBlockSize
; // Yes, so only map up to PEOF
513 // Compute the number of sectors in an allocation block
514 sectorsPerBlock
= allocBlockSize
/ sectorSize
; // sectors per allocation block
517 // Compute the absolute sector number that contains the offset of the given file
518 // offset in sectors from start of the extent +
519 // offset in sectors from start of allocation block space
521 temp
= (daddr64_t
)((offset
- (off_t
)((off_t
)(firstFABN
) * (off_t
)(allocBlockSize
)))/sectorSize
);
522 temp
+= startBlock
* sectorsPerBlock
;
524 /* Add in any volume offsets */
525 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
526 temp
+= vcb
->hfsPlusIOPosOffset
/ sectorSize
;
528 temp
+= vcb
->vcbAlBlSt
;
530 // Return the desired sector for file position "offset"
534 // Determine the number of contiguous bytes until the end of the extent
535 // (or the amount they asked for, whichever comes first).
539 tmpOff
= dataEnd
- offset
;
540 if (tmpOff
> (off_t
)(numberOfBytes
))
541 *availableBytes
= numberOfBytes
; // more there than they asked for, so pin the output
543 *availableBytes
= tmpOff
;
550 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
551 // Routine: ReleaseExtents
553 // Function: Release the extents of a single extent data record.
554 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
556 static OSErr
ReleaseExtents(
558 const HFSPlusExtentRecord extentRecord
,
559 UInt32
*numReleasedAllocationBlocks
,
560 Boolean
*releasedLastExtent
)
563 UInt32 numberOfExtents
;
566 *numReleasedAllocationBlocks
= 0;
567 *releasedLastExtent
= false;
569 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
570 numberOfExtents
= kHFSPlusExtentDensity
;
572 numberOfExtents
= kHFSExtentDensity
;
574 for( extentIndex
= 0; extentIndex
< numberOfExtents
; extentIndex
++)
576 UInt32 numAllocationBlocks
;
578 // Loop over the extent record and release the blocks associated with each extent.
580 numAllocationBlocks
= extentRecord
[extentIndex
].blockCount
;
581 if ( numAllocationBlocks
== 0 )
583 *releasedLastExtent
= true;
587 err
= BlockDeallocate( vcb
, extentRecord
[extentIndex
].startBlock
, numAllocationBlocks
);
591 *numReleasedAllocationBlocks
+= numAllocationBlocks
; // bump FABN to beg of next extent
599 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
600 // Routine: TruncateExtents
602 // Purpose: Delete extent records whose starting file allocation block number
603 // is greater than or equal to a given starting block number. The
604 // allocation blocks represented by the extents are deallocated.
607 // vcb Volume to operate on
608 // fileID Which file to operate on
609 // startBlock Starting file allocation block number for first extent
611 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
613 static OSErr
TruncateExtents(
618 Boolean
* recordDeleted
)
621 UInt32 numberExtentsReleased
;
622 Boolean releasedLastExtent
;
624 HFSPlusExtentKey key
;
625 HFSPlusExtentRecord extents
;
629 * The lock taken by callers of TruncateFileC is speculative and
630 * only occurs when the file already has overflow extents. So
631 * We need to make sure we have the lock here. The extents
632 * btree lock can be nested (its recursive) so we always take
635 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
638 err
= FindExtentRecord(vcb
, forkType
, fileID
, startBlock
, false, &key
, extents
, &hint
);
640 if (err
== btNotFound
)
645 err
= ReleaseExtents( vcb
, extents
, &numberExtentsReleased
, &releasedLastExtent
);
646 if (err
!= noErr
) break;
648 err
= DeleteExtentRecord(vcb
, forkType
, fileID
, startBlock
);
649 if (err
!= noErr
) break;
651 *recordDeleted
= true;
652 startBlock
+= numberExtentsReleased
;
654 hfs_systemfile_unlock(vcb
, lockflags
);
661 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
662 // Routine: DeallocateFork
664 // Function: De-allocates all disk space allocated to a specified fork.
665 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
667 static OSErr
DeallocateFork(
669 HFSCatalogNodeID fileID
,
671 HFSPlusExtentRecord catalogExtents
,
672 Boolean
* recordDeleted
) /* true if a record was deleted */
675 UInt32 numReleasedAllocationBlocks
;
676 Boolean releasedLastExtent
;
678 // Release the catalog extents
679 err
= ReleaseExtents( vcb
, catalogExtents
, &numReleasedAllocationBlocks
, &releasedLastExtent
);
680 // Release the extra extents, if present
681 if (err
== noErr
&& !releasedLastExtent
)
682 err
= TruncateExtents(vcb
, forkType
, fileID
, numReleasedAllocationBlocks
, recordDeleted
);
687 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
688 // Routine: FlushExtentFile
690 // Function: Flushes the extent file for a specified volume
691 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
694 OSErr
FlushExtentFile( ExtendedVCB
*vcb
)
700 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
702 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
703 err
= BTFlushPath(fcb
);
704 hfs_systemfile_unlock(vcb
, lockflags
);
708 // If the FCB for the extent "file" is dirty, mark the VCB as dirty.
710 if (FTOC(fcb
)->c_flag
& C_MODIFIED
)
713 // err = FlushVolumeControlBlock( vcb );
721 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
722 // Routine: CompareExtentKeys
724 // Function: Compares two extent file keys (a search key and a trial key) for
726 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
729 SInt32
CompareExtentKeys( const HFSExtentKey
*searchKey
, const HFSExtentKey
*trialKey
)
731 SInt32 result
; // ± 1
734 if (searchKey
->keyLength
!= kHFSExtentKeyMaximumLength
)
735 DebugStr("\pHFS: search Key is wrong length");
736 if (trialKey
->keyLength
!= kHFSExtentKeyMaximumLength
)
737 DebugStr("\pHFS: trial Key is wrong length");
740 result
= -1; // assume searchKey < trialKey
742 if (searchKey
->fileID
== trialKey
->fileID
) {
744 // FileNum's are equal; compare fork types
746 if (searchKey
->forkType
== trialKey
->forkType
) {
748 // Fork types are equal; compare allocation block number
750 if (searchKey
->startBlock
== trialKey
->startBlock
) {
752 // Everything is equal
758 // Allocation block numbers differ; determine sign
760 if (searchKey
->startBlock
> trialKey
->startBlock
)
766 // Fork types differ; determine sign
768 if (searchKey
->forkType
> trialKey
->forkType
)
774 // FileNums differ; determine sign
776 if (searchKey
->fileID
> trialKey
->fileID
)
785 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
786 // Routine: CompareExtentKeysPlus
788 // Function: Compares two extent file keys (a search key and a trial key) for
790 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
793 SInt32
CompareExtentKeysPlus( const HFSPlusExtentKey
*searchKey
, const HFSPlusExtentKey
*trialKey
)
795 SInt32 result
; // ± 1
798 if (searchKey
->keyLength
!= kHFSPlusExtentKeyMaximumLength
)
799 DebugStr("\pHFS: search Key is wrong length");
800 if (trialKey
->keyLength
!= kHFSPlusExtentKeyMaximumLength
)
801 DebugStr("\pHFS: trial Key is wrong length");
804 result
= -1; // assume searchKey < trialKey
806 if (searchKey
->fileID
== trialKey
->fileID
) {
808 // FileNum's are equal; compare fork types
810 if (searchKey
->forkType
== trialKey
->forkType
) {
812 // Fork types are equal; compare allocation block number
814 if (searchKey
->startBlock
== trialKey
->startBlock
) {
816 // Everything is equal
822 // Allocation block numbers differ; determine sign
824 if (searchKey
->startBlock
> trialKey
->startBlock
)
830 // Fork types differ; determine sign
832 if (searchKey
->forkType
> trialKey
->forkType
)
838 // FileNums differ; determine sign
840 if (searchKey
->fileID
> trialKey
->fileID
)
848 * Add a file extent to a file.
850 * Used by hfs_extendfs to extend the volume allocation bitmap file.
855 AddFileExtent(ExtendedVCB
*vcb
, FCB
*fcb
, UInt32 startBlock
, UInt32 blockCount
)
857 HFSPlusExtentKey foundKey
;
858 HFSPlusExtentRecord foundData
;
866 peof
= (SInt64
)(fcb
->ff_blocks
+ blockCount
) * (SInt64
)vcb
->blockSize
;
868 error
= SearchExtentFile(vcb
, fcb
, peof
-1, &foundKey
, foundData
, &foundIndex
, &hint
, &nextBlock
);
869 if (error
!= fxRangeErr
)
873 * Add new extent. See if there is room in the current record.
875 if (foundData
[foundIndex
].blockCount
!= 0)
877 if (foundIndex
== kHFSPlusExtentDensity
) {
879 * Existing record is full so create a new one.
881 foundKey
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
882 foundKey
.forkType
= kDataForkType
;
884 foundKey
.fileID
= FTOC(fcb
)->c_fileid
;
885 foundKey
.startBlock
= nextBlock
;
887 foundData
[0].startBlock
= startBlock
;
888 foundData
[0].blockCount
= blockCount
;
890 /* zero out remaining extents. */
891 for (i
= 1; i
< kHFSPlusExtentDensity
; ++i
) {
892 foundData
[i
].startBlock
= 0;
893 foundData
[i
].blockCount
= 0;
898 error
= CreateExtentRecord(vcb
, &foundKey
, foundData
, &hint
);
899 if (error
== fxOvFlErr
)
903 * Add a new extent into existing record.
905 foundData
[foundIndex
].startBlock
= startBlock
;
906 foundData
[foundIndex
].blockCount
= blockCount
;
907 error
= UpdateExtentRecord(vcb
, fcb
, &foundKey
, foundData
, hint
);
909 (void) FlushExtentFile(vcb
);
915 //_________________________________________________________________________________
917 // Routine: Extendfile
919 // Function: Extends the disk space allocated to a file.
921 //_________________________________________________________________________________
925 ExtendedVCB
*vcb
, // volume that file resides on
926 FCB
*fcb
, // FCB of file to truncate
927 SInt64 bytesToAdd
, // number of bytes to allocate
928 UInt32 blockHint
, // desired starting allocation block
929 UInt32 flags
, // EFContig and/or EFAll
930 SInt64
*actualBytesAdded
) // number of bytes actually allocated
933 UInt32 volumeBlockSize
;
935 SInt64 bytesThisExtent
;
936 HFSPlusExtentKey foundKey
;
937 HFSPlusExtentRecord foundData
;
942 Boolean allOrNothing
;
947 UInt32 actualStartBlock
;
948 UInt32 actualNumBlocks
;
949 UInt32 numExtentsPerRecord
;
956 *actualBytesAdded
= 0;
957 volumeBlockSize
= vcb
->blockSize
;
958 allOrNothing
= ((flags
& kEFAllMask
) != 0);
959 forceContig
= ((flags
& kEFContigMask
) != 0);
960 prevblocks
= fcb
->ff_blocks
;
962 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
963 numExtentsPerRecord
= kHFSPlusExtentDensity
;
965 numExtentsPerRecord
= kHFSExtentDensity
;
968 // Make sure the request and new PEOF are less than 2GB if HFS.
970 if (vcb
->vcbSigWord
== kHFSSigWord
) {
971 if (bytesToAdd
>= kTwoGigabytes
)
973 if ((((SInt64
)fcb
->ff_blocks
* (SInt64
)volumeBlockSize
) + bytesToAdd
) >= kTwoGigabytes
)
977 // Determine how many blocks need to be allocated.
978 // Round up the number of desired bytes to add.
980 blocksToAdd
= howmany(bytesToAdd
, volumeBlockSize
);
981 bytesToAdd
= (SInt64
)((SInt64
)blocksToAdd
* (SInt64
)volumeBlockSize
);
984 * For deferred allocations just reserve the blocks.
986 if ((flags
& kEFDeferMask
)
987 && (vcb
->vcbSigWord
== kHFSPlusSigWord
)
988 && (bytesToAdd
< (SInt64
)HFS_MAX_DEFERED_ALLOC
)
989 && (blocksToAdd
< hfs_freeblks(VCBTOHFS(vcb
), 1))) {
990 HFS_MOUNT_LOCK(vcb
, TRUE
);
991 vcb
->loanedBlocks
+= blocksToAdd
;
992 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
994 fcb
->ff_unallocblocks
+= blocksToAdd
;
995 FTOC(fcb
)->c_blocks
+= blocksToAdd
;
996 fcb
->ff_blocks
+= blocksToAdd
;
998 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
999 *actualBytesAdded
= bytesToAdd
;
1003 * Give back any unallocated blocks before doing real allocations.
1005 if (fcb
->ff_unallocblocks
> 0) {
1006 u_int32_t loanedBlocks
;
1008 loanedBlocks
= fcb
->ff_unallocblocks
;
1009 blocksToAdd
+= loanedBlocks
;
1010 bytesToAdd
= (SInt64
)blocksToAdd
* (SInt64
)volumeBlockSize
;
1011 FTOC(fcb
)->c_blocks
-= loanedBlocks
;
1012 fcb
->ff_blocks
-= loanedBlocks
;
1013 fcb
->ff_unallocblocks
= 0;
1015 HFS_MOUNT_LOCK(vcb
, TRUE
);
1016 vcb
->loanedBlocks
-= loanedBlocks
;
1017 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
1021 // If the file's clump size is larger than the allocation block size,
1022 // then set the maximum number of bytes to the requested number of bytes
1023 // rounded up to a multiple of the clump size.
1025 if ((vcb
->vcbClpSiz
> (int32_t)volumeBlockSize
)
1026 && (bytesToAdd
< (SInt64
)HFS_MAX_DEFERED_ALLOC
)
1027 && (flags
& kEFNoClumpMask
) == 0) {
1028 maximumBytes
= (SInt64
)howmany(bytesToAdd
, vcb
->vcbClpSiz
);
1029 maximumBytes
*= vcb
->vcbClpSiz
;
1031 maximumBytes
= bytesToAdd
;
1035 // Compute new physical EOF, rounded up to a multiple of a block.
1037 if ( (vcb
->vcbSigWord
== kHFSSigWord
) && // Too big?
1038 ((((SInt64
)fcb
->ff_blocks
* (SInt64
)volumeBlockSize
) + bytesToAdd
) >= kTwoGigabytes
) ) {
1039 if (allOrNothing
) // Yes, must they have it all?
1040 goto Overflow
; // Yes, can't have it
1042 --blocksToAdd
; // No, give give 'em one block less
1043 bytesToAdd
-= volumeBlockSize
;
1048 // If allocation is all-or-nothing, make sure there are
1049 // enough free blocks on the volume (quick test).
1052 (blocksToAdd
> hfs_freeblks(VCBTOHFS(vcb
), flags
& kEFReserveMask
))) {
1058 // See if there are already enough blocks allocated to the file.
1060 peof
= ((SInt64
)fcb
->ff_blocks
* (SInt64
)volumeBlockSize
) + bytesToAdd
; // potential new PEOF
1061 err
= SearchExtentFile(vcb
, fcb
, peof
-1, &foundKey
, foundData
, &foundIndex
, &hint
, &nextBlock
);
1063 // Enough blocks are already allocated. Just update the FCB to reflect the new length.
1064 fcb
->ff_blocks
= peof
/ volumeBlockSize
;
1065 FTOC(fcb
)->c_blocks
+= (bytesToAdd
/ volumeBlockSize
);
1066 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1069 if (err
!= fxRangeErr
) // Any real error?
1070 goto ErrorExit
; // Yes, so exit immediately
1073 // Adjust the PEOF to the end of the last extent.
1075 peof
= (SInt64
)((SInt64
)nextBlock
* (SInt64
)volumeBlockSize
); // currently allocated PEOF
1076 bytesThisExtent
= (SInt64
)(nextBlock
- fcb
->ff_blocks
) * (SInt64
)volumeBlockSize
;
1077 if (bytesThisExtent
!= 0) {
1078 fcb
->ff_blocks
= nextBlock
;
1079 FTOC(fcb
)->c_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1080 FTOC(fcb
)->c_flag
|= C_MODIFIED
;
1081 bytesToAdd
-= bytesThisExtent
;
1085 // Allocate some more space.
1087 // First try a contiguous allocation (of the whole amount).
1088 // If that fails, get whatever we can.
1089 // If forceContig, then take whatever we got
1090 // else, keep getting bits and pieces (non-contig)
1093 useMetaZone
= flags
& kEFMetadataMask
;
1094 vcb
->vcbFreeExtCnt
= 0; /* For now, force rebuild of free extent list */
1097 startBlock
= blockHint
;
1099 startBlock
= foundData
[foundIndex
].startBlock
+ foundData
[foundIndex
].blockCount
;
1101 /* Force reserve checking if requested. */
1102 if (flags
& kEFReserveMask
) {
1105 actualNumBlocks
= 0;
1106 actualStartBlock
= 0;
1108 availbytes
= (SInt64
)hfs_freeblks(VCBTOHFS(vcb
), 1) *
1109 (SInt64
)volumeBlockSize
;
1110 if (availbytes
<= 0) {
1113 if (wantContig
&& (availbytes
< bytesToAdd
))
1116 err
= BlockAllocate(
1119 howmany(MIN(bytesToAdd
, availbytes
), volumeBlockSize
),
1120 howmany(MIN(maximumBytes
, availbytes
), volumeBlockSize
),
1128 err
= BlockAllocate(vcb
, startBlock
, howmany(bytesToAdd
, volumeBlockSize
),
1129 howmany(maximumBytes
, volumeBlockSize
), wantContig
, useMetaZone
,
1130 &actualStartBlock
, &actualNumBlocks
);
1132 if (err
== dskFulErr
) {
1134 break; // AllocContig failed because not enough contiguous space
1136 // Couldn't get one big chunk, so get whatever we can.
1141 if (actualNumBlocks
!= 0)
1143 if (useMetaZone
== 0) {
1144 /* Couldn't get anything so dip into metadat zone */
1151 if (actualNumBlocks
!= 0) {
1152 // this catalog entry *must* get forced to disk when
1153 // hfs_update() is called
1154 FTOC(fcb
)->c_flag
|= C_FORCEUPDATE
;
1157 // Add the new extent to the existing extent record, or create a new one.
1158 if ((actualStartBlock
== startBlock
) && (blockHint
== 0)) {
1159 // We grew the file's last extent, so just adjust the number of blocks.
1160 foundData
[foundIndex
].blockCount
+= actualNumBlocks
;
1161 err
= UpdateExtentRecord(vcb
, fcb
, &foundKey
, foundData
, hint
);
1162 if (err
!= noErr
) break;
1167 // Need to add a new extent. See if there is room in the current record.
1168 if (foundData
[foundIndex
].blockCount
!= 0) // Is current extent free to use?
1169 ++foundIndex
; // No, so use the next one.
1170 if (foundIndex
== numExtentsPerRecord
) {
1171 // This record is full. Need to create a new one.
1172 if (FTOC(fcb
)->c_fileid
== kHFSExtentsFileID
) {
1173 (void) BlockDeallocate(vcb
, actualStartBlock
, actualNumBlocks
);
1174 err
= dskFulErr
; // Oops. Can't extend extents file past first record.
1178 foundKey
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
1179 if (FORK_IS_RSRC(fcb
))
1180 foundKey
.forkType
= kResourceForkType
;
1182 foundKey
.forkType
= kDataForkType
;
1184 foundKey
.fileID
= FTOC(fcb
)->c_fileid
;
1185 foundKey
.startBlock
= nextBlock
;
1187 foundData
[0].startBlock
= actualStartBlock
;
1188 foundData
[0].blockCount
= actualNumBlocks
;
1190 // zero out remaining extents...
1191 for (i
= 1; i
< kHFSPlusExtentDensity
; ++i
)
1193 foundData
[i
].startBlock
= 0;
1194 foundData
[i
].blockCount
= 0;
1199 err
= CreateExtentRecord(vcb
, &foundKey
, foundData
, &hint
);
1200 if (err
== fxOvFlErr
) {
1201 // We couldn't create an extent record because extents B-tree
1202 // couldn't grow. Dellocate the extent just allocated and
1203 // return a disk full error.
1204 (void) BlockDeallocate(vcb
, actualStartBlock
, actualNumBlocks
);
1207 if (err
!= noErr
) break;
1209 needsFlush
= true; // We need to update the B-tree header
1212 // Add a new extent into this record and update.
1213 foundData
[foundIndex
].startBlock
= actualStartBlock
;
1214 foundData
[foundIndex
].blockCount
= actualNumBlocks
;
1215 err
= UpdateExtentRecord(vcb
, fcb
, &foundKey
, foundData
, hint
);
1216 if (err
!= noErr
) break;
1220 // Figure out how many bytes were actually allocated.
1221 // NOTE: BlockAllocate could have allocated more than we asked for.
1222 // Don't set the PEOF beyond what our client asked for.
1223 nextBlock
+= actualNumBlocks
;
1224 bytesThisExtent
= (SInt64
)((SInt64
)actualNumBlocks
* (SInt64
)volumeBlockSize
);
1225 if (bytesThisExtent
> bytesToAdd
) {
1229 bytesToAdd
-= bytesThisExtent
;
1230 maximumBytes
-= bytesThisExtent
;
1232 fcb
->ff_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1233 FTOC(fcb
)->c_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1234 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1236 // If contiguous allocation was requested, then we've already got one contiguous
1237 // chunk. If we didn't get all we wanted, then adjust the error to disk full.
1239 if (bytesToAdd
!= 0)
1241 break; // We've already got everything that's contiguous
1244 } while (err
== noErr
&& bytesToAdd
);
1248 if (VCBTOHFS(vcb
)->hfs_flags
& HFS_METADATA_ZONE
) {
1249 /* Keep the roving allocator out of the metadata zone. */
1250 if (vcb
->nextAllocation
>= VCBTOHFS(vcb
)->hfs_metazone_start
&&
1251 vcb
->nextAllocation
<= VCBTOHFS(vcb
)->hfs_metazone_end
) {
1252 HFS_MOUNT_LOCK(vcb
, TRUE
);
1253 vcb
->nextAllocation
= VCBTOHFS(vcb
)->hfs_metazone_end
+ 1;
1254 vcb
->vcbFlags
|= 0xFF00;
1255 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
1258 if (prevblocks
< fcb
->ff_blocks
) {
1259 *actualBytesAdded
= (SInt64
)(fcb
->ff_blocks
- prevblocks
) * (SInt64
)volumeBlockSize
;
1261 *actualBytesAdded
= 0;
1265 (void) FlushExtentFile(vcb
);
1270 err
= fileBoundsErr
;
1276 //_________________________________________________________________________________
1278 // Routine: TruncateFileC
1280 // Function: Truncates the disk space allocated to a file. The file space is
1281 // truncated to a specified new PEOF rounded up to the next allocation
1282 // block boundry. If the 'TFTrunExt' option is specified, the file is
1283 // truncated to the end of the extent containing the new PEOF.
1285 //_________________________________________________________________________________
1288 OSErr
TruncateFileC (
1289 ExtendedVCB
*vcb
, // volume that file resides on
1290 FCB
*fcb
, // FCB of file to truncate
1291 SInt64 peof
, // new physical size for file
1292 Boolean truncateToExtent
) // if true, truncate to end of extent containing newPEOF
1295 UInt32 nextBlock
; // next file allocation block to consider
1296 UInt32 startBlock
; // Physical (volume) allocation block number of start of a range
1297 UInt32 physNumBlocks
; // Number of allocation blocks in file (according to PEOF)
1299 HFSPlusExtentKey key
; // key for current extent record; key->keyLength == 0 if FCB's extent record
1300 UInt32 hint
; // BTree hint corresponding to key
1301 HFSPlusExtentRecord extentRecord
;
1303 UInt32 extentNextBlock
;
1304 UInt32 numExtentsPerRecord
;
1307 Boolean extentChanged
; // true if we actually changed an extent
1308 Boolean recordDeleted
; // true if an extent record got deleted
1310 recordDeleted
= false;
1312 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1313 numExtentsPerRecord
= kHFSPlusExtentDensity
;
1315 numExtentsPerRecord
= kHFSExtentDensity
;
1317 if (FORK_IS_RSRC(fcb
))
1318 forkType
= kResourceForkType
;
1320 forkType
= kDataForkType
;
1322 temp64
= fcb
->ff_blocks
;
1323 physNumBlocks
= (UInt32
)temp64
;
1326 // Round newPEOF up to a multiple of the allocation block size. If new size is
1327 // two gigabytes or more, then round down by one allocation block (??? really?
1328 // shouldn't that be an error?).
1330 nextBlock
= howmany(peof
, vcb
->blockSize
); // number of allocation blocks to remain in file
1331 peof
= (SInt64
)((SInt64
)nextBlock
* (SInt64
)vcb
->blockSize
); // number of bytes in those blocks
1332 if ((vcb
->vcbSigWord
== kHFSSigWord
) && (peof
>= kTwoGigabytes
)) {
1334 DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
1336 err
= fileBoundsErr
;
1341 // Update FCB's length
1344 * XXX Any errors could cause ff_blocks and c_blocks to get out of sync...
1346 numBlocks
= peof
/ vcb
->blockSize
;
1347 FTOC(fcb
)->c_blocks
-= (fcb
->ff_blocks
- numBlocks
);
1348 fcb
->ff_blocks
= numBlocks
;
1350 // this catalog entry is modified and *must* get forced
1351 // to disk when hfs_update() is called
1352 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1355 // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
1361 // Deallocate all the extents for this fork
1362 err
= DeallocateFork(vcb
, FTOC(fcb
)->c_fileid
, forkType
, fcb
->fcbExtents
, &recordDeleted
);
1363 if (err
!= noErr
) goto ErrorExit
; // got some error, so return it
1365 // Update the catalog extent record (making sure it's zeroed out)
1367 for (i
=0; i
< kHFSPlusExtentDensity
; i
++) {
1368 fcb
->fcbExtents
[i
].startBlock
= 0;
1369 fcb
->fcbExtents
[i
].blockCount
= 0;
1376 // Find the extent containing byte (peof-1). This is the last extent we'll keep.
1377 // (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only
1378 // keep up through peof). The search will tell us how many allocation blocks exist
1379 // in the found extent plus all previous extents.
1381 err
= SearchExtentFile(vcb
, fcb
, peof
-1, &key
, extentRecord
, &extentIndex
, &hint
, &extentNextBlock
);
1382 if (err
!= noErr
) goto ErrorExit
;
1384 extentChanged
= false; // haven't changed the extent yet
1386 if (!truncateToExtent
) {
1388 // Shorten this extent. It may be the case that the entire extent gets
1391 numBlocks
= extentNextBlock
- nextBlock
; // How many blocks in this extent to free up
1392 if (numBlocks
!= 0) {
1393 // Compute first volume allocation block to free
1394 startBlock
= extentRecord
[extentIndex
].startBlock
+ extentRecord
[extentIndex
].blockCount
- numBlocks
;
1395 // Free the blocks in bitmap
1396 err
= BlockDeallocate(vcb
, startBlock
, numBlocks
);
1397 if (err
!= noErr
) goto ErrorExit
;
1398 // Adjust length of this extent
1399 extentRecord
[extentIndex
].blockCount
-= numBlocks
;
1400 // If extent is empty, set start block to 0
1401 if (extentRecord
[extentIndex
].blockCount
== 0)
1402 extentRecord
[extentIndex
].startBlock
= 0;
1403 // Remember that we changed the extent record
1404 extentChanged
= true;
1409 // Now move to the next extent in the record, and set up the file allocation block number
1411 nextBlock
= extentNextBlock
; // Next file allocation block to free
1412 ++extentIndex
; // Its index within the extent record
1415 // Release all following extents in this extent record. Update the record.
1417 while (extentIndex
< numExtentsPerRecord
&& extentRecord
[extentIndex
].blockCount
!= 0) {
1418 numBlocks
= extentRecord
[extentIndex
].blockCount
;
1419 // Deallocate this extent
1420 err
= BlockDeallocate(vcb
, extentRecord
[extentIndex
].startBlock
, numBlocks
);
1421 if (err
!= noErr
) goto ErrorExit
;
1422 // Update next file allocation block number
1423 nextBlock
+= numBlocks
;
1424 // Zero out start and length of this extent to delete it from record
1425 extentRecord
[extentIndex
].startBlock
= 0;
1426 extentRecord
[extentIndex
].blockCount
= 0;
1427 // Remember that we changed an extent
1428 extentChanged
= true;
1429 // Move to next extent in record
1434 // If any of the extents in the current record were changed, then update that
1435 // record (in the FCB, or extents file).
1437 if (extentChanged
) {
1438 err
= UpdateExtentRecord(vcb
, fcb
, &key
, extentRecord
, hint
);
1439 if (err
!= noErr
) goto ErrorExit
;
1443 // If there are any following allocation blocks, then we need
1444 // to seach for their extent records and delete those allocation
1447 if (nextBlock
< physNumBlocks
)
1448 err
= TruncateExtents(vcb
, forkType
, FTOC(fcb
)->c_fileid
, nextBlock
, &recordDeleted
);
1453 (void) FlushExtentFile(vcb
);
1464 OSErr
HeadTruncateFile (
1469 HFSPlusExtentRecord extents
;
1470 HFSPlusExtentRecord tailExtents
;
1471 HFSCatalogNodeID fileID
;
1481 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
1484 forkType
= FORK_IS_RSRC(fcb
) ? kResourceForkType
: kDataForkType
;
1485 fileID
= FTOC(fcb
)->c_fileid
;
1486 bzero(tailExtents
, sizeof(tailExtents
));
1492 * Process catalog resident extents
1494 for (i
= 0, j
= 0; i
< kHFSPlusExtentDensity
; ++i
) {
1495 blkcnt
= fcb
->fcbExtents
[i
].blockCount
;
1497 break; /* end of extents */
1499 if (blksfreed
< headblks
) {
1500 error
= BlockDeallocate(vcb
, fcb
->fcbExtents
[i
].startBlock
, blkcnt
);
1502 * Any errors after the first BlockDeallocate
1503 * must be ignored so we can put the file in
1508 goto ErrorExit
; /* uh oh */
1511 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1512 FTOC(fcb
)->c_desc
.cd_nameptr
? FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1516 blksfreed
+= blkcnt
;
1517 fcb
->fcbExtents
[i
].startBlock
= 0;
1518 fcb
->fcbExtents
[i
].blockCount
= 0;
1520 tailExtents
[j
].startBlock
= fcb
->fcbExtents
[i
].startBlock
;
1521 tailExtents
[j
].blockCount
= blkcnt
;
1530 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1533 * Process overflow extents
1538 error
= FindExtentRecord(vcb
, forkType
, fileID
, startblk
, false, NULL
, extents
, NULL
);
1541 * Any errors after the first BlockDeallocate
1542 * must be ignored so we can put the file in
1545 if (error
!= btNotFound
)
1546 printf("HeadTruncateFile: problems finding extents %s (%d)\n",
1547 FTOC(fcb
)->c_desc
.cd_nameptr
? FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1552 for(i
= 0, extblks
= 0; i
< kHFSPlusExtentDensity
; ++i
) {
1553 blkcnt
= extents
[i
].blockCount
;
1555 break; /* end of extents */
1557 if (blksfreed
< headblks
) {
1558 error
= BlockDeallocate(vcb
, extents
[i
].startBlock
, blkcnt
);
1560 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1561 FTOC(fcb
)->c_desc
.cd_nameptr
? FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1564 blksfreed
+= blkcnt
;
1566 tailExtents
[j
].startBlock
= extents
[i
].startBlock
;
1567 tailExtents
[j
].blockCount
= blkcnt
;
1573 error
= DeleteExtentRecord(vcb
, forkType
, fileID
, startblk
);
1575 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1576 FTOC(fcb
)->c_desc
.cd_nameptr
? FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1581 break; /* all done */
1583 startblk
+= extblks
;
1585 hfs_systemfile_unlock(vcb
, lockflags
);
1589 bcopy(tailExtents
, fcb
->fcbExtents
, sizeof(tailExtents
));
1590 blkcnt
= fcb
->ff_blocks
- headblks
;
1591 FTOC(fcb
)->c_blocks
-= blkcnt
;
1592 fcb
->ff_blocks
= blkcnt
;
1594 FTOC(fcb
)->c_flag
|= C_FORCEUPDATE
;
1595 FTOC(fcb
)->c_touch_chgtime
= TRUE
;
1597 (void) FlushExtentFile(vcb
);
1601 return MacToVFSError(error
);
1606 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1607 // Routine: SearchExtentRecord (was XRSearch)
1609 // Function: Searches extent record for the extent mapping a given file
1610 // allocation block number (FABN).
1612 // Input: searchFABN - desired FABN
1613 // extentData - pointer to extent data record (xdr)
1614 // extentDataStartFABN - beginning FABN for extent record
1616 // Output: foundExtentDataOffset - offset to extent entry within xdr
1617 // result = noErr, offset to extent mapping desired FABN
1618 // result = FXRangeErr, offset to last extent in record
1619 // endingFABNPlusOne - ending FABN +1
1620 // noMoreExtents - True if the extent was not found, and the
1621 // extent record was not full (so don't bother
1622 // looking in subsequent records); false otherwise.
1624 // Result: noErr = ok
1625 // FXRangeErr = desired FABN > last mapped FABN in record
1626 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1628 static OSErr
SearchExtentRecord(
1631 const HFSPlusExtentRecord extentData
,
1632 UInt32 extentDataStartFABN
,
1633 UInt32
*foundExtentIndex
,
1634 UInt32
*endingFABNPlusOne
,
1635 Boolean
*noMoreExtents
)
1639 UInt32 numberOfExtents
;
1640 UInt32 numAllocationBlocks
;
1641 Boolean foundExtent
;
1643 *endingFABNPlusOne
= extentDataStartFABN
;
1644 *noMoreExtents
= false;
1645 foundExtent
= false;
1647 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1648 numberOfExtents
= kHFSPlusExtentDensity
;
1650 numberOfExtents
= kHFSExtentDensity
;
1652 for( extentIndex
= 0; extentIndex
< numberOfExtents
; ++extentIndex
)
1655 // Loop over the extent record and find the search FABN.
1657 numAllocationBlocks
= extentData
[extentIndex
].blockCount
;
1658 if ( numAllocationBlocks
== 0 )
1663 *endingFABNPlusOne
+= numAllocationBlocks
;
1665 if( searchFABN
< *endingFABNPlusOne
)
1667 // Found the extent.
1675 // Found the extent. Note the extent offset
1676 *foundExtentIndex
= extentIndex
;
1680 // Did not find the extent. Set foundExtentDataOffset accordingly
1681 if( extentIndex
> 0 )
1683 *foundExtentIndex
= extentIndex
- 1;
1687 *foundExtentIndex
= 0;
1690 // If we found an empty extent, then set noMoreExtents.
1691 if (extentIndex
< numberOfExtents
)
1692 *noMoreExtents
= true;
1694 // Finally, return an error to the caller
1701 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1702 // Routine: SearchExtentFile (was XFSearch)
1704 // Function: Searches extent file (including the FCB resident extent record)
1705 // for the extent mapping a given file position.
1707 // Input: vcb - VCB pointer
1708 // fcb - FCB pointer
1709 // filePosition - file position (byte address)
1711 // Output: foundExtentKey - extent key record (xkr)
1712 // If extent was found in the FCB's resident extent record,
1713 // then foundExtentKey->keyLength will be set to 0.
1714 // foundExtentData - extent data record(xdr)
1715 // foundExtentIndex - index to extent entry in xdr
1716 // result = 0, offset to extent mapping desired FABN
1717 // result = FXRangeErr, offset to last extent in record
1718 // (i.e., kNumExtentsPerRecord-1)
1719 // extentBTreeHint - BTree hint for extent record
1720 // kNoHint = Resident extent record
1721 // endingFABNPlusOne - ending FABN +1
1724 // noErr Found an extent that contains the given file position
1725 // FXRangeErr Given position is beyond the last allocated extent
1726 // (other) (some other internal I/O error)
1727 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1729 static OSErr
SearchExtentFile(
1732 SInt64 filePosition
,
1733 HFSPlusExtentKey
*foundExtentKey
,
1734 HFSPlusExtentRecord foundExtentData
,
1735 UInt32
*foundExtentIndex
,
1736 UInt32
*extentBTreeHint
,
1737 UInt32
*endingFABNPlusOne
)
1740 UInt32 filePositionBlock
;
1742 Boolean noMoreExtents
;
1745 temp64
= filePosition
/ (SInt64
)vcb
->blockSize
;
1746 filePositionBlock
= (UInt32
)temp64
;
1748 bcopy ( fcb
->fcbExtents
, foundExtentData
, sizeof(HFSPlusExtentRecord
));
1750 // Search the resident FCB first.
1751 err
= SearchExtentRecord( vcb
, filePositionBlock
, foundExtentData
, 0,
1752 foundExtentIndex
, endingFABNPlusOne
, &noMoreExtents
);
1754 if( err
== noErr
) {
1755 // Found the extent. Set results accordingly
1756 *extentBTreeHint
= kNoHint
; // no hint, because not in the BTree
1757 foundExtentKey
->keyLength
= 0; // 0 = the FCB itself
1762 // Didn't find extent in FCB. If FCB's extent record wasn't full, there's no point
1763 // in searching the extents file. Note that SearchExtentRecord left us pointing at
1764 // the last valid extent (or the first one, if none were valid). This means we need
1765 // to fill in the hint and key outputs, just like the "if" statement above.
1766 if ( noMoreExtents
) {
1767 *extentBTreeHint
= kNoHint
; // no hint, because not in the BTree
1768 foundExtentKey
->keyLength
= 0; // 0 = the FCB itself
1769 err
= fxRangeErr
; // There are no more extents, so must be beyond PEOF
1774 // Find the desired record, or the previous record if it is the same fork
1776 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1778 err
= FindExtentRecord(vcb
, FORK_IS_RSRC(fcb
) ? kResourceForkType
: kDataForkType
,
1779 FTOC(fcb
)->c_fileid
, filePositionBlock
, true, foundExtentKey
, foundExtentData
, extentBTreeHint
);
1780 hfs_systemfile_unlock(vcb
, lockflags
);
1782 if (err
== btNotFound
) {
1784 // If we get here, the desired position is beyond the extents in the FCB, and there are no extents
1785 // in the extents file. Return the FCB's extents and a range error.
1787 *extentBTreeHint
= kNoHint
;
1788 foundExtentKey
->keyLength
= 0;
1789 err
= GetFCBExtentRecord(fcb
, foundExtentData
);
1790 // Note: foundExtentIndex and endingFABNPlusOne have already been set as a result of the very
1791 // first SearchExtentRecord call in this function (when searching in the FCB's extents, and
1792 // we got a range error).
1798 // If we get here, there was either a BTree error, or we found an appropriate record.
1799 // If we found a record, then search it for the correct index into the extents.
1802 // Find appropriate index into extent record
1803 err
= SearchExtentRecord(vcb
, filePositionBlock
, foundExtentData
, foundExtentKey
->startBlock
,
1804 foundExtentIndex
, endingFABNPlusOne
, &noMoreExtents
);
1813 //============================================================================
1814 // Routine: UpdateExtentRecord
1816 // Function: Write new extent data to an existing extent record with a given key.
1817 // If all of the extents are empty, and the extent record is in the
1818 // extents file, then the record is deleted.
1820 // Input: vcb - the volume containing the extents
1821 // fcb - the file that owns the extents
1822 // extentFileKey - pointer to extent key record (xkr)
1823 // If the key length is 0, then the extents are actually part
1824 // of the catalog record, stored in the FCB.
1825 // extentData - pointer to extent data record (xdr)
1826 // extentBTreeHint - hint for given key, or kNoHint
1828 // Result: noErr = ok
1829 // (other) = error from BTree
1830 //============================================================================
1832 static OSErr
UpdateExtentRecord (
1835 const HFSPlusExtentKey
*extentFileKey
,
1836 const HFSPlusExtentRecord extentData
,
1837 UInt32 extentBTreeHint
)
1841 if (extentFileKey
->keyLength
== 0) { // keyLength == 0 means the FCB's extent record
1842 BlockMoveData(extentData
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
1843 FTOC(fcb
)->c_flag
|= C_MODIFIED
;
1846 BTreeIterator
* btIterator
;
1847 FSBufferDescriptor btRecord
;
1848 UInt16 btRecordSize
;
1853 // Need to find and change a record in Extents BTree
1855 btFCB
= GetFileControlBlock(vcb
->extentsRefNum
);
1857 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
1858 bzero(btIterator
, sizeof(*btIterator
));
1861 * The lock taken by callers of ExtendFileC/TruncateFileC is
1862 * speculative and only occurs when the file already has
1863 * overflow extents. So we need to make sure we have the lock
1864 * here. The extents btree lock can be nested (its recursive)
1865 * so we always take it here.
1867 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1869 if (vcb
->vcbSigWord
== kHFSSigWord
) {
1870 HFSExtentKey
* key
; // Actual extent key used on disk in HFS
1871 HFSExtentRecord foundData
; // The extent data actually found
1873 key
= (HFSExtentKey
*) &btIterator
->key
;
1874 key
->keyLength
= kHFSExtentKeyMaximumLength
;
1875 key
->forkType
= extentFileKey
->forkType
;
1876 key
->fileID
= extentFileKey
->fileID
;
1877 key
->startBlock
= extentFileKey
->startBlock
;
1879 btIterator
->hint
.index
= 0;
1880 btIterator
->hint
.nodeNum
= extentBTreeHint
;
1882 btRecord
.bufferAddress
= &foundData
;
1883 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
1884 btRecord
.itemCount
= 1;
1886 err
= BTSearchRecord(btFCB
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
1889 err
= HFSPlusToHFSExtents(extentData
, (HFSExtentDescriptor
*)&foundData
);
1892 err
= BTReplaceRecord(btFCB
, btIterator
, &btRecord
, btRecordSize
);
1893 (void) BTFlushPath(btFCB
);
1895 else { // HFS Plus volume
1896 HFSPlusExtentRecord foundData
; // The extent data actually found
1898 BlockMoveData(extentFileKey
, &btIterator
->key
, sizeof(HFSPlusExtentKey
));
1900 btIterator
->hint
.index
= 0;
1901 btIterator
->hint
.nodeNum
= extentBTreeHint
;
1903 btRecord
.bufferAddress
= &foundData
;
1904 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
1905 btRecord
.itemCount
= 1;
1907 err
= BTSearchRecord(btFCB
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
1910 BlockMoveData(extentData
, &foundData
, sizeof(HFSPlusExtentRecord
));
1911 err
= BTReplaceRecord(btFCB
, btIterator
, &btRecord
, btRecordSize
);
1913 (void) BTFlushPath(btFCB
);
1915 hfs_systemfile_unlock(vcb
, lockflags
);
1916 FREE(btIterator
, M_TEMP
);
1925 static OSErr
HFSPlusToHFSExtents(
1926 const HFSPlusExtentRecord oldExtents
,
1927 HFSExtentRecord newExtents
)
1933 // copy the first 3 extents
1934 newExtents
[0].startBlock
= oldExtents
[0].startBlock
;
1935 newExtents
[0].blockCount
= oldExtents
[0].blockCount
;
1936 newExtents
[1].startBlock
= oldExtents
[1].startBlock
;
1937 newExtents
[1].blockCount
= oldExtents
[1].blockCount
;
1938 newExtents
[2].startBlock
= oldExtents
[2].startBlock
;
1939 newExtents
[2].blockCount
= oldExtents
[2].blockCount
;
1942 if (oldExtents
[3].startBlock
|| oldExtents
[3].blockCount
) {
1943 DebugStr("\pExtentRecord with > 3 extents is invalid for HFS");
1954 static OSErr
GetFCBExtentRecord(
1956 HFSPlusExtentRecord extents
)
1959 BlockMoveData(fcb
->fcbExtents
, extents
, sizeof(HFSPlusExtentRecord
));
1965 //_________________________________________________________________________________
1967 // Routine: ExtentsAreIntegral
1969 // Purpose: Ensure that each extent can hold an integral number of nodes
1970 // Called by the NodesAreContiguous function
1971 //_________________________________________________________________________________
1973 static Boolean
ExtentsAreIntegral(
1974 const HFSPlusExtentRecord extentRecord
,
1976 UInt32
*blocksChecked
,
1977 Boolean
*checkedLastExtent
)
1983 *checkedLastExtent
= false;
1985 for(extentIndex
= 0; extentIndex
< kHFSPlusExtentDensity
; extentIndex
++)
1987 blocks
= extentRecord
[extentIndex
].blockCount
;
1991 *checkedLastExtent
= true;
1995 *blocksChecked
+= blocks
;
2005 //_________________________________________________________________________________
2007 // Routine: NodesAreContiguous
2009 // Purpose: Ensure that all b-tree nodes are contiguous on disk
2010 // Called by BTOpenPath during volume mount
2011 //_________________________________________________________________________________
2014 Boolean
NodesAreContiguous(
2021 UInt32 blocksChecked
;
2023 HFSPlusExtentKey key
;
2024 HFSPlusExtentRecord extents
;
2026 Boolean lastExtentReached
;
2030 if (vcb
->blockSize
>= nodeSize
)
2033 mask
= (nodeSize
/ vcb
->blockSize
) - 1;
2035 // check the local extents
2036 (void) GetFCBExtentRecord(fcb
, extents
);
2037 if ( !ExtentsAreIntegral(extents
, mask
, &blocksChecked
, &lastExtentReached
) )
2040 if ( lastExtentReached
||
2041 (SInt64
)((SInt64
)blocksChecked
* (SInt64
)vcb
->blockSize
) >= (SInt64
)fcb
->ff_size
)
2044 startBlock
= blocksChecked
;
2046 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
2048 // check the overflow extents (if any)
2049 while ( !lastExtentReached
)
2051 result
= FindExtentRecord(vcb
, kDataForkType
, fcb
->ff_cp
->c_fileid
, startBlock
, FALSE
, &key
, extents
, &hint
);
2054 if ( !ExtentsAreIntegral(extents
, mask
, &blocksChecked
, &lastExtentReached
) ) {
2055 hfs_systemfile_unlock(vcb
, lockflags
);
2058 startBlock
+= blocksChecked
;
2060 hfs_systemfile_unlock(vcb
, lockflags
);