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 SInt64 kTwoGigabytes
= 0x80000000LL
;
105 kResourceForkType
= 0xFF,
111 static OSErr
HFSPlusToHFSExtents(
112 const HFSPlusExtentRecord oldExtents
,
113 HFSExtentRecord newExtents
);
115 static OSErr
FindExtentRecord(
116 const ExtendedVCB
*vcb
,
120 Boolean allowPrevious
,
121 HFSPlusExtentKey
*foundKey
,
122 HFSPlusExtentRecord foundData
,
125 static OSErr
DeleteExtentRecord(
126 const ExtendedVCB
*vcb
,
131 static OSErr
CreateExtentRecord(
133 HFSPlusExtentKey
*key
,
134 HFSPlusExtentRecord extents
,
138 static OSErr
GetFCBExtentRecord(
140 HFSPlusExtentRecord extents
);
142 static OSErr
SearchExtentFile(
146 HFSPlusExtentKey
*foundExtentKey
,
147 HFSPlusExtentRecord foundExtentData
,
148 UInt32
*foundExtentDataIndex
,
149 UInt32
*extentBTreeHint
,
150 UInt32
*endingFABNPlusOne
);
152 static OSErr
SearchExtentRecord(
155 const HFSPlusExtentRecord extentData
,
156 UInt32 extentDataStartFABN
,
157 UInt32
*foundExtentDataOffset
,
158 UInt32
*endingFABNPlusOne
,
159 Boolean
*noMoreExtents
);
161 static OSErr
ReleaseExtents(
163 const HFSPlusExtentRecord extentRecord
,
164 UInt32
*numReleasedAllocationBlocks
,
165 Boolean
*releasedLastExtent
);
167 static OSErr
DeallocateFork(
169 HFSCatalogNodeID fileID
,
171 HFSPlusExtentRecord catalogExtents
,
172 Boolean
* recordDeleted
);
174 static OSErr
TruncateExtents(
179 Boolean
* recordDeleted
);
181 static OSErr
UpdateExtentRecord (
184 const HFSPlusExtentKey
*extentFileKey
,
185 const HFSPlusExtentRecord extentData
,
186 UInt32 extentBTreeHint
);
188 static Boolean
ExtentsAreIntegral(
189 const HFSPlusExtentRecord extentRecord
,
191 UInt32
*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
,
221 Boolean allowPrevious
,
222 HFSPlusExtentKey
*foundKey
,
223 HFSPlusExtentRecord foundData
,
227 BTreeIterator
*btIterator
;
228 FSBufferDescriptor btRecord
;
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
;
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
,
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 UInt32 allocBlockSize
; // Size of the volume's allocation block
477 HFSPlusExtentKey foundKey
;
478 HFSPlusExtentRecord foundData
;
481 UInt32 firstFABN
; // file allocation block of first block in found extent
482 UInt32 nextFABN
; // file allocation block of block after end of found extent
483 off_t dataEnd
; // (offset) end of range that is contiguous
484 UInt32 sectorsPerBlock
; // Number of sectors per allocation block
485 UInt32 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
+= startBlock
* 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 UInt32
*numReleasedAllocationBlocks
,
558 Boolean
*releasedLastExtent
)
561 UInt32 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 UInt32 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(
616 Boolean
* recordDeleted
)
619 UInt32 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 UInt32 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 SInt32
CompareExtentKeys( const HFSExtentKey
*searchKey
, const HFSExtentKey
*trialKey
)
729 SInt32 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 SInt32
CompareExtentKeysPlus( const HFSPlusExtentKey
*searchKey
, const HFSPlusExtentKey
*trialKey
)
793 SInt32 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
, UInt32 startBlock
, UInt32 blockCount
)
855 HFSPlusExtentKey foundKey
;
856 HFSPlusExtentRecord foundData
;
864 peof
= (SInt64
)(fcb
->ff_blocks
+ blockCount
) * (SInt64
)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 SInt64 bytesToAdd
, // number of bytes to allocate
926 UInt32 blockHint
, // desired starting allocation block
927 UInt32 flags
, // EFContig and/or EFAll
928 SInt64
*actualBytesAdded
) // number of bytes actually allocated
931 UInt32 volumeBlockSize
;
933 SInt64 bytesThisExtent
;
934 HFSPlusExtentKey foundKey
;
935 HFSPlusExtentRecord foundData
;
940 Boolean allOrNothing
;
945 UInt32 actualStartBlock
;
946 UInt32 actualNumBlocks
;
947 UInt32 numExtentsPerRecord
;
954 *actualBytesAdded
= 0;
955 volumeBlockSize
= vcb
->blockSize
;
956 allOrNothing
= ((flags
& kEFAllMask
) != 0);
957 forceContig
= ((flags
& kEFContigMask
) != 0);
958 prevblocks
= fcb
->ff_blocks
;
960 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
961 numExtentsPerRecord
= kHFSPlusExtentDensity
;
963 numExtentsPerRecord
= kHFSExtentDensity
;
966 // Make sure the request and new PEOF are less than 2GB if HFS.
968 if (vcb
->vcbSigWord
== kHFSSigWord
) {
969 if (bytesToAdd
>= kTwoGigabytes
)
971 if ((((SInt64
)fcb
->ff_blocks
* (SInt64
)volumeBlockSize
) + bytesToAdd
) >= kTwoGigabytes
)
975 // Determine how many blocks need to be allocated.
976 // Round up the number of desired bytes to add.
978 blocksToAdd
= howmany(bytesToAdd
, volumeBlockSize
);
979 bytesToAdd
= (SInt64
)((SInt64
)blocksToAdd
* (SInt64
)volumeBlockSize
);
982 * For deferred allocations just reserve the blocks.
984 if ((flags
& kEFDeferMask
)
985 && (vcb
->vcbSigWord
== kHFSPlusSigWord
)
986 && (bytesToAdd
< (SInt64
)HFS_MAX_DEFERED_ALLOC
)
987 && (blocksToAdd
< hfs_freeblks(VCBTOHFS(vcb
), 1))) {
988 HFS_MOUNT_LOCK(vcb
, TRUE
);
989 vcb
->loanedBlocks
+= blocksToAdd
;
990 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
992 fcb
->ff_unallocblocks
+= blocksToAdd
;
993 FTOC(fcb
)->c_blocks
+= blocksToAdd
;
994 fcb
->ff_blocks
+= blocksToAdd
;
996 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
997 *actualBytesAdded
= bytesToAdd
;
1001 * Give back any unallocated blocks before doing real allocations.
1003 if (fcb
->ff_unallocblocks
> 0) {
1004 u_int32_t loanedBlocks
;
1006 loanedBlocks
= fcb
->ff_unallocblocks
;
1007 blocksToAdd
+= loanedBlocks
;
1008 bytesToAdd
= (SInt64
)blocksToAdd
* (SInt64
)volumeBlockSize
;
1009 FTOC(fcb
)->c_blocks
-= loanedBlocks
;
1010 fcb
->ff_blocks
-= loanedBlocks
;
1011 fcb
->ff_unallocblocks
= 0;
1013 HFS_MOUNT_LOCK(vcb
, TRUE
);
1014 vcb
->loanedBlocks
-= loanedBlocks
;
1015 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
1019 // If the file's clump size is larger than the allocation block size,
1020 // then set the maximum number of bytes to the requested number of bytes
1021 // rounded up to a multiple of the clump size.
1023 if ((vcb
->vcbClpSiz
> (int32_t)volumeBlockSize
)
1024 && (bytesToAdd
< (SInt64
)HFS_MAX_DEFERED_ALLOC
)
1025 && (flags
& kEFNoClumpMask
) == 0) {
1026 maximumBytes
= (SInt64
)howmany(bytesToAdd
, vcb
->vcbClpSiz
);
1027 maximumBytes
*= vcb
->vcbClpSiz
;
1029 maximumBytes
= bytesToAdd
;
1033 // Compute new physical EOF, rounded up to a multiple of a block.
1035 if ( (vcb
->vcbSigWord
== kHFSSigWord
) && // Too big?
1036 ((((SInt64
)fcb
->ff_blocks
* (SInt64
)volumeBlockSize
) + bytesToAdd
) >= kTwoGigabytes
) ) {
1037 if (allOrNothing
) // Yes, must they have it all?
1038 goto Overflow
; // Yes, can't have it
1040 --blocksToAdd
; // No, give give 'em one block less
1041 bytesToAdd
-= volumeBlockSize
;
1046 // If allocation is all-or-nothing, make sure there are
1047 // enough free blocks on the volume (quick test).
1050 (blocksToAdd
> hfs_freeblks(VCBTOHFS(vcb
), flags
& kEFReserveMask
))) {
1056 // See if there are already enough blocks allocated to the file.
1058 peof
= ((SInt64
)fcb
->ff_blocks
* (SInt64
)volumeBlockSize
) + bytesToAdd
; // potential new PEOF
1059 err
= SearchExtentFile(vcb
, fcb
, peof
-1, &foundKey
, foundData
, &foundIndex
, &hint
, &nextBlock
);
1061 // Enough blocks are already allocated. Just update the FCB to reflect the new length.
1062 fcb
->ff_blocks
= peof
/ volumeBlockSize
;
1063 FTOC(fcb
)->c_blocks
+= (bytesToAdd
/ volumeBlockSize
);
1064 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1067 if (err
!= fxRangeErr
) // Any real error?
1068 goto ErrorExit
; // Yes, so exit immediately
1071 // Adjust the PEOF to the end of the last extent.
1073 peof
= (SInt64
)((SInt64
)nextBlock
* (SInt64
)volumeBlockSize
); // currently allocated PEOF
1074 bytesThisExtent
= (SInt64
)(nextBlock
- fcb
->ff_blocks
) * (SInt64
)volumeBlockSize
;
1075 if (bytesThisExtent
!= 0) {
1076 fcb
->ff_blocks
= nextBlock
;
1077 FTOC(fcb
)->c_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1078 FTOC(fcb
)->c_flag
|= C_MODIFIED
;
1079 bytesToAdd
-= bytesThisExtent
;
1083 // Allocate some more space.
1085 // First try a contiguous allocation (of the whole amount).
1086 // If that fails, get whatever we can.
1087 // If forceContig, then take whatever we got
1088 // else, keep getting bits and pieces (non-contig)
1091 useMetaZone
= flags
& kEFMetadataMask
;
1092 vcb
->vcbFreeExtCnt
= 0; /* For now, force rebuild of free extent list */
1095 startBlock
= blockHint
;
1097 startBlock
= foundData
[foundIndex
].startBlock
+ foundData
[foundIndex
].blockCount
;
1099 /* Force reserve checking if requested. */
1100 if (flags
& kEFReserveMask
) {
1103 actualNumBlocks
= 0;
1104 actualStartBlock
= 0;
1106 availbytes
= (SInt64
)hfs_freeblks(VCBTOHFS(vcb
), 1) *
1107 (SInt64
)volumeBlockSize
;
1108 if (availbytes
<= 0) {
1111 if (wantContig
&& (availbytes
< bytesToAdd
))
1114 err
= BlockAllocate(
1117 howmany(MIN(bytesToAdd
, availbytes
), volumeBlockSize
),
1118 howmany(MIN(maximumBytes
, availbytes
), volumeBlockSize
),
1126 err
= BlockAllocate(vcb
, startBlock
, howmany(bytesToAdd
, volumeBlockSize
),
1127 howmany(maximumBytes
, volumeBlockSize
), wantContig
, useMetaZone
,
1128 &actualStartBlock
, &actualNumBlocks
);
1130 if (err
== dskFulErr
) {
1132 break; // AllocContig failed because not enough contiguous space
1134 // Couldn't get one big chunk, so get whatever we can.
1139 if (actualNumBlocks
!= 0)
1141 if (useMetaZone
== 0) {
1142 /* Couldn't get anything so dip into metadat zone */
1149 if (actualNumBlocks
!= 0) {
1150 // this catalog entry *must* get forced to disk when
1151 // hfs_update() is called
1152 FTOC(fcb
)->c_flag
|= C_FORCEUPDATE
;
1155 // Add the new extent to the existing extent record, or create a new one.
1156 if ((actualStartBlock
== startBlock
) && (blockHint
== 0)) {
1157 // We grew the file's last extent, so just adjust the number of blocks.
1158 foundData
[foundIndex
].blockCount
+= actualNumBlocks
;
1159 err
= UpdateExtentRecord(vcb
, fcb
, &foundKey
, foundData
, hint
);
1160 if (err
!= noErr
) break;
1165 // Need to add a new extent. See if there is room in the current record.
1166 if (foundData
[foundIndex
].blockCount
!= 0) // Is current extent free to use?
1167 ++foundIndex
; // No, so use the next one.
1168 if (foundIndex
== numExtentsPerRecord
) {
1169 // This record is full. Need to create a new one.
1170 if (FTOC(fcb
)->c_fileid
== kHFSExtentsFileID
) {
1171 (void) BlockDeallocate(vcb
, actualStartBlock
, actualNumBlocks
);
1172 err
= dskFulErr
; // Oops. Can't extend extents file past first record.
1176 foundKey
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
1177 if (FORK_IS_RSRC(fcb
))
1178 foundKey
.forkType
= kResourceForkType
;
1180 foundKey
.forkType
= kDataForkType
;
1182 foundKey
.fileID
= FTOC(fcb
)->c_fileid
;
1183 foundKey
.startBlock
= nextBlock
;
1185 foundData
[0].startBlock
= actualStartBlock
;
1186 foundData
[0].blockCount
= actualNumBlocks
;
1188 // zero out remaining extents...
1189 for (i
= 1; i
< kHFSPlusExtentDensity
; ++i
)
1191 foundData
[i
].startBlock
= 0;
1192 foundData
[i
].blockCount
= 0;
1197 err
= CreateExtentRecord(vcb
, &foundKey
, foundData
, &hint
);
1198 if (err
== fxOvFlErr
) {
1199 // We couldn't create an extent record because extents B-tree
1200 // couldn't grow. Dellocate the extent just allocated and
1201 // return a disk full error.
1202 (void) BlockDeallocate(vcb
, actualStartBlock
, actualNumBlocks
);
1205 if (err
!= noErr
) break;
1207 needsFlush
= true; // We need to update the B-tree header
1210 // Add a new extent into this record and update.
1211 foundData
[foundIndex
].startBlock
= actualStartBlock
;
1212 foundData
[foundIndex
].blockCount
= actualNumBlocks
;
1213 err
= UpdateExtentRecord(vcb
, fcb
, &foundKey
, foundData
, hint
);
1214 if (err
!= noErr
) break;
1218 // Figure out how many bytes were actually allocated.
1219 // NOTE: BlockAllocate could have allocated more than we asked for.
1220 // Don't set the PEOF beyond what our client asked for.
1221 nextBlock
+= actualNumBlocks
;
1222 bytesThisExtent
= (SInt64
)((SInt64
)actualNumBlocks
* (SInt64
)volumeBlockSize
);
1223 if (bytesThisExtent
> bytesToAdd
) {
1227 bytesToAdd
-= bytesThisExtent
;
1228 maximumBytes
-= bytesThisExtent
;
1230 fcb
->ff_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1231 FTOC(fcb
)->c_blocks
+= (bytesThisExtent
/ volumeBlockSize
);
1232 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1234 // If contiguous allocation was requested, then we've already got one contiguous
1235 // chunk. If we didn't get all we wanted, then adjust the error to disk full.
1237 if (bytesToAdd
!= 0)
1239 break; // We've already got everything that's contiguous
1242 } while (err
== noErr
&& bytesToAdd
);
1246 if (VCBTOHFS(vcb
)->hfs_flags
& HFS_METADATA_ZONE
) {
1247 /* Keep the roving allocator out of the metadata zone. */
1248 if (vcb
->nextAllocation
>= VCBTOHFS(vcb
)->hfs_metazone_start
&&
1249 vcb
->nextAllocation
<= VCBTOHFS(vcb
)->hfs_metazone_end
) {
1250 HFS_MOUNT_LOCK(vcb
, TRUE
);
1251 vcb
->nextAllocation
= VCBTOHFS(vcb
)->hfs_metazone_end
+ 1;
1252 vcb
->vcbFlags
|= 0xFF00;
1253 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
1256 if (prevblocks
< fcb
->ff_blocks
) {
1257 *actualBytesAdded
= (SInt64
)(fcb
->ff_blocks
- prevblocks
) * (SInt64
)volumeBlockSize
;
1259 *actualBytesAdded
= 0;
1263 (void) FlushExtentFile(vcb
);
1268 err
= fileBoundsErr
;
1274 //_________________________________________________________________________________
1276 // Routine: TruncateFileC
1278 // Function: Truncates the disk space allocated to a file. The file space is
1279 // truncated to a specified new PEOF rounded up to the next allocation
1280 // block boundry. If the 'TFTrunExt' option is specified, the file is
1281 // truncated to the end of the extent containing the new PEOF.
1283 //_________________________________________________________________________________
1286 OSErr
TruncateFileC (
1287 ExtendedVCB
*vcb
, // volume that file resides on
1288 FCB
*fcb
, // FCB of file to truncate
1289 SInt64 peof
, // new physical size for file
1290 Boolean truncateToExtent
) // if true, truncate to end of extent containing newPEOF
1293 UInt32 nextBlock
; // next file allocation block to consider
1294 UInt32 startBlock
; // Physical (volume) allocation block number of start of a range
1295 UInt32 physNumBlocks
; // Number of allocation blocks in file (according to PEOF)
1297 HFSPlusExtentKey key
; // key for current extent record; key->keyLength == 0 if FCB's extent record
1298 UInt32 hint
; // BTree hint corresponding to key
1299 HFSPlusExtentRecord extentRecord
;
1301 UInt32 extentNextBlock
;
1302 UInt32 numExtentsPerRecord
;
1305 Boolean extentChanged
; // true if we actually changed an extent
1306 Boolean recordDeleted
; // true if an extent record got deleted
1308 recordDeleted
= false;
1310 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1311 numExtentsPerRecord
= kHFSPlusExtentDensity
;
1313 numExtentsPerRecord
= kHFSExtentDensity
;
1315 if (FORK_IS_RSRC(fcb
))
1316 forkType
= kResourceForkType
;
1318 forkType
= kDataForkType
;
1320 temp64
= fcb
->ff_blocks
;
1321 physNumBlocks
= (UInt32
)temp64
;
1324 // Round newPEOF up to a multiple of the allocation block size. If new size is
1325 // two gigabytes or more, then round down by one allocation block (??? really?
1326 // shouldn't that be an error?).
1328 nextBlock
= howmany(peof
, vcb
->blockSize
); // number of allocation blocks to remain in file
1329 peof
= (SInt64
)((SInt64
)nextBlock
* (SInt64
)vcb
->blockSize
); // number of bytes in those blocks
1330 if ((vcb
->vcbSigWord
== kHFSSigWord
) && (peof
>= kTwoGigabytes
)) {
1332 DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
1334 err
= fileBoundsErr
;
1339 // Update FCB's length
1342 * XXX Any errors could cause ff_blocks and c_blocks to get out of sync...
1344 numBlocks
= peof
/ vcb
->blockSize
;
1345 FTOC(fcb
)->c_blocks
-= (fcb
->ff_blocks
- numBlocks
);
1346 fcb
->ff_blocks
= numBlocks
;
1348 // this catalog entry is modified and *must* get forced
1349 // to disk when hfs_update() is called
1350 FTOC(fcb
)->c_flag
|= C_MODIFIED
| C_FORCEUPDATE
;
1353 // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
1359 // Deallocate all the extents for this fork
1360 err
= DeallocateFork(vcb
, FTOC(fcb
)->c_fileid
, forkType
, fcb
->fcbExtents
, &recordDeleted
);
1361 if (err
!= noErr
) goto ErrorExit
; // got some error, so return it
1363 // Update the catalog extent record (making sure it's zeroed out)
1365 for (i
=0; i
< kHFSPlusExtentDensity
; i
++) {
1366 fcb
->fcbExtents
[i
].startBlock
= 0;
1367 fcb
->fcbExtents
[i
].blockCount
= 0;
1374 // Find the extent containing byte (peof-1). This is the last extent we'll keep.
1375 // (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only
1376 // keep up through peof). The search will tell us how many allocation blocks exist
1377 // in the found extent plus all previous extents.
1379 err
= SearchExtentFile(vcb
, fcb
, peof
-1, &key
, extentRecord
, &extentIndex
, &hint
, &extentNextBlock
);
1380 if (err
!= noErr
) goto ErrorExit
;
1382 extentChanged
= false; // haven't changed the extent yet
1384 if (!truncateToExtent
) {
1386 // Shorten this extent. It may be the case that the entire extent gets
1389 numBlocks
= extentNextBlock
- nextBlock
; // How many blocks in this extent to free up
1390 if (numBlocks
!= 0) {
1391 // Compute first volume allocation block to free
1392 startBlock
= extentRecord
[extentIndex
].startBlock
+ extentRecord
[extentIndex
].blockCount
- numBlocks
;
1393 // Free the blocks in bitmap
1394 err
= BlockDeallocate(vcb
, startBlock
, numBlocks
);
1395 if (err
!= noErr
) goto ErrorExit
;
1396 // Adjust length of this extent
1397 extentRecord
[extentIndex
].blockCount
-= numBlocks
;
1398 // If extent is empty, set start block to 0
1399 if (extentRecord
[extentIndex
].blockCount
== 0)
1400 extentRecord
[extentIndex
].startBlock
= 0;
1401 // Remember that we changed the extent record
1402 extentChanged
= true;
1407 // Now move to the next extent in the record, and set up the file allocation block number
1409 nextBlock
= extentNextBlock
; // Next file allocation block to free
1410 ++extentIndex
; // Its index within the extent record
1413 // Release all following extents in this extent record. Update the record.
1415 while (extentIndex
< numExtentsPerRecord
&& extentRecord
[extentIndex
].blockCount
!= 0) {
1416 numBlocks
= extentRecord
[extentIndex
].blockCount
;
1417 // Deallocate this extent
1418 err
= BlockDeallocate(vcb
, extentRecord
[extentIndex
].startBlock
, numBlocks
);
1419 if (err
!= noErr
) goto ErrorExit
;
1420 // Update next file allocation block number
1421 nextBlock
+= numBlocks
;
1422 // Zero out start and length of this extent to delete it from record
1423 extentRecord
[extentIndex
].startBlock
= 0;
1424 extentRecord
[extentIndex
].blockCount
= 0;
1425 // Remember that we changed an extent
1426 extentChanged
= true;
1427 // Move to next extent in record
1432 // If any of the extents in the current record were changed, then update that
1433 // record (in the FCB, or extents file).
1435 if (extentChanged
) {
1436 err
= UpdateExtentRecord(vcb
, fcb
, &key
, extentRecord
, hint
);
1437 if (err
!= noErr
) goto ErrorExit
;
1441 // If there are any following allocation blocks, then we need
1442 // to seach for their extent records and delete those allocation
1445 if (nextBlock
< physNumBlocks
)
1446 err
= TruncateExtents(vcb
, forkType
, FTOC(fcb
)->c_fileid
, nextBlock
, &recordDeleted
);
1451 (void) FlushExtentFile(vcb
);
1462 OSErr
HeadTruncateFile (
1467 HFSPlusExtentRecord extents
;
1468 HFSPlusExtentRecord tailExtents
;
1469 HFSCatalogNodeID fileID
;
1479 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
1482 forkType
= FORK_IS_RSRC(fcb
) ? kResourceForkType
: kDataForkType
;
1483 fileID
= FTOC(fcb
)->c_fileid
;
1484 bzero(tailExtents
, sizeof(tailExtents
));
1490 * Process catalog resident extents
1492 for (i
= 0, j
= 0; i
< kHFSPlusExtentDensity
; ++i
) {
1493 blkcnt
= fcb
->fcbExtents
[i
].blockCount
;
1495 break; /* end of extents */
1497 if (blksfreed
< headblks
) {
1498 error
= BlockDeallocate(vcb
, fcb
->fcbExtents
[i
].startBlock
, blkcnt
);
1500 * Any errors after the first BlockDeallocate
1501 * must be ignored so we can put the file in
1506 goto ErrorExit
; /* uh oh */
1509 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1510 FTOC(fcb
)->c_desc
.cd_nameptr
? FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1514 blksfreed
+= blkcnt
;
1515 fcb
->fcbExtents
[i
].startBlock
= 0;
1516 fcb
->fcbExtents
[i
].blockCount
= 0;
1518 tailExtents
[j
].startBlock
= fcb
->fcbExtents
[i
].startBlock
;
1519 tailExtents
[j
].blockCount
= blkcnt
;
1528 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1531 * Process overflow extents
1536 error
= FindExtentRecord(vcb
, forkType
, fileID
, startblk
, false, NULL
, extents
, NULL
);
1539 * Any errors after the first BlockDeallocate
1540 * must be ignored so we can put the file in
1543 if (error
!= btNotFound
)
1544 printf("HeadTruncateFile: problems finding extents %s (%d)\n",
1545 FTOC(fcb
)->c_desc
.cd_nameptr
? FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1550 for(i
= 0, extblks
= 0; i
< kHFSPlusExtentDensity
; ++i
) {
1551 blkcnt
= extents
[i
].blockCount
;
1553 break; /* end of extents */
1555 if (blksfreed
< headblks
) {
1556 error
= BlockDeallocate(vcb
, extents
[i
].startBlock
, blkcnt
);
1558 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1559 FTOC(fcb
)->c_desc
.cd_nameptr
? FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1562 blksfreed
+= blkcnt
;
1564 tailExtents
[j
].startBlock
= extents
[i
].startBlock
;
1565 tailExtents
[j
].blockCount
= blkcnt
;
1571 error
= DeleteExtentRecord(vcb
, forkType
, fileID
, startblk
);
1573 printf("HeadTruncateFile: problems deallocating %s (%d)\n",
1574 FTOC(fcb
)->c_desc
.cd_nameptr
? FTOC(fcb
)->c_desc
.cd_nameptr
: "", error
);
1579 break; /* all done */
1581 startblk
+= extblks
;
1583 hfs_systemfile_unlock(vcb
, lockflags
);
1587 bcopy(tailExtents
, fcb
->fcbExtents
, sizeof(tailExtents
));
1588 blkcnt
= fcb
->ff_blocks
- headblks
;
1589 FTOC(fcb
)->c_blocks
-= blkcnt
;
1590 fcb
->ff_blocks
= blkcnt
;
1592 FTOC(fcb
)->c_flag
|= C_FORCEUPDATE
;
1593 FTOC(fcb
)->c_touch_chgtime
= TRUE
;
1595 (void) FlushExtentFile(vcb
);
1599 return MacToVFSError(error
);
1604 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1605 // Routine: SearchExtentRecord (was XRSearch)
1607 // Function: Searches extent record for the extent mapping a given file
1608 // allocation block number (FABN).
1610 // Input: searchFABN - desired FABN
1611 // extentData - pointer to extent data record (xdr)
1612 // extentDataStartFABN - beginning FABN for extent record
1614 // Output: foundExtentDataOffset - offset to extent entry within xdr
1615 // result = noErr, offset to extent mapping desired FABN
1616 // result = FXRangeErr, offset to last extent in record
1617 // endingFABNPlusOne - ending FABN +1
1618 // noMoreExtents - True if the extent was not found, and the
1619 // extent record was not full (so don't bother
1620 // looking in subsequent records); false otherwise.
1622 // Result: noErr = ok
1623 // FXRangeErr = desired FABN > last mapped FABN in record
1624 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1626 static OSErr
SearchExtentRecord(
1629 const HFSPlusExtentRecord extentData
,
1630 UInt32 extentDataStartFABN
,
1631 UInt32
*foundExtentIndex
,
1632 UInt32
*endingFABNPlusOne
,
1633 Boolean
*noMoreExtents
)
1637 UInt32 numberOfExtents
;
1638 UInt32 numAllocationBlocks
;
1639 Boolean foundExtent
;
1641 *endingFABNPlusOne
= extentDataStartFABN
;
1642 *noMoreExtents
= false;
1643 foundExtent
= false;
1645 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1646 numberOfExtents
= kHFSPlusExtentDensity
;
1648 numberOfExtents
= kHFSExtentDensity
;
1650 for( extentIndex
= 0; extentIndex
< numberOfExtents
; ++extentIndex
)
1653 // Loop over the extent record and find the search FABN.
1655 numAllocationBlocks
= extentData
[extentIndex
].blockCount
;
1656 if ( numAllocationBlocks
== 0 )
1661 *endingFABNPlusOne
+= numAllocationBlocks
;
1663 if( searchFABN
< *endingFABNPlusOne
)
1665 // Found the extent.
1673 // Found the extent. Note the extent offset
1674 *foundExtentIndex
= extentIndex
;
1678 // Did not find the extent. Set foundExtentDataOffset accordingly
1679 if( extentIndex
> 0 )
1681 *foundExtentIndex
= extentIndex
- 1;
1685 *foundExtentIndex
= 0;
1688 // If we found an empty extent, then set noMoreExtents.
1689 if (extentIndex
< numberOfExtents
)
1690 *noMoreExtents
= true;
1692 // Finally, return an error to the caller
1699 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1700 // Routine: SearchExtentFile (was XFSearch)
1702 // Function: Searches extent file (including the FCB resident extent record)
1703 // for the extent mapping a given file position.
1705 // Input: vcb - VCB pointer
1706 // fcb - FCB pointer
1707 // filePosition - file position (byte address)
1709 // Output: foundExtentKey - extent key record (xkr)
1710 // If extent was found in the FCB's resident extent record,
1711 // then foundExtentKey->keyLength will be set to 0.
1712 // foundExtentData - extent data record(xdr)
1713 // foundExtentIndex - index to extent entry in xdr
1714 // result = 0, offset to extent mapping desired FABN
1715 // result = FXRangeErr, offset to last extent in record
1716 // (i.e., kNumExtentsPerRecord-1)
1717 // extentBTreeHint - BTree hint for extent record
1718 // kNoHint = Resident extent record
1719 // endingFABNPlusOne - ending FABN +1
1722 // noErr Found an extent that contains the given file position
1723 // FXRangeErr Given position is beyond the last allocated extent
1724 // (other) (some other internal I/O error)
1725 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
1727 static OSErr
SearchExtentFile(
1730 SInt64 filePosition
,
1731 HFSPlusExtentKey
*foundExtentKey
,
1732 HFSPlusExtentRecord foundExtentData
,
1733 UInt32
*foundExtentIndex
,
1734 UInt32
*extentBTreeHint
,
1735 UInt32
*endingFABNPlusOne
)
1738 UInt32 filePositionBlock
;
1740 Boolean noMoreExtents
;
1743 temp64
= filePosition
/ (SInt64
)vcb
->blockSize
;
1744 filePositionBlock
= (UInt32
)temp64
;
1746 bcopy ( fcb
->fcbExtents
, foundExtentData
, sizeof(HFSPlusExtentRecord
));
1748 // Search the resident FCB first.
1749 err
= SearchExtentRecord( vcb
, filePositionBlock
, foundExtentData
, 0,
1750 foundExtentIndex
, endingFABNPlusOne
, &noMoreExtents
);
1752 if( err
== noErr
) {
1753 // Found the extent. Set results accordingly
1754 *extentBTreeHint
= kNoHint
; // no hint, because not in the BTree
1755 foundExtentKey
->keyLength
= 0; // 0 = the FCB itself
1760 // Didn't find extent in FCB. If FCB's extent record wasn't full, there's no point
1761 // in searching the extents file. Note that SearchExtentRecord left us pointing at
1762 // the last valid extent (or the first one, if none were valid). This means we need
1763 // to fill in the hint and key outputs, just like the "if" statement above.
1764 if ( noMoreExtents
) {
1765 *extentBTreeHint
= kNoHint
; // no hint, because not in the BTree
1766 foundExtentKey
->keyLength
= 0; // 0 = the FCB itself
1767 err
= fxRangeErr
; // There are no more extents, so must be beyond PEOF
1772 // Find the desired record, or the previous record if it is the same fork
1774 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1776 err
= FindExtentRecord(vcb
, FORK_IS_RSRC(fcb
) ? kResourceForkType
: kDataForkType
,
1777 FTOC(fcb
)->c_fileid
, filePositionBlock
, true, foundExtentKey
, foundExtentData
, extentBTreeHint
);
1778 hfs_systemfile_unlock(vcb
, lockflags
);
1780 if (err
== btNotFound
) {
1782 // If we get here, the desired position is beyond the extents in the FCB, and there are no extents
1783 // in the extents file. Return the FCB's extents and a range error.
1785 *extentBTreeHint
= kNoHint
;
1786 foundExtentKey
->keyLength
= 0;
1787 err
= GetFCBExtentRecord(fcb
, foundExtentData
);
1788 // Note: foundExtentIndex and endingFABNPlusOne have already been set as a result of the very
1789 // first SearchExtentRecord call in this function (when searching in the FCB's extents, and
1790 // we got a range error).
1796 // If we get here, there was either a BTree error, or we found an appropriate record.
1797 // If we found a record, then search it for the correct index into the extents.
1800 // Find appropriate index into extent record
1801 err
= SearchExtentRecord(vcb
, filePositionBlock
, foundExtentData
, foundExtentKey
->startBlock
,
1802 foundExtentIndex
, endingFABNPlusOne
, &noMoreExtents
);
1811 //============================================================================
1812 // Routine: UpdateExtentRecord
1814 // Function: Write new extent data to an existing extent record with a given key.
1815 // If all of the extents are empty, and the extent record is in the
1816 // extents file, then the record is deleted.
1818 // Input: vcb - the volume containing the extents
1819 // fcb - the file that owns the extents
1820 // extentFileKey - pointer to extent key record (xkr)
1821 // If the key length is 0, then the extents are actually part
1822 // of the catalog record, stored in the FCB.
1823 // extentData - pointer to extent data record (xdr)
1824 // extentBTreeHint - hint for given key, or kNoHint
1826 // Result: noErr = ok
1827 // (other) = error from BTree
1828 //============================================================================
1830 static OSErr
UpdateExtentRecord (
1833 const HFSPlusExtentKey
*extentFileKey
,
1834 const HFSPlusExtentRecord extentData
,
1835 UInt32 extentBTreeHint
)
1839 if (extentFileKey
->keyLength
== 0) { // keyLength == 0 means the FCB's extent record
1840 BlockMoveData(extentData
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
1841 FTOC(fcb
)->c_flag
|= C_MODIFIED
;
1844 BTreeIterator
* btIterator
;
1845 FSBufferDescriptor btRecord
;
1846 UInt16 btRecordSize
;
1851 // Need to find and change a record in Extents BTree
1853 btFCB
= GetFileControlBlock(vcb
->extentsRefNum
);
1855 MALLOC(btIterator
, BTreeIterator
*, sizeof(*btIterator
), M_TEMP
, M_WAITOK
);
1856 bzero(btIterator
, sizeof(*btIterator
));
1859 * The lock taken by callers of ExtendFileC/TruncateFileC is
1860 * speculative and only occurs when the file already has
1861 * overflow extents. So we need to make sure we have the lock
1862 * here. The extents btree lock can be nested (its recursive)
1863 * so we always take it here.
1865 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
1867 if (vcb
->vcbSigWord
== kHFSSigWord
) {
1868 HFSExtentKey
* key
; // Actual extent key used on disk in HFS
1869 HFSExtentRecord foundData
; // The extent data actually found
1871 key
= (HFSExtentKey
*) &btIterator
->key
;
1872 key
->keyLength
= kHFSExtentKeyMaximumLength
;
1873 key
->forkType
= extentFileKey
->forkType
;
1874 key
->fileID
= extentFileKey
->fileID
;
1875 key
->startBlock
= extentFileKey
->startBlock
;
1877 btIterator
->hint
.index
= 0;
1878 btIterator
->hint
.nodeNum
= extentBTreeHint
;
1880 btRecord
.bufferAddress
= &foundData
;
1881 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
1882 btRecord
.itemCount
= 1;
1884 err
= BTSearchRecord(btFCB
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
1887 err
= HFSPlusToHFSExtents(extentData
, (HFSExtentDescriptor
*)&foundData
);
1890 err
= BTReplaceRecord(btFCB
, btIterator
, &btRecord
, btRecordSize
);
1891 (void) BTFlushPath(btFCB
);
1893 else { // HFS Plus volume
1894 HFSPlusExtentRecord foundData
; // The extent data actually found
1896 BlockMoveData(extentFileKey
, &btIterator
->key
, sizeof(HFSPlusExtentKey
));
1898 btIterator
->hint
.index
= 0;
1899 btIterator
->hint
.nodeNum
= extentBTreeHint
;
1901 btRecord
.bufferAddress
= &foundData
;
1902 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
1903 btRecord
.itemCount
= 1;
1905 err
= BTSearchRecord(btFCB
, btIterator
, &btRecord
, &btRecordSize
, btIterator
);
1908 BlockMoveData(extentData
, &foundData
, sizeof(HFSPlusExtentRecord
));
1909 err
= BTReplaceRecord(btFCB
, btIterator
, &btRecord
, btRecordSize
);
1911 (void) BTFlushPath(btFCB
);
1913 hfs_systemfile_unlock(vcb
, lockflags
);
1914 FREE(btIterator
, M_TEMP
);
1923 static OSErr
HFSPlusToHFSExtents(
1924 const HFSPlusExtentRecord oldExtents
,
1925 HFSExtentRecord newExtents
)
1931 // copy the first 3 extents
1932 newExtents
[0].startBlock
= oldExtents
[0].startBlock
;
1933 newExtents
[0].blockCount
= oldExtents
[0].blockCount
;
1934 newExtents
[1].startBlock
= oldExtents
[1].startBlock
;
1935 newExtents
[1].blockCount
= oldExtents
[1].blockCount
;
1936 newExtents
[2].startBlock
= oldExtents
[2].startBlock
;
1937 newExtents
[2].blockCount
= oldExtents
[2].blockCount
;
1940 if (oldExtents
[3].startBlock
|| oldExtents
[3].blockCount
) {
1941 DebugStr("\pExtentRecord with > 3 extents is invalid for HFS");
1952 static OSErr
GetFCBExtentRecord(
1954 HFSPlusExtentRecord extents
)
1957 BlockMoveData(fcb
->fcbExtents
, extents
, sizeof(HFSPlusExtentRecord
));
1963 //_________________________________________________________________________________
1965 // Routine: ExtentsAreIntegral
1967 // Purpose: Ensure that each extent can hold an integral number of nodes
1968 // Called by the NodesAreContiguous function
1969 //_________________________________________________________________________________
1971 static Boolean
ExtentsAreIntegral(
1972 const HFSPlusExtentRecord extentRecord
,
1974 UInt32
*blocksChecked
,
1975 Boolean
*checkedLastExtent
)
1981 *checkedLastExtent
= false;
1983 for(extentIndex
= 0; extentIndex
< kHFSPlusExtentDensity
; extentIndex
++)
1985 blocks
= extentRecord
[extentIndex
].blockCount
;
1989 *checkedLastExtent
= true;
1993 *blocksChecked
+= blocks
;
2003 //_________________________________________________________________________________
2005 // Routine: NodesAreContiguous
2007 // Purpose: Ensure that all b-tree nodes are contiguous on disk
2008 // Called by BTOpenPath during volume mount
2009 //_________________________________________________________________________________
2012 Boolean
NodesAreContiguous(
2019 UInt32 blocksChecked
;
2021 HFSPlusExtentKey key
;
2022 HFSPlusExtentRecord extents
;
2024 Boolean lastExtentReached
;
2028 if (vcb
->blockSize
>= nodeSize
)
2031 mask
= (nodeSize
/ vcb
->blockSize
) - 1;
2033 // check the local extents
2034 (void) GetFCBExtentRecord(fcb
, extents
);
2035 if ( !ExtentsAreIntegral(extents
, mask
, &blocksChecked
, &lastExtentReached
) )
2038 if ( lastExtentReached
||
2039 (SInt64
)((SInt64
)blocksChecked
* (SInt64
)vcb
->blockSize
) >= (SInt64
)fcb
->ff_size
)
2042 startBlock
= blocksChecked
;
2044 lockflags
= hfs_systemfile_lock(vcb
, SFL_EXTENTS
, HFS_EXCLUSIVE_LOCK
);
2046 // check the overflow extents (if any)
2047 while ( !lastExtentReached
)
2049 result
= FindExtentRecord(vcb
, kDataForkType
, fcb
->ff_cp
->c_fileid
, startBlock
, FALSE
, &key
, extents
, &hint
);
2052 if ( !ExtentsAreIntegral(extents
, mask
, &blocksChecked
, &lastExtentReached
) ) {
2053 hfs_systemfile_unlock(vcb
, lockflags
);
2056 startBlock
+= blocksChecked
;
2058 hfs_systemfile_unlock(vcb
, lockflags
);