|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: File: FileExtentMapping.c
24:
25: Contains: xxx put contents here xxx
26:
27: Version: HFS Plus 1.0
28:
29: Written by: Dave Heller, Mark Day
30:
31: Copyright: � 1996-1999 by Apple Computer, Inc., all rights reserved.
32:
33: File Ownership:
34:
35: DRI: Mark Day
36:
37: Other Contact: xxx put other contact here xxx
38:
39: Technology: xxx put technology here xxx
40:
41: Writers:
42:
43: (DSH) Deric Horn
44: (msd) Mark Day
45: (djb) Don Brady
46:
47: Change History (most recent first):
48: <MacOSX> 9/9/99 djb Fix fcbModifiedMask flag testing logic.
49: <MacOSX> 8/25/98 djb Flush extents b-tree header if dirty (2371088).
50: <MacOSX> 6/30/98 djb Add functions NodesAreContiguous and ExtentsAreIntegral (for radar #2249539).
51: <MacOSX> 6/23/98 djb Changed DeallocFile to DeleteFile which now deletes the catalog record.
52: Fixed UpdateExtentRecord to pass correct fcb to Btree routines. Fixed
53: hfs+ bug in CreateExtentRecord (double dereference).
54: <MacOSX> 5/20/98 djb In ExtendFileC don't lie about the peof! (radar #2230094).
55: <MacOSX> 4/17/98 djb Add VCB locking.
56: <MacOSX> 4/2/98 djb Switch over to real BTree interface (no more BTreeWrapper.c).
57: <MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file.
58:
59: <CS24> 1/23/98 msd Bug 2208024: AllocContig is actually allocating one extent even
60: though there is not enough contiguous space.
61: <CS23> 12/2/97 DSH GetFCBExtentRecord no longer static so DFA can use it.
62: <CS22> 10/20/97 msd When allocating more space for a file, do the clump size
63: calculations in ExtendFileC, not BlockAllocate. Undo change from
64: <CS18>.
65: <CS21> 10/17/97 msd Conditionalize DebugStrs.
66: <CS20> 10/16/97 msd Simplify the code path for MapFileBlockC (logical to physical
67: block mapping) in the typical case where the file isn't
68: fragmented so badly that it has extents in the extents B-tree.
69: Simplified some of the calculations for all cases.
70: <CS19> 10/13/97 DSH FindExtentRecord & DeleteExtentRecord are also being used by DFA
71: no longer static.
72: <CS18> 10/6/97 msd When extending a file, set the physical EOF to include any extra
73: space allocated due to a file's clump size.
74: <CS17> 9/19/97 msd Remove the MapLogicalToPhysical SPI. It was never used and is
75: not being tested anyway.
76: <CS16> 9/5/97 msd In CompareExtentKeys and CompareExtentKeysPlus, use the symbolic
77: constants for key length. Don't DebugStr unless DEBUG_BUILD is
78: set.
79: <CS15> 7/24/97 djb Add instrumentation to MapFileBlockC
80: <CS14> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
81: collision
82: <CS13> 7/15/97 DSH AdjEOF() mark the FCB as modified. (1664389)
83: <CS12> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
84: <CS11> 7/3/97 msd Bug #1663518. Remove DebugStr when setting the FCB extent record
85: for a volume control file.
86: <CS10> 6/27/97 msd Moved enum kFirstFileRefnum to FilesInternal.
87: <CS9> 6/24/97 djb Include "CatalogPrivate.h"
88: <CS8> 6/16/97 msd Finish implementation of CreateLargeFile SPI.
89: <CS7> 6/12/97 msd Add stub for CreateLargeFile SPI.
90: <CS6> 6/5/97 msd Add MapLogicalToPhysical.
91: <CS5> 6/2/97 msd In TruncateFileC, don't update the extent record unless it was
92: actually changed (prevents extra updates when truncating to the
93: end of the extent, and it is the last extent of the file.) Added
94: an AdjustEOF routine called by the assembly AdjEOF routine. It
95: copies the EOF, physical length, and extent information from one
96: FCB to all other FCBs for that fork.
97: <CS4> 5/20/97 DSH Removed const declaration in MapFileBlocC, const is benign when
98: passing by value, and SC requires it to match prototype.
99: <CS3> 5/15/97 msd Change enum kResourceForkType from -1 to 0xFF since it is now
100: unsigned. Change all forkType parameters to UInt8.
101: <CS2> 5/7/97 msd When checking for an unused extent descriptor, check the length,
102: not the starting block.
103: <CS1> 4/24/97 djb first checked in
104: <HFS25> 4/11/97 DSH use extended VCB fields catalogRefNum, and extentsRefNum.
105: <HFS24> 4/4/97 djb Get in sync with volume format changes.
106: <HFS23> 3/17/97 DSH Casting to compile with SC.
107: <HFS22> 2/26/97 msd Add instrumentation in ExtendFileC and TruncateFileC. In
108: CompareExtentKeys and CompareExtentKeysPlus, make sure the key
109: lengths are correct.
110: <HFS21> 2/5/97 msd The comparison with fsBTStartOfIterationErr didn't work because
111: the enum is an unsigned long; it is now casted to an OSErr
112: before comparing.
113: <HFS20> 1/31/97 msd In FindExtentRecord, turn an fsBTStartOfIterationErr error into
114: btNotFound.
115: <HFS19> 1/28/97 msd Fixed bug in MapFileBlockC where it returned the wrong number of
116: bytes available at the given block number. This could
117: potentially cause programs to read or write over other files.
118: <HFS18> 1/16/97 djb Extent key compare procs now return SInt32. Fixed
119: UpdateExtentRecord - it was passing a pointer to an ExtentKey
120: pointer.
121: <HFS17> 1/10/97 msd Change TruncateFileC to call DellocateFork when the new PEOF is
122: 0. Fixes a fxRangeErr returned when no extents existed.
123: <HFS16> 1/6/97 msd Previous change prevents extent records from being removed if
124: the files new PEOF is in the local (FCB/catalog) extents.
125: <HFS15> 1/3/97 djb Temp fix in TruncateFileC to prevent unwanted calls to
126: TruncateExtents.
127: <HFS14> 12/23/96 msd Previous change to SearchExtentFile didn't set up the outputs
128: for hint and key when the FCB extent record wasn't full.
129: <HFS13> 12/20/96 msd In SearchExtentFile, don't bother searching the extents file if
130: the FCB's extent record wasn't full, or if the FCB was for the
131: extents file itself. Modified SearchExtentRecord to return a
132: Boolean to indicate that the record was not full.
133: <HFS12> 12/19/96 DSH Changed refs from VCB to ExtendedVCB
134: <HFS11> 12/19/96 djb Updated for new B-tree Manager interface.
135: <HFS10> 12/12/96 djb Really use new SPI for GetCatalogNode.
136: <HFS9> 12/12/96 djb Use new Catalog SPI for GetCatalogNode. Added Mark's changes to
137: MapFileBlockC.
138: <HFS8> 12/11/96 msd TruncateFileC must always release extents, even if PEOF hasn't
139: changed (since allocation may have been rounded up due to clump
140: size).
141: <HFS7> 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
142: <HFS6> 12/4/96 DSH Precompiled headers
143: <HFS5> 11/26/96 msd Add an exported routine to grow the parallel FCB table to
144: accomodate the HFS+ ExtentRecord.
145: <HFS4> 11/26/96 msd Convert internal routines to use ExtentKey and ExtentRecord
146: (instead of the raw HFS structures).
147: <HFS3> 11/21/96 msd Added CompareExtentKeysPlus().
148: <HFS2> 11/20/96 msd Finish porting FXM to C.
149: <HFS1> 11/6/96 DKH first checked in
150:
151: */
152:
153:
154: #include "../../hfs.h"
155: #include "../../hfs_format.h"
156:
157: #include "../headers/FileMgrInternal.h"
158: #include "../headers/BTreesInternal.h"
159: #include "../headers/CatalogPrivate.h" // calling a private catalog routine (LocateCatalogNode)
160:
161: #include "../headers/HFSInstrumentation.h"
162:
163:
164: /*
165: ============================================================
166: Public (Exported) Routines:
167: ============================================================
168: DeAllocFile Deallocate all disk space allocated to a specified file.
169: Both forks are deallocated.
170:
171: ExtendFileC Allocate more space to a given file.
172:
173: CompareExtentKeys
174: Compare two extents file keys (a search key and a trial
175: key). Used by the BTree manager when searching for,
176: adding, or deleting keys in the extents file of an HFS
177: volume.
178:
179: CompareExtentKeysPlus
180: Compare two extents file keys (a search key and a trial
181: key). Used by the BTree manager when searching for,
182: adding, or deleting keys in the extents file of an HFS+
183: volume.
184:
185: MapFileBlockC Convert (map) an offset within a given file into a
186: physical disk address.
187:
188: TruncateFileC Truncates the disk space allocated to a file. The file
189: space is truncated to a specified new physical EOF, rounded
190: up to the next allocation block boundry. There is an option
191: to truncate to the end of the extent containing the new EOF.
192:
193: FlushExtentFile
194: Flush the extents file for a given volume.
195:
196: GrowParallelFCBs
197: Make sure the parallel FCB entries are big enough to support
198: the HFS+ ExtentRecord. If not, the array is grown and the
199: pre-existing data copied over.
200:
201: AdjustEOF
202: Copy EOF, physical length, and extent records from one FCB
203: to all other FCBs for that fork. This is used when a file is
204: grown or shrunk as the result of a Write, SetEOF, or Allocate.
205:
206: MapLogicalToPhysical
207: Map some position in a file to a volume block number. Also
208: returns the number of contiguous bytes that are mapped there.
209: This is a queued HFSDispatch call that does the equivalent of
210: MapFileBlockC, using a parameter block.
211:
212: ============================================================
213: Internal Routines:
214: ============================================================
215: FindExtentRecord
216: Search the extents BTree for a particular extent record.
217: SearchExtentFile
218: Search the FCB and extents file for an extent record that
219: contains a given file position (in bytes).
220: SearchExtentRecord
221: Search a given extent record to see if it contains a given
222: file position (in bytes). Used by SearchExtentFile.
223: ReleaseExtents
224: Deallocate all allocation blocks in all extents of an extent
225: data record.
226: TruncateExtents
227: Deallocate blocks and delete extent records for all allocation
228: blocks beyond a certain point in a file. The starting point
229: must be the first file allocation block for some extent record
230: for the file.
231: DeallocateFork
232: Deallocate all allocation blocks belonging to a given fork.
233: UpdateExtentRecord
234: If the extent record came from the extents file, write out
235: the updated record; otherwise, copy the updated record into
236: the FCB resident extent record. If the record has no extents,
237: and was in the extents file, then delete the record instead.
238: */
239:
240: enum
241: {
242: kTwoGigabytes = (UInt32) 0x80000000,
243:
244: kDataForkType = 0,
245: kResourceForkType = 0xFF,
246:
247: kPreviousRecord = -1,
248:
249: kSectorSize = 512 // Size of a physical sector
250: };
251:
252: void HFSToHFSPlusExtents(
253: const HFSExtentRecord oldExtents,
254: HFSPlusExtentRecord newExtents);
255:
256: OSErr HFSPlusToHFSExtents(
257: const HFSPlusExtentRecord oldExtents,
258: HFSExtentRecord newExtents);
259:
260: OSErr FindExtentRecord(
261: const ExtendedVCB *vcb,
262: UInt8 forkType,
263: UInt32 fileID,
264: UInt32 startBlock,
265: Boolean allowPrevious,
266: HFSPlusExtentKey *foundKey,
267: HFSPlusExtentRecord foundData,
268: UInt32 *foundHint);
269:
270: OSErr DeleteExtentRecord(
271: const ExtendedVCB *vcb,
272: UInt8 forkType,
273: UInt32 fileID,
274: UInt32 startBlock);
275:
276: static OSErr CreateExtentRecord(
277: const ExtendedVCB *vcb,
278: HFSPlusExtentKey *key,
279: HFSPlusExtentRecord extents,
280: UInt32 *hint);
281:
282:
283: OSErr GetFCBExtentRecord(
284: const FCB *fcb,
285: HFSPlusExtentRecord extents);
286:
287: static OSErr SearchExtentFile(
288: const ExtendedVCB *vcb,
289: const FCB *fcb,
290: SInt64 filePosition,
291: HFSPlusExtentKey *foundExtentKey,
292: HFSPlusExtentRecord foundExtentData,
293: UInt32 *foundExtentDataIndex,
294: UInt32 *extentBTreeHint,
295: UInt32 *endingFABNPlusOne );
296:
297: static OSErr SearchExtentRecord(
298: const ExtendedVCB *vcb,
299: UInt32 searchFABN,
300: const HFSPlusExtentRecord extentData,
301: UInt32 extentDataStartFABN,
302: UInt32 *foundExtentDataOffset,
303: UInt32 *endingFABNPlusOne,
304: Boolean *noMoreExtents);
305:
306: static OSErr ReleaseExtents(
307: ExtendedVCB *vcb,
308: const HFSPlusExtentRecord extentRecord,
309: UInt32 *numReleasedAllocationBlocks,
310: Boolean *releasedLastExtent);
311:
312: static OSErr DeallocateFork(
313: ExtendedVCB *vcb,
314: HFSCatalogNodeID fileID,
315: UInt8 forkType,
316: HFSPlusExtentRecord catalogExtents,
317: Boolean * recordDeleted);
318:
319: static OSErr TruncateExtents(
320: ExtendedVCB *vcb,
321: UInt8 forkType,
322: UInt32 fileID,
323: UInt32 startBlock,
324: Boolean * recordDeleted);
325:
326: static OSErr UpdateExtentRecord (
327: const ExtendedVCB *vcb,
328: FCB *fcb,
329: const HFSPlusExtentKey *extentFileKey,
330: const HFSPlusExtentRecord extentData,
331: UInt32 extentBTreeHint);
332:
333: static OSErr MapFileBlockFromFCB(
334: const ExtendedVCB *vcb,
335: const FCB *fcb,
336: SInt64 offset, // Desired offset in bytes from start of file
337: UInt32 *firstFABN, // FABN of first block of found extent
338: UInt32 *firstBlock, // Corresponding allocation block number
339: UInt32 *nextFABN); // FABN of block after end of extent
340:
341: static Boolean ExtentsAreIntegral(
342: const HFSPlusExtentRecord extentRecord,
343: UInt32 mask,
344: UInt32 *blocksChecked,
345: Boolean *checkedLastExtent);
346:
347: //_________________________________________________________________________________
348: //
349: // Routine: FindExtentRecord
350: //
351: // Purpose: Search the extents BTree for an extent record matching the given
352: // FileID, fork, and starting file allocation block number.
353: //
354: // Inputs:
355: // vcb Volume to search
356: // forkType 0 = data fork, -1 = resource fork
357: // fileID File's FileID (CatalogNodeID)
358: // startBlock Starting file allocation block number
359: // allowPrevious If the desired record isn't found and this flag is set,
360: // then see if the previous record belongs to the same fork.
361: // If so, then return it.
362: //
363: // Outputs:
364: // foundKey The key data for the record actually found
365: // foundData The extent record actually found (NOTE: on an HFS volume, the
366: // fourth entry will be zeroes.
367: // foundHint The BTree hint to find the node again
368: //_________________________________________________________________________________
369: OSErr FindExtentRecord(
370: const ExtendedVCB *vcb,
371: UInt8 forkType,
372: UInt32 fileID,
373: UInt32 startBlock,
374: Boolean allowPrevious,
375: HFSPlusExtentKey *foundKey,
376: HFSPlusExtentRecord foundData,
377: UInt32 *foundHint)
378: {
379: FCB * fcb;
380: BTreeIterator btIterator;
381: FSBufferDescriptor btRecord;
382: OSErr err;
383: UInt16 btRecordSize;
384:
385: err = noErr;
386: *foundHint = 0;
387: fcb = GetFileControlBlock(vcb->extentsRefNum);
388:
389: (void) BTInvalidateHint(&btIterator);
390:
391: if (vcb->vcbSigWord == kHFSSigWord) {
392: HFSExtentKey * extentKeyPtr;
393: HFSExtentRecord extentData;
394:
395: extentKeyPtr = (HFSExtentKey*) &btIterator.key;
396: extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
397: extentKeyPtr->forkType = forkType;
398: extentKeyPtr->fileID = fileID;
399: extentKeyPtr->startBlock = startBlock;
400:
401: btRecord.bufferAddress = &extentData;
402: btRecord.itemSize = sizeof(HFSExtentRecord);
403: btRecord.itemCount = 1;
404:
405: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
406:
407: if (err == btNotFound && allowPrevious) {
408: err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
409:
410: // A previous record may not exist, so just return btNotFound (like we would if
411: // it was for the wrong file/fork).
412: if (err == (OSErr) fsBTStartOfIterationErr) //�� fsBTStartOfIterationErr is type unsigned long
413: err = btNotFound;
414:
415: if (err == noErr) {
416: // Found a previous record. Does it belong to the same fork of the same file?
417: if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
418: err = btNotFound;
419: }
420: }
421:
422: if (err == noErr) {
423: UInt16 i;
424:
425: // Copy the found key back for the caller
426: foundKey->keyLength = kHFSPlusExtentKeyMaximumLength;
427: foundKey->forkType = extentKeyPtr->forkType;
428: foundKey->pad = 0;
429: foundKey->fileID = extentKeyPtr->fileID;
430: foundKey->startBlock = extentKeyPtr->startBlock;
431:
432: // Copy the found data back for the caller
433: foundData[0].startBlock = extentData[0].startBlock;
434: foundData[0].blockCount = extentData[0].blockCount;
435: foundData[1].startBlock = extentData[1].startBlock;
436: foundData[1].blockCount = extentData[1].blockCount;
437: foundData[2].startBlock = extentData[2].startBlock;
438: foundData[2].blockCount = extentData[2].blockCount;
439:
440: for (i = 3; i < kHFSPlusExtentDensity; ++i)
441: {
442: foundData[i].startBlock = 0;
443: foundData[i].blockCount = 0;
444: }
445: }
446: }
447: else { // HFS Plus volume
448: HFSPlusExtentKey * extentKeyPtr;
449: HFSPlusExtentRecord extentData;
450:
451: extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key;
452: extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
453: extentKeyPtr->forkType = forkType;
454: extentKeyPtr->pad = 0;
455: extentKeyPtr->fileID = fileID;
456: extentKeyPtr->startBlock = startBlock;
457:
458: btRecord.bufferAddress = &extentData;
459: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
460: btRecord.itemCount = 1;
461:
462: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
463:
464: if (err == btNotFound && allowPrevious) {
465: err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
466:
467: // A previous record may not exist, so just return btNotFound (like we would if
468: // it was for the wrong file/fork).
469: if (err == (OSErr) fsBTStartOfIterationErr) //�� fsBTStartOfIterationErr is type unsigned long
470: err = btNotFound;
471:
472: if (err == noErr) {
473: // Found a previous record. Does it belong to the same fork of the same file?
474: if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
475: err = btNotFound;
476: }
477: }
478:
479: if (err == noErr) {
480: // Copy the found key back for the caller
481: BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
482: // Copy the found data back for the caller
483: BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
484: }
485: }
486:
487: *foundHint = btIterator.hint.nodeNum;
488: return err;
489: }
490:
491:
492:
493: static OSErr CreateExtentRecord(
494: const ExtendedVCB *vcb,
495: HFSPlusExtentKey *key,
496: HFSPlusExtentRecord extents,
497: UInt32 *hint)
498: {
499: BTreeIterator btIterator;
500: FSBufferDescriptor btRecord;
501: UInt16 btRecordSize;
502: OSErr err;
503:
504: err = noErr;
505: *hint = 0;
506: (void) BTInvalidateHint(&btIterator);
507:
508: if (vcb->vcbSigWord == kHFSSigWord) {
509: HFSExtentKey * keyPtr;
510: HFSExtentRecord data;
511:
512: btRecordSize = sizeof(HFSExtentRecord);
513: btRecord.bufferAddress = &data;
514: btRecord.itemSize = btRecordSize;
515: btRecord.itemCount = 1;
516:
517: keyPtr = (HFSExtentKey*) &btIterator.key;
518: keyPtr->keyLength = kHFSExtentKeyMaximumLength;
519: keyPtr->forkType = key->forkType;
520: keyPtr->fileID = key->fileID;
521: keyPtr->startBlock = key->startBlock;
522:
523: err = HFSPlusToHFSExtents(extents, data);
524: }
525: else { // HFS Plus volume
526: btRecordSize = sizeof(HFSPlusExtentRecord);
527: btRecord.bufferAddress = extents;
528: btRecord.itemSize = btRecordSize;
529: btRecord.itemCount = 1;
530:
531: BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey));
532: }
533:
534: if (err == noErr)
535: err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize);
536:
537: if (err == noErr)
538: *hint = btIterator.hint.nodeNum;
539:
540: return err;
541: }
542:
543:
544: OSErr DeleteExtentRecord(
545: const ExtendedVCB *vcb,
546: UInt8 forkType,
547: UInt32 fileID,
548: UInt32 startBlock)
549: {
550: BTreeIterator btIterator;
551: OSErr err;
552:
553: err = noErr;
554: (void) BTInvalidateHint(&btIterator);
555:
556: if (vcb->vcbSigWord == kHFSSigWord) {
557: HFSExtentKey * keyPtr;
558:
559: keyPtr = (HFSExtentKey*) &btIterator.key;
560: keyPtr->keyLength = kHFSExtentKeyMaximumLength;
561: keyPtr->forkType = forkType;
562: keyPtr->fileID = fileID;
563: keyPtr->startBlock = startBlock;
564: }
565: else { // HFS Plus volume
566: HFSPlusExtentKey * keyPtr;
567:
568: keyPtr = (HFSPlusExtentKey*) &btIterator.key;
569: keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
570: keyPtr->forkType = forkType;
571: keyPtr->pad = 0;
572: keyPtr->fileID = fileID;
573: keyPtr->startBlock = startBlock;
574: }
575:
576: err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator);
577:
578: return err;
579: }
580:
581:
582:
583: //_________________________________________________________________________________
584: //
585: // Routine: MapFileBlock
586: //
587: // Function: Maps a file position into a physical disk address.
588: //
589: // Input: A2.L - VCB pointer
590: // (A1,D1.W) - FCB pointer
591: // D4.L - number of bytes desired
592: // D5.L - file position (byte address)
593: //
594: // Output: D3.L - physical start block
595: // D6.L - number of contiguous bytes available (up to D4 bytes)
596: // D0.L - result code <01Oct85>
597: // 0 = ok
598: // FXRangeErr = file position beyond mapped range <17Oct85>
599: // FXOvFlErr = extents file overflow <17Oct85>
600: // other = error <17Oct85>
601: //
602: // Called By: Log2Phys (read/write in place), Cache (map a file block).
603: //_________________________________________________________________________________
604:
605: OSErr MapFileBlockC (
606: ExtendedVCB *vcb, // volume that file resides on
607: FCB *fcb, // FCB of file
608: SInt64 numberOfBytes, // number of contiguous bytes desired
609: SInt64 offset, // starting offset within file (in bytes)
610: UInt32 *startSector, // first 512-byte sector (NOT an allocation block)
611: UInt32 *availableBytes) // number of contiguous bytes (up to numberOfBytes)
612: {
613: OSErr err;
614: UInt32 allocBlockSize; // Size of the volume's allocation block
615: HFSPlusExtentKey foundKey;
616: HFSPlusExtentRecord foundData;
617: UInt32 foundIndex;
618: UInt32 hint;
619: UInt32 firstFABN; // file allocation block of first block in found extent
620: UInt32 nextFABN; // file allocation block of block after end of found extent
621: SInt64 dataEnd; // (offset) end of range that is contiguous
622: UInt32 sectorsPerBlock; // Number of sectors per allocation block
623: UInt32 startBlock; // volume allocation block corresponding to firstFABN
624: UInt32 temp;
625:
626:
627: LogStartTime(kTraceMapFileBlock);
628:
629: allocBlockSize = vcb->blockSize;
630:
631: err = MapFileBlockFromFCB(vcb, fcb, offset, &firstFABN, &startBlock, &nextFABN);
632: if (err != noErr) {
633: err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
634: if (err == noErr) {
635: startBlock = foundData[foundIndex].startBlock;
636: firstFABN = nextFABN - foundData[foundIndex].blockCount;
637: }
638: }
639:
640: if (err != noErr)
641: {
642: LogEndTime(kTraceMapFileBlock, err);
643:
644: return err;
645: }
646:
647: //
648: // Determine the end of the available space. It will either be the end of the extent,
649: // or the file's PEOF, whichever is smaller.
650: //
651: dataEnd = nextFABN * allocBlockSize; // Assume valid data through end of this extent
652: if (fcb->fcbPLen < dataEnd) // Is PEOF shorter?
653: dataEnd = fcb->fcbPLen; // Yes, so only map up to PEOF
654:
655: // Compute the number of sectors in an allocation block
656: sectorsPerBlock = allocBlockSize / kSectorSize; // sectors per allocation block
657:
658: //
659: // Compute the absolute sector number that contains the offset of the given file
660: //
661: temp = (UInt32)((offset - (firstFABN * allocBlockSize))/kSectorSize); // offset in sectors from start of the extent
662: temp += startBlock * sectorsPerBlock; // offset in sectors from start of allocation block space
663: if (vcb->vcbSigWord == kHFSPlusSigWord)
664: temp += vcb->hfsPlusIOPosOffset/512; /* offset inside wrapper */
665: else
666: temp += vcb->vcbAlBlSt; /* offset in sectors from start of volume */
667:
668: // Return the desired sector for file position "offset"
669: *startSector = temp;
670:
671: //
672: // Determine the number of contiguous bytes until the end of the extent
673: // (or the amount they asked for, whichever comes first).
674: //
675: temp = (UInt32)(dataEnd - offset);
676: if (temp > numberOfBytes)
677: *availableBytes = numberOfBytes; // more there than they asked for, so pin the output
678: else
679: *availableBytes = temp;
680:
681: LogEndTime(kTraceMapFileBlock, noErr);
682:
683: return noErr;
684: }
685:
686:
687: //�������������������������������������������������������������������������������
688: // Routine: ReleaseExtents
689: //
690: // Function: Release the extents of a single extent data record.
691: //�������������������������������������������������������������������������������
692:
693: static OSErr ReleaseExtents(
694: ExtendedVCB *vcb,
695: const HFSPlusExtentRecord extentRecord,
696: UInt32 *numReleasedAllocationBlocks,
697: Boolean *releasedLastExtent)
698: {
699: UInt32 extentIndex;
700: UInt32 numberOfExtents;
701: OSErr err = noErr;
702:
703: *numReleasedAllocationBlocks = 0;
704: *releasedLastExtent = false;
705:
706: if (vcb->vcbSigWord == kHFSPlusSigWord)
707: numberOfExtents = kHFSPlusExtentDensity;
708: else
709: numberOfExtents = kHFSExtentDensity;
710:
711: for( extentIndex = 0; extentIndex < numberOfExtents; extentIndex++)
712: {
713: UInt32 numAllocationBlocks;
714:
715: // Loop over the extent record and release the blocks associated with each extent.
716:
717: numAllocationBlocks = extentRecord[extentIndex].blockCount;
718: if ( numAllocationBlocks == 0 )
719: {
720: *releasedLastExtent = true;
721: break;
722: }
723:
724: err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks );
725: if ( err != noErr )
726: break;
727:
728: *numReleasedAllocationBlocks += numAllocationBlocks; // bump FABN to beg of next extent
729: }
730:
731: return( err );
732: }
733:
734:
735:
736: //�������������������������������������������������������������������������������
737: // Routine: TruncateExtents
738: //
739: // Purpose: Delete extent records whose starting file allocation block number
740: // is greater than or equal to a given starting block number. The
741: // allocation blocks represented by the extents are deallocated.
742: //
743: // Inputs:
744: // vcb Volume to operate on
745: // fileID Which file to operate on
746: // startBlock Starting file allocation block number for first extent
747: // record to delete.
748: //�������������������������������������������������������������������������������
749:
750: static OSErr TruncateExtents(
751: ExtendedVCB *vcb,
752: UInt8 forkType,
753: UInt32 fileID,
754: UInt32 startBlock,
755: Boolean * recordDeleted)
756: {
757: OSErr err;
758: UInt32 numberExtentsReleased;
759: Boolean releasedLastExtent;
760: UInt32 hint;
761: HFSPlusExtentKey key;
762: HFSPlusExtentRecord extents;
763:
764: while (true) {
765: err = FindExtentRecord(vcb, forkType, fileID, startBlock, false, &key, extents, &hint);
766: if (err != noErr) {
767: if (err == btNotFound)
768: err = noErr;
769: break;
770: }
771:
772: err = ReleaseExtents( vcb, extents, &numberExtentsReleased, &releasedLastExtent );
773: if (err != noErr) break;
774:
775: err = DeleteExtentRecord(vcb, forkType, fileID, startBlock);
776: if (err != noErr) break;
777:
778: *recordDeleted = true;
779: startBlock += numberExtentsReleased;
780: }
781:
782: return err;
783: }
784:
785:
786:
787: //�������������������������������������������������������������������������������
788: // Routine: DeallocateFork
789: //
790: // Function: De-allocates all disk space allocated to a specified fork.
791: //�������������������������������������������������������������������������������
792:
793: static OSErr DeallocateFork(
794: ExtendedVCB *vcb,
795: HFSCatalogNodeID fileID,
796: UInt8 forkType,
797: HFSPlusExtentRecord catalogExtents,
798: Boolean * recordDeleted) /* true if a record was deleted */
799: {
800: OSErr err;
801: UInt32 numReleasedAllocationBlocks;
802: Boolean releasedLastExtent;
803:
804: // Release the catalog extents
805: err = ReleaseExtents( vcb, catalogExtents, &numReleasedAllocationBlocks, &releasedLastExtent );
806: // Release the extra extents, if present
807: if (err == noErr && !releasedLastExtent)
808: err = TruncateExtents(vcb, forkType, fileID, numReleasedAllocationBlocks, recordDeleted);
809:
810: return( err );
811: }
812:
813: //�������������������������������������������������������������������������������
814: // Routine: FlushExtentFile
815: //
816: // Function: Flushes the extent file for a specified volume
817: //�������������������������������������������������������������������������������
818:
819: OSErr FlushExtentFile( ExtendedVCB *vcb )
820: {
821: FCB * fcb;
822: OSErr err;
823:
824: fcb = GetFileControlBlock(vcb->extentsRefNum);
825: err = BTFlushPath(fcb);
826: if ( err == noErr )
827: {
828: // If the FCB for the extent "file" is dirty, mark the VCB as dirty.
829:
830: if ((fcb->fcbFlags & fcbModifiedMask) != 0)
831: {
832: MarkVCBDirty( vcb );
833: err = FlushVolumeControlBlock( vcb );
834: }
835: }
836:
837: return( err );
838: }
839:
840: //-------------------------------------------------------------------------------
841: // Routine: DeleteFile
842: //
843: // Function: De-allocates all disk space allocated to a specified file
844: // including the space used by the catalog (ie the catalog record).
845: // The space occupied by both forks is also deallocated.
846: //
847: //-------------------------------------------------------------------------------
848:
849: OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint )
850: {
851: OSErr err;
852: OSErr errDF, errRF;
853: CatalogNodeData catalogData;
854: FSSpec fileSpec; /* 264 bytes */
855: Boolean recordDeleted;
856:
857: recordDeleted = false;
858:
859: // Find catalog data in catalog
860: err = GetCatalogNode( vcb, parDirID, catalogName, kUndefinedStrLen, catalogHint, &fileSpec, &catalogData, &catalogHint);
861: if( err != noErr )
862: goto Exit;
863:
864: // Check to make sure record is for a file
865: if ( catalogData.cnd_type != kCatalogFileNode )
866: {
867: err = notAFileErr;
868: goto Exit;
869: }
870:
871: //
872: // Always delete the Catalog record first (to minimize disk corruption)
873: //
874: err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint);
875: if( err != noErr )
876: goto Exit;
877:
878: //
879: // Note: we don't report errors from DeallocateFork since the
880: // file no longer exists (since DeleteCatalogNode succeeded).
881: // Any errors mean that there are possibly some orphaned disk
882: // blocks but from the clients perspective the file was deleted.
883: //
884:
885: // Deallocate data fork extents
886: errDF = DeallocateFork( vcb, catalogData.cnd_nodeID, kDataForkType,
887: catalogData.cnd_datafork.extents, &recordDeleted );
888:
889: // Deallocate resource fork extents
890: errRF = DeallocateFork( vcb, catalogData.cnd_nodeID, kResourceForkType,
891: catalogData.cnd_rsrcfork.extents, &recordDeleted );
892:
893: if (recordDeleted)
894: err = FlushExtentFile( vcb );
895:
896: return (errDF ? errDF : (errRF ? errRF : err));
897: Exit:
898:
899: return( err );
900: }
901:
902: //�������������������������������������������������������������������������������
903: // Routine: CompareExtentKeys
904: //
905: // Function: Compares two extent file keys (a search key and a trial key) for
906: // an HFS volume.
907: //�������������������������������������������������������������������������������
908:
909: SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey )
910: {
911: SInt32 result; // � 1
912:
913: #if DEBUG_BUILD
914: if (searchKey->keyLength != kHFSExtentKeyMaximumLength)
915: DebugStr("\pHFS: search Key is wrong length");
916: if (trialKey->keyLength != kHFSExtentKeyMaximumLength)
917: DebugStr("\pHFS: trial Key is wrong length");
918: #endif
919:
920: result = -1; // assume searchKey < trialKey
921:
922: if (searchKey->fileID == trialKey->fileID) {
923: //
924: // FileNum's are equal; compare fork types
925: //
926: if (searchKey->forkType == trialKey->forkType) {
927: //
928: // Fork types are equal; compare allocation block number
929: //
930: if (searchKey->startBlock == trialKey->startBlock) {
931: //
932: // Everything is equal
933: //
934: result = 0;
935: }
936: else {
937: //
938: // Allocation block numbers differ; determine sign
939: //
940: if (searchKey->startBlock > trialKey->startBlock)
941: result = 1;
942: }
943: }
944: else {
945: //
946: // Fork types differ; determine sign
947: //
948: if (searchKey->forkType > trialKey->forkType)
949: result = 1;
950: }
951: }
952: else {
953: //
954: // FileNums differ; determine sign
955: //
956: if (searchKey->fileID > trialKey->fileID)
957: result = 1;
958: }
959:
960: return( result );
961: }
962:
963:
964:
965: //�������������������������������������������������������������������������������
966: // Routine: CompareExtentKeysPlus
967: //
968: // Function: Compares two extent file keys (a search key and a trial key) for
969: // an HFS volume.
970: //�������������������������������������������������������������������������������
971:
972: SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey )
973: {
974: SInt32 result; // � 1
975:
976: #if DEBUG_BUILD
977: if (searchKey->keyLength != kHFSPlusExtentKeyMaximumLength)
978: DebugStr("\pHFS: search Key is wrong length");
979: if (trialKey->keyLength != kHFSPlusExtentKeyMaximumLength)
980: DebugStr("\pHFS: trial Key is wrong length");
981: #endif
982:
983: result = -1; // assume searchKey < trialKey
984:
985: if (searchKey->fileID == trialKey->fileID) {
986: //
987: // FileNum's are equal; compare fork types
988: //
989: if (searchKey->forkType == trialKey->forkType) {
990: //
991: // Fork types are equal; compare allocation block number
992: //
993: if (searchKey->startBlock == trialKey->startBlock) {
994: //
995: // Everything is equal
996: //
997: result = 0;
998: }
999: else {
1000: //
1001: // Allocation block numbers differ; determine sign
1002: //
1003: if (searchKey->startBlock > trialKey->startBlock)
1004: result = 1;
1005: }
1006: }
1007: else {
1008: //
1009: // Fork types differ; determine sign
1010: //
1011: if (searchKey->forkType > trialKey->forkType)
1012: result = 1;
1013: }
1014: }
1015: else {
1016: //
1017: // FileNums differ; determine sign
1018: //
1019: if (searchKey->fileID > trialKey->fileID)
1020: result = 1;
1021: }
1022:
1023: return( result );
1024: }
1025:
1026:
1027:
1028: //_________________________________________________________________________________
1029: //
1030: // Routine: Extendfile
1031: //
1032: // Function: Extends the disk space allocated to a file.
1033: //
1034: // Input: A2.L - VCB pointer
1035: // A1.L - pointer to FCB array
1036: // D1.W - file refnum
1037: // D3.B - option flags
1038: // kEFContigMask - force contiguous allocation
1039: // kEFAllMask - allocate all requested bytes or none
1040: // NOTE: You may not set both options.
1041: // D4.L - number of additional bytes to allocate
1042: //
1043: // Output: D0.W - result code
1044: // 0 = ok
1045: // -n = IO error
1046: // D6.L - number of bytes allocated
1047: //
1048: // Called by: FileAloc,FileWrite,SetEof
1049: //
1050: // Note: ExtendFile updates the PEOF in the FCB.
1051: //_________________________________________________________________________________
1052:
1053: OSErr ExtendFileC (
1054: ExtendedVCB *vcb, // volume that file resides on
1055: FCB *fcb, // FCB of file to truncate
1056: SInt64 bytesToAdd, // number of bytes to allocate
1057: UInt32 flags, // EFContig and/or EFAll
1058: SInt64 *actualBytesAdded) // number of bytes actually allocated
1059: {
1060: OSErr err;
1061: UInt32 volumeBlockSize;
1062: UInt32 blocksToAdd;
1063: UInt32 bytesThisExtent;
1064: HFSPlusExtentKey foundKey;
1065: HFSPlusExtentRecord foundData;
1066: UInt32 foundIndex;
1067: UInt32 hint;
1068: UInt32 nextBlock;
1069: UInt32 startBlock;
1070: Boolean allOrNothing;
1071: Boolean forceContig;
1072: Boolean wantContig;
1073: Boolean needsFlush;
1074: UInt32 actualStartBlock;
1075: UInt32 actualNumBlocks;
1076: UInt32 numExtentsPerRecord;
1077: SInt64 maximumBytes;
1078: SInt64 peof;
1079: SInt64 previousPEOF;
1080:
1081:
1082: #if HFSInstrumentation
1083: InstTraceClassRef trace;
1084: InstEventTag eventTag;
1085: InstDataDescriptorRef traceDescriptor;
1086: FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars();
1087:
1088: traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
1089:
1090: err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:ExtendFileC", 'hfs+', kInstEnableClassMask, &trace);
1091: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
1092:
1093: eventTag = InstCreateEventTag();
1094: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
1095: #endif
1096:
1097: needsFlush = false;
1098: *actualBytesAdded = 0;
1099: volumeBlockSize = vcb->blockSize;
1100: allOrNothing = ((flags & kEFAllMask) != 0);
1101: forceContig = ((flags & kEFContigMask) != 0);
1102: previousPEOF = fcb->fcbPLen;
1103:
1104: if (vcb->vcbSigWord == kHFSPlusSigWord)
1105: numExtentsPerRecord = kHFSPlusExtentDensity;
1106: else
1107: numExtentsPerRecord = kHFSExtentDensity;
1108:
1109: //
1110: // Make sure the request and new PEOF are less than 2GB if HFS.
1111: //
1112: if (vcb->vcbSigWord == kHFSSigWord) {
1113: if (bytesToAdd >= kTwoGigabytes)
1114: goto Overflow;
1115: if ((fcb->fcbPLen + bytesToAdd) >= kTwoGigabytes)
1116: goto Overflow;
1117: }
1118: //
1119: // Determine how many blocks need to be allocated.
1120: // Round up the number of desired bytes to add.
1121: //
1122: blocksToAdd = FileBytesToBlocks(bytesToAdd, volumeBlockSize);
1123: bytesToAdd = (SInt64)(blocksToAdd * volumeBlockSize);
1124:
1125: //
1126: // If the file's clump size is larger than the allocation block size,
1127: // then set the maximum number of bytes to the requested number of bytes
1128: // rounded up to a multiple of the clump size.
1129: //
1130: if (fcb->fcbClmpSize > volumeBlockSize) {
1131: maximumBytes = (SInt64)FileBytesToBlocks(bytesToAdd, fcb->fcbClmpSize);
1132: maximumBytes *= fcb->fcbClmpSize;
1133: }
1134: else {
1135: maximumBytes = bytesToAdd;
1136: }
1137:
1138: //
1139: // Compute new physical EOF, rounded up to a multiple of a block.
1140: //
1141: if ((vcb->vcbSigWord == kHFSSigWord) && ((fcb->fcbPLen + bytesToAdd) >= (SInt64) kTwoGigabytes)) // Too big?
1142: if (allOrNothing) // Yes, must they have it all?
1143: goto Overflow; // Yes, can't have it
1144: else {
1145: --blocksToAdd; // No, give give 'em one block less
1146: bytesToAdd -= volumeBlockSize;
1147: }
1148:
1149: //
1150: // If allocation is all-or-nothing, make sure there are
1151: // enough free blocks on the volume (quick test).
1152: //
1153: if (allOrNothing && blocksToAdd > vcb->freeBlocks) {
1154: err = dskFulErr;
1155: goto ErrorExit;
1156: }
1157:
1158: //
1159: // See if there are already enough blocks allocated to the file.
1160: //
1161: peof = fcb->fcbPLen + bytesToAdd; // potential new PEOF
1162: err = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock);
1163: if (err == noErr) {
1164: // Enough blocks are already allocated. Just update the FCB to reflect the new length.
1165: fcb->fcbPLen = peof;
1166: fcb->fcbFlags |= fcbModifiedMask;
1167: goto Exit;
1168: }
1169: if (err != fxRangeErr) // Any real error?
1170: goto ErrorExit; // Yes, so exit immediately
1171:
1172: //
1173: // Adjust the PEOF to the end of the last extent.
1174: //
1175: peof = (SInt64)(nextBlock * volumeBlockSize); // currently allocated PEOF
1176: bytesThisExtent = (UInt32)(peof - fcb->fcbPLen);
1177: if (bytesThisExtent != 0) {
1178: fcb->fcbPLen = peof;
1179: fcb->fcbFlags |= fcbModifiedMask;
1180: bytesToAdd -= bytesThisExtent;
1181: }
1182:
1183: //
1184: // Allocate some more space.
1185: //
1186: // First try a contiguous allocation (of the whole amount).
1187: // If that fails, get whatever we can.
1188: // If forceContig, then take whatever we got
1189: // else, keep getting bits and pieces (non-contig)
1190: err = noErr;
1191: wantContig = true;
1192: do {
1193: startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
1194: err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks);
1195: if (err == dskFulErr) {
1196: if (forceContig)
1197: break; // AllocContig failed because not enough contiguous space
1198: if (wantContig) {
1199: // Couldn't get one big chunk, so get whatever we can.
1200: err = noErr;
1201: wantContig = false;
1202: continue;
1203: }
1204: if (actualNumBlocks != 0)
1205: err = noErr;
1206: }
1207: if (err == noErr) {
1208: #if HFSInstrumentation
1209: {
1210: struct {
1211: UInt32 fileID;
1212: UInt32 start;
1213: UInt32 count;
1214: UInt32 fabn;
1215: } x;
1216:
1217: x.fileID = H_FILEID(fcb);
1218: x.start = actualStartBlock;
1219: x.count = actualNumBlocks;
1220: x.fabn = nextBlock;
1221:
1222: InstLogTraceEventWithDataStructure( trace, eventTag, kInstMiddleEvent, traceDescriptor,
1223: (UInt8 *) &x, sizeof(x));
1224: }
1225: #endif
1226: // Add the new extent to the existing extent record, or create a new one.
1227: if (actualStartBlock == startBlock) {
1228: // We grew the file's last extent, so just adjust the number of blocks.
1229: foundData[foundIndex].blockCount += actualNumBlocks;
1230: err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
1231: if (err != noErr) break;
1232: }
1233: else {
1234: UInt16 i;
1235:
1236: // Need to add a new extent. See if there is room in the current record.
1237: if (foundData[foundIndex].blockCount != 0) // Is current extent free to use?
1238: ++foundIndex; // No, so use the next one.
1239: if (foundIndex == numExtentsPerRecord) {
1240: // This record is full. Need to create a new one.
1241: if (H_FILEID(fcb) == kHFSExtentsFileID) {
1242: err = fxOvFlErr; // Oops. Can't extend extents file (?? really ??)
1243: break;
1244: }
1245:
1246: foundKey.keyLength = kHFSPlusExtentKeyMaximumLength;
1247: if (fcb->fcbFlags & fcbResourceMask)
1248: foundKey.forkType = kResourceForkType;
1249: else
1250: foundKey.forkType = kDataForkType;
1251: foundKey.pad = 0;
1252: foundKey.fileID = H_FILEID(fcb);
1253: foundKey.startBlock = nextBlock;
1254:
1255: foundData[0].startBlock = actualStartBlock;
1256: foundData[0].blockCount = actualNumBlocks;
1257:
1258: // zero out remaining extents...
1259: for (i = 1; i < kHFSPlusExtentDensity; ++i)
1260: {
1261: foundData[i].startBlock = 0;
1262: foundData[i].blockCount = 0;
1263: }
1264:
1265: foundIndex = 0;
1266:
1267: err = CreateExtentRecord(vcb, &foundKey, foundData, &hint);
1268: if (err == fxOvFlErr) {
1269: // We couldn't create an extent record because extents B-tree
1270: // couldn't grow. Dellocate the extent just allocated and
1271: // return a disk full error.
1272: (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks);
1273: err = dskFulErr;
1274: }
1275: if (err != noErr) break;
1276:
1277: needsFlush = true; // We need to update the B-tree header
1278: }
1279: else {
1280: // Add a new extent into this record and update.
1281: foundData[foundIndex].startBlock = actualStartBlock;
1282: foundData[foundIndex].blockCount = actualNumBlocks;
1283: err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
1284: if (err != noErr) break;
1285: }
1286: }
1287:
1288: // Figure out how many bytes were actually allocated.
1289: // NOTE: BlockAllocate could have allocated more than we asked for.
1290: // Don't set the PEOF beyond what our client asked for.
1291: nextBlock += actualNumBlocks;
1292: bytesThisExtent = actualNumBlocks * volumeBlockSize;
1293: if (bytesThisExtent > bytesToAdd) {
1294: bytesToAdd = 0;
1295: }
1296: else {
1297: bytesToAdd -= bytesThisExtent;
1298: maximumBytes -= bytesThisExtent;
1299: }
1300: fcb->fcbPLen += bytesThisExtent;
1301: fcb->fcbFlags |= fcbModifiedMask;
1302:
1303: // If contiguous allocation was requested, then we've already got one contiguous
1304: // chunk. If we didn't get all we wanted, then adjust the error to disk full.
1305: if (forceContig) {
1306: if (bytesToAdd != 0)
1307: err = dskFulErr;
1308: break; // We've already got everything that's contiguous
1309: }
1310: }
1311: } while (err == noErr && bytesToAdd);
1312:
1313: ErrorExit:
1314: Exit:
1315: *actualBytesAdded = fcb->fcbPLen - previousPEOF;
1316:
1317: if (needsFlush)
1318: (void) FlushExtentFile(vcb);
1319:
1320: #if HFSInstrumentation
1321: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
1322: #endif
1323:
1324: return err;
1325:
1326: Overflow:
1327: err = fileBoundsErr;
1328: goto ErrorExit;
1329: }
1330:
1331:
1332:
1333: //_________________________________________________________________________________
1334: //
1335: // Routine: TruncateFileC
1336: //
1337: // Function: Truncates the disk space allocated to a file. The file space is
1338: // truncated to a specified new PEOF rounded up to the next allocation
1339: // block boundry. If the 'TFTrunExt' option is specified, the file is
1340: // truncated to the end of the extent containing the new PEOF.
1341: //
1342: // Input: A2.L - VCB pointer
1343: // A1.L - pointer to FCB array
1344: // D1.W - file refnum
1345: // D2.B - option flags
1346: // TFTrunExt - truncate to the extent containing new PEOF
1347: // D3.L - new PEOF
1348: //
1349: // Output: D0.W - result code
1350: // 0 = ok
1351: // -n = IO error
1352: //
1353: // Note: TruncateFile updates the PEOF in the FCB.
1354: //_________________________________________________________________________________
1355:
1356: OSErr TruncateFileC (
1357: ExtendedVCB *vcb, // volume that file resides on
1358: FCB *fcb, // FCB of file to truncate
1359: SInt64 peof, // new physical size for file
1360: Boolean truncateToExtent) // if true, truncate to end of extent containing newPEOF
1361: {
1362: OSErr err;
1363: UInt32 nextBlock; // next file allocation block to consider
1364: UInt32 startBlock; // Physical (volume) allocation block number of start of a range
1365: UInt32 physNumBlocks; // Number of allocation blocks in file (according to PEOF)
1366: UInt32 numBlocks;
1367: HFSPlusExtentKey key; // key for current extent record; key->keyLength == 0 if FCB's extent record
1368: UInt32 hint; // BTree hint corresponding to key
1369: HFSPlusExtentRecord extentRecord;
1370: UInt32 extentIndex;
1371: UInt32 extentNextBlock;
1372: UInt32 numExtentsPerRecord;
1373: UInt8 forkType;
1374: Boolean extentChanged; // true if we actually changed an extent
1375: Boolean recordDeleted; // true if an extent record got deleted
1376:
1377: #if HFSInstrumentation
1378: InstTraceClassRef trace;
1379: InstEventTag eventTag;
1380: InstDataDescriptorRef traceDescriptor;
1381: FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars();
1382:
1383: traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
1384:
1385: err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:TruncateFileC", 'hfs+', kInstEnableClassMask, &trace);
1386: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
1387:
1388: eventTag = InstCreateEventTag();
1389: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
1390: #endif
1391:
1392: recordDeleted = false;
1393:
1394: if (vcb->vcbSigWord == kHFSPlusSigWord)
1395: numExtentsPerRecord = kHFSPlusExtentDensity;
1396: else
1397: numExtentsPerRecord = kHFSExtentDensity;
1398:
1399: if (fcb->fcbFlags & fcbResourceMask)
1400: forkType = kResourceForkType;
1401: else
1402: forkType = kDataForkType;
1403:
1404: physNumBlocks = fcb->fcbPLen / vcb->blockSize; // number of allocation blocks currently in file
1405:
1406: //
1407: // Round newPEOF up to a multiple of the allocation block size. If new size is
1408: // two gigabytes or more, then round down by one allocation block (??? really?
1409: // shouldn't that be an error?).
1410: //
1411: nextBlock = FileBytesToBlocks(peof, vcb->blockSize); // number of allocation blocks to remain in file
1412: peof = (SInt64)(nextBlock * vcb->blockSize); // number of bytes in those blocks
1413: if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= (UInt32) kTwoGigabytes)) {
1414: #if DEBUG_BUILD
1415: DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
1416: #endif
1417: err = fileBoundsErr;
1418: goto ErrorExit;
1419: }
1420:
1421: //
1422: // Update FCB's length
1423: //
1424: fcb->fcbPLen = peof;
1425: fcb->fcbFlags |= fcbModifiedMask;
1426:
1427: //
1428: // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
1429: // all storage).
1430: //
1431: if (peof == 0) {
1432: int i;
1433:
1434: // Deallocate all the extents for this fork
1435: err = DeallocateFork(vcb, H_FILEID(fcb), forkType, fcb->fcbExtents, &recordDeleted);
1436: if (err != noErr) goto ErrorExit; // got some error, so return it
1437:
1438: // Update the catalog extent record (making sure it's zeroed out)
1439: if (err == noErr) {
1440: for (i=0; i < kHFSPlusExtentDensity; i++) {
1441: fcb->fcbExtents[i].startBlock = 0;
1442: fcb->fcbExtents[i].blockCount = 0;
1443: }
1444: }
1445: goto Done;
1446: }
1447:
1448: //
1449: // Find the extent containing byte (peof-1). This is the last extent we'll keep.
1450: // (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only
1451: // keep up through peof). The search will tell us how many allocation blocks exist
1452: // in the found extent plus all previous extents.
1453: //
1454: err = SearchExtentFile(vcb, fcb, peof-1, &key, extentRecord, &extentIndex, &hint, &extentNextBlock);
1455: if (err != noErr) goto ErrorExit;
1456:
1457: extentChanged = false; // haven't changed the extent yet
1458:
1459: if (!truncateToExtent) {
1460: //
1461: // Shorten this extent. It may be the case that the entire extent gets
1462: // freed here.
1463: //
1464: numBlocks = extentNextBlock - nextBlock; // How many blocks in this extent to free up
1465: if (numBlocks != 0) {
1466: // Compute first volume allocation block to free
1467: startBlock = extentRecord[extentIndex].startBlock + extentRecord[extentIndex].blockCount - numBlocks;
1468: // Free the blocks in bitmap
1469: err = BlockDeallocate(vcb, startBlock, numBlocks);
1470: if (err != noErr) goto ErrorExit;
1471: // Adjust length of this extent
1472: extentRecord[extentIndex].blockCount -= numBlocks;
1473: // If extent is empty, set start block to 0
1474: if (extentRecord[extentIndex].blockCount == 0)
1475: extentRecord[extentIndex].startBlock = 0;
1476: // Remember that we changed the extent record
1477: extentChanged = true;
1478: }
1479: }
1480:
1481: //
1482: // Now move to the next extent in the record, and set up the file allocation block number
1483: //
1484: nextBlock = extentNextBlock; // Next file allocation block to free
1485: ++extentIndex; // Its index within the extent record
1486:
1487: //
1488: // Release all following extents in this extent record. Update the record.
1489: //
1490: while (extentIndex < numExtentsPerRecord && extentRecord[extentIndex].blockCount != 0) {
1491: numBlocks = extentRecord[extentIndex].blockCount;
1492: // Deallocate this extent
1493: err = BlockDeallocate(vcb, extentRecord[extentIndex].startBlock, numBlocks);
1494: if (err != noErr) goto ErrorExit;
1495: // Update next file allocation block number
1496: nextBlock += numBlocks;
1497: // Zero out start and length of this extent to delete it from record
1498: extentRecord[extentIndex].startBlock = 0;
1499: extentRecord[extentIndex].blockCount = 0;
1500: // Remember that we changed an extent
1501: extentChanged = true;
1502: // Move to next extent in record
1503: ++extentIndex;
1504: }
1505:
1506: //
1507: // If any of the extents in the current record were changed, then update that
1508: // record (in the FCB, or extents file).
1509: //
1510: if (extentChanged) {
1511: err = UpdateExtentRecord(vcb, fcb, &key, extentRecord, hint);
1512: if (err != noErr) goto ErrorExit;
1513: }
1514:
1515: //
1516: // If there are any following allocation blocks, then we need
1517: // to seach for their extent records and delete those allocation
1518: // blocks.
1519: //
1520: if (nextBlock < physNumBlocks)
1521: err = TruncateExtents(vcb, forkType, H_FILEID(fcb), nextBlock, &recordDeleted);
1522:
1523: Done:
1524: ErrorExit:
1525:
1526: if (recordDeleted)
1527: (void) FlushExtentFile(vcb);
1528:
1529: #if HFSInstrumentation
1530: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
1531: #endif
1532:
1533: return err;
1534: }
1535:
1536:
1537:
1538: //�������������������������������������������������������������������������������
1539: // Routine: SearchExtentRecord (was XRSearch)
1540: //
1541: // Function: Searches extent record for the extent mapping a given file
1542: // allocation block number (FABN).
1543: //
1544: // Input: searchFABN - desired FABN
1545: // extentData - pointer to extent data record (xdr)
1546: // extentDataStartFABN - beginning FABN for extent record
1547: //
1548: // Output: foundExtentDataOffset - offset to extent entry within xdr
1549: // result = noErr, offset to extent mapping desired FABN
1550: // result = FXRangeErr, offset to last extent in record
1551: // endingFABNPlusOne - ending FABN +1
1552: // noMoreExtents - True if the extent was not found, and the
1553: // extent record was not full (so don't bother
1554: // looking in subsequent records); false otherwise.
1555: //
1556: // Result: noErr = ok
1557: // FXRangeErr = desired FABN > last mapped FABN in record
1558: //�������������������������������������������������������������������������������
1559:
1560: static OSErr SearchExtentRecord(
1561: const ExtendedVCB *vcb,
1562: UInt32 searchFABN,
1563: const HFSPlusExtentRecord extentData,
1564: UInt32 extentDataStartFABN,
1565: UInt32 *foundExtentIndex,
1566: UInt32 *endingFABNPlusOne,
1567: Boolean *noMoreExtents)
1568: {
1569: OSErr err = noErr;
1570: UInt32 extentIndex;
1571: UInt32 numberOfExtents;
1572: UInt32 numAllocationBlocks;
1573: Boolean foundExtent;
1574:
1575: *endingFABNPlusOne = extentDataStartFABN;
1576: *noMoreExtents = false;
1577: foundExtent = false;
1578:
1579: if (vcb->vcbSigWord == kHFSPlusSigWord)
1580: numberOfExtents = kHFSPlusExtentDensity;
1581: else
1582: numberOfExtents = kHFSExtentDensity;
1583:
1584: for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex )
1585: {
1586:
1587: // Loop over the extent record and find the search FABN.
1588:
1589: numAllocationBlocks = extentData[extentIndex].blockCount;
1590: if ( numAllocationBlocks == 0 )
1591: {
1592: break;
1593: }
1594:
1595: *endingFABNPlusOne += numAllocationBlocks;
1596:
1597: if( searchFABN < *endingFABNPlusOne )
1598: {
1599: // Found the extent.
1600: foundExtent = true;
1601: break;
1602: }
1603: }
1604:
1605: if( foundExtent )
1606: {
1607: // Found the extent. Note the extent offset
1608: *foundExtentIndex = extentIndex;
1609: }
1610: else
1611: {
1612: // Did not find the extent. Set foundExtentDataOffset accordingly
1613: if( extentIndex > 0 )
1614: {
1615: *foundExtentIndex = extentIndex - 1;
1616: }
1617: else
1618: {
1619: *foundExtentIndex = 0;
1620: }
1621:
1622: // If we found an empty extent, then set noMoreExtents.
1623: if (extentIndex < numberOfExtents)
1624: *noMoreExtents = true;
1625:
1626: // Finally, return an error to the caller
1627: err = fxRangeErr;
1628: }
1629:
1630: return( err );
1631: }
1632:
1633: //�������������������������������������������������������������������������������
1634: // Routine: SearchExtentFile (was XFSearch)
1635: //
1636: // Function: Searches extent file (including the FCB resident extent record)
1637: // for the extent mapping a given file position.
1638: //
1639: // Input: vcb - VCB pointer
1640: // fcb - FCB pointer
1641: // filePosition - file position (byte address)
1642: //
1643: // Output: foundExtentKey - extent key record (xkr)
1644: // If extent was found in the FCB's resident extent record,
1645: // then foundExtentKey->keyLength will be set to 0.
1646: // foundExtentData - extent data record(xdr)
1647: // foundExtentIndex - index to extent entry in xdr
1648: // result = 0, offset to extent mapping desired FABN
1649: // result = FXRangeErr, offset to last extent in record
1650: // (i.e., kNumExtentsPerRecord-1)
1651: // extentBTreeHint - BTree hint for extent record
1652: // kNoHint = Resident extent record
1653: // endingFABNPlusOne - ending FABN +1
1654: //
1655: // Result:
1656: // noErr Found an extent that contains the given file position
1657: // FXRangeErr Given position is beyond the last allocated extent
1658: // (other) (some other internal I/O error)
1659: //�������������������������������������������������������������������������������
1660:
1661: static OSErr SearchExtentFile(
1662: const ExtendedVCB *vcb,
1663: const FCB *fcb,
1664: SInt64 filePosition,
1665: HFSPlusExtentKey *foundExtentKey,
1666: HFSPlusExtentRecord foundExtentData,
1667: UInt32 *foundExtentIndex,
1668: UInt32 *extentBTreeHint,
1669: UInt32 *endingFABNPlusOne )
1670: {
1671: OSErr err;
1672: UInt32 filePositionBlock;
1673: Boolean noMoreExtents;
1674:
1675: filePositionBlock = filePosition / vcb->blockSize;
1676: bcopy ( fcb->fcbExtents, foundExtentData, sizeof(HFSPlusExtentRecord));
1677:
1678: // Search the resident FCB first.
1679: err = SearchExtentRecord( vcb, filePositionBlock, foundExtentData, 0,
1680: foundExtentIndex, endingFABNPlusOne, &noMoreExtents );
1681:
1682: if( err == noErr ) {
1683: // Found the extent. Set results accordingly
1684: *extentBTreeHint = kNoHint; // no hint, because not in the BTree
1685: foundExtentKey->keyLength = 0; // 0 = the FCB itself
1686:
1687: goto Exit;
1688: }
1689:
1690: // Didn't find extent in FCB. If FCB's extent record wasn't full, there's no point
1691: // in searching the extents file. Note that SearchExtentRecord left us pointing at
1692: // the last valid extent (or the first one, if none were valid). This means we need
1693: // to fill in the hint and key outputs, just like the "if" statement above.
1694: if ( noMoreExtents ) {
1695: *extentBTreeHint = kNoHint; // no hint, because not in the BTree
1696: foundExtentKey->keyLength = 0; // 0 = the FCB itself
1697: err = fxRangeErr; // There are no more extents, so must be beyond PEOF
1698: goto Exit;
1699: }
1700:
1701: //
1702: // Find the desired record, or the previous record if it is the same fork
1703: //
1704: err = FindExtentRecord(vcb, (fcb->fcbFlags & fcbResourceMask) ? kResourceForkType : kDataForkType,
1705: H_FILEID(fcb), filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint);
1706:
1707: if (err == btNotFound) {
1708: //
1709: // If we get here, the desired position is beyond the extents in the FCB, and there are no extents
1710: // in the extents file. Return the FCB's extents and a range error.
1711: //
1712: *extentBTreeHint = kNoHint;
1713: foundExtentKey->keyLength = 0;
1714: err = GetFCBExtentRecord(fcb, foundExtentData);
1715: // Note: foundExtentIndex and endingFABNPlusOne have already been set as a result of the very
1716: // first SearchExtentRecord call in this function (when searching in the FCB's extents, and
1717: // we got a range error).
1718:
1719: return fxRangeErr;
1720: }
1721:
1722: //
1723: // If we get here, there was either a BTree error, or we found an appropriate record.
1724: // If we found a record, then search it for the correct index into the extents.
1725: //
1726: if (err == noErr) {
1727: // Find appropriate index into extent record
1728: err = SearchExtentRecord(vcb, filePositionBlock, foundExtentData, foundExtentKey->startBlock,
1729: foundExtentIndex, endingFABNPlusOne, &noMoreExtents);
1730: }
1731:
1732: Exit:
1733: return err;
1734: }
1735:
1736:
1737:
1738: //�������������������������������������������������������������������������������
1739: // Routine: UpdateExtentRecord
1740: //
1741: // Function: Write new extent data to an existing extent record with a given key.
1742: // If all of the extents are empty, and the extent record is in the
1743: // extents file, then the record is deleted.
1744: //
1745: // Input: vcb - the volume containing the extents
1746: // fcb - the file that owns the extents
1747: // extentFileKey - pointer to extent key record (xkr)
1748: // If the key length is 0, then the extents are actually part
1749: // of the catalog record, stored in the FCB.
1750: // extentData - pointer to extent data record (xdr)
1751: // extentBTreeHint - hint for given key, or kNoHint
1752: //
1753: // Result: noErr = ok
1754: // (other) = error from BTree
1755: //�������������������������������������������������������������������������������
1756:
1757: static OSErr UpdateExtentRecord (
1758: const ExtendedVCB *vcb,
1759: FCB *fcb,
1760: const HFSPlusExtentKey *extentFileKey,
1761: const HFSPlusExtentRecord extentData,
1762: UInt32 extentBTreeHint)
1763: {
1764: BTreeIterator btIterator;
1765: FSBufferDescriptor btRecord;
1766: UInt16 btRecordSize;
1767: FCB * btFCB;
1768: OSErr err = noErr;
1769:
1770: if (extentFileKey->keyLength == 0) { // keyLength == 0 means the FCB's extent record
1771: BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
1772: fcb->fcbFlags |= fcbModifiedMask;
1773: }
1774: else {
1775: //
1776: // Need to find and change a record in Extents BTree
1777: //
1778: btFCB = GetFileControlBlock(vcb->extentsRefNum);
1779:
1780: if (vcb->vcbSigWord == kHFSSigWord) {
1781: HFSExtentKey * key; // Actual extent key used on disk in HFS
1782: HFSExtentRecord foundData; // The extent data actually found
1783:
1784: key = (HFSExtentKey*) &btIterator.key;
1785: key->keyLength = kHFSExtentKeyMaximumLength;
1786: key->forkType = extentFileKey->forkType;
1787: key->fileID = extentFileKey->fileID;
1788: key->startBlock = extentFileKey->startBlock;
1789:
1790: btIterator.hint.index = 0;
1791: btIterator.hint.nodeNum = extentBTreeHint;
1792:
1793: btRecord.bufferAddress = &foundData;
1794: btRecord.itemSize = sizeof(HFSExtentRecord);
1795: btRecord.itemCount = 1;
1796:
1797: err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord,
1798: &btRecordSize, &btIterator);
1799:
1800: if (err == noErr)
1801: err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData);
1802:
1803: if (err == noErr)
1804: err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize);
1805: }
1806: else { // HFS Plus volume
1807: HFSPlusExtentRecord foundData; // The extent data actually found
1808:
1809: BlockMoveData(extentFileKey, &btIterator.key, sizeof(HFSPlusExtentKey));
1810:
1811: btIterator.hint.index = 0;
1812: btIterator.hint.nodeNum = extentBTreeHint;
1813:
1814: btRecord.bufferAddress = &foundData;
1815: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
1816: btRecord.itemCount = 1;
1817:
1818: err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord,
1819: &btRecordSize, &btIterator);
1820:
1821: if (err == noErr) {
1822: BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
1823: err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize);
1824: }
1825: }
1826: }
1827:
1828: return err;
1829: }
1830:
1831:
1832:
1833: void HFSToHFSPlusExtents(
1834: const HFSExtentRecord oldExtents,
1835: HFSPlusExtentRecord newExtents)
1836: {
1837: UInt32 i;
1838:
1839: // copy the first 3 extents
1840: newExtents[0].startBlock = oldExtents[0].startBlock;
1841: newExtents[0].blockCount = oldExtents[0].blockCount;
1842: newExtents[1].startBlock = oldExtents[1].startBlock;
1843: newExtents[1].blockCount = oldExtents[1].blockCount;
1844: newExtents[2].startBlock = oldExtents[2].startBlock;
1845: newExtents[2].blockCount = oldExtents[2].blockCount;
1846:
1847: // zero out the remaining ones
1848: for (i = 3; i < kHFSPlusExtentDensity; ++i)
1849: {
1850: newExtents[i].startBlock = 0;
1851: newExtents[i].blockCount = 0;
1852: }
1853: }
1854:
1855:
1856:
1857: OSErr HFSPlusToHFSExtents(
1858: const HFSPlusExtentRecord oldExtents,
1859: HFSExtentRecord newExtents)
1860: {
1861: OSErr err;
1862:
1863: err = noErr;
1864:
1865: // copy the first 3 extents
1866: newExtents[0].startBlock = oldExtents[0].startBlock;
1867: newExtents[0].blockCount = oldExtents[0].blockCount;
1868: newExtents[1].startBlock = oldExtents[1].startBlock;
1869: newExtents[1].blockCount = oldExtents[1].blockCount;
1870: newExtents[2].startBlock = oldExtents[2].startBlock;
1871: newExtents[2].blockCount = oldExtents[2].blockCount;
1872:
1873: #if DEBUG_BUILD
1874: if (oldExtents[3].startBlock || oldExtents[3].blockCount) {
1875: DebugStr("\pExtentRecord with > 3 extents is invalid for HFS");
1876: err = fsDSIntErr;
1877: }
1878: #endif
1879:
1880: return err;
1881: }
1882:
1883:
1884:
1885:
1886: OSErr GetFCBExtentRecord(
1887: const FCB *fcb,
1888: HFSPlusExtentRecord extents)
1889: {
1890:
1891: BlockMoveData(fcb->fcbExtents, extents, sizeof(HFSPlusExtentRecord));
1892:
1893: return noErr;
1894: }
1895:
1896:
1897:
1898: //�������������������������������������������������������������������������������
1899: // Routine: MapFileBlockFromFCB
1900: //
1901: // Function: Determine if the given file offset is within the set of extents
1902: // stored in the FCB. If so, return the file allocation
1903: // block number of the start of the extent, volume allocation block number
1904: // of the start of the extent, and file allocation block number immediately
1905: // following the extent.
1906: //
1907: // Input: vcb - the volume containing the extents
1908: // fcb - the file that owns the extents
1909: // offset - desired offset in bytes
1910: //
1911: // Output: firstFABN - file alloc block number of start of extent
1912: // firstBlock - volume alloc block number of start of extent
1913: // nextFABN - file alloc block number of next extent
1914: //
1915: // Result: noErr = ok
1916: // fxRangeErr = beyond FCB's extents
1917: //�������������������������������������������������������������������������������
1918: static OSErr MapFileBlockFromFCB(
1919: const ExtendedVCB *vcb,
1920: const FCB *fcb,
1921: SInt64 offset, // Desired offset in bytes from start of file
1922: UInt32 *firstFABN, // FABN of first block of found extent
1923: UInt32 *firstBlock, // Corresponding allocation block number
1924: UInt32 *nextFABN) // FABN of block after end of extent
1925: {
1926: UInt32 index;
1927: UInt32 offsetBlocks;
1928:
1929: offsetBlocks = offset / vcb->blockSize;
1930:
1931: if (vcb->vcbSigWord == kHFSSigWord) {
1932: /* XXX SER Do we need to test for overflow values ??? */
1933: UInt16 blockCount;
1934: UInt16 currentFABN;
1935:
1936: currentFABN = 0;
1937:
1938: for (index=0; index<kHFSExtentDensity; index++) {
1939:
1940: blockCount = fcb->fcbExtents[index].blockCount;
1941:
1942: if (blockCount == 0)
1943: return fxRangeErr; // ran out of extents!
1944:
1945: // Is it in this extent?
1946: if (offsetBlocks < blockCount) {
1947: *firstFABN = currentFABN;
1948: *firstBlock = fcb->fcbExtents[index].startBlock;
1949: currentFABN += blockCount; // faster to add these as UInt16 first, then extend to UInt32
1950: *nextFABN = currentFABN;
1951: return noErr; // found the right extent
1952: }
1953:
1954: // Not in current extent, so adjust counters and loop again
1955: offsetBlocks -= blockCount;
1956: currentFABN += blockCount;
1957: }
1958: }
1959: else {
1960: UInt32 blockCount;
1961: UInt32 currentFABN;
1962:
1963: currentFABN = 0;
1964:
1965: for (index=0; index<kHFSPlusExtentDensity; index++) {
1966:
1967: blockCount = fcb->fcbExtents[index].blockCount;
1968:
1969: if (blockCount == 0)
1970: return fxRangeErr; // ran out of extents!
1971:
1972: // Is it in this extent?
1973: if (offsetBlocks < blockCount) {
1974: *firstFABN = currentFABN;
1975: *firstBlock = fcb->fcbExtents[index].startBlock;
1976: *nextFABN = currentFABN + blockCount;
1977: return noErr; // found the right extent
1978: }
1979:
1980: // Not in current extent, so adjust counters and loop again
1981: offsetBlocks -= blockCount;
1982: currentFABN += blockCount;
1983: }
1984: }
1985:
1986: // If we fall through here, the extent record was full, but the offset was
1987: // beyond those extents.
1988:
1989: return fxRangeErr;
1990: }
1991:
1992:
1993: //_________________________________________________________________________________
1994: //
1995: // Routine: ExtentsAreIntegral
1996: //
1997: // Purpose: Ensure that each extent can hold an integral number of nodes
1998: // Called by the NodesAreContiguous function
1999: //_________________________________________________________________________________
2000:
2001: static Boolean ExtentsAreIntegral(
2002: const HFSPlusExtentRecord extentRecord,
2003: UInt32 mask,
2004: UInt32 *blocksChecked,
2005: Boolean *checkedLastExtent)
2006: {
2007: UInt32 blocks;
2008: UInt32 extentIndex;
2009:
2010: *blocksChecked = 0;
2011: *checkedLastExtent = false;
2012:
2013: for(extentIndex = 0; extentIndex < kHFSPlusExtentDensity; extentIndex++)
2014: {
2015: blocks = extentRecord[extentIndex].blockCount;
2016:
2017: if ( blocks == 0 )
2018: {
2019: *checkedLastExtent = true;
2020: break;
2021: }
2022:
2023: *blocksChecked += blocks;
2024:
2025: if (blocks & mask)
2026: return false;
2027: }
2028:
2029: return true;
2030: }
2031:
2032:
2033: //_________________________________________________________________________________
2034: //
2035: // Routine: NodesAreContiguous
2036: //
2037: // Purpose: Ensure that all b-tree nodes are contiguous on disk
2038: // Called by BTOpenPath during volume mount
2039: //_________________________________________________________________________________
2040:
2041: Boolean NodesAreContiguous(
2042: ExtendedVCB *vcb,
2043: FCB *fcb,
2044: UInt32 nodeSize)
2045: {
2046: UInt32 mask;
2047: UInt32 startBlock;
2048: UInt32 blocksChecked;
2049: UInt32 hint;
2050: HFSPlusExtentKey key;
2051: HFSPlusExtentRecord extents;
2052: OSErr result;
2053: Boolean lastExtentReached;
2054:
2055:
2056: if (vcb->blockSize >= nodeSize)
2057: return TRUE;
2058:
2059: mask = (nodeSize / vcb->blockSize) - 1;
2060:
2061: // check the local extents
2062: (void) GetFCBExtentRecord(fcb, extents);
2063: if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
2064: return FALSE;
2065:
2066: if (lastExtentReached || (blocksChecked * vcb->blockSize) >= fcb->fcbPLen)
2067: return TRUE;
2068:
2069: startBlock = blocksChecked;
2070:
2071: // check the overflow extents (if any)
2072: while ( !lastExtentReached )
2073: {
2074: result = FindExtentRecord(vcb, kDataForkType, H_FILEID(fcb), startBlock, FALSE, &key, extents, &hint);
2075: if (result) break;
2076:
2077: if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
2078: return FALSE;
2079:
2080: startBlock += blocksChecked;
2081: }
2082:
2083: return TRUE;
2084: }
2085:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.