|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: File: FileExtentMapping.c
27:
28: Contains: xxx put contents here xxx
29:
30: Version: HFS Plus 1.0
31:
32: Written by: Dave Heller, Mark Day
33:
34: Copyright: � 1996-1998 by Apple Computer, Inc., all rights reserved.
35:
36: File Ownership:
37:
38: DRI: Mark Day
39:
40: Other Contact: xxx put other contact here xxx
41:
42: Technology: xxx put technology here xxx
43:
44: Writers:
45:
46: (DSH) Deric Horn
47: (msd) Mark Day
48: (djb) Don Brady
49:
50: Change History (most recent first):
51: <Rhap> 6/30/98 djb Add functions NodesAreContiguous and ExtentsAreIntegral (for radar #2249539).
52: <Rhap> 6/23/98 djb Changed DeallocFile to DeleteFile which now deletes the catalog record.
53: Fixed UpdateExtentRecord to pass correct fcb to Btree routines. Fixed
54: hfs+ bug in CreateExtentRecord (double dereference).
55: <Rhap> 5/20/98 djb In ExtendFileC don't lie about the peof! (radar #2230094).
56: <Rhap> 4/17/98 djb Add VCB locking.
57: <Rhap> 4/2/98 djb Switch over to real BTree interface (no more BTreeWrapper.c).
58: <Rhap> 3/31/98 djb Sync up with final HFSVolumes.h header file.
59:
60: <CS24> 1/23/98 msd Bug 2208024: AllocContig is actually allocating one extent even
61: though there is not enough contiguous space.
62: <CS23> 12/2/97 DSH GetFCBExtentRecord no longer static so DFA can use it.
63: <CS22> 10/20/97 msd When allocating more space for a file, do the clump size
64: calculations in ExtendFileC, not BlockAllocate. Undo change from
65: <CS18>.
66: <CS21> 10/17/97 msd Conditionalize DebugStrs.
67: <CS20> 10/16/97 msd Simplify the code path for MapFileBlockC (logical to physical
68: block mapping) in the typical case where the file isn't
69: fragmented so badly that it has extents in the extents B-tree.
70: Simplified some of the calculations for all cases.
71: <CS19> 10/13/97 DSH FindExtentRecord & DeleteExtentRecord are also being used by DFA
72: no longer static.
73: <CS18> 10/6/97 msd When extending a file, set the physical EOF to include any extra
74: space allocated due to a file's clump size.
75: <CS17> 9/19/97 msd Remove the MapLogicalToPhysical SPI. It was never used and is
76: not being tested anyway.
77: <CS16> 9/5/97 msd In CompareExtentKeys and CompareExtentKeysPlus, use the symbolic
78: constants for key length. Don't DebugStr unless DEBUG_BUILD is
79: set.
80: <CS15> 7/24/97 djb Add instrumentation to MapFileBlockC
81: <CS14> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
82: collision
83: <CS13> 7/15/97 DSH AdjEOF() mark the FCB as modified. (1664389)
84: <CS12> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
85: <CS11> 7/3/97 msd Bug #1663518. Remove DebugStr when setting the FCB extent record
86: for a volume control file.
87: <CS10> 6/27/97 msd Moved enum kFirstFileRefnum to FilesInternal.
88: <CS9> 6/24/97 djb Include "CatalogPrivate.h"
89: <CS8> 6/16/97 msd Finish implementation of CreateLargeFile SPI.
90: <CS7> 6/12/97 msd Add stub for CreateLargeFile SPI.
91: <CS6> 6/5/97 msd Add MapLogicalToPhysical.
92: <CS5> 6/2/97 msd In TruncateFileC, don't update the extent record unless it was
93: actually changed (prevents extra updates when truncating to the
94: end of the extent, and it is the last extent of the file.) Added
95: an AdjustEOF routine called by the assembly AdjEOF routine. It
96: copies the EOF, physical length, and extent information from one
97: FCB to all other FCBs for that fork.
98: <CS4> 5/20/97 DSH Removed const declaration in MapFileBlocC, const is benign when
99: passing by value, and SC requires it to match prototype.
100: <CS3> 5/15/97 msd Change enum kResourceForkType from -1 to 0xFF since it is now
101: unsigned. Change all forkType parameters to UInt8.
102: <CS2> 5/7/97 msd When checking for an unused extent descriptor, check the length,
103: not the starting block.
104: <CS1> 4/24/97 djb first checked in
105: <HFS25> 4/11/97 DSH use extended VCB fields catalogRefNum, and extentsRefNum.
106: <HFS24> 4/4/97 djb Get in sync with volume format changes.
107: <HFS23> 3/17/97 DSH Casting to compile with SC.
108: <HFS22> 2/26/97 msd Add instrumentation in ExtendFileC and TruncateFileC. In
109: CompareExtentKeys and CompareExtentKeysPlus, make sure the key
110: lengths are correct.
111: <HFS21> 2/5/97 msd The comparison with fsBTStartOfIterationErr didn't work because
112: the enum is an unsigned long; it is now casted to an OSErr
113: before comparing.
114: <HFS20> 1/31/97 msd In FindExtentRecord, turn an fsBTStartOfIterationErr error into
115: btNotFound.
116: <HFS19> 1/28/97 msd Fixed bug in MapFileBlockC where it returned the wrong number of
117: bytes available at the given block number. This could
118: potentially cause programs to read or write over other files.
119: <HFS18> 1/16/97 djb Extent key compare procs now return SInt32. Fixed
120: UpdateExtentRecord - it was passing a pointer to an ExtentKey
121: pointer.
122: <HFS17> 1/10/97 msd Change TruncateFileC to call DellocateFork when the new PEOF is
123: 0. Fixes a fxRangeErr returned when no extents existed.
124: <HFS16> 1/6/97 msd Previous change prevents extent records from being removed if
125: the files new PEOF is in the local (FCB/catalog) extents.
126: <HFS15> 1/3/97 djb Temp fix in TruncateFileC to prevent unwanted calls to
127: TruncateExtents.
128: <HFS14> 12/23/96 msd Previous change to SearchExtentFile didn't set up the outputs
129: for hint and key when the FCB extent record wasn't full.
130: <HFS13> 12/20/96 msd In SearchExtentFile, don't bother searching the extents file if
131: the FCB's extent record wasn't full, or if the FCB was for the
132: extents file itself. Modified SearchExtentRecord to return a
133: Boolean to indicate that the record was not full.
134: <HFS12> 12/19/96 DSH Changed refs from VCB to ExtendedVCB
135: <HFS11> 12/19/96 djb Updated for new B-tree Manager interface.
136: <HFS10> 12/12/96 djb Really use new SPI for GetCatalogNode.
137: <HFS9> 12/12/96 djb Use new Catalog SPI for GetCatalogNode. Added Mark's changes to
138: MapFileBlockC.
139: <HFS8> 12/11/96 msd TruncateFileC must always release extents, even if PEOF hasn't
140: changed (since allocation may have been rounded up due to clump
141: size).
142: <HFS7> 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
143: <HFS6> 12/4/96 DSH Precompiled headers
144: <HFS5> 11/26/96 msd Add an exported routine to grow the parallel FCB table to
145: accomodate the HFS+ ExtentRecord.
146: <HFS4> 11/26/96 msd Convert internal routines to use ExtentKey and ExtentRecord
147: (instead of the raw HFS structures).
148: <HFS3> 11/21/96 msd Added CompareExtentKeysPlus().
149: <HFS2> 11/20/96 msd Finish porting FXM to C.
150: <HFS1> 11/6/96 DKH first checked in
151:
152: */
153:
154:
155: #if ( PRAGMA_LOAD_SUPPORTED )
156: #pragma load PrecompiledHeaders
157: #else
158: #if TARGET_OS_MAC
159: #include <FSM.h>
160: #include <LowMem.h>
161: #include <LowMemPriv.h>
162: #include <Memory.h>
163: #include <stddef.h>
164: #include <Math64.h>
165: #else
166: #include "../../hfs.h"
167: #include "../headers/system/MacOSStubs.h"
168: #endif /* TARGET_OS_MAC */
169: #endif /* PRAGMA_LOAD_SUPPORTED */
170:
171: #if TARGET_OS_MAC
172: #include <Math64.h>
173: #endif
174: #include "../headers/HFSVolumes.h"
175: #include "../headers/FileMgrInternal.h"
176: #include "../headers/BTreesInternal.h"
177: #include "../headers/CatalogPrivate.h" // calling a private catalog routine (LocateCatalogNode)
178:
179: #include "../headers/system/HFSInstrumentation.h"
180:
181:
182: /*
183: ============================================================
184: Public (Exported) Routines:
185: ============================================================
186: DeAllocFile Deallocate all disk space allocated to a specified file.
187: Both forks are deallocated.
188:
189: ExtendFileC Allocate more space to a given file.
190:
191: CompareExtentKeys
192: Compare two extents file keys (a search key and a trial
193: key). Used by the BTree manager when searching for,
194: adding, or deleting keys in the extents file of an HFS
195: volume.
196:
197: CompareExtentKeysPlus
198: Compare two extents file keys (a search key and a trial
199: key). Used by the BTree manager when searching for,
200: adding, or deleting keys in the extents file of an HFS+
201: volume.
202:
203: MapFileBlockC Convert (map) an offset within a given file into a
204: physical disk address.
205:
206: TruncateFileC Truncates the disk space allocated to a file. The file
207: space is truncated to a specified new physical EOF, rounded
208: up to the next allocation block boundry. There is an option
209: to truncate to the end of the extent containing the new EOF.
210:
211: FlushExtentFile
212: Flush the extents file for a given volume.
213:
214: GrowParallelFCBs
215: Make sure the parallel FCB entries are big enough to support
216: the HFS+ ExtentRecord. If not, the array is grown and the
217: pre-existing data copied over.
218:
219: AdjustEOF
220: Copy EOF, physical length, and extent records from one FCB
221: to all other FCBs for that fork. This is used when a file is
222: grown or shrunk as the result of a Write, SetEOF, or Allocate.
223:
224: MapLogicalToPhysical
225: Map some position in a file to a volume block number. Also
226: returns the number of contiguous bytes that are mapped there.
227: This is a queued HFSDispatch call that does the equivalent of
228: MapFileBlockC, using a parameter block.
229:
230: ============================================================
231: Internal Routines:
232: ============================================================
233: FindExtentRecord
234: Search the extents BTree for a particular extent record.
235: SearchExtentFile
236: Search the FCB and extents file for an extent record that
237: contains a given file position (in bytes).
238: SearchExtentRecord
239: Search a given extent record to see if it contains a given
240: file position (in bytes). Used by SearchExtentFile.
241: ReleaseExtents
242: Deallocate all allocation blocks in all extents of an extent
243: data record.
244: TruncateExtents
245: Deallocate blocks and delete extent records for all allocation
246: blocks beyond a certain point in a file. The starting point
247: must be the first file allocation block for some extent record
248: for the file.
249: DeallocateFork
250: Deallocate all allocation blocks belonging to a given fork.
251: UpdateExtentRecord
252: If the extent record came from the extents file, write out
253: the updated record; otherwise, copy the updated record into
254: the FCB resident extent record. If the record has no extents,
255: and was in the extents file, then delete the record instead.
256: */
257:
258: enum
259: {
260: kTwoGigabytes = (UInt32) 0x80000000,
261:
262: kDataForkType = 0,
263: kResourceForkType = 0xFF,
264:
265: kPreviousRecord = -1,
266:
267: kSectorSize = 512 // Size of a physical sector
268: };
269:
270: static void ExtDataRecToExtents(
271: const HFSExtentRecord oldExtents,
272: HFSPlusExtentRecord newExtents);
273:
274: static OSErr ExtentsToExtDataRec(
275: const HFSPlusExtentRecord oldExtents,
276: HFSExtentRecord newExtents);
277:
278: OSErr FindExtentRecord(
279: const ExtendedVCB *vcb,
280: UInt8 forkType,
281: UInt32 fileID,
282: UInt32 startBlock,
283: Boolean allowPrevious,
284: HFSPlusExtentKey *foundKey,
285: HFSPlusExtentRecord foundData,
286: UInt32 *foundHint);
287:
288: OSErr DeleteExtentRecord(
289: const ExtendedVCB *vcb,
290: UInt8 forkType,
291: UInt32 fileID,
292: UInt32 startBlock);
293:
294: static OSErr CreateExtentRecord(
295: const ExtendedVCB *vcb,
296: HFSPlusExtentKey *key,
297: HFSPlusExtentRecord extents,
298: UInt32 *hint);
299:
300: static ExtendedFCB *GetExtendedFCB(const FCB *fcb);
301:
302: OSErr GetFCBExtentRecord(
303: const ExtendedVCB *vcb,
304: const FCB *fcb,
305: HFSPlusExtentRecord extents);
306:
307: static OSErr SetFCBExtentRecord(
308: const ExtendedVCB *vcb,
309: FCB *fcb,
310: const HFSPlusExtentRecord extents);
311:
312: static OSErr SearchExtentFile(
313: const ExtendedVCB *vcb,
314: const FCB *fcb,
315: UInt32 filePosition,
316: HFSPlusExtentKey *foundExtentKey,
317: HFSPlusExtentRecord foundExtentData,
318: UInt32 *foundExtentDataIndex,
319: UInt32 *extentBTreeHint,
320: UInt32 *endingFABNPlusOne );
321:
322: static OSErr SearchExtentRecord(
323: const ExtendedVCB *vcb,
324: UInt32 searchFABN,
325: const HFSPlusExtentRecord extentData,
326: UInt32 extentDataStartFABN,
327: UInt32 *foundExtentDataOffset,
328: UInt32 *endingFABNPlusOne,
329: Boolean *noMoreExtents);
330:
331: static OSErr ReleaseExtents(
332: ExtendedVCB *vcb,
333: const HFSPlusExtentRecord extentRecord,
334: UInt32 *numReleasedAllocationBlocks,
335: Boolean *releasedLastExtent);
336:
337: static OSErr DeallocateFork(
338: ExtendedVCB *vcb,
339: HFSCatalogNodeID fileID,
340: UInt8 forkType,
341: HFSPlusExtentRecord catalogExtents);
342:
343: static OSErr TruncateExtents(
344: ExtendedVCB *vcb,
345: UInt8 forkType,
346: UInt32 fileID,
347: UInt32 startBlock);
348:
349: static OSErr UpdateExtentRecord (
350: const ExtendedVCB *vcb,
351: FCB *fcb,
352: const HFSPlusExtentKey *extentFileKey,
353: const HFSPlusExtentRecord extentData,
354: UInt32 extentBTreeHint);
355:
356: static OSErr MapFileBlockFromFCB(
357: const ExtendedVCB *vcb,
358: const FCB *fcb,
359: UInt32 offset, // Desired offset in bytes from start of file
360: UInt32 *firstFABN, // FABN of first block of found extent
361: UInt32 *firstBlock, // Corresponding allocation block number
362: UInt32 *nextFABN); // FABN of block after end of extent
363:
364: static Boolean ExtentsAreIntegral(
365: const HFSPlusExtentRecord extentRecord,
366: UInt32 mask,
367: UInt32 *blocksChecked,
368: Boolean *checkedLastExtent);
369:
370: //_________________________________________________________________________________
371: //
372: // Routine: FindExtentRecord
373: //
374: // Purpose: Search the extents BTree for an extent record matching the given
375: // FileID, fork, and starting file allocation block number.
376: //
377: // Inputs:
378: // vcb Volume to search
379: // forkType 0 = data fork, -1 = resource fork
380: // fileID File's FileID (CatalogNodeID)
381: // startBlock Starting file allocation block number
382: // allowPrevious If the desired record isn't found and this flag is set,
383: // then see if the previous record belongs to the same fork.
384: // If so, then return it.
385: //
386: // Outputs:
387: // foundKey The key data for the record actually found
388: // foundData The extent record actually found (NOTE: on an HFS volume, the
389: // fourth entry will be zeroes.
390: // foundHint The BTree hint to find the node again
391: //_________________________________________________________________________________
392: OSErr FindExtentRecord(
393: const ExtendedVCB *vcb,
394: UInt8 forkType,
395: UInt32 fileID,
396: UInt32 startBlock,
397: Boolean allowPrevious,
398: HFSPlusExtentKey *foundKey,
399: HFSPlusExtentRecord foundData,
400: UInt32 *foundHint)
401: {
402: FCB * fcb;
403: BTreeIterator btIterator;
404: FSBufferDescriptor btRecord;
405: OSErr err;
406: UInt16 btRecordSize;
407:
408: err = noErr;
409: *foundHint = 0;
410: fcb = GetFileControlBlock(vcb->extentsRefNum);
411:
412: (void) BTInvalidateHint(&btIterator);
413:
414: if (vcb->vcbSigWord == kHFSSigWord) {
415: HFSExtentKey * extentKeyPtr;
416: HFSExtentRecord extentData;
417:
418: extentKeyPtr = (HFSExtentKey*) &btIterator.key;
419: extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
420: extentKeyPtr->forkType = forkType;
421: extentKeyPtr->fileID = fileID;
422: extentKeyPtr->startBlock = startBlock;
423:
424: btRecord.bufferAddress = &extentData;
425: btRecord.itemSize = sizeof(HFSExtentRecord);
426: btRecord.itemCount = 1;
427:
428: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
429:
430: if (err == btNotFound && allowPrevious) {
431: err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
432:
433: // A previous record may not exist, so just return btNotFound (like we would if
434: // it was for the wrong file/fork).
435: if (err == (OSErr) fsBTStartOfIterationErr) //�� fsBTStartOfIterationErr is type unsigned long
436: err = btNotFound;
437:
438: if (err == noErr) {
439: // Found a previous record. Does it belong to the same fork of the same file?
440: if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
441: err = btNotFound;
442: }
443: }
444:
445: if (err == noErr) {
446: UInt16 i;
447:
448: // Copy the found key back for the caller
449: foundKey->keyLength = kHFSPlusExtentKeyMaximumLength;
450: foundKey->forkType = extentKeyPtr->forkType;
451: foundKey->pad = 0;
452: foundKey->fileID = extentKeyPtr->fileID;
453: foundKey->startBlock = extentKeyPtr->startBlock;
454:
455: // Copy the found data back for the caller
456: foundData[0].startBlock = extentData[0].startBlock;
457: foundData[0].blockCount = extentData[0].blockCount;
458: foundData[1].startBlock = extentData[1].startBlock;
459: foundData[1].blockCount = extentData[1].blockCount;
460: foundData[2].startBlock = extentData[2].startBlock;
461: foundData[2].blockCount = extentData[2].blockCount;
462:
463: for (i = 3; i < kHFSPlusExtentDensity; ++i)
464: {
465: foundData[i].startBlock = 0;
466: foundData[i].blockCount = 0;
467: }
468: }
469: }
470: else { // HFS Plus volume
471: HFSPlusExtentKey * extentKeyPtr;
472: HFSPlusExtentRecord extentData;
473:
474: extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key;
475: extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
476: extentKeyPtr->forkType = forkType;
477: extentKeyPtr->pad = 0;
478: extentKeyPtr->fileID = fileID;
479: extentKeyPtr->startBlock = startBlock;
480:
481: btRecord.bufferAddress = &extentData;
482: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
483: btRecord.itemCount = 1;
484:
485: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
486:
487: if (err == btNotFound && allowPrevious) {
488: err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
489:
490: // A previous record may not exist, so just return btNotFound (like we would if
491: // it was for the wrong file/fork).
492: if (err == (OSErr) fsBTStartOfIterationErr) //�� fsBTStartOfIterationErr is type unsigned long
493: err = btNotFound;
494:
495: if (err == noErr) {
496: // Found a previous record. Does it belong to the same fork of the same file?
497: if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
498: err = btNotFound;
499: }
500: }
501:
502: if (err == noErr) {
503: // Copy the found key back for the caller
504: BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
505: // Copy the found data back for the caller
506: BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
507: }
508: }
509:
510: *foundHint = btIterator.hint.nodeNum;
511: return err;
512: }
513:
514:
515:
516: static OSErr CreateExtentRecord(
517: const ExtendedVCB *vcb,
518: HFSPlusExtentKey *key,
519: HFSPlusExtentRecord extents,
520: UInt32 *hint)
521: {
522: BTreeIterator btIterator;
523: FSBufferDescriptor btRecord;
524: UInt16 btRecordSize;
525: OSErr err;
526:
527: err = noErr;
528: *hint = 0;
529: (void) BTInvalidateHint(&btIterator);
530:
531: if (vcb->vcbSigWord == kHFSSigWord) {
532: HFSExtentKey * keyPtr;
533: HFSExtentRecord data;
534:
535: btRecordSize = sizeof(HFSExtentRecord);
536: btRecord.bufferAddress = &data;
537: btRecord.itemSize = btRecordSize;
538: btRecord.itemCount = 1;
539:
540: keyPtr = (HFSExtentKey*) &btIterator.key;
541: keyPtr->keyLength = kHFSExtentKeyMaximumLength;
542: keyPtr->forkType = key->forkType;
543: keyPtr->fileID = key->fileID;
544: keyPtr->startBlock = key->startBlock;
545:
546: err = ExtentsToExtDataRec(extents, data);
547: }
548: else { // HFS Plus volume
549: btRecordSize = sizeof(HFSPlusExtentRecord);
550: btRecord.bufferAddress = extents;
551: btRecord.itemSize = btRecordSize;
552: btRecord.itemCount = 1;
553:
554: BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey));
555: }
556:
557: if (err == noErr)
558: err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize);
559:
560: if (err == noErr)
561: *hint = btIterator.hint.nodeNum;
562:
563: return err;
564: }
565:
566:
567: OSErr DeleteExtentRecord(
568: const ExtendedVCB *vcb,
569: UInt8 forkType,
570: UInt32 fileID,
571: UInt32 startBlock)
572: {
573: BTreeIterator btIterator;
574: OSErr err;
575:
576: err = noErr;
577: (void) BTInvalidateHint(&btIterator);
578:
579: if (vcb->vcbSigWord == kHFSSigWord) {
580: HFSExtentKey * keyPtr;
581:
582: keyPtr = (HFSExtentKey*) &btIterator.key;
583: keyPtr->keyLength = kHFSExtentKeyMaximumLength;
584: keyPtr->forkType = forkType;
585: keyPtr->fileID = fileID;
586: keyPtr->startBlock = startBlock;
587: }
588: else { // HFS Plus volume
589: HFSPlusExtentKey * keyPtr;
590:
591: keyPtr = (HFSPlusExtentKey*) &btIterator.key;
592: keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
593: keyPtr->forkType = forkType;
594: keyPtr->pad = 0;
595: keyPtr->fileID = fileID;
596: keyPtr->startBlock = startBlock;
597: }
598:
599: err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator);
600:
601: return err;
602: }
603:
604:
605:
606: //_________________________________________________________________________________
607: //
608: // Routine: MapFileBlock
609: //
610: // Function: Maps a file position into a physical disk address.
611: //
612: // Input: A2.L - VCB pointer
613: // (A1,D1.W) - FCB pointer
614: // D4.L - number of bytes desired
615: // D5.L - file position (byte address)
616: //
617: // Output: D3.L - physical start block
618: // D6.L - number of contiguous bytes available (up to D4 bytes)
619: // D0.L - result code <01Oct85>
620: // 0 = ok
621: // FXRangeErr = file position beyond mapped range <17Oct85>
622: // FXOvFlErr = extents file overflow <17Oct85>
623: // other = error <17Oct85>
624: //
625: // Called By: Log2Phys (read/write in place), Cache (map a file block).
626: //_________________________________________________________________________________
627:
628: OSErr MapFileBlockC (
629: ExtendedVCB *vcb, // volume that file resides on
630: FCB *fcb, // FCB of file
631: UInt32 numberOfBytes, // number of contiguous bytes desired
632: UInt32 offset, // starting offset within file (in bytes)
633: UInt32 *startSector, // first 512-byte sector (NOT an allocation block)
634: UInt32 *availableBytes) // number of contiguous bytes (up to numberOfBytes)
635: {
636: OSErr err;
637: UInt32 allocBlockSize; // Size of the volume's allocation block
638: HFSPlusExtentKey foundKey;
639: HFSPlusExtentRecord foundData;
640: UInt32 foundIndex;
641: UInt32 hint;
642: UInt32 firstFABN; // file allocation block of first block in found extent
643: UInt32 nextFABN; // file allocation block of block after end of found extent
644: UInt32 dataEnd; // (offset) end of range that is contiguous
645: UInt32 sectorsPerBlock; // Number of sectors per allocation block
646: UInt32 startBlock; // volume allocation block corresponding to firstFABN
647: UInt32 temp;
648:
649:
650: LogStartTime(kTraceMapFileBlock);
651:
652: allocBlockSize = vcb->blockSize;
653:
654: err = MapFileBlockFromFCB(vcb, fcb, offset, &firstFABN, &startBlock, &nextFABN);
655: if (err != noErr) {
656: err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
657: if (err == noErr) {
658: startBlock = foundData[foundIndex].startBlock;
659: firstFABN = nextFABN - foundData[foundIndex].blockCount;
660: }
661: }
662:
663: if (err != noErr)
664: {
665: LogEndTime(kTraceMapFileBlock, err);
666:
667: return err;
668: }
669:
670: //
671: // Determine the end of the available space. It will either be the end of the extent,
672: // or the file's PEOF, whichever is smaller.
673: //
674: dataEnd = nextFABN * allocBlockSize; // Assume valid data through end of this extent
675: if (fcb->fcbPLen < dataEnd) // Is PEOF shorter?
676: dataEnd = fcb->fcbPLen; // Yes, so only map up to PEOF
677:
678: // Compute the number of sectors in an allocation block
679: sectorsPerBlock = allocBlockSize / kSectorSize; // sectors per allocation block
680:
681: //
682: // Compute the absolute sector number that contains the offset of the given file
683: //
684: temp = offset - (firstFABN * allocBlockSize); // offset in bytes from start of the extent
685: temp /= kSectorSize; // offset in sectors from start of the extent
686: temp += startBlock * sectorsPerBlock; // offset in sectors from start of allocation block space
687: temp += vcb->vcbAlBlSt; // offset in sectors from start of volume
688:
689: // Return the desired sector for file position "offset"
690: *startSector = temp;
691:
692: //
693: // Determine the number of contiguous bytes until the end of the extent
694: // (or the amount they asked for, whichever comes first).
695: //
696: temp = dataEnd - offset;
697: if (temp > numberOfBytes)
698: *availableBytes = numberOfBytes; // more there than they asked for, so pin the output
699: else
700: *availableBytes = temp;
701:
702: LogEndTime(kTraceMapFileBlock, noErr);
703:
704: return noErr;
705: }
706:
707:
708: //�������������������������������������������������������������������������������
709: // Routine: ReleaseExtents
710: //
711: // Function: Release the extents of a single extent data record.
712: //�������������������������������������������������������������������������������
713:
714: static OSErr ReleaseExtents(
715: ExtendedVCB *vcb,
716: const HFSPlusExtentRecord extentRecord,
717: UInt32 *numReleasedAllocationBlocks,
718: Boolean *releasedLastExtent)
719: {
720: UInt32 extentIndex;
721: UInt32 numberOfExtents;
722: OSErr err = noErr;
723:
724: *numReleasedAllocationBlocks = 0;
725: *releasedLastExtent = false;
726:
727: if (vcb->vcbSigWord == kHFSPlusSigWord)
728: numberOfExtents = kHFSPlusExtentDensity;
729: else
730: numberOfExtents = kHFSExtentDensity;
731:
732: for( extentIndex = 0; extentIndex < numberOfExtents; extentIndex++)
733: {
734: UInt32 numAllocationBlocks;
735:
736: // Loop over the extent record and release the blocks associated with each extent.
737:
738: numAllocationBlocks = extentRecord[extentIndex].blockCount;
739: if ( numAllocationBlocks == 0 )
740: {
741: *releasedLastExtent = true;
742: break;
743: }
744:
745: err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks );
746: if ( err != noErr )
747: break;
748:
749: *numReleasedAllocationBlocks += numAllocationBlocks; // bump FABN to beg of next extent
750: }
751:
752: return( err );
753: }
754:
755:
756:
757: //�������������������������������������������������������������������������������
758: // Routine: TruncateExtents
759: //
760: // Purpose: Delete extent records whose starting file allocation block number
761: // is greater than or equal to a given starting block number. The
762: // allocation blocks represented by the extents are deallocated.
763: //
764: // Inputs:
765: // vcb Volume to operate on
766: // fileID Which file to operate on
767: // startBlock Starting file allocation block number for first extent
768: // record to delete.
769: //�������������������������������������������������������������������������������
770:
771: static OSErr TruncateExtents(
772: ExtendedVCB *vcb,
773: UInt8 forkType,
774: UInt32 fileID,
775: UInt32 startBlock)
776: {
777: OSErr err;
778: UInt32 numberExtentsReleased;
779: Boolean releasedLastExtent;
780: UInt32 hint;
781: HFSPlusExtentKey key;
782: HFSPlusExtentRecord extents;
783:
784: while (true) {
785: err = FindExtentRecord(vcb, forkType, fileID, startBlock, false, &key, extents, &hint);
786: if (err != noErr) {
787: if (err == btNotFound)
788: err = noErr;
789: break;
790: }
791:
792: err = ReleaseExtents( vcb, extents, &numberExtentsReleased, &releasedLastExtent );
793: if (err != noErr) break;
794:
795: err = DeleteExtentRecord(vcb, forkType, fileID, startBlock);
796: if (err != noErr) break;
797:
798: startBlock += numberExtentsReleased;
799: }
800:
801: return err;
802: }
803:
804:
805:
806: //�������������������������������������������������������������������������������
807: // Routine: DeallocateFork
808: //
809: // Function: De-allocates all disk space allocated to a specified fork.
810: //�������������������������������������������������������������������������������
811:
812: static OSErr DeallocateFork(
813: ExtendedVCB *vcb,
814: HFSCatalogNodeID fileID,
815: UInt8 forkType,
816: HFSPlusExtentRecord catalogExtents)
817: {
818: OSErr err;
819: UInt32 numReleasedAllocationBlocks;
820: Boolean releasedLastExtent;
821:
822: // Release the catalog extents
823: err = ReleaseExtents( vcb, catalogExtents, &numReleasedAllocationBlocks, &releasedLastExtent );
824: // Release the extra extents, if present
825: if (err == noErr && !releasedLastExtent)
826: err = TruncateExtents(vcb, forkType, fileID, numReleasedAllocationBlocks);
827:
828: return( err );
829: }
830:
831: //�������������������������������������������������������������������������������
832: // Routine: FlushExtentFile
833: //
834: // Function: Flushes the extent file for a specified volume
835: //�������������������������������������������������������������������������������
836:
837: OSErr FlushExtentFile( ExtendedVCB *vcb )
838: {
839: FCB * fcb;
840: OSErr err;
841:
842: fcb = GetFileControlBlock(vcb->extentsRefNum);
843: err = BTFlushPath(fcb);
844: if ( err == noErr )
845: {
846: // If the FCB for the extent "file" is dirty, mark the VCB as dirty.
847:
848: if ((fcb->fcbFlags && fcbModifiedMask) != 0)
849: {
850: MarkVCBDirty( vcb );
851: err = FlushVolumeControlBlock( vcb );
852: }
853: }
854:
855: return( err );
856: }
857:
858: //-------------------------------------------------------------------------------
859: // Routine: DeleteFile
860: //
861: // Function: De-allocates all disk space allocated to a specified file
862: // including the space used by the catalog (ie the catalog record).
863: // The space occupied by both forks is also deallocated.
864: //
865: //-------------------------------------------------------------------------------
866:
867: OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint )
868: {
869: OSErr err;
870: OSErr errDF, errRF;
871: CatalogNodeData catalogData;
872: FSSpec fileSpec; /* 264 bytes */
873:
874: // Find catalog data in catalog
875: err = GetCatalogNode( vcb, parDirID, catalogName, catalogHint, &fileSpec, &catalogData, &catalogHint);
876: if( err != noErr )
877: goto Exit;
878:
879: // Check to make sure record is for a file
880: if ( catalogData.nodeType != kCatalogFileNode )
881: {
882: err = notAFileErr;
883: goto Exit;
884: }
885:
886: //
887: // Always delete the Catalog record first (to minimize disk corruption)
888: //
889: err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint);
890: if( err != noErr )
891: goto Exit;
892:
893: //
894: // Note: we don't report errors from DeallocateFork since the
895: // file no longer exists (since DeleteCatalogNode succeeded).
896: // Any errors mean that there are possibly some orphaned disk
897: // blocks but from the clients perspective the file was deleted.
898: //
899:
900: // Deallocate data fork extents
901: errDF = DeallocateFork( vcb, catalogData.nodeID, kDataForkType, catalogData.dataExtents );
902:
903: // Deallocate resource fork extents
904: errRF = DeallocateFork( vcb, catalogData.nodeID, kResourceForkType, catalogData.rsrcExtents );
905:
906: if ((errDF | errRF) == 0)
907: (void) FlushExtentFile( vcb );
908:
909: Exit:
910:
911: return( err );
912: }
913:
914: //�������������������������������������������������������������������������������
915: // Routine: CompareExtentKeys
916: //
917: // Function: Compares two extent file keys (a search key and a trial key) for
918: // an HFS volume.
919: //�������������������������������������������������������������������������������
920:
921: SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey )
922: {
923: SInt32 result; // � 1
924:
925: #if DEBUG_BUILD
926: if (searchKey->keyLength != kHFSExtentKeyMaximumLength)
927: DebugStr("\pHFS: search Key is wrong length");
928: if (trialKey->keyLength != kHFSExtentKeyMaximumLength)
929: DebugStr("\pHFS: trial Key is wrong length");
930: #endif
931:
932: result = -1; // assume searchKey < trialKey
933:
934: if (searchKey->fileID == trialKey->fileID) {
935: //
936: // FileNum's are equal; compare fork types
937: //
938: if (searchKey->forkType == trialKey->forkType) {
939: //
940: // Fork types are equal; compare allocation block number
941: //
942: if (searchKey->startBlock == trialKey->startBlock) {
943: //
944: // Everything is equal
945: //
946: result = 0;
947: }
948: else {
949: //
950: // Allocation block numbers differ; determine sign
951: //
952: if (searchKey->startBlock > trialKey->startBlock)
953: result = 1;
954: }
955: }
956: else {
957: //
958: // Fork types differ; determine sign
959: //
960: if (searchKey->forkType > trialKey->forkType)
961: result = 1;
962: }
963: }
964: else {
965: //
966: // FileNums differ; determine sign
967: //
968: if (searchKey->fileID > trialKey->fileID)
969: result = 1;
970: }
971:
972: return( result );
973: }
974:
975:
976:
977: //�������������������������������������������������������������������������������
978: // Routine: CompareExtentKeysPlus
979: //
980: // Function: Compares two extent file keys (a search key and a trial key) for
981: // an HFS volume.
982: //�������������������������������������������������������������������������������
983:
984: SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey )
985: {
986: SInt32 result; // � 1
987:
988: #if DEBUG_BUILD
989: if (searchKey->keyLength != kHFSPlusExtentKeyMaximumLength)
990: DebugStr("\pHFS: search Key is wrong length");
991: if (trialKey->keyLength != kHFSPlusExtentKeyMaximumLength)
992: DebugStr("\pHFS: trial Key is wrong length");
993: #endif
994:
995: result = -1; // assume searchKey < trialKey
996:
997: if (searchKey->fileID == trialKey->fileID) {
998: //
999: // FileNum's are equal; compare fork types
1000: //
1001: if (searchKey->forkType == trialKey->forkType) {
1002: //
1003: // Fork types are equal; compare allocation block number
1004: //
1005: if (searchKey->startBlock == trialKey->startBlock) {
1006: //
1007: // Everything is equal
1008: //
1009: result = 0;
1010: }
1011: else {
1012: //
1013: // Allocation block numbers differ; determine sign
1014: //
1015: if (searchKey->startBlock > trialKey->startBlock)
1016: result = 1;
1017: }
1018: }
1019: else {
1020: //
1021: // Fork types differ; determine sign
1022: //
1023: if (searchKey->forkType > trialKey->forkType)
1024: result = 1;
1025: }
1026: }
1027: else {
1028: //
1029: // FileNums differ; determine sign
1030: //
1031: if (searchKey->fileID > trialKey->fileID)
1032: result = 1;
1033: }
1034:
1035: return( result );
1036: }
1037:
1038:
1039:
1040: //_________________________________________________________________________________
1041: //
1042: // Routine: Extendfile
1043: //
1044: // Function: Extends the disk space allocated to a file.
1045: //
1046: // Input: A2.L - VCB pointer
1047: // A1.L - pointer to FCB array
1048: // D1.W - file refnum
1049: // D3.B - option flags
1050: // kEFContigMask - force contiguous allocation
1051: // kEFAllMask - allocate all requested bytes or none
1052: // NOTE: You may not set both options.
1053: // D4.L - number of additional bytes to allocate
1054: //
1055: // Output: D0.W - result code
1056: // 0 = ok
1057: // -n = IO error
1058: // D6.L - number of bytes allocated
1059: //
1060: // Called by: FileAloc,FileWrite,SetEof
1061: //
1062: // Note: ExtendFile updates the PEOF in the FCB.
1063: //_________________________________________________________________________________
1064:
1065: OSErr ExtendFileC (
1066: ExtendedVCB *vcb, // volume that file resides on
1067: FCB *fcb, // FCB of file to truncate
1068: UInt32 bytesToAdd, // number of bytes to allocate
1069: UInt32 flags, // EFContig and/or EFAll
1070: UInt32 *actualBytesAdded) // number of bytes actually allocated
1071: {
1072: OSErr err;
1073: UInt32 volumeBlockSize;
1074: UInt32 blocksToAdd;
1075: UInt32 peof;
1076: UInt32 bytesThisExtent;
1077: HFSPlusExtentKey foundKey;
1078: HFSPlusExtentRecord foundData;
1079: UInt32 foundIndex;
1080: UInt32 hint;
1081: UInt32 nextBlock;
1082: UInt32 startBlock;
1083: Boolean allOrNothing;
1084: Boolean forceContig;
1085: Boolean wantContig;
1086: UInt32 actualStartBlock;
1087: UInt32 actualNumBlocks;
1088: UInt32 previousPEOF;
1089: UInt32 numExtentsPerRecord;
1090: UInt32 maximumBytes;
1091:
1092:
1093: #if HFSInstrumentation
1094: InstTraceClassRef trace;
1095: InstEventTag eventTag;
1096: InstDataDescriptorRef traceDescriptor;
1097: FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars();
1098:
1099: traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
1100:
1101: err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:ExtendFileC", 'hfs+', kInstEnableClassMask, &trace);
1102: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
1103:
1104: eventTag = InstCreateEventTag();
1105: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
1106: #endif
1107:
1108: *actualBytesAdded = 0;
1109: volumeBlockSize = vcb->blockSize;
1110: allOrNothing = ((flags & kEFAllMask) != 0);
1111: forceContig = ((flags & kEFContigMask) != 0);
1112: previousPEOF = fcb->fcbPLen;
1113:
1114: if (vcb->vcbSigWord == kHFSPlusSigWord)
1115: numExtentsPerRecord = kHFSPlusExtentDensity;
1116: else
1117: numExtentsPerRecord = kHFSExtentDensity;
1118:
1119: //
1120: // Make sure the request and new PEOF are less than 2GB.
1121: //
1122: if (bytesToAdd >= (UInt32) kTwoGigabytes)
1123: goto Overflow;
1124: if ((fcb->fcbPLen + bytesToAdd) >= (UInt32) kTwoGigabytes)
1125: goto Overflow;
1126: //
1127: // Determine how many blocks need to be allocated.
1128: // Round up the number of desired bytes to add.
1129: //
1130: blocksToAdd = DivideAndRoundUp(bytesToAdd, volumeBlockSize);
1131: bytesToAdd = blocksToAdd * volumeBlockSize;
1132:
1133: //
1134: // If the file's clump size is larger than the allocation block size,
1135: // then set the maximum number of bytes to the requested number of bytes
1136: // rounded up to a multiple of the clump size.
1137: //
1138: if (fcb->fcbClmpSize > volumeBlockSize) {
1139: maximumBytes = DivideAndRoundUp(bytesToAdd, fcb->fcbClmpSize);
1140: maximumBytes *= fcb->fcbClmpSize;
1141: }
1142: else {
1143: maximumBytes = bytesToAdd;
1144: }
1145:
1146: //
1147: // Compute new physical EOF, rounded up to a multiple of a block.
1148: //
1149: if ((fcb->fcbPLen + bytesToAdd) >= (UInt32) kTwoGigabytes) // Too big?
1150: if (allOrNothing) // Yes, must they have it all?
1151: goto Overflow; // Yes, can't have it
1152: else {
1153: --blocksToAdd; // No, give give 'em one block less
1154: bytesToAdd -= volumeBlockSize;
1155: }
1156:
1157: //
1158: // If allocation is all-or-nothing, make sure there are
1159: // enough free blocks on the volume (quick test).
1160: //
1161: if (allOrNothing && blocksToAdd > vcb->freeBlocks) {
1162: err = dskFulErr;
1163: goto ErrorExit;
1164: }
1165:
1166: //
1167: // See if there are already enough blocks allocated to the file.
1168: //
1169: peof = fcb->fcbPLen + bytesToAdd; // potential new PEOF
1170: err = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock);
1171: if (err == noErr) {
1172: // Enough blocks are already allocated. Just update the FCB to reflect the new length.
1173: fcb->fcbPLen = peof;
1174: fcb->fcbFlags |= fcbModifiedMask;
1175: goto Exit;
1176: }
1177: if (err != fxRangeErr) // Any real error?
1178: goto ErrorExit; // Yes, so exit immediately
1179:
1180: //
1181: // Adjust the PEOF to the end of the last extent.
1182: //
1183: peof = nextBlock * volumeBlockSize; // currently allocated PEOF
1184: bytesThisExtent = peof - fcb->fcbPLen;
1185: if (bytesThisExtent != 0) {
1186: fcb->fcbPLen = peof;
1187: fcb->fcbFlags |= fcbModifiedMask;
1188: bytesToAdd -= bytesThisExtent;
1189: }
1190:
1191: //
1192: // Allocate some more space.
1193: //
1194: // First try a contiguous allocation (of the whole amount).
1195: // If that fails, get whatever we can.
1196: // If forceContig, then take whatever we got
1197: // else, keep getting bits and pieces (non-contig)
1198: err = noErr;
1199: wantContig = true;
1200: do {
1201: startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
1202: err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks);
1203: if (err == dskFulErr) {
1204: if (forceContig)
1205: break; // AllocContig failed because not enough contiguous space
1206: if (wantContig) {
1207: // Couldn't get one big chunk, so get whatever we can.
1208: err = noErr;
1209: wantContig = false;
1210: continue;
1211: }
1212: if (actualNumBlocks != 0)
1213: err = noErr;
1214: }
1215: if (err == noErr) {
1216: #if HFSInstrumentation
1217: {
1218: struct {
1219: UInt32 fileID;
1220: UInt32 start;
1221: UInt32 count;
1222: UInt32 fabn;
1223: } x;
1224:
1225: x.fileID = fcb->fcbFlNm;
1226: x.start = actualStartBlock;
1227: x.count = actualNumBlocks;
1228: x.fabn = nextBlock;
1229:
1230: InstLogTraceEventWithDataStructure( trace, eventTag, kInstMiddleEvent, traceDescriptor,
1231: (UInt8 *) &x, sizeof(x));
1232: }
1233: #endif
1234: // Add the new extent to the existing extent record, or create a new one.
1235: if (actualStartBlock == startBlock) {
1236: // We grew the file's last extent, so just adjust the number of blocks.
1237: foundData[foundIndex].blockCount += actualNumBlocks;
1238: err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
1239: if (err != noErr) break;
1240: }
1241: else {
1242: UInt16 i;
1243:
1244: // Need to add a new extent. See if there is room in the current record.
1245: if (foundData[foundIndex].blockCount != 0) // Is current extent free to use?
1246: ++foundIndex; // No, so use the next one.
1247: if (foundIndex == numExtentsPerRecord) {
1248: // This record is full. Need to create a new one.
1249: if (fcb->fcbFlNm == kHFSExtentsFileID) {
1250: err = fxOvFlErr; // Oops. Can't extend extents file (?? really ??)
1251: break;
1252: }
1253:
1254: foundKey.keyLength = kHFSPlusExtentKeyMaximumLength;
1255: if (fcb->fcbFlags & fcbResourceMask)
1256: foundKey.forkType = kResourceForkType;
1257: else
1258: foundKey.forkType = kDataForkType;
1259: foundKey.pad = 0;
1260: foundKey.fileID = fcb->fcbFlNm;
1261: foundKey.startBlock = nextBlock;
1262:
1263: foundData[0].startBlock = actualStartBlock;
1264: foundData[0].blockCount = actualNumBlocks;
1265:
1266: // zero out remaining extents...
1267: for (i = 1; i < kHFSPlusExtentDensity; ++i)
1268: {
1269: foundData[i].startBlock = 0;
1270: foundData[i].blockCount = 0;
1271: }
1272:
1273: foundIndex = 0;
1274:
1275: err = CreateExtentRecord(vcb, &foundKey, foundData, &hint);
1276: if (err != noErr) break;
1277: }
1278: else {
1279: // Add a new extent into this record and update.
1280: foundData[foundIndex].startBlock = actualStartBlock;
1281: foundData[foundIndex].blockCount = actualNumBlocks;
1282: err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
1283: if (err != noErr) break;
1284: }
1285: }
1286:
1287: // Figure out how many bytes were actually allocated.
1288: // NOTE: BlockAllocate could have allocated more than we asked for.
1289: // Don't set the PEOF beyond what our client asked for.
1290: nextBlock += actualNumBlocks;
1291: bytesThisExtent = actualNumBlocks * volumeBlockSize;
1292: if (bytesThisExtent > bytesToAdd) {
1293: if (TARGET_OS_RHAPSODY)
1294: fcb->fcbPLen += bytesThisExtent; /* don't lie about the peof in Rhapsody */
1295: else
1296: fcb->fcbPLen += bytesToAdd; /* Mac OS semantics support lying (peof <= sum of extents) */
1297: bytesToAdd = 0;
1298: }
1299: else {
1300: bytesToAdd -= bytesThisExtent;
1301: maximumBytes -= bytesThisExtent;
1302: fcb->fcbPLen += bytesThisExtent;
1303: }
1304: fcb->fcbFlags |= fcbModifiedMask;
1305:
1306: // If contiguous allocation was requested, then we've already got one contiguous
1307: // chunk. If we didn't get all we wanted, then adjust the error to disk full.
1308: if (forceContig) {
1309: if (bytesToAdd != 0)
1310: err = dskFulErr;
1311: break; // We've already got everything that's contiguous
1312: }
1313: }
1314: } while (err == noErr && bytesToAdd);
1315:
1316: ErrorExit:
1317: Exit:
1318: *actualBytesAdded = fcb->fcbPLen - previousPEOF;
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: UInt32 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:
1376: #if HFSInstrumentation
1377: InstTraceClassRef trace;
1378: InstEventTag eventTag;
1379: InstDataDescriptorRef traceDescriptor;
1380: FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars();
1381:
1382: traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
1383:
1384: err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:TruncateFileC", 'hfs+', kInstEnableClassMask, &trace);
1385: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
1386:
1387: eventTag = InstCreateEventTag();
1388: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
1389: #endif
1390:
1391: if (vcb->vcbSigWord == kHFSPlusSigWord)
1392: numExtentsPerRecord = kHFSPlusExtentDensity;
1393: else
1394: numExtentsPerRecord = kHFSExtentDensity;
1395:
1396: if (fcb->fcbFlags & fcbResourceMask)
1397: forkType = kResourceForkType;
1398: else
1399: forkType = kDataForkType;
1400:
1401: physNumBlocks = fcb->fcbPLen / vcb->blockSize; // number of allocation blocks currently in file
1402:
1403: //
1404: // Round newPEOF up to a multiple of the allocation block size. If new size is
1405: // two gigabytes or more, then round down by one allocation block (??? really?
1406: // shouldn't that be an error?).
1407: //
1408: nextBlock = DivideAndRoundUp(peof, vcb->blockSize); // number of allocation blocks to remain in file
1409: peof = nextBlock * vcb->blockSize; // number of bytes in those blocks
1410: if (peof >= (UInt32) kTwoGigabytes) {
1411: #if DEBUG_BUILD
1412: DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
1413: #endif
1414: err = fileBoundsErr;
1415: goto ErrorExit;
1416: }
1417:
1418: //
1419: // Update FCB's length
1420: //
1421: fcb->fcbPLen = peof;
1422: fcb->fcbFlags |= fcbModifiedMask;
1423:
1424: //
1425: // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
1426: // all storage).
1427: //
1428: if (peof == 0) {
1429: int i;
1430:
1431: // Find the catalog extent record
1432: err = GetFCBExtentRecord(vcb, fcb, extentRecord);
1433: if (err != noErr) goto ErrorExit; // got some error, so return it
1434:
1435: // Deallocate all the extents for this fork
1436: err = DeallocateFork(vcb, fcb->fcbFlNm, forkType, extentRecord);
1437: if (err != noErr) goto ErrorExit; // got some error, so return it
1438:
1439: // Update the catalog extent record (making sure it's zeroed out)
1440: if (err == noErr) {
1441: for (i=0; i < numExtentsPerRecord; i++) {
1442: extentRecord[i].startBlock = 0;
1443: extentRecord[i].blockCount = 0;
1444: }
1445: }
1446: err = SetFCBExtentRecord(vcb, fcb, extentRecord);
1447: goto Done;
1448: }
1449:
1450: //
1451: // Find the extent containing byte (peof-1). This is the last extent we'll keep.
1452: // (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only
1453: // keep up through peof). The search will tell us how many allocation blocks exist
1454: // in the found extent plus all previous extents.
1455: //
1456: err = SearchExtentFile(vcb, fcb, peof-1, &key, extentRecord, &extentIndex, &hint, &extentNextBlock);
1457: if (err != noErr) goto ErrorExit;
1458:
1459: extentChanged = false; // haven't changed the extent yet
1460:
1461: if (!truncateToExtent) {
1462: //
1463: // Shorten this extent. It may be the case that the entire extent gets
1464: // freed here.
1465: //
1466: numBlocks = extentNextBlock - nextBlock; // How many blocks in this extent to free up
1467: if (numBlocks != 0) {
1468: // Compute first volume allocation block to free
1469: startBlock = extentRecord[extentIndex].startBlock + extentRecord[extentIndex].blockCount - numBlocks;
1470: // Free the blocks in bitmap
1471: err = BlockDeallocate(vcb, startBlock, numBlocks);
1472: if (err != noErr) goto ErrorExit;
1473: // Adjust length of this extent
1474: extentRecord[extentIndex].blockCount -= numBlocks;
1475: // If extent is empty, set start block to 0
1476: if (extentRecord[extentIndex].blockCount == 0)
1477: extentRecord[extentIndex].startBlock = 0;
1478: // Remember that we changed the extent record
1479: extentChanged = true;
1480: }
1481: }
1482:
1483: //
1484: // Now move to the next extent in the record, and set up the file allocation block number
1485: //
1486: nextBlock = extentNextBlock; // Next file allocation block to free
1487: ++extentIndex; // Its index within the extent record
1488:
1489: //
1490: // Release all following extents in this extent record. Update the record.
1491: //
1492: while (extentIndex < numExtentsPerRecord && extentRecord[extentIndex].blockCount != 0) {
1493: numBlocks = extentRecord[extentIndex].blockCount;
1494: // Deallocate this extent
1495: err = BlockDeallocate(vcb, extentRecord[extentIndex].startBlock, numBlocks);
1496: if (err != noErr) goto ErrorExit;
1497: // Update next file allocation block number
1498: nextBlock += numBlocks;
1499: // Zero out start and length of this extent to delete it from record
1500: extentRecord[extentIndex].startBlock = 0;
1501: extentRecord[extentIndex].blockCount = 0;
1502: // Remember that we changed an extent
1503: extentChanged = true;
1504: // Move to next extent in record
1505: ++extentIndex;
1506: }
1507:
1508: //
1509: // If any of the extents in the current record were changed, then update that
1510: // record (in the FCB, or extents file).
1511: //
1512: if (extentChanged) {
1513: err = UpdateExtentRecord(vcb, fcb, &key, extentRecord, hint);
1514: if (err != noErr) goto ErrorExit;
1515: }
1516:
1517: //
1518: // If there are any following allocation blocks, then we need
1519: // to seach for their extent records and delete those allocation
1520: // blocks.
1521: //
1522: if (nextBlock < physNumBlocks)
1523: err = TruncateExtents(vcb, forkType, fcb->fcbFlNm, nextBlock);
1524:
1525: Done:
1526: ErrorExit:
1527:
1528: #if HFSInstrumentation
1529: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
1530: #endif
1531:
1532: return err;
1533: }
1534:
1535:
1536:
1537: //�������������������������������������������������������������������������������
1538: // Routine: SearchExtentRecord (was XRSearch)
1539: //
1540: // Function: Searches extent record for the extent mapping a given file
1541: // allocation block number (FABN).
1542: //
1543: // Input: searchFABN - desired FABN
1544: // extentData - pointer to extent data record (xdr)
1545: // extentDataStartFABN - beginning FABN for extent record
1546: //
1547: // Output: foundExtentDataOffset - offset to extent entry within xdr
1548: // result = noErr, offset to extent mapping desired FABN
1549: // result = FXRangeErr, offset to last extent in record
1550: // endingFABNPlusOne - ending FABN +1
1551: // noMoreExtents - True if the extent was not found, and the
1552: // extent record was not full (so don't bother
1553: // looking in subsequent records); false otherwise.
1554: //
1555: // Result: noErr = ok
1556: // FXRangeErr = desired FABN > last mapped FABN in record
1557: //�������������������������������������������������������������������������������
1558:
1559: static OSErr SearchExtentRecord(
1560: const ExtendedVCB *vcb,
1561: UInt32 searchFABN,
1562: const HFSPlusExtentRecord extentData,
1563: UInt32 extentDataStartFABN,
1564: UInt32 *foundExtentIndex,
1565: UInt32 *endingFABNPlusOne,
1566: Boolean *noMoreExtents)
1567: {
1568: OSErr err = noErr;
1569: UInt32 extentIndex;
1570: UInt32 numberOfExtents;
1571: UInt32 numAllocationBlocks;
1572: Boolean foundExtent;
1573:
1574: *endingFABNPlusOne = extentDataStartFABN;
1575: *noMoreExtents = false;
1576: foundExtent = false;
1577:
1578: if (vcb->vcbSigWord == kHFSPlusSigWord)
1579: numberOfExtents = kHFSPlusExtentDensity;
1580: else
1581: numberOfExtents = kHFSExtentDensity;
1582:
1583: for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex )
1584: {
1585:
1586: // Loop over the extent record and find the search FABN.
1587:
1588: numAllocationBlocks = extentData[extentIndex].blockCount;
1589: if ( numAllocationBlocks == 0 )
1590: {
1591: break;
1592: }
1593:
1594: *endingFABNPlusOne += numAllocationBlocks;
1595:
1596: if( searchFABN < *endingFABNPlusOne )
1597: {
1598: // Found the extent.
1599: foundExtent = true;
1600: break;
1601: }
1602: }
1603:
1604: if( foundExtent )
1605: {
1606: // Found the extent. Note the extent offset
1607: *foundExtentIndex = extentIndex;
1608: }
1609: else
1610: {
1611: // Did not find the extent. Set foundExtentDataOffset accordingly
1612: if( extentIndex > 0 )
1613: {
1614: *foundExtentIndex = extentIndex - 1;
1615: }
1616: else
1617: {
1618: *foundExtentIndex = 0;
1619: }
1620:
1621: // If we found an empty extent, then set noMoreExtents.
1622: if (extentIndex < numberOfExtents)
1623: *noMoreExtents = true;
1624:
1625: // Finally, return an error to the caller
1626: err = fxRangeErr;
1627: }
1628:
1629: return( err );
1630: }
1631:
1632: //�������������������������������������������������������������������������������
1633: // Routine: SearchExtentFile (was XFSearch)
1634: //
1635: // Function: Searches extent file (including the FCB resident extent record)
1636: // for the extent mapping a given file position.
1637: //
1638: // Input: vcb - VCB pointer
1639: // fcb - FCB pointer
1640: // filePosition - file position (byte address)
1641: //
1642: // Output: foundExtentKey - extent key record (xkr)
1643: // If extent was found in the FCB's resident extent record,
1644: // then foundExtentKey->keyLength will be set to 0.
1645: // foundExtentData - extent data record(xdr)
1646: // foundExtentIndex - index to extent entry in xdr
1647: // result = 0, offset to extent mapping desired FABN
1648: // result = FXRangeErr, offset to last extent in record
1649: // (i.e., kNumExtentsPerRecord-1)
1650: // extentBTreeHint - BTree hint for extent record
1651: // kNoHint = Resident extent record
1652: // endingFABNPlusOne - ending FABN +1
1653: //
1654: // Result:
1655: // noErr Found an extent that contains the given file position
1656: // FXRangeErr Given position is beyond the last allocated extent
1657: // (other) (some other internal I/O error)
1658: //�������������������������������������������������������������������������������
1659:
1660: static OSErr SearchExtentFile(
1661: const ExtendedVCB *vcb,
1662: const FCB *fcb,
1663: UInt32 filePosition,
1664: HFSPlusExtentKey *foundExtentKey,
1665: HFSPlusExtentRecord foundExtentData,
1666: UInt32 *foundExtentIndex,
1667: UInt32 *extentBTreeHint,
1668: UInt32 *endingFABNPlusOne )
1669: {
1670: OSErr err;
1671: UInt32 filePositionBlock;
1672: Boolean noMoreExtents;
1673:
1674: filePositionBlock = filePosition / vcb->blockSize;
1675:
1676: // Search the resident FCB first.
1677: err = GetFCBExtentRecord(vcb, fcb, foundExtentData);
1678: if (err == noErr)
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: fcb->fcbFlNm, 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(vcb, 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;
1769:
1770: if (extentFileKey->keyLength == 0) { // keyLength == 0 means the FCB's extent record
1771: err = SetFCBExtentRecord(vcb, fcb, extentData);
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 = ExtentsToExtDataRec(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: static void ExtDataRecToExtents(
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: static OSErr ExtentsToExtDataRec(
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: #if TARGET_OS_MAC
1886: OSErr GrowParallelFCBs(void)
1887: {
1888: ParallelFCB *parallelFCBs;
1889: ParallelFCB *newParallel;
1890: char *oldData;
1891: char *newData;
1892: UInt32 i;
1893: UInt32 count;
1894: UInt32 oldSize;
1895:
1896: //
1897: // Get header for parallel FCB array
1898: //
1899: parallelFCBs = ((FSVarsRec *) LMGetFSMVars())->fcbPBuf;
1900:
1901: //
1902: // See if the array needs to grow
1903: //
1904: if (parallelFCBs->unitSize < sizeof(ExtendedFCB)) {
1905: //
1906: // Get the size and count from existing array
1907: //
1908: count = parallelFCBs->count;
1909: oldSize = parallelFCBs->unitSize;
1910: oldData = (char *) ¶llelFCBs->extendedFCB[0];
1911:
1912: //
1913: // Allocate the new array
1914: //
1915: newParallel = (ParallelFCB *) NewPtrSysClear(offsetof(ParallelFCB, extendedFCB[count]));
1916: if (newParallel == NULL)
1917: return memFullErr;
1918:
1919: //
1920: // Initialize the header of the new array
1921: //
1922: newParallel->count = count;
1923: newParallel->unitSize = sizeof(ExtendedFCB);
1924: newData = (char *) &newParallel->extendedFCB[0];
1925:
1926: //
1927: // Copy the existing data into the new array
1928: //
1929: for (i=0; i<count; i++) {
1930: BlockMoveData(oldData, newData, oldSize); // copy the old data into new array
1931: oldData += oldSize;
1932: newData += sizeof(ExtendedFCB);
1933: }
1934:
1935: //
1936: // Install the new array and deallocate the old one
1937: //
1938: ((FSVarsRec *) LMGetFSMVars())->fcbPBuf = newParallel;
1939: DisposePtr((Ptr) parallelFCBs);
1940: }
1941:
1942: return noErr;
1943: }
1944: #endif
1945:
1946:
1947:
1948: static ExtendedFCB *GetExtendedFCB(const FCB *fcb)
1949: {
1950: #if TARGET_OS_MAC
1951: ParallelFCB *parallelFCBs;
1952: UInt32 index;
1953:
1954: //
1955: // First, turn the FCB pointer into an index into the FCB table
1956: //
1957: index = (((UInt32) fcb) - ((UInt32) LMGetFCBSPtr())) / sizeof(FCB);
1958:
1959: //
1960: // Get header for parallel FCB array
1961: //
1962: parallelFCBs = ((FSVarsRec *) LMGetFSMVars())->fcbPBuf;
1963:
1964: //
1965: // Make sure parallel FCBs are big enough
1966: //
1967: #if DEBUG_BUILD
1968: if (parallelFCBs->unitSize < sizeof(ExtendedFCB)) {
1969: DebugStr("\pFATAL: Parallel FCBs are too small!");
1970: return NULL;
1971: }
1972: #endif
1973: //
1974: // Finally, return a pointer to the index'th element of
1975: // the parallel FCB array.
1976: //
1977: return &(parallelFCBs->extendedFCB[index]);
1978: #else
1979: return &(((struct vfsFCB *)(fcb))->fcb_extFCB);
1980: #endif
1981: }
1982:
1983:
1984:
1985:
1986: OSErr GetFCBExtentRecord(
1987: const ExtendedVCB *vcb,
1988: const FCB *fcb,
1989: HFSPlusExtentRecord extents)
1990: {
1991: OSErr err;
1992: ExtendedFCB *extendedFCB;
1993:
1994: err = noErr;
1995:
1996: if (vcb->vcbSigWord == kHFSSigWord) {
1997: ExtDataRecToExtents(fcb->fcbExtRec, extents);
1998: }
1999: else {
2000: extendedFCB = GetExtendedFCB(fcb);
2001: BlockMoveData(extendedFCB->extents, extents, sizeof(HFSPlusExtentRecord));
2002: }
2003:
2004: return err;
2005: }
2006:
2007:
2008:
2009: static OSErr SetFCBExtentRecord(
2010: const ExtendedVCB *vcb,
2011: FCB *fcb,
2012: const HFSPlusExtentRecord extents)
2013: {
2014: OSErr err;
2015: Boolean isHFSPlus;
2016: UInt32 fileNum;
2017: ExtendedFCB *extendedFCB;
2018: UInt8 resourceFlag; // fcbResourceMask bit from fcbFlags
2019:
2020: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
2021: fileNum = fcb->fcbFlNm;
2022: resourceFlag = fcb->fcbFlags & fcbResourceMask;
2023:
2024: err = noErr;
2025:
2026: #if DEBUG_BUILD
2027: if (fcb->fcbVPtr != vcb)
2028: DebugStr("\pVCB does not match FCB");
2029: #endif
2030:
2031: if ( isHFSPlus ) {
2032: extendedFCB = GetExtendedFCB(fcb);
2033: BlockMoveData(extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord));
2034: }
2035: else {
2036: err = ExtentsToExtDataRec(extents, fcb->fcbExtRec);
2037: }
2038:
2039: return err;
2040: }
2041:
2042:
2043:
2044: //�������������������������������������������������������������������������������
2045: // Routine: MapFileBlockFromFCB
2046: //
2047: // Function: Determine if the given file offset is within the set of extents
2048: // stored in the FCB or ExtendedFCB. If so, return the file allocation
2049: // block number of the start of the extent, volume allocation block number
2050: // of the start of the extent, and file allocation block number immediately
2051: // following the extent.
2052: //
2053: // Input: vcb - the volume containing the extents
2054: // fcb - the file that owns the extents
2055: // offset - desired offset in bytes
2056: //
2057: // Output: firstFABN - file alloc block number of start of extent
2058: // firstBlock - volume alloc block number of start of extent
2059: // nextFABN - file alloc block number of next extent
2060: //
2061: // Result: noErr = ok
2062: // fxRangeErr = beyond FCB's extents
2063: //�������������������������������������������������������������������������������
2064: static OSErr MapFileBlockFromFCB(
2065: const ExtendedVCB *vcb,
2066: const FCB *fcb,
2067: UInt32 offset, // Desired offset in bytes from start of file
2068: UInt32 *firstFABN, // FABN of first block of found extent
2069: UInt32 *firstBlock, // Corresponding allocation block number
2070: UInt32 *nextFABN) // FABN of block after end of extent
2071: {
2072: UInt32 index;
2073: UInt32 offsetBlocks;
2074:
2075: offsetBlocks = offset / vcb->blockSize;
2076:
2077: if (vcb->vcbSigWord == kHFSSigWord) {
2078: const HFSExtentDescriptor *extent;
2079: UInt16 blockCount;
2080: UInt16 currentFABN;
2081:
2082: extent = fcb->fcbExtRec;
2083: currentFABN = 0;
2084:
2085: for (index=0; index<kHFSExtentDensity; index++) {
2086:
2087: blockCount = extent->blockCount;
2088:
2089: if (blockCount == 0)
2090: return fxRangeErr; // ran out of extents!
2091:
2092: // Is it in this extent?
2093: if (offsetBlocks < blockCount) {
2094: *firstFABN = currentFABN;
2095: *firstBlock = extent->startBlock;
2096: currentFABN += blockCount; // faster to add these as UInt16 first, then extend to UInt32
2097: *nextFABN = currentFABN;
2098: return noErr; // found the right extent
2099: }
2100:
2101: // Not in current extent, so adjust counters and loop again
2102: offsetBlocks -= blockCount;
2103: currentFABN += blockCount;
2104: extent++;
2105: }
2106: }
2107: else {
2108: const HFSPlusExtentDescriptor *extent;
2109: UInt32 blockCount;
2110: UInt32 currentFABN;
2111:
2112: extent = GetExtendedFCB(fcb)->extents;
2113: currentFABN = 0;
2114:
2115: for (index=0; index<kHFSPlusExtentDensity; index++) {
2116:
2117: blockCount = extent->blockCount;
2118:
2119: if (blockCount == 0)
2120: return fxRangeErr; // ran out of extents!
2121:
2122: // Is it in this extent?
2123: if (offsetBlocks < blockCount) {
2124: *firstFABN = currentFABN;
2125: *firstBlock = extent->startBlock;
2126: *nextFABN = currentFABN + blockCount;
2127: return noErr; // found the right extent
2128: }
2129:
2130: // Not in current extent, so adjust counters and loop again
2131: offsetBlocks -= blockCount;
2132: currentFABN += blockCount;
2133: extent++;
2134: }
2135: }
2136:
2137: // If we fall through here, the extent record was full, but the offset was
2138: // beyond those extents.
2139:
2140: return fxRangeErr;
2141: }
2142:
2143:
2144: //_________________________________________________________________________________
2145: //
2146: // Routine: ExtentsAreIntegral
2147: //
2148: // Purpose: Ensure that each extent can hold an integral number of nodes
2149: // Called by the NodesAreContiguous function
2150: //_________________________________________________________________________________
2151:
2152: static Boolean ExtentsAreIntegral(
2153: const HFSPlusExtentRecord extentRecord,
2154: UInt32 mask,
2155: UInt32 *blocksChecked,
2156: Boolean *checkedLastExtent)
2157: {
2158: UInt32 blocks;
2159: UInt32 extentIndex;
2160:
2161: *blocksChecked = 0;
2162: *checkedLastExtent = false;
2163:
2164: for(extentIndex = 0; extentIndex < kHFSPlusExtentDensity; extentIndex++)
2165: {
2166: blocks = extentRecord[extentIndex].blockCount;
2167:
2168: if ( blocks == 0 )
2169: {
2170: *checkedLastExtent = true;
2171: break;
2172: }
2173:
2174: *blocksChecked += blocks;
2175:
2176: if (blocks & mask)
2177: return false;
2178: }
2179:
2180: return true;
2181: }
2182:
2183:
2184: //_________________________________________________________________________________
2185: //
2186: // Routine: NodesAreContiguous
2187: //
2188: // Purpose: Ensure that all b-tree nodes are contiguous on disk
2189: // Called by BTOpenPath during volume mount
2190: //_________________________________________________________________________________
2191:
2192: Boolean NodesAreContiguous(
2193: ExtendedVCB *vcb,
2194: FCB *fcb,
2195: UInt32 nodeSize)
2196: {
2197: UInt32 mask;
2198: UInt32 startBlock;
2199: UInt32 blocksChecked;
2200: UInt32 hint;
2201: HFSPlusExtentKey key;
2202: HFSPlusExtentRecord extents;
2203: OSErr result;
2204: Boolean lastExtentReached;
2205:
2206:
2207: if (vcb->blockSize >= nodeSize)
2208: return TRUE;
2209:
2210: mask = (nodeSize / vcb->blockSize) - 1;
2211:
2212: // check the local extents
2213: (void) GetFCBExtentRecord(vcb, fcb, extents);
2214: if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
2215: return FALSE;
2216:
2217: if (lastExtentReached || (blocksChecked * vcb->blockSize) >= fcb->fcbPLen)
2218: return TRUE;
2219:
2220: startBlock = blocksChecked;
2221:
2222: // check the overflow extents (if any)
2223: while ( !lastExtentReached )
2224: {
2225: result = FindExtentRecord(vcb, kDataForkType, fcb->fcbFlNm, startBlock, FALSE, &key, extents, &hint);
2226: if (result) break;
2227:
2228: if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
2229: return FALSE;
2230:
2231: startBlock += blocksChecked;
2232: }
2233:
2234: return TRUE;
2235: }
2236:
2237:
2238: #if TARGET_OS_MAC
2239: void AdjustEOF(FCB *sourceFCB)
2240: {
2241: ExtendedVCB *vcb; // sourceFCB's volume
2242: UInt32 fileID; // File's ID
2243: FCB *destFCB; // A matching FCB
2244: FileReference refnum; // Used for iterating over FCBs
2245: UInt16 maxRefnum; // First refnum beyond end of FCB table
2246: UInt16 lengthFCB; // Size of an FCB
2247: Boolean isHFSPlus; // True if sourceFCB is on an HFS Plus volume
2248: UInt8 resourceFlag; // Contains fcbResourceMask bit from fcbFlags
2249:
2250: vcb = sourceFCB->fcbVPtr;
2251: sourceFCB->fcbFlags |= fcbModifiedMask;
2252: fileID = sourceFCB->fcbFlNm;
2253: resourceFlag = sourceFCB->fcbFlags & fcbResourceMask;
2254:
2255: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
2256:
2257: maxRefnum = * ((UInt16 *) LMGetFCBSPtr());
2258: lengthFCB = LMGetFSFCBLen();
2259:
2260: for (refnum=kFirstFileRefnum; refnum<maxRefnum; refnum+=lengthFCB) {
2261: destFCB = GetFileControlBlock(refnum);
2262: if (destFCB->fcbFlNm == fileID &&
2263: destFCB->fcbVPtr == vcb &&
2264: destFCB != sourceFCB &&
2265: (destFCB->fcbFlags & fcbResourceMask) == resourceFlag)
2266: {
2267: // We found another FCB for the same fork. Copy the fields.
2268: destFCB->fcbSBlk = sourceFCB->fcbSBlk; //���MFS only?
2269: destFCB->fcbEOF = sourceFCB->fcbEOF;
2270: destFCB->fcbPLen = sourceFCB->fcbPLen;
2271:
2272: // Copy extent info, too
2273: if (isHFSPlus) {
2274: ExtendedFCB *srcExtendedFCB;
2275: ExtendedFCB *destExtendedFCB;
2276:
2277: srcExtendedFCB = GetExtendedFCB(sourceFCB);
2278: destExtendedFCB = GetExtendedFCB(destFCB);
2279:
2280: BlockMoveData(srcExtendedFCB->extents, destExtendedFCB->extents, sizeof(HFSPlusExtentRecord));
2281: }
2282: else {
2283: destFCB->fcbExtRec[0] = sourceFCB->fcbExtRec[0];
2284: destFCB->fcbExtRec[1] = sourceFCB->fcbExtRec[1];
2285: destFCB->fcbExtRec[2] = sourceFCB->fcbExtRec[2];
2286: }
2287: }
2288: }
2289: }
2290: #endif /* TARGET_OS_MAC */
2291:
2292:
2293: #if TARGET_OS_MAC
2294: static OSErr ValidateRefnum(short ref)
2295: {
2296: FCB *fcb;
2297:
2298: //
2299: // Make sure refnum is multiple of FCB length, plus 2.
2300: //
2301: if ((ref % LMGetFSFCBLen()) != 2)
2302: return rfNumErr;
2303:
2304: //
2305: // Make sure refnum isn't too large
2306: //
2307: if (ref > *((short *) LMGetFCBSPtr()))
2308: return rfNumErr;
2309:
2310: //
2311: // Make sure file is open
2312: //
2313: fcb = GetFileControlBlock(ref);
2314: if (fcb->fcbFlNm == 0)
2315: return fnOpnErr;
2316:
2317: //
2318: // If we got here, refnum was valid and file was open
2319: //
2320: return noErr;
2321: }
2322: #endif /* TARGET_OS_MAC */
2323:
2324:
2325: #if TARGET_OS_MAC
2326: static UInt32 BytesToBlocks(UInt64 bytes, UInt32 blockSize)
2327: {
2328: UInt32 carry;
2329: UnsignedWide temp;
2330:
2331: temp = UInt64ToUnsignedWide(bytes);
2332:
2333: // This loop divides "bytes" by "blockSize". It assumes blockSize
2334: // is a power of two. The division is done by shifting both numerator
2335: // and divisor until the divisor is one.
2336:
2337: while (blockSize > 1) {
2338: blockSize >>= 1;
2339: carry = (temp.hi & 1) ? 0x80000000 : 0;
2340: temp.hi >>= 1;
2341: temp.lo = carry | temp.lo >> 1;
2342: }
2343:
2344: return temp.lo;
2345: }
2346: #endif /* TARGET_OS_MAC */
2347:
2348: #if TARGET_OS_MAC
2349: static OSErr AllocateLargeFile(
2350: CreateLargeFileParam *pb,
2351: ExtendedVCB *vcb,
2352: UInt32 *dataBlocks,
2353: UInt32 *rsrcBlocks,
2354: HFSPlusExtentRecord dataExtents,
2355: HFSPlusExtentRecord rsrcExtents)
2356: {
2357: OSErr err;
2358: int i;
2359: UInt32 blockSize;
2360: UInt32 blocksToAllocate; // how many blocks are left to allocate
2361: UInt32 startBlock;
2362: UInt32 numBlocks;
2363:
2364:
2365: // Initialize the extent lists
2366: ClearMemory(dataExtents, sizeof(HFSPlusExtentRecord));
2367: ClearMemory(rsrcExtents, sizeof(HFSPlusExtentRecord));
2368:
2369: blockSize = vcb->blockSize;
2370:
2371: // Allocate data fork
2372: blocksToAllocate = BytesToBlocks(pb->dataPhysicalEOF, blockSize);
2373: if (blocksToAllocate > vcb->freeBlocks) {
2374: err = dskFulErr;
2375: goto Cleanup;
2376: }
2377: *dataBlocks = blocksToAllocate;
2378:
2379: if (blocksToAllocate) {
2380: for (i=0; i<kHFSPlusExtentDensity && blocksToAllocate; i++) {
2381: err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, blocksToAllocate, &startBlock, &numBlocks);
2382: if (err != noErr) goto Cleanup;
2383:
2384: dataExtents[i].startBlock = startBlock;
2385: dataExtents[i].blockCount = numBlocks;
2386:
2387: blocksToAllocate -= numBlocks;
2388: VCB_LOCK(vcb);
2389: vcb->freeBlocks -= numBlocks;
2390: VCB_UNLOCK(vcb);
2391: }
2392:
2393: if (blocksToAllocate != 0) { // too fragmented?
2394: err = fsDataTooBigErr;
2395: goto Cleanup;
2396: }
2397: }
2398:
2399: // Allocate resource fork
2400: blocksToAllocate = BytesToBlocks(pb->rsrcPhysicalEOF, blockSize);
2401: if (blocksToAllocate > vcb->freeBlocks) {
2402: err = dskFulErr;
2403: goto Cleanup;
2404: }
2405: *rsrcBlocks = blocksToAllocate;
2406:
2407: if (blocksToAllocate) {
2408: for (i=0; i<kHFSPlusExtentDensity && blocksToAllocate; i++) {
2409: err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, blocksToAllocate, &startBlock, &numBlocks);
2410: if (err != noErr) goto Cleanup;
2411:
2412: rsrcExtents[i].startBlock = startBlock;
2413: rsrcExtents[i].blockCount = numBlocks;
2414:
2415: blocksToAllocate -= numBlocks;
2416: VCB_LOCK(vcb);
2417: vcb->freeBlocks -= numBlocks;
2418: VCB_UNLOCK(vcb);
2419: }
2420:
2421: if (blocksToAllocate != 0) { // too fragmented?
2422: err = fsDataTooBigErr;
2423: goto Cleanup;
2424: }
2425: }
2426:
2427: UpdateVCBFreeBlks( vcb );
2428: MarkVCBDirty(vcb);
2429:
2430: return noErr;
2431:
2432: //
2433: // If we get here, there was an error. Deallocate anything we allocated and then
2434: // return the previous error.
2435: //
2436: Cleanup:
2437: for (i=0; i<kHFSPlusExtentDensity; i++) {
2438: BlockDeallocate(vcb, dataExtents[i].startBlock, dataExtents[i].blockCount);
2439: BlockDeallocate(vcb, rsrcExtents[i].startBlock, rsrcExtents[i].blockCount);
2440: *dataBlocks = 0;
2441: *rsrcBlocks = 0;
2442: }
2443:
2444: return err;
2445: }
2446: #endif /* TARGET_OS_MAC */
2447:
2448: #if TARGET_OS_MAC
2449: OSErr CreateLargeFile(CreateLargeFileParam *pb)
2450: {
2451: OSErr err;
2452: ExtendedVCB *vcb;
2453: FindFileNameGlueRec fileInfo;
2454: Str31 name;
2455: CatalogNodeID fileID;
2456: UInt32 hint;
2457: UInt32 dataBlocks;
2458: UInt32 rsrcBlocks;
2459: HFSPlusExtentRecord dataExtents;
2460: HFSPlusExtentRecord rsrcExtents;
2461: CatalogKey recordKey;
2462: CatalogRecord recordData;
2463:
2464: //
2465: // Try finding the file
2466: //
2467: err = FindFileName((ParamBlockRec *) pb, &fileInfo);
2468:
2469: //
2470: // Make sure file wasn't found
2471: //
2472: if (err == noErr) // did file already exist?
2473: err = dupFNErr; // if so, duplicate error
2474: if (err != fnfErr) // we expect a not found error
2475: return err; // anything else is a real error
2476:
2477: //
2478: // Make sure volume is writable and online
2479: //
2480: vcb = fileInfo.vcb;
2481:
2482: err = VolumeWritable( vcb );
2483: ReturnIfError( err );
2484:
2485: err = CheckVolumeOffLine( vcb );
2486: ReturnIfError( err );
2487:
2488: //
2489: // And make sure it is HFS Plus.
2490: //
2491: if (vcb->vcbSigWord != kHFSPlusSigWord)
2492: return wrgVolTypErr;
2493:
2494: //
2495: // Allocate the space
2496: //
2497: err = AllocateHFSPlusFile(pb, vcb, &dataBlocks, &rsrcBlocks, dataExtents, rsrcExtents);
2498: ReturnIfError( err );
2499:
2500: //
2501: // Copy the name into a p-string buffer
2502: //
2503: BlockMoveData(fileInfo.nameBuffer, name+1, fileInfo.nameLength);
2504: name[0] = fileInfo.nameLength;
2505:
2506: //
2507: // Create a new (empty) file
2508: //
2509: err = CreateCatalogNode(vcb, fileInfo.id, name, kHFSFileRecord, &fileID, &hint);
2510: ReturnIfError( err );
2511:
2512: //
2513: // Get the raw b-tree record for the new file
2514: //
2515: //�� LocateCatalogNode is a private Catalog routine, should probally call GetCatalogNode and UpdateCatalogNode instead...
2516: err = LocateCatalogNode(vcb, fileID, NULL, kNoHint, &recordKey, &recordData, &hint);
2517: ReturnIfError( err );
2518:
2519: //
2520: // Update the record's data
2521: //
2522: recordData.hfsPlusFile.dataFork.logicalSize = pb->dataLogicalEOF;
2523: recordData.hfsPlusFile.dataFork.totalBlocks = dataBlocks;
2524: BlockMoveData(dataExtents, recordData.hfsPlusFile.dataFork.extents, sizeof(HFSPlusExtentRecord));
2525:
2526: recordData.hfsPlusFile.resourceFork.logicalSize = pb->rsrcLogicalEOF;
2527: recordData.hfsPlusFile.resourceFork.totalBlocks = rsrcBlocks;
2528: BlockMoveData(rsrcExtents, recordData.hfsPlusFile.resourceFork.extents, sizeof(HFSPlusExtentRecord));
2529:
2530: //
2531: // Write the updated record back out
2532: //
2533: err = ReplaceBTreeRecord(vcb->catalogRefNum, &recordKey, hint, &recordData, sizeof(HFSPlusCatalogFile), &hint);
2534:
2535: return err;
2536: }
2537: #endif /* TARGET_OS_MAC */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.