|
|
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: VolumeRequests.c
27:
28: Contains: MountVolume and related utility routines for HFS & HFS Plus
29:
30: Version: HFS Plus 1.0
31:
32: Written by: Deric Horn
33:
34: Copyright: � 1996-1998 by Apple Computer, Inc., all rights reserved.
35:
36: File Ownership:
37:
38: DRI: Deric Horn
39:
40: Other Contacts: Mark Day, Don Brady
41:
42: Technology: File Systems
43:
44: Writers:
45:
46: (JL) Jim Luther
47: (msd) Mark Day
48: (DSH) Deric Horn
49: (djb) Don Brady
50:
51: Change History (most recent first):
52: <Rhap> 7/28/98 djb GetDiskBlocks is now implemented in MacOSStubs.c (radar #2258148).
53: <Rhap> 4/3/98 djb Conditionally remove FSVars reference from GetVolumeNameFromCatalog.
54: <Rhap> 3/31/98 djb Sync up with final HFSVolumes.h header file.
55: <CS47> 1/29/98 DSH TrashAllFSCaches is responsible for trashing all file system and
56: disk caches. Called from FlushVol when the HFS bit is set.
57: <CS46> 12/12/97 DSH 2003877, when vcbAllocPtr was copied to nextAllocation it was
58: getting sign extended.
59: <CS45> 11/26/97 DSH 2003459, fcbs was not being initialized if volume was offline
60: and we are executing an unconditional unmount.
61: <CS44> 11/24/97 DSH 2005507, FlushVolumeControlBlock() keeps MDB drCrDate in sync
62: with VolumeHeader createDate.
63: <CS43> 11/11/97 DSH 1685873, RemountWrappedVolumes was only remounting the first
64: HFS+ volume in the queue, causing HFS wrappers to be mounted if
65: multiple volumes had been mounted before InitHFSPlus.
66: <CS42> 11/4/97 DSH Clear FCB when getting a new one.
67: <CS41> 11/3/97 JL #2001483 - Removed unneeded parameters from MountVolume,
68: MountHFSVolume, MountHFSPlusVolume, GetVolumeInformation,
69: GetXVolumeInformation and AddVCB (and added local variables as
70: needed). Return WDCBRecPtr from UnMountVolume. Set wdcb
71: parameter to NULL in GetXVolumeInformation if working directory
72: was not specified.
73: <CS40> 10/31/97 DSH Added consistencyStatus parameter to MountCheck
74: <CS39> 10/23/97 msd Bug 1685113. The VolumeHeader's createDate should be in local
75: time (not GMT) and identical to the MDB's drCrDate (and VCB's
76: vcbCrDate). When checking for a remount of an offline HFS Plus
77: volume, compare write counts instead of mod dates (which could
78: be fooled by the user changing time zones). Force MountCheck to
79: run if the volume was last mounted by Bride 1.0b2 or earlier.
80: <CS38> 10/17/97 msd Conditionalize DebugStrs.
81: <CS37> 10/13/97 djb Update volumeNameEncodingHint when updating the volume name.
82: <CS36> 10/10/97 msd Bug 1683571. The dates in the volume header are in GMT, so be
83: sure to convert them when mounting a volume or flushing the
84: volume header.
85: <CS35> 10/2/97 DSH In UnmountVolume() check that the drive is on line before
86: determining if wrapper volume needs to be renamed causing IO.
87: <CS34> 10/1/97 DSH Run on disk version of MountCheck instead of ROM version for
88: boot volumes1682475.
89: <CS33> 10/1/97 djb Add calls to InvalidateCatalogCache (part of radar #1678833).
90: <CS32> 9/26/97 DSH Removed debugging code: support for 'W' key wrapper mounting.
91: <CS31> 9/17/97 DSH hfsPlusIOPosOffset was uninitialized for Wrapperless volumes.
92: <CS30> 9/5/97 djb In MountVol initialize Catalog cache before calling Catalog!
93: <CS29> 9/4/97 msd PropertyCloseVolume renamed to AttributesCloseVolume. Remove
94: call to AttributesOpenVolume (it no longer exists).
95: <CS28> 9/2/97 DSH VolumeHeader is now 3rd sector in partition, altVH is 2nd to
96: last cor compatability. Initial support for wrapperless
97: volumes.
98: <CS27> 8/26/97 djb Only call CountRootFiles during MountVol.
99: <CS26> 8/20/97 msd If the HFS Plus volume version doesn't match, mount the wrapper
100: instead.
101: <CS25> 8/19/97 djb Add error handling to RenameWrapperVolume.
102: <CS24> 8/15/97 msd Bug 1673999. In MakeVCBsExtendedVCBs, copy old VCB's vcbAllocPtr
103: to new VCB's nextAllocation field.
104: <CS23> 8/12/97 djb Fixed GetXVolInfo to only use extended vcb fields for local
105: volumes (radar# 1673177)
106: <CS22> 8/11/97 DSH vcbNmAlBlks is now taken from the embededExtent.blockCount
107: (1669121).
108: <CS21> 8/11/97 djb Return actual count of files in root directory for HFS Plus
109: volumes (Radar #1669118). Added local CountRootFiles routine.
110: 8/5/97 msd Make sure version field in VolumeHeader is exactly
111: kHFSPlusVersion. 8/1/97 djb GetXVolumeInformation now returns
112: extFSErr when FSID is nonzero (Radar #1649503).
113: <CS20> 7/25/97 DSH Init and Dispose of GenericMRUCache within ExtendedVCB.
114: <CS19> 7/16/97 DSH FilesInternal.x -> FileMgrInternal.x to avoid name collision
115: <CS18> 7/15/97 DSH Remount Wrapper volumes mounted before HFS+ initialization
116: (166729)
117: <CS17> 7/15/97 djb Remove ioXVersion checking in GetXVolInfo (radar #1666217).
118: <CS16> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
119: <CS15> 7/7/97 djb Add GetVolumeNameFromCatalog routine.
120: <CS14> 7/7/97 DSH GetNewVRefNum now get's a recycled vRefNum. Bug 1664445 in
121: Installer was cacheing the vRefNum while CheckDisk unmounts and
122: remounts disk.
123: <CS13> 6/30/97 DSH shadowing values obsoleteVCBXTRef, and obsoleteVCBCTRef when
124: HFS+ volume is mounted.
125: <CS12> 6/26/97 DSH GetVolInfo returns HFS signature for HFS+ volumes, GetXVolInfo
126: returns real signature.
127: <CS11> 6/24/97 DSH MakeVCBsExtendedVCBs was using wdcb->count as count not byte
128: count.
129: <CS10> 6/18/97 djb Set/get volume encodingsBitmap.
130: <CS9> 6/16/97 msd Include String.h and Disks.h.
131: <CS8> 6/12/97 djb Get in sync with HFS Plus format changes.
132: <CS7> 6/11/97 msd Make GetXVolumeInformation return true allocation block size. It
133: now checks the ioXVersion field.
134: <CS6> 5/28/97 msd When flushing the volume header, write out the allocation file's
135: clump size (from the FCB). When mounting an HFS Plus volume,
136: zero the entire FCB extent record, not just the first extent,
137: for the various volume control files.
138: <CS5> 5/19/97 djb Add calls to CreateVolumeCatalogCache,
139: DisposeVolumeCatalogCache.
140: <CS4> 5/9/97 djb Get in sync with new FilesInternal.i
141: <CS3> 5/8/97 DSH Only mount HFS+ volumes with version < 2.0 in the VolumeHeader.
142: Return wrgVolTypErr if too new.
143: <CS2> 5/2/97 djb Disable Manual Eject code since its buggy!
144: <CS1> 4/25/97 djb first checked in
145:
146: <HFS32> 4/11/97 DSH MountHFSPlusVolume gets volume name from catalog, and
147: UnmountVolume shadows the name back to the wrapper partition.
148: <HFS31> 4/8/97 msd Once volume is mounted, call AttributesOpenVolume to allow a
149: buffer to be allocated.
150: <HFS30> 4/7/97 msd In FlushVolumeControlBlock, don't update the attributes BTree
151: fields in the Volume Header unless an attributes BTree was
152: already open.
153: <HFS29> 4/7/97 msd In SetupFCB, add case for attributes BTree. Add code to set up
154: the attributes BTree. Remove call to PropertyOpenVolume. In
155: FlushVolumeControlBlock, write out any changes to the attributes
156: BTree.
157: <HFS28> 4/4/97 djb Get in sync with volume format changes.
158: <HFS27> 3/31/97 djb Added catalogDataCache to VCB; Remove ClearMem routine.
159: <HFS26> 3/18/97 msd In MountHFSPlusVolume, the free blocks calculation can overflow,
160: setting vcbFreeBks to a too-small value.
161: <HFS25> 3/17/97 DSH Added some utility functions AddVCB, GetParallelFCBFromRefNum,
162: casting for SC, and made some functions extern for DFA.
163: <HFS24> 3/5/97 msd Add calls to Property Manager to open and close the volume. When
164: unmounting an HFS+ volume, the allocation (bitmap) file now gets
165: closed.
166: <HFS23> 2/19/97 djb Update to 16-bit HFS Plus signature.
167: <HFS22> 2/12/97 msd In GetXVolumeInformation, the result code could be
168: uninitialized.
169: <HFS21> 1/23/97 DSH UpdateAlternateVoumeControlBlock()
170: <HFS20> 1/15/97 djb Remove MountCheckStub. Add file names to fcbs for debugging.
171: <HFS19> 1/13/97 DSH Use ExtendedVCB nextAllocation instead of vcbAllocPtr through
172: all code.
173: <HFS18> 1/9/97 djb Get in sync with new VolumeHeader and Extended VCB.
174: <HFS17> 1/6/97 djb Changed API to ParallelFCBFromRefnum (pragma parameter was
175: broken).
176: <HFS16> 1/6/97 msd Set only the defined bits in the MDB drAtrb field (when copying
177: from VCB vcbAtrb field).
178: <HFS15> 1/6/97 DSH CloseFile requires VCB to be passed in.
179: <HFS14> 1/6/97 djb FlushVolumeControlBlock was writing to absolute block 0 instead
180: of to block zero of the embedded volume.
181: <HFS13> 12/20/96 msd A comparison was using "=" instead of "=="; might have caused
182: the wrong volume to be set as the default.
183: <HFS12> 12/19/96 DSH Setting up ExtendedVCBs
184: <HFS11> 12/19/96 djb Updated for new B-tree Manager interface.
185: <HFS10> 12/18/96 msd Change GetVCBRefNum so it can actually return a VCB pointer.
186: <HFS9> 12/12/96 djb Use new SPI for GetCatalogNode.
187: <HFS8> 12/12/96 msd Fix a bunch of errors (mostly type mismatch) when compiling with
188: Metrowerks.
189: <HFS7> 12/12/96 DSH adding some util functions
190: <HFS6> 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
191: <HFS5> 12/4/96 DSH Ported GetVolumeInformation & GetXVolumeInformation.
192: <3*> 11/20/96 DSH HFS Plus support to MountVolume
193: <HFS3> 11/20/96 DSH Added UnmountVol and related routines, also backed out <2>
194: because C_FXMKeyCmp is passed as a parameter from C but called
195: from Asm in BTOpen so we need a Case ON Asm entry point.
196: <HFS2> 11/20/96 msd Use CompareExtentKeys() instead of CFXMKeyCmp().
197: <HFS1> 11/19/96 DSH first checked in
198: <1> 11/19/96 DSH first checked in
199:
200: */
201:
202: #if ( PRAGMA_LOAD_SUPPORTED )
203: #pragma load PrecompiledHeaders
204: #else
205: #if TARGET_OS_MAC
206: #include <Files.h>
207: #include <FSM.h>
208: #include <OSUtils.h>
209: #include <LowMemPriv.h>
210: #include <LowMem.h>
211: #include <StringCompare.h>
212: #include <Errors.h>
213: #include <Devices.h>
214: #include <SonyPriv.h>
215: #include <EDiskPriv.h>
216: #include <String.h>
217: #include <Disks.h>
218: #else
219: #include "../../hfs.h"
220: #include "../headers/system/MacOSStubs.h"
221: #endif /* TARGET_OS_MAC */
222: #endif /* PRAGMA_LOAD_SUPPORTED */
223:
224: #if TARGET_OS_MAC
225: #include <HardwarePriv.h>
226: #endif
227:
228: #include "../headers/FileMgrInternal.h"
229: #include "../headers/HFSVolumes.h"
230:
231:
232: #define kIDSectorOffset 2
233:
234: // Exported routine prototypes
235: OSErr MountVolume( VolumeParam *volume, Boolean forceHFSWrapperToMount );
236:
237: OSErr MountHFSVolume( short driveNumber, IOParam* lowMemParamBlock, OSErr err );
238:
239: OSErr MountHFSPlusVolume( short driveNumber, IOParam* lowMemParamBlock, OSErr err, Boolean pureHFSPlusVolume );
240:
241: OSErr GetVolumeInformation( HVolumeParam *volume, WDCBRecPtr *wdcb );
242:
243: OSErr GetXVolumeInformation( XVolumeParam *volume, WDCBRecPtr *wdcb );
244:
245:
246: // Utility function prototypes
247: #if TARGET_OS_MAC
248: OSErr FindFileControlBlock( File *index, Ptr *fcbsH );
249:
250: Boolean GetNextFileControlBlock( UInt16 *index, Ptr fcbsPtr );
251:
252: void Get1stFileControlBlock( UInt16 *index, Ptr *fcbsH );
253:
254: void DisposeFileControlBlocks( ExtendedVCB *vcb );
255: #else
256: OSErr GetNewFCB( ExtendedVCB *vcb, FileReference* fRefPtr);
257: #endif
258:
259: OSErr AccessBTree( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize, void *CompareRoutine );
260:
261: UInt16 DivUp( UInt32 byteRun, UInt32 blockSize );
262:
263: Boolean IsARamDiskDriver( void );
264:
265: OSErr GetVCBRefNum( ExtendedVCB **vcb, short vRefNum );
266:
267: OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb );
268:
269: void RenameWrapperVolume( Str27 newVolumeName, UInt16 driveNumber );
270:
271: OSErr CheckExternalFileSystem( ExtendedVCB *vcb );
272:
273: OSErr FlushVolume( ExtendedVCB *vcb );
274:
275: FCB *SetupFCB( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize );
276:
277: OSErr GetDiskBlocks( ExtendedVCB *vcb, unsigned long *numBlocks);
278:
279: void AddVCB( ExtendedVCB *vcb, short driveNumber, short ioDRefNum );
280:
281: short IsPressed( unsigned short k );
282:
283: FileReference GetNewVRefNum();
284:
285: OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
286:
287: #if TARGET_OS_MAC
288: static UInt16 CountRootFiles(ExtendedVCB *vcb);
289: #endif /* TARGET_OS_MAC */
290:
291:
292: #if ( hasHFSManualEject )
293: static void SetVCBManEject(ExtendedVCB *vcb);
294: #endif
295:
296: // External routines
297:
298: extern OSErr C_FlushMDB( ExtendedVCB *volume );
299:
300: extern OSErr DisposeVolumeCacheBlocks( ExtendedVCB *vcb );
301:
302: extern void DisposeVolumeControlBlock( ExtendedVCB *vcb );
303:
304: extern OSErr DeturmineVolume1( VolumeParam *iopb, short *nameLength, Boolean *nameSpecified, ExtendedVCB **vcb, WDCBRec **wdcb, unsigned char **pathName );
305:
306: extern OSErr DeturmineVolume3( VolumeParam *iopb, short *nameLength, Boolean *nameSpecified, ExtendedVCB **vcb, WDCBRec **wdcb, unsigned char **pathName );
307:
308: extern OSErr FlushVolumeBuffers( ExtendedVCB *vcb );
309:
310: extern void MultiplyUInt32IntoUInt64( UInt64 *wideResult, UInt32 num1, UInt32 num2 );
311:
312: extern void TrashCatalogNodeCache( void );
313:
314:
315:
316: #if TARGET_OS_MAC
317: //�������������������������������������������������������������������������������
318: // Routine: MountVolume
319: //
320: // Function: The VCB pointers are checked to see if a volume in the
321: // specified drive is already on-line (error if so). Reads in the
322: // directory master block and allocates memory for VCB and additional
323: // data structures, depending on the volume type:
324: //
325: // - For MFS volumes (handled in MFSVol), space is allocated for
326: // a volume buffer, as well as the block map, which is read in
327: // from disk).
328: //
329: // - For TFS volumes, space is allocated for a bitmap cache, a volume
330: // control cache (for B*-Tree use), and a volume cache. In addition,
331: // two FCBs are used by the B*-Trees.
332: //
333: // No new VCB storage is allocated for remounts.
334: //
335: //�������������������������������������������������������������������������������
336:
337: OSErr MountVolume( VolumeParam *volume, Boolean forceHFSWrapperToMount )
338: {
339: Byte blockBuffer[512];
340: IOParam *lowMemParamBlock;
341: short ioRefNum;
342: short vRefNum;
343: OSErr err;
344: DrvQEl *dqe;
345: Boolean pureHFSPlusVolume;
346:
347:
348: //--- FSQueueSync was already called by the MountVol glue.
349:
350: vRefNum = volume->ioVRefNum;
351: err = FindDrive( &ioRefNum, &dqe, vRefNum ); // Get driver refnum
352: if ( err == noErr )
353: {
354: lowMemParamBlock = (IOParam *) LMParamBlock;
355: lowMemParamBlock->ioVRefNum = vRefNum;
356: lowMemParamBlock->ioRefNum = ioRefNum;
357: lowMemParamBlock->ioBuffer = (char *)blockBuffer;
358: lowMemParamBlock->ioPosMode = fsFromStart;
359: lowMemParamBlock->ioPosOffset = kIDSectorOffset * 512; // MDB is always at block #2
360: lowMemParamBlock->ioReqCount = 512; // MDB is always 1 512 byte block
361:
362: err = PBReadSync( (ParmBlkPtr) lowMemParamBlock ); // Read the MDB
363:
364: pureHFSPlusVolume = ((HFSPlusVolumeHeader *)blockBuffer)->signature == kHFSPlusSigWord;
365:
366: if ( ( ((HFSMasterDirectoryBlock *)blockBuffer)->drEmbedSigWord == kHFSPlusSigWord // Wrapped HFS+ volume
367: || pureHFSPlusVolume == true ) // Pure HFS+ volume
368: && err == noErr
369: && forceHFSWrapperToMount == false ) // if we don't want to force the wrapper to mount
370: {
371: err = MountHFSPlusVolume( vRefNum, lowMemParamBlock, err, pureHFSPlusVolume );
372: }
373: else // pass all other volume formats / errors to MountHFSVolume
374: {
375: err = MountHFSVolume( vRefNum, lowMemParamBlock, err );
376: }
377: }
378:
379: return( err ); // pass the error back to CmdDone
380: }
381: #endif /* TARGET_OS_MAC */
382:
383:
384: #if TARGET_OS_MAC
385: //�������������������������������������������������������������������������������
386: // Routine: MountHFSPlusVolume
387: //
388: // Function: Called by MountVolume()
389: //
390: // At this point we know that the MDB's Embeded signature indicates that
391: // this is an HFS Plus disk with an HFS wrapper.
392: //
393: //�������������������������������������������������������������������������������
394:
395: OSErr MountHFSPlusVolume( short driveNumber, IOParam* lowMemParamBlock, OSErr err, Boolean pureHFSPlusVolume )
396: {
397: HFSMasterDirectoryBlock *mdb;
398: Byte blockBuffer[512];
399: HFSPlusVolumeHeader *volumeHeader;
400: ExtendedVCB *vcb;
401: QHdr *vcbQHdr;
402: Byte *flagsP;
403: Byte *pbFlagsP;
404: SInt16 ioRefNum;
405: FSVarsRec *fsVars;
406: DrvQEl *dqe;
407: IOParam *currentIORequestPB;
408: FCB *fcb;
409: Ptr fcbsP;
410: ExtendedFCB *extendedFCB;
411: UInt32 hfsPlusIOPosOffset;
412: UInt16 hfsBlockCount;
413: UInt32 hfsBlockSize;
414: UInt32 lastMountedVersion;
415: UInt16 fcbIndexP;
416:
417: //-- Now read the HFS Plus VolumeHeader located at the first block within the embeded volume
418:
419: ioRefNum = lowMemParamBlock->ioRefNum;
420:
421: if ( pureHFSPlusVolume == false )
422: {
423: mdb = (HFSMasterDirectoryBlock *) lowMemParamBlock->ioBuffer;
424:
425: hfsPlusIOPosOffset = (mdb->drEmbedExtent.startBlock * mdb->drAlBlkSiz) + ( mdb->drAlBlSt * 512 );
426:
427: lowMemParamBlock->ioPosMode = fsFromStart;
428: lowMemParamBlock->ioPosOffset = hfsPlusIOPosOffset + (kIDSectorOffset * 512); // VolumeHeader is 2 sectors in
429: lowMemParamBlock->ioBuffer = (char *)blockBuffer;
430:
431: err = PBReadSync( (ParmBlkPtr) lowMemParamBlock ); // Read the VolumeHeader
432: }
433: else
434: {
435: hfsPlusIOPosOffset = 0; // From beginning of volume.
436: }
437:
438: volumeHeader = (HFSPlusVolumeHeader *) lowMemParamBlock->ioBuffer;
439:
440: err = ValidVolumeHeader( volumeHeader );
441:
442: if (err == badMDBErr || err == noMacDskErr)
443: return err; // it's not valid, so don't try to mount it
444:
445: if ( err == noErr )
446: {
447: err = notARemountErr; // cuz we're looking for remounts only here
448: vcbQHdr = LMGetVCBQHdr(); // search the queue of VCBs
449:
450: for ( vcb = (ExtendedVCB*)vcbQHdr->qHead ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink ) // search the queue of VCBs
451: {
452: if ( (vcb->vcbDrvNum == 0) // matching volume better be off-line (0 drive num)
453: && (vcb->vcbSigWord == volumeHeader->signature) // Same signature?
454: && (vcb->vcbCrDate == volumeHeader->createDate) // Same create date?
455: && (vcb->vcbWrCnt == volumeHeader->writeCount) // Same write count?
456: )
457: {
458: // At this point, we're fairly certain that the two volumes are, in fact, the same,
459: // but just to make sure (and avoid problems with stuck clocks), we'll compare the
460: // volume names as well:
461:
462: //�� How do I compare unicode names?
463: //�� do we just skip this check?
464: // if ( EqualString( vcb->volumeName, volumeHeader->volumeName, true, true) ) // caseSensitive, diacSensitive
465: break; // Remount
466: }
467: }
468: if ( vcb == nil ) goto RemountExit;
469:
470:
471: ((CntrlParam*)lowMemParamBlock)->csCode = drvStsCode; // Drive status!
472: ((CntrlParam*)lowMemParamBlock)->csParam[1] &= 0x00ff; // Clear status byte for return
473:
474: err = PBStatusSync( (ParmBlkPtr)lowMemParamBlock ); // refnum and drivenum set up by read call
475:
476:
477: //-- Now propagate the write protect status byte back to the vcb
478: flagsP = (Byte *)((Ptr)(&(vcb->vcbAtrb))) + 1;
479: pbFlagsP = (Byte *)((Ptr)(((CntrlParam*)lowMemParamBlock)->csParam)+2);
480: *flagsP = *pbFlagsP & kVolumeHardwareLockMask;
481:
482: vcb->vcbDrvNum = driveNumber;
483: vcb->vcbDRefNum = ioRefNum; // Driver RefNum
484:
485: #if ( hasHFSManualEject )
486: SetVCBManEject(vcb);
487: #endif
488:
489:
490: if ( !(*flagsP & kVolumeHardwareLockMask) ) // if bit is NOT set
491: {
492: vcb->vcbAtrb &= ~kVolumeUnmountedMask; // clear the kVolumeUnmounted attribute
493: MarkVCBDirty( vcb );
494: err = FlushVolumeControlBlock( vcb );
495: }
496:
497: err = noErr;
498:
499: }
500:
501:
502: RemountExit:
503: if ( err == noErr ) goto CmdDone; // noErr implies a successful remount
504:
505: //-- if we are allowing new mounts, let the ROM handle the details. Otherwise, let the error stand
506: fsVars = (FSVarsRec*)LMGetFSMVars();
507: if ( fsVars->fsFlags & fsNoAllocateMask )
508: goto CmdDone;
509:
510: LMSetNewMount( -1 ); // assume now that it's a new volume
511:
512:
513:
514: //-- First see if the disk is already mounted.
515: mv_Start:
516: err = paramErr;
517: driveNumber = lowMemParamBlock->ioVRefNum;
518: if ( driveNumber <= 0 ) goto MtVolDone;
519: err = GetVCBDriveNum( &vcb, driveNumber );
520: if ( err == noErr )
521: {
522: if ( vcb->vcbDrvNum != 0 )
523: {
524: err = volOnLinErr;
525: goto MtVolDone;
526: }
527: }
528:
529: //-- Find the appropriate drive queue entry and allocate a VCB.
530: err = FindDrive( &ioRefNum, &dqe, driveNumber );
531: if ( err != noErr ) goto MtVolDone;
532:
533: vcb = (ExtendedVCB *) NewPtrSysClear( sizeof( ExtendedVCB ) ); // Zero out the Extended VCB
534:
535: if ( vcb == nil ) goto MtVolDone; // exit if we got no memory
536:
537: AddVCB( vcb, driveNumber, ioRefNum ); // prep the VCB for cache calls
538:
539: //-- Now try reading in the Volume Header.
540: // We use "hfsPlusIOPosOffset / 512" cuz the VCB is not set up yet, so it's an absolute read
541: err = GetBlock_glue( gbDefault, (hfsPlusIOPosOffset / 512) + kIDSectorOffset , (Ptr*)&volumeHeader, vcb->vcbVRefNum, vcb ); // no Flags, VH is always block #0, vcb->vcbBufAdr == CacheQueueHeader
542:
543: if ( err != noErr ) goto MtVolEr2; // Quit & Release VCB on errors
544:
545: //-- Now check what manner of animal we have before us:
546: err = RelBlock_glue( (Ptr)volumeHeader, rbTrashMask );
547:
548: err = ValidVolumeHeader( volumeHeader );
549: if ( err != noErr )
550: {
551: if ( err == noMacDskErr )
552: goto MtVolEr2;
553: else
554: goto MtVolEr1;
555: }
556:
557: // The VolumeHeader seems OK: transfer info from buffer into VCB.
558:
559: // Initialize our dirID/nodePtr cache associated with this volume.
560: err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
561: ReturnIfError( err );
562:
563: //-- Copy fields between [vcbSigWord, vcbVN]
564:
565: vcb->vcbCrDate = volumeHeader->createDate; // NOTE: local time, not GMT!
566: vcb->vcbLsMod = UTCToLocal(volumeHeader->modifyDate);
567: vcb->vcbAtrb = (UInt16)volumeHeader->attributes; // VCB uses 16 bits, next 16 are for future API changes
568: vcb->vcbClpSiz = volumeHeader->rsrcClumpSize;
569: vcb->vcbNxtCNID = volumeHeader->nextCatalogID;
570: vcb->vcbVolBkUp = UTCToLocal(volumeHeader->backupDate);
571: vcb->vcbWrCnt = volumeHeader->writeCount;
572: vcb->vcbXTClpSiz = volumeHeader->extentsFile.clumpSize;
573: vcb->vcbCTClpSiz = volumeHeader->catalogFile.clumpSize;
574: vcb->attributesClumpSize = volumeHeader->attributesFile.clumpSize;
575: vcb->vcbFilCnt = volumeHeader->fileCount;
576: vcb->vcbDirCnt = volumeHeader->folderCount;
577: BlockMoveData( volumeHeader->finderInfo, vcb->vcbFndrInfo, sizeof( SInt32 ) * 8 );
578:
579: if ( pureHFSPlusVolume == true )
580: {
581: UInt32 totalSectors = (volumeHeader->blockSize / 512) * volumeHeader->totalBlocks;
582: HFSBlocksFromTotalSectors( totalSectors, &hfsBlockSize, &hfsBlockCount );
583: }
584: else
585: {
586: hfsBlockSize = mdb->drAlBlkSiz;
587: hfsBlockCount = mdb->drEmbedExtent.blockCount;
588: }
589:
590: // vcbFreeBks is the number of free bytes divided by the (HFS compatible) allocation block size. Since the
591: // number of free bytes could overflow a UInt32, we actually divide both free bytes and allocation block size by
592: // 512 before doing the division. This prevents intermediate values from overflowing until the volume size is
593: // 2 TB. It's OK to divide by 512 since both HFS and HFS Plus require allocation blocks to be a multiple of 512.
594: vcb->vcbFreeBks = (volumeHeader->freeBlocks * (volumeHeader->blockSize / 512)) / (hfsBlockSize / 512);
595:
596:
597: //-- Fields taken from the MDB
598: vcb->vcbSigWord = kHFSPlusSigWord; // new field in VCB space
599: vcb->vcbNmAlBlks = hfsBlockCount; // number of HFS allocation blocks HFS+ volume
600: vcb->vcbAlBlkSiz = hfsBlockSize; // add to extended vcb
601:
602: //-- Now fill in the Extended VCB info
603: vcb->vcbSigWord = volumeHeader->signature;
604: vcb->nextAllocation = volumeHeader->nextAllocation;
605: vcb->totalBlocks = volumeHeader->totalBlocks;
606: vcb->freeBlocks = volumeHeader->freeBlocks;
607: vcb->blockSize = volumeHeader->blockSize;
608: vcb->allocationsClumpSize = volumeHeader->allocationFile.clumpSize;
609: vcb->checkedDate = volumeHeader->checkedDate;
610: vcb->encodingsBitmap = volumeHeader->encodingsBitmap;
611:
612: // Set the allocation block start for this HFS Plus wrapped volume
613: vcb->vcbAlBlSt = hfsPlusIOPosOffset / 512;
614: vcb->hfsPlusIOPosOffset = hfsPlusIOPosOffset;
615:
616: //�� Questionables
617: vcb->vcbVBMSt = 0; //�� (We should set this) BitMap start NOT used in HFS Plus
618: vcb->vcbEmbedSigWord = 0;
619: vcb->vcbEmbedExtent.startBlock = 0;
620: vcb->vcbEmbedExtent.blockCount = 0;
621:
622:
623: //-- Mark all the unused VCB fields with 0
624: vcb->vcbAllocPtr = 0; // use extended VCB value
625:
626: // Remember which implementation last mounted this volume
627: lastMountedVersion = volumeHeader->lastMountedVersion;
628:
629: currentIORequestPB = (IOParam *) ((QHdr *)LMGetFSQHdr())->qHead; // current request
630: currentIORequestPB->ioVRefNum = vcb->vcbVRefNum; // return volume refnum to user
631:
632: lowMemParamBlock = (IOParam *) LMParamBlock;
633: ((CntrlParam*)lowMemParamBlock)->csCode = drvStsCode; // drive status!
634: ((CntrlParam*)lowMemParamBlock)->csParam[1] &= 0x00ff; // Clear status byte for return
635:
636: err = PBStatusSync( (ParmBlkPtr)lowMemParamBlock );
637:
638: flagsP = (Byte *)((Ptr)(&(vcb->vcbAtrb))) + 1;
639: pbFlagsP = (Byte *)((Ptr)(((CntrlParam*)lowMemParamBlock)->csParam)+2);
640: *flagsP = *pbFlagsP & kVolumeHardwareLockMask;
641:
642: if ( IsARamDiskDriver() )
643: {
644: vcb->vcbAtrb |= kVolumeNoCacheRequiredMask; // yes:�mark VCB as a RAM Disk
645: }
646:
647: vcb->vcbXTAlBlks = 0; // Unused, use fcb.fcbPLen instead
648: vcb->vcbCTAlBlks = 0; // Unused, use fcb.fcbPLen instead
649:
650: vcb->vcbWrCnt++; // Compensate for write of MDB on last flush
651:
652:
653: //-- Try to find three free FCBs for use by the volume control B*-Trees:
654:
655: //
656: //-- Set up the Extent FCB
657: //
658: err = FindFileControlBlock( &fcbIndexP, &fcbsP ); // Get new FCB
659: if ( err != noErr ) goto MtVolErr;
660:
661: fcb = GetFileControlBlock( fcbIndexP );
662: fcb->fcbEOF = volumeHeader->extentsFile.logicalSize.lo; // Set extent tree's LEOF
663: fcb->fcbPLen = volumeHeader->extentsFile.totalBlocks * volumeHeader->blockSize; // Set extent tree's PEOF
664:
665: vcb->extentsRefNum = fcbIndexP; // Set Extents B*-Tree file RefNum
666:
667: ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
668:
669: extendedFCB = ParallelFCBFromRefnum( fcbIndexP );
670: BlockMoveData( volumeHeader->extentsFile.extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
671:
672: //
673: //-- Set up the Catalog FCB
674: //
675: err = FindFileControlBlock( &fcbIndexP, &fcbsP );
676: if ( err != noErr ) goto MtVolErr;
677:
678: fcb = GetFileControlBlock( fcbIndexP );
679: fcb->fcbEOF = volumeHeader->catalogFile.logicalSize.lo; // Set catalog tree's LEOF
680: fcb->fcbPLen = volumeHeader->catalogFile.totalBlocks * volumeHeader->blockSize; // Set catalog tree's PEOF
681:
682: vcb->catalogRefNum = fcbIndexP; // Set Catalog B*-Tree file RefNum
683:
684: ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
685:
686: extendedFCB = ParallelFCBFromRefnum( fcbIndexP );
687: BlockMoveData( volumeHeader->catalogFile.extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
688:
689:
690: //
691: //-- Set up the Allocations FCB
692: //
693: err = FindFileControlBlock( &fcbIndexP, &fcbsP );
694: if ( err != noErr ) goto MtVolErr;
695:
696: fcb = GetFileControlBlock( fcbIndexP );
697: fcb->fcbEOF = volumeHeader->allocationFile.logicalSize.lo; // Set catalog tree's LEOF
698: fcb->fcbPLen = volumeHeader->allocationFile.totalBlocks * volumeHeader->blockSize; // Set catalog tree's PEOF
699:
700: vcb->allocationsRefNum = fcbIndexP; // Set Catalog B*-Tree file RefNum
701:
702: ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
703:
704: extendedFCB = ParallelFCBFromRefnum( fcbIndexP );
705: BlockMoveData( volumeHeader->allocationFile.extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
706:
707:
708: //
709: //-- Set up the Attributes FCB
710: //
711: vcb->attributesRefNum = 0; // In case there isn't an attributes BTree
712:
713: if (volumeHeader->attributesFile.extents[0].blockCount != 0)
714: {
715: err = FindFileControlBlock( &fcbIndexP, &fcbsP );
716: if ( err != noErr ) goto MtVolErr;
717:
718: fcb = GetFileControlBlock( fcbIndexP );
719: fcb->fcbEOF = volumeHeader->attributesFile.logicalSize.lo; // Set attribute tree's LEOF
720: fcb->fcbPLen = volumeHeader->attributesFile.totalBlocks * volumeHeader->blockSize; // Set attribute tree's PEOF
721:
722: vcb->attributesRefNum = fcbIndexP; // Set Catalog B*-Tree file RefNum
723:
724: ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
725:
726: extendedFCB = ParallelFCBFromRefnum( fcbIndexP );
727: BlockMoveData( volumeHeader->attributesFile.extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
728: }
729:
730:
731: vcb->vcbMAdr = (Ptr)*(long *)SysBMCPtr; // Set up the volume bitmap cache
732: vcb->vcbCtlBuf = (Ptr)*(long *)SysCtlCPtr; // Set up the volume control cache
733:
734: //
735: //-- Finish setting up the FCBs for the extent B*-Tree and the catalog B*-Tree:
736: //
737:
738: err = AccessBTree( vcb, vcb->extentsRefNum, kHFSExtentsFileID, vcb->vcbXTClpSiz, (void *) CompareExtentKeysPlus );
739: if ( err != noErr ) goto MtChkErr;
740:
741: err = AccessBTree( vcb, vcb->catalogRefNum, kHFSCatalogFileID, vcb->vcbCTClpSiz, (void *) CompareExtendedCatalogKeys );
742: if ( err != noErr ) goto MtChkErr;
743:
744: if (vcb->attributesRefNum)
745: {
746: err = AccessBTree( vcb, vcb->attributesRefNum, kHFSAttributesFileID, vcb->attributesClumpSize, (void *) CompareAttributeKeys );
747: if ( err != noErr ) goto MtChkErr;
748: }
749:
750: (void) SetupFCB( vcb, vcb->allocationsRefNum, kHFSAllocationFileID, volumeHeader->allocationFile.clumpSize );
751:
752:
753: err = CreateVolumeCatalogCache(vcb);
754: if ( err )
755: goto MtChkErr;
756:
757: // set up root file count...
758:
759: vcb->vcbNmFls = CountRootFiles(vcb);
760:
761:
762: // Get the volume name from the catalog file
763: (void) GetVolumeNameFromCatalog(vcb);
764:
765: // If the volume was not unmounted properly, then run MountCheck.
766: // If the volume was last mounted by Bride 1.0b2 ('8.01'), then the create date may be wrong, so
767: // we should run MountCheck to fix it.
768: if ( !(vcb->vcbAtrb & (short)kVolumeUnmountedMask) ||
769: lastMountedVersion == '8.01')
770: {
771: UInt32 consistencyStatus;
772:
773: vcb->vcbAtrb &= ~kVolumeUnmountedMask; // From now until _Unmount (clear the bit)
774: *(Ptr)FSCallAsync = 0;
775: err = MountCheck( vcb, &consistencyStatus );
776: if ( err )
777: goto MtChkErr;
778: }
779: else
780: {
781: vcb->vcbAtrb &= ~kVolumeUnmountedMask; // From now until _Unmount (clear the bit)
782: }
783:
784: CheckRemount:
785:
786: // ��This comment was in TFSVol.a, should look into it
787: // Deleted stuff patched out by KillCheckRemountNiceWay in FileMgrPatches.a <SM1>
788:
789:
790: MtVolOK:
791: err = noErr;
792:
793: MtVolDone:
794: if ( err == noErr )
795: {
796: if ( !(vcb->vcbAtrb & kVolumeHardwareLockMask) ) // if the disk is not write protected
797: {
798: MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
799: err = FlushVolumeControlBlock( vcb ); // Go flush the VCB info BEFORE close
800: }
801: }
802: goto CmdDone;
803:
804:
805:
806: MtChkErr:
807: (void) DisposeVolumeCatalogCache(vcb);
808: InvalidateCatalogCache( vcb );
809:
810: *((OSErr *)HFSDSErr) = err;
811: err = badMDBErr;
812:
813: //-- Release any resources allocated so far before exiting with an error:
814: MtVolErr:
815: DisposeFileControlBlocks( vcb ); // deallocate control file FCBs
816:
817: MtVolEr1:
818: DisposeVolumeCacheBlocks( vcb ); // invalidate any cache blocks for this volume
819:
820: MtVolEr2:
821: if ( (Byte)LMGetNewMount() == 0 ) // only deallocate VCB for new mounts
822: {
823: // Remount case -- Must zero buffer and map ptrs in old VCB.
824: // Restore VCB to its original off-line state (ie clear VCBDrvNum,
825: // and move drive number to VCBDRefNum field)
826: vcb->vcbDRefNum = vcb->vcbDrvNum; // write drv number to VCBDRefNum field
827: vcb->vcbDRefNum = 0; // clear drive number field of VCB
828: vcb->vcbMAdr = nil; // clear mapptr in VCB
829: vcb->vcbBufAdr = nil; // clear buffptr in VCB
830: }
831: else
832: {
833: DisposeVolumeControlBlock( vcb );
834: }
835:
836: if ( err <= 0 ) goto CmdDone;
837:
838: currentIORequestPB = (IOParam *) ((QHdr *)LMGetFSQHdr())->qHead;
839: goto mv_Start;
840:
841: CmdDone:
842: return( err );
843:
844: }
845: #endif /* TARGET_OS_MAC */
846:
847:
848:
849: #if TARGET_OS_MAC
850: //�������������������������������������������������������������������������������
851: // Routine: MountHFSVolume
852: //
853: // Function: The VCB pointers are checked to see if a volume in the
854: // specified drive is already on-line (error if so). Reads in the
855: // directory master block and allocates memory for VCB and additional
856: // data structures, depending on the volume type:
857: //
858: // - For MFS volumes (handled in MFSVol), space is allocated for
859: // a volume buffer, as well as the block map, which is read in
860: // from disk).
861: //
862: // - For TFS volumes, space is allocated for a bitmap cache, a volume
863: // control cache (for B*-Tree use), and a volume cache. In addition,
864: // two FCBs are used by the B*-Trees.
865: //
866: // No new VCB storage is allocated for remounts.
867: //
868: //�������������������������������������������������������������������������������
869:
870: OSErr MountHFSVolume( short driveNumber, IOParam* lowMemParamBlock, OSErr err )
871: {
872: HFSMasterDirectoryBlock *mdb;
873: QHdr *vcbQHdr;
874: Byte *flagsP;
875: Byte *mdbFlagsP;
876: FSVarsRec *fsVars;
877: IOParam *currentIORequestPB;
878: Ptr fcbsP;
879: FCB *fcb;
880: ExtendedVCB *vcb;
881: DrvQEl *dqe;
882: short ioRefNum;
883: UInt16 fcbIndexP;
884:
885: if ( err != noErr )
886: goto RemountExit;
887:
888: ioRefNum = lowMemParamBlock->ioRefNum;
889: mdb = (HFSMasterDirectoryBlock *) lowMemParamBlock->ioBuffer; // �� figure out how we use VolumeHeader & MasterDirectoryBlock, size of structures, etc.
890:
891: err = ValidMasterDirectoryBlock( mdb ); // is this an HFS/HFS PlusDisk
892: if ( err == noErr )
893: {
894: err = notARemountErr; // cuz we're looking for remounts only here
895: vcbQHdr = LMGetVCBQHdr(); // search the queue of VCBs
896:
897: // CheckRemountLoop:
898: for ( vcb = (ExtendedVCB*)vcbQHdr->qHead ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink ) // search the queue of VCBs
899: {
900: if ( (vcb->vcbDrvNum == 0) // matching volume better be off-line (0 drive num)
901: && (vcb->vcbSigWord == mdb->drSigWord) // Same signature?
902: && (vcb->vcbCrDate == mdb->drCrDate) // Same create date?
903: && (vcb->vcbLsMod == mdb->drLsMod) // Same mod date?
904: )
905: {
906: // At this point, we're fairly certain that the two volumes are, in fact, the same,
907: // but just to make sure (and avoid problems with stuck clocks), we'll compare the
908: // volume names as well:
909: //�� Modify this call to use the extended VCB ascii name, not the Unicode name
910: if ( EqualString( vcb->vcbVN, mdb->drVN, true, true) ) // caseSensitive, diacSensitive
911: break; // Remount
912: }
913: }
914: if ( vcb == nil ) goto RemountExit;
915:
916: // We are now convinced that we have a remount. We will rebuild the attributes
917: // byte, which is the only one that could have changed. We'll also store the
918: // current drive number and driver refNum, and mark the volume dirty.
919: // Remount:
920:
921: ((CntrlParam*)lowMemParamBlock)->csCode = drvStsCode; // Drive status!
922: ((CntrlParam*)lowMemParamBlock)->csParam[1] &= 0x00ff; // Clear status byte for return
923:
924: err = PBStatusSync( (ParmBlkPtr)lowMemParamBlock ); // refnum and drivenum set up by read call
925:
926: //-- Now propagate the write protect status byte back to the vcb
927: flagsP = ((Byte *)(&(vcb->vcbAtrb))) + 1;
928: mdbFlagsP = ((Byte *)(((CntrlParam*)lowMemParamBlock)->csParam)+2);
929: *flagsP = *mdbFlagsP & kVolumeHardwareLockMask;
930:
931: vcb->vcbDrvNum = driveNumber;
932: vcb->vcbDRefNum = ioRefNum; // Driver RefNum
933:
934: #if ( hasHFSManualEject )
935: SetVCBManEject(vcb);
936: #endif
937:
938: if ( !(*flagsP & kVolumeHardwareLockMask) ) // if bit is NOT set
939: {
940: vcb->vcbAtrb &= ~kVolumeUnmountedMask; // clear the kVolumeUnmounted attribute
941: MarkVCBDirty( vcb );
942: err = FlushVolumeControlBlock( vcb ); // Go flush the VCB info BEFORE close
943: }
944:
945: err = noErr;
946: }
947:
948:
949: RemountExit:
950: if ( err == noErr )
951: goto CmdDone; // noErr implies a successful remount
952:
953: //-- if we are allowing new mounts, let the ROM handle the details. Otherwise, let the error stand
954: fsVars = (FSVarsRec*)LMGetFSMVars(); // $BB8
955: if ( fsVars->fsFlags & fsNoAllocateMask )
956: goto CmdDone;
957:
958: //�� This sets the word to -1, Asm only set the byte to -1
959: LMSetNewMount( -1 ); // assume now that it's a new volume
960:
961:
962:
963: //-- First see if the disk is already mounted.
964: mv_Start:
965: err = paramErr;
966: driveNumber = lowMemParamBlock->ioVRefNum;
967: if ( driveNumber <= 0 )
968: goto MtVolDone;
969:
970: err = GetVCBDriveNum( &vcb, driveNumber );
971: if ( err == noErr )
972: {
973: if ( vcb->vcbDrvNum != 0 )
974: {
975: err = volOnLinErr;
976: goto MtVolDone;
977: }
978: }
979:
980: //-- Find the appropriate drive queue entry and allocate a VCB.
981: err = FindDrive( &ioRefNum, &dqe, driveNumber );
982: if ( err != noErr ) goto MtVolDone;
983:
984: vcb = (ExtendedVCB *) NewPtrSysClear( sizeof( ExtendedVCB ) );
985:
986: if ( vcb == nil ) goto MtVolDone; // exit if we got no memory
987:
988: AddVCB( vcb, driveNumber, ioRefNum ); // prep the VCB for cache calls
989:
990: //-- Now try reading in the master directory block.
991: err = GetBlock_glue( gbDefault, kIDSectorOffset, (Ptr*)&mdb, vcb->vcbVRefNum, vcb ); // no Flags, MDB is always block #2, vcb->vcbBufAdr == CacheQueueHeader
992: if ( err != noErr ) goto MtVolEr2; // Quit & Release VCB on errors
993:
994: //-- Now check what manner of animal we have before us:
995: err = RelBlock_glue( (Ptr)mdb, rbTrashMask );
996:
997: err = ValidMasterDirectoryBlock( mdb );
998: if ( err != noErr )
999: {
1000: if ( err == noMacDskErr )
1001: goto MtVolEr2;
1002: else
1003: goto MtVolEr1;
1004: }
1005:
1006: // The MDB seems OK: transfer all master directory info from buffer into VCB.
1007:
1008: // vcbSigWord is the start of duplicate mdb/vcb info. Asm VCBDInfoSt Equ 8
1009: // copy all fields in mdb till the drVolBkUp field
1010:
1011: BlockMoveData( mdb, &(vcb->vcbSigWord), (Size)(&(mdb->drVolBkUp)) - (Size)mdb );
1012:
1013: // Initialize our dirID/nodePtr cache associated with this volume.
1014: err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
1015: ReturnIfError( err );
1016:
1017: //-- Some fields, vcbNmAlBlks, vcbAlBlkSiz, and vcbFreeBks are just around for API compatability.
1018: //-- The HFS/HFS Plus code we will use the corresponding ExtendedVCB fields. vcbNmAlBlks * vcbAlBlkSiz
1019: //-- still gives correct volume size.
1020: vcb->totalBlocks = vcb->vcbNmAlBlks;
1021: vcb->freeBlocks = vcb->vcbFreeBks;
1022: vcb->blockSize = vcb->vcbAlBlkSiz;
1023:
1024:
1025: currentIORequestPB = (IOParam *) ((QHdr *)LMGetFSQHdr())->qHead; // current request
1026: currentIORequestPB->ioVRefNum = vcb->vcbVRefNum; // return volume refnum to user
1027:
1028: lowMemParamBlock = (IOParam *) LMParamBlock;
1029: ((CntrlParam*)lowMemParamBlock)->csCode = drvStsCode; // drive status!
1030: ((CntrlParam*)lowMemParamBlock)->csParam[1] &= 0x00ff; // Clear status byte for return
1031:
1032: err = PBStatusSync( (ParmBlkPtr)lowMemParamBlock );
1033:
1034: flagsP = ((Byte *)(&(vcb->vcbAtrb))) + 1;
1035: mdbFlagsP = ((Byte *)(((CntrlParam*)lowMemParamBlock)->csParam)+2);
1036: *flagsP = *mdbFlagsP & kVolumeHardwareLockMask;
1037:
1038: if ( IsARamDiskDriver() )
1039: {
1040: vcb->vcbAtrb |= kVolumeNoCacheRequiredMask; // yes:�mark VCB as a RAM Disk
1041: }
1042:
1043: //-- copy all fields in mdb between drXTFlSize & drVolBkUp
1044: BlockMoveData( &(mdb->drVolBkUp), &(vcb->vcbVolBkUp), (Size)&(mdb->drXTFlSize) - (Size)&(mdb->drVolBkUp) ); // 66 bytes
1045:
1046: vcb->vcbXTAlBlks = DivUp( mdb->drXTFlSize, vcb->blockSize ); // Pick up PEOF of extent B*-Tree
1047: vcb->vcbCTAlBlks = DivUp( mdb->drCTFlSize, vcb->blockSize ); // Pick up PEOF of catalog B*-Tree
1048:
1049: // ��� WHY ARE WE RESTARTING THE ROAVING PTR
1050: vcb->nextAllocation = mdb->drAllocPtr;
1051: vcb->vcbAllocPtr = 0; // Restart the roving allocation ptr
1052: vcb->vcbWrCnt++; // Compensate for write of MDB on last flush
1053:
1054:
1055: //-- Try to find two free FCBs for use by the volume control B*-Trees:
1056:
1057: //-- Set up the Extent FCB
1058: err = FindFileControlBlock( &fcbIndexP, &fcbsP );
1059: if ( err != noErr ) goto MtVolErr;
1060:
1061: fcb = GetFileControlBlock( fcbIndexP );
1062: fcb->fcbEOF = mdb->drXTFlSize; // Set catalog tree's LEOF
1063: fcb->fcbPLen = mdb->drXTFlSize; // Set catalog tree's PEOF
1064:
1065: vcb->extentsRefNum = fcbIndexP; // Set Extents B*-Tree file RefNum
1066: BlockMoveData( mdb->drXTExtRec, fcb->fcbExtRec, sizeof(HFSExtentRecord) );
1067:
1068:
1069: //-- Set up the Catalog FCB
1070: err = FindFileControlBlock( &fcbIndexP, &fcbsP );
1071: if ( err != noErr ) goto MtVolErr;
1072:
1073: fcb = GetFileControlBlock( fcbIndexP );
1074: fcb->fcbEOF = mdb->drCTFlSize; // Set catalog tree's LEOF
1075: fcb->fcbPLen = mdb->drCTFlSize; // Set catalog tree's PEOF
1076:
1077: vcb->catalogRefNum = fcbIndexP; // Set Catalog B*-Tree file RefNum
1078: BlockMoveData( mdb->drCTExtRec, fcb->fcbExtRec, sizeof(HFSExtentRecord) );
1079:
1080:
1081: vcb->vcbMAdr = (Ptr)*(long *)SysBMCPtr; // Set up the volume bitmap cache
1082: vcb->vcbCtlBuf = (Ptr)*(long *)SysCtlCPtr; // Set up the volume control cache
1083:
1084:
1085: //-- Finish setting up the FCBs for the extent B*-Tree and the catalog B*-Tree:
1086:
1087: err = AccessBTree( vcb, vcb->extentsRefNum, kHFSExtentsFileID, vcb->vcbXTClpSiz, (void *) CompareExtentKeys );
1088: if ( err != noErr ) goto MtChkErr;
1089:
1090: err = AccessBTree( vcb, vcb->catalogRefNum, kHFSCatalogFileID, vcb->vcbCTClpSiz, (void *) CompareCatalogKeys );
1091: if ( err != noErr ) goto MtChkErr;
1092:
1093: err = CreateVolumeCatalogCache(vcb);
1094: if ( err ) goto MtChkErr;
1095:
1096: if ( !(vcb->vcbAtrb & (short)kVolumeUnmountedMask) )
1097: {
1098: UInt32 consistencyStatus;
1099:
1100: vcb->vcbAtrb &= ~kVolumeUnmountedMask; // From now until _Unmount (clear the bit)
1101: *(Ptr)FSCallAsync = 0;
1102: err = MountCheck( vcb, &consistencyStatus );
1103: if ( err ) goto MtChkErr;
1104: }
1105: else
1106: {
1107: vcb->vcbAtrb &= ~kVolumeUnmountedMask; // From now until _Unmount (clear the bit)
1108: }
1109:
1110: CheckRemount:
1111:
1112: // ��This comment was in TFSVol.a, should look into it
1113: // Deleted stuff patched out by KillCheckRemountNiceWay in FileMgrPatches.a <SM1>
1114:
1115:
1116: MtVolOK:
1117: err = noErr;
1118:
1119: MtVolDone:
1120: if ( err == noErr )
1121: {
1122: if ( !(vcb->vcbAtrb & kVolumeHardwareLockMask) ) // if the disk is not write protected
1123: {
1124: MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
1125: err = FlushVolumeControlBlock( vcb ); // Go flush the VCB info BEFORE close
1126: }
1127: }
1128: goto CmdDone;
1129:
1130:
1131:
1132: MtChkErr:
1133: (void) DisposeVolumeCatalogCache(vcb);
1134: InvalidateCatalogCache( vcb );
1135:
1136:
1137: *((OSErr *)HFSDSErr) = err;
1138: err = badMDBErr;
1139:
1140: //-- Release any resources allocated so far before exiting with an error:
1141: MtVolErr:
1142: DisposeFileControlBlocks( vcb ); // deallocate control file FCBs
1143:
1144: MtVolEr1:
1145: DisposeVolumeCacheBlocks( vcb ); // invalidate any cache blocks for this volume
1146:
1147: MtVolEr2:
1148: if ( (Byte)LMGetNewMount() == 0 ) // only deallocate VCB for new mounts
1149: {
1150: // Remount case -- Must zero buffer and map ptrs in old VCB.
1151: // Restore VCB to its original off-line state (ie clear VCBDrvNum,
1152: // and move drive number to VCBDRefNum field)
1153: vcb->vcbDRefNum = vcb->vcbDrvNum; // write drv number to VCBDRefNum field
1154: vcb->vcbDRefNum = 0; // clear drive number field of VCB
1155: vcb->vcbMAdr = nil; // clear mapptr in VCB
1156: vcb->vcbBufAdr = nil; // clear buffptr in VCB
1157: }
1158: else
1159: {
1160: DisposeVolumeControlBlock( vcb );
1161: }
1162:
1163: if ( err <= 0 )
1164: goto CmdDone;
1165: currentIORequestPB = (IOParam *) ((QHdr *)LMGetFSQHdr())->qHead;
1166: goto mv_Start;
1167:
1168: CmdDone:
1169: return( err );
1170:
1171: }
1172: #endif /* TARGET_OS_MAC */
1173:
1174:
1175: #if TARGET_OS_MAC
1176: //�������������������������������������������������������������������������������
1177: // Routine: UnMountVolume
1178: //
1179: // Function: All files on the volume in the drive are closed and any changed
1180: // directory information is written out to the diskette. Memory
1181: // for the VCB, volume buffer, and block map is deallocated.
1182: //
1183: //�������������������������������������������������������������������������������
1184:
1185: OSErr UnMountVolume( VolumeParam *volume, WDCBRecPtr *wdcb )
1186: {
1187: FCB *fcb;
1188: OSErr err;
1189: SInt16 nameLength;
1190: Boolean nameSpecified;
1191: ExtendedVCB *vcb;
1192: unsigned char *pathName;
1193: UInt16 index;
1194: Ptr fcbs;
1195: Boolean doneSearching;
1196: Boolean isHFSPlus;
1197: FSSpec spec;
1198: UInt16 driveNumber;
1199: HFSMasterDirectoryBlock *mdb;
1200: Boolean mustRenameWrapperVolume = false;
1201:
1202: LMSetFlushOnly( 0 ); // Setup same as UnmountVol
1203: err = DeturmineVolume3( volume, &nameLength, &nameSpecified, &vcb, wdcb, &pathName );
1204: if ( err != noErr )
1205: goto CmdDone;
1206:
1207: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
1208:
1209: //-- Get the volume name from the catalog file to set in the HFS wrapper later
1210: if ( (isHFSPlus) && (vcb->vcbDrvNum != 0) ) // HFS+ volume and on-line
1211: {
1212: UInt32 hint;
1213: CatalogNodeData nodeData;
1214:
1215: err = GetCatalogNode( vcb, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint );
1216: if ( err == noErr )
1217: {
1218: err = GetBlock_glue( gbDefault, kIDSectorOffset, (Ptr*)&mdb, vcb->vcbVRefNum, vcb ); // Read the MDB
1219: if ( err == noErr )
1220: {
1221: if ( mdb->drSigWord == kHFSSigWord ) // it's a wrapped volume
1222: {
1223: if ( memcmp( spec.name, mdb->drVN, spec.name[0]+1 ) != 0 ) // Has the name changed?
1224: {
1225: driveNumber = vcb->vcbDrvNum;
1226: mustRenameWrapperVolume = true;
1227: }
1228: }
1229: err = RelBlock_glue( (Ptr)mdb, rbTrashMask );
1230: }
1231: }
1232: }
1233:
1234: // Initialize fcbs pointer
1235: Get1stFileControlBlock( &index, &fcbs );
1236:
1237: if ( !(volume->ioTrap & kHFSMask) ) // if NOT Unconditional unmount?
1238: {
1239: //-- Search the FCB array for open files that reference the volume...
1240: do
1241: {
1242: fcb = GetFileControlBlock( index );
1243: if ( (fcb->fcbFlNm != 0) && (fcb->fcbVPtr == vcb) ) // The file is currently open and on this volume
1244: {
1245: if ( fcb->fcbFlNm >= fsUsrCNID ) // is it a user file?
1246: {
1247: //-- Found an open user file on the volume, so return a busy condition...
1248: err = fBsyErr;
1249: break;
1250: }
1251: }
1252:
1253: doneSearching = GetNextFileControlBlock( &index, fcbs );
1254:
1255: } while ( !doneSearching );
1256: }
1257:
1258: if ( err == noErr )
1259: {
1260: err = CheckExternalFileSystem( vcb );
1261: if ( err == noErr )
1262: {
1263: FlushVolume( vcb );
1264: // Unmounting a TFS volume: close the volume control B*-Tree and use the
1265: // volume buffer to write out the MDB
1266:
1267: // From UnmountForTheNineties in FileMgrPatches.a
1268: // Here's the change: we no longer check whether the volume is offline. Instead we always
1269: // go ahead and close the control files, since we no longer close them on _Offline or _Eject.
1270:
1271: if ( vcb->vcbDrvNum != 0 ) // Check drive number: vol. offline?
1272: {
1273: err = FlushVolumeBuffers( vcb );
1274: if ( err != noErr )
1275: goto CmdDone; // Punt on errors
1276: }
1277: else
1278: {
1279: // here begins CloseControlFiles, which is derived from FlushBuffers
1280: // Now we have to close the control files because we no longer close them
1281: // in Eject and Offline
1282:
1283: if ( LMGetFlushOnly() == 0 ) // volume needs flushing
1284: {
1285: err = CloseFile( vcb, vcb->catalogRefNum, fcbs );
1286: if ( err != noErr )
1287: goto CmdDone; // Punt on errors
1288:
1289: err = CloseFile( vcb, vcb->extentsRefNum, fcbs );
1290: if ( err != noErr )
1291: goto CmdDone; // Punt on errors
1292:
1293: if ( isHFSPlus )
1294: {
1295: err = AttributesCloseVolume( vcb );
1296: if ( err != noErr )
1297: goto CmdDone;
1298:
1299: err = CloseFile( vcb, vcb->allocationsRefNum, fcbs );
1300: if ( err != noErr )
1301: goto CmdDone;
1302: }
1303:
1304: (void) DisposeMRUCache(vcb->hintCachePtr);
1305: (void) DisposeVolumeCatalogCache(vcb);
1306: InvalidateCatalogCache( vcb );
1307: DisposeVolumeCacheBlocks( vcb );
1308: }
1309: }
1310:
1311: if ( LMGetFlushOnly() == 0 ) // volume needs flushing
1312: {
1313: // For UnMountVol, dequeue the VCB and trash any WDCBs for this volume ...
1314: DisposeVolumeControlBlock( vcb );
1315: }
1316:
1317: // The volume is now unmounted, if it's an HFS+ volume, and the name does not match what's
1318: // in the MDB, mount the HFS wrapper rename the wrapper volume and unmount it.
1319: if ( mustRenameWrapperVolume )
1320: {
1321: RenameWrapperVolume( spec.name, driveNumber );
1322: }
1323:
1324: err = noErr;
1325: }
1326: }
1327:
1328: CmdDone:
1329: return( err );
1330: }
1331: #endif /* TARGET_OS_MAC */
1332:
1333:
1334: #if TARGET_OS_MAC
1335: //�������������������������������������������������������������������������������
1336: // Routine: RenameWrapperVolume
1337: //
1338: // Function: Called during UnmountVolume if the HFS+ volume name does not
1339: // match the name stored in the wrapper MDB. This function
1340: // renames the HFS wrapper volume.
1341: //
1342: //�������������������������������������������������������������������������������
1343: void RenameWrapperVolume( Str27 newVolumeName, UInt16 driveNumber )
1344: {
1345: VolumeParam volume;
1346: ExtendedVCB *vcb;
1347: OSErr err;
1348: UInt32 hint;
1349: FSSpec spec;
1350: CatalogNodeData nodeData;
1351: Ptr pmsp;
1352: UInt32 modDate;
1353: WDCBRecPtr wdcbPtr;
1354:
1355: ClearMemory( &volume, sizeof(VolumeParam) );
1356: volume.ioVRefNum = driveNumber;
1357:
1358: err = MountVolume( &volume, true );
1359: if ( err != noErr )
1360: return; // punt on errors
1361:
1362: err = GetVCBDriveNum( &vcb, driveNumber );
1363: if ( err != noErr )
1364: goto ErrorExit; // punt on errors
1365:
1366: modDate = vcb->vcbLsMod;
1367:
1368: err = GetCatalogNode( vcb, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint );
1369: if ( err != noErr )
1370: {
1371: #if DEBUG_BUILD
1372: DebugStr("\p GetCatalogNode failed");
1373: #endif
1374: goto ErrorExit; // punt on errors
1375: }
1376:
1377: err = RenameCatalogNode( vcb, kHFSRootParentID, spec.name, newVolumeName, hint, &hint );
1378: if ( err != noErr )
1379: {
1380: #if DEBUG_BUILD
1381: DebugStr("\p RenameCatalogNode failed");
1382: #endif
1383: goto ErrorExit; // punt on errors
1384: }
1385:
1386: BlockMoveData( newVolumeName, vcb->vcbVN, sizeof(Str27) );
1387: vcb->vcbLsMod = modDate;
1388: MarkVCBDirty( vcb );
1389:
1390: pmsp = LMGetPMSPPtr();
1391: *((short*)(pmsp + kPoorMansSearchIndex)) = 0; // Invalidate Poor Mans search path
1392:
1393: ErrorExit:
1394:
1395: (void) UnMountVolume( &volume, &wdcbPtr );
1396: }
1397: #endif /*TARGET_OS_MAC */
1398:
1399:
1400: #if TARGET_OS_MAC
1401: //�������������������������������������������������������������������������������
1402: // Routine: CheckExternalFileSystem Asm: CkExtFS
1403: //
1404: // Function: Simple routine to separate out calls to be handled by an
1405: // external file system.
1406: //
1407: //�������������������������������������������������������������������������������
1408: OSErr CheckExternalFileSystem( ExtendedVCB *vcb )
1409: {
1410: if ( vcb->vcbFSID == 0 )
1411: {
1412: return( noErr );
1413: }
1414: else
1415: {
1416: return( extFSErr );
1417: }
1418: }
1419: #endif /* TARGET_OS_MAC */
1420:
1421:
1422:
1423:
1424: //�������������������������������������������������������������������������������
1425: // Routine: CheckVolumeConsistancy
1426: //
1427: // Function: Check kBootVolumeInconsistentMask, and run MountCheck if necessary
1428: //�������������������������������������������������������������������������������
1429: OSErr CheckVolumeConsistency( ExtendedVCB *vcb )
1430: {
1431: UInt32 consistencyStatus;
1432: OSErr err = noErr;
1433:
1434: #if TARGET_OS_RHAPSODY
1435: if ( vcb->vcbSigWord == kHFSSigWord) // and is an HFS disk
1436: #else /* TARGET_OS_RHAPSODY */
1437: if ( ( *((UInt16*)&(((ROMHeaderRec *) LMGetROMBase())->MachineNumber)) == 0x077D ) && // is supermario based
1438: ( vcb->vcbSigWord == kHFSSigWord ) ) // and is an HFS disk
1439: #endif /* TARGET_OS_RHAPSODY */
1440: {
1441: if ( vcb->vcbAtrb & kHFSBootVolumeInconsistentMask ) // was marked inconsistant
1442: {
1443: err = MountCheck( vcb, &consistencyStatus );
1444:
1445: if ( err == noErr )
1446: vcb->vcbAtrb &= ~kHFSVolumeSoftwareLockMask; // clear the bit
1447: }
1448: #if TARGET_OS_MAC
1449: if ( LMGetBootDrive() == vcb->vcbDrvNum ) // this is the boot volume
1450: vcb->vcbAtrb |= kHFSBootVolumeInconsistentMask;
1451: #endif /* TARGET_OS_MAC */
1452: }
1453:
1454: return( err );
1455: }
1456:
1457:
1458:
1459:
1460: //�������������������������������������������������������������������������������
1461: // Routine: VolumeWritable Asm: CVFlgs
1462: //
1463: // Function: Check the volume's flags to see if modify requests are allowed.
1464: //
1465: //�������������������������������������������������������������������������������
1466: OSErr VolumeWritable( ExtendedVCB *vcb )
1467: {
1468: if ( !(vcb->vcbAtrb & 0x8000) ) // if the volume is not locked
1469: {
1470: if ( ! (*((Ptr)&(vcb->vcbAtrb) + 1) & kHFSVolumeHardwareLockMask) ) // if it's not write protected
1471: return( noErr );
1472: else
1473: return( wPrErr );
1474: }
1475: else
1476: {
1477: return( vLckdErr );
1478: }
1479: }
1480:
1481:
1482:
1483:
1484:
1485: #if TARGET_OS_MAC
1486:
1487: //�������������������������������������������������������������������������������
1488: // Routine: FlushVolume Asm: FlushVFiles
1489: //
1490: // Function: All file buffers on the volume are flushed and any changed
1491: // directory information is written out to the disk.
1492: //
1493: //�������������������������������������������������������������������������������
1494: OSErr FlushVolume( ExtendedVCB *vcb )
1495: {
1496: UInt16 index;
1497: Ptr fcbs;
1498: FCB *fcb;
1499: OSErr err;
1500: Boolean doneSearching;
1501:
1502: Get1stFileControlBlock( &index, &fcbs );
1503:
1504: //ckNxtFCB
1505: err = noErr;
1506: do
1507: {
1508: fcb = GetFileControlBlock( index );
1509: if ( (fcb->fcbFlNm != 0) && (fcb->fcbVPtr == vcb) ) // The file is currently open and on this volume
1510: {
1511: if ( fcb->fcbFlNm >= fsUsrCNID ) // is it a user file?
1512: {
1513: //-- Found an open user file on the volume, so return a busy condition...
1514: err = CloseFile( vcb, index, fcbs );
1515: if ( err != noErr )
1516: break;
1517: }
1518: }
1519:
1520: doneSearching = GetNextFileControlBlock( &index, fcbs );
1521:
1522: } while ( !doneSearching );
1523:
1524: return( err );
1525: }
1526:
1527:
1528:
1529: //�������������������������������������������������������������������������������
1530: // Routine: DisposeFileControlBlocks from Asm: DsposFCBs
1531: //
1532: // Function: Clears the extent B*-Tree refNum & catalog refnum
1533: //
1534: //�������������������������������������������������������������������������������
1535: void DisposeFileControlBlocks( ExtendedVCB *vcb )
1536: {
1537: OSErr err;
1538:
1539: err = AttributesCloseVolume( vcb );
1540: #if DEBUG_BUILD
1541: if ( err != noErr ) DebugStr("\pHFS+: Can't close Property Manager");
1542: #endif
1543:
1544: if ( vcb->extentsRefNum != 0 )
1545: {
1546: //-- Clear extent B*-Tree refNum file number in FCB as unused
1547: ( (FCB *) ( LMGetFCBSPtr() + vcb->extentsRefNum ) )->fcbFlNm = 0L;
1548: }
1549: if ( vcb->catalogRefNum != 0 )
1550: {
1551: //-- Clear catalog refnum file number in FCB as unused
1552: ( (FCB *) ( LMGetFCBSPtr() + vcb->catalogRefNum ) )->fcbFlNm = 0L;
1553: }
1554:
1555: if ( vcb->vcbSigWord == kHFSPlusSigWord && vcb->allocationsRefNum != 0)
1556: {
1557: //-- Clear allocation (bitmap) file number in FCB as unused
1558: ( (FCB *) ( LMGetFCBSPtr() + vcb->allocationsRefNum ) )->fcbFlNm = 0L;
1559: }
1560: }
1561:
1562: #endif /* TARGET_OS_MAC */
1563:
1564:
1565: //�������������������������������������������������������������������������������
1566: // Routine: AccessBTree from Asm: AccessBT
1567: //
1568: // Function: Create an access path for a B*-Tree file:
1569: // 1. Initialize the FCB
1570: // 2. Attach a B*-Tree control block
1571: //
1572: // Note: For now the compare proc is the entry to the assembly glue calling a C compare function.
1573: // Once BTOpen is ported to C, we can pass in C comparison routines.
1574: //
1575: // Result: I/O result from BTOpen
1576: //�������������������������������������������������������������������������������
1577: #if TARGET_OS_MAC
1578: OSErr AccessBTree( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize, void *CompareRoutine )
1579: {
1580: FCB *fcb;
1581: OSErr err;
1582:
1583: fcb = SetupFCB( vcb, refNum, fileID, fileClumpSize );
1584:
1585: err = OpenBTree( refNum, CompareRoutine );
1586:
1587: return( err );
1588: }
1589: #endif /* TARGET_OS_MAC */
1590:
1591: //�������������������������������������������������������������������������������
1592: // Routine: SetupFCB fills in the FCB info
1593: //
1594: // Returns: The filled up FCB
1595: //�������������������������������������������������������������������������������
1596: #if TARGET_OS_MAC
1597: FCB *SetupFCB( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize )
1598: {
1599: FCB *fcb;
1600:
1601: fcb = (FCB *) GetFileControlBlock( refNum );
1602:
1603: fcb->fcbFlags = 0;
1604: fcb->fcbSBlk = 0;
1605: fcb->fcbCrPs = 0;
1606: fcb->fcbFlNm = fileID;
1607: fcb->fcbVPtr = vcb;
1608: fcb->fcbClmpSize = fileClumpSize;
1609:
1610: // for debugging...
1611: switch (fileID)
1612: {
1613: case kHFSExtentsFileID:
1614: BlockMoveData( "\p**** EXTENTS B-TREE", fcb->fcbCName, sizeof("\p**** EXTENTS B-TREE") );
1615: break;
1616: case kHFSCatalogFileID:
1617: BlockMoveData( "\p**** CATALOG B-TREE", fcb->fcbCName, sizeof("\p**** CATALOG B-TREE") );
1618: break;
1619: case kHFSAllocationFileID:
1620: BlockMoveData( "\p**** VOLUME BITMAP", fcb->fcbCName, sizeof("\p**** VOLUME BITMAP") );
1621: break;
1622: case kHFSAttributesFileID:
1623: BlockMoveData( "\p**** ATTRIBUTES B-TREE", fcb->fcbCName, sizeof("\p**** ATTRIBUTES B-TREE") );
1624: break;
1625: }
1626:
1627: return( fcb );
1628: }
1629: #endif /* TARGET_OS_MAC */
1630:
1631:
1632: #if TARGET_OS_MAC
1633:
1634: //�������������������������������������������������������������������������������
1635: // Routine: FindFileControlBlock from Asm: FindFCB
1636: //
1637: // Function: Find an unused FCB
1638: //
1639: // Result: error
1640: //�������������������������������������������������������������������������������
1641: OSErr FindFileControlBlock( UInt16 *index, Ptr *fcbsH )
1642: {
1643: Boolean doneSearching;
1644: OSErr err;
1645: FCB *fcb;
1646:
1647: Get1stFileControlBlock( index, fcbsH );
1648:
1649: do
1650: {
1651: doneSearching = GetNextFileControlBlock( index, *fcbsH );
1652: if ( doneSearching == false )
1653: {
1654: fcb = GetFileControlBlock( *index );
1655: if ( fcb->fcbFlNm == 0 ) // FCB unused?
1656: {
1657: ClearMemory( fcb, sizeof( FCB ) );
1658: fcb->fcbFlNm = -1; // Mark it in use
1659: err = noErr;
1660: doneSearching = true;
1661: }
1662: }
1663: else
1664: {
1665: err = tmfoErr;
1666: }
1667: } while ( doneSearching == false );
1668:
1669: return( err );
1670: }
1671:
1672:
1673: //�������������������������������������������������������������������������������
1674: // Routine: Get1stFileControlBlock from Asm: Gt1stFCB
1675: //
1676: // Function: Point to the first FCB
1677: //�������������������������������������������������������������������������������
1678: void Get1stFileControlBlock( UInt16 *index, Ptr *fcbsH )
1679: {
1680: // struct FCBSRec {
1681: // UInt16 length; // first word is FCB part length
1682: // FCB fcb[1]; // fcb array
1683: // };
1684: *fcbsH = LMGetFCBSPtr();
1685: *index = 2;
1686: }
1687:
1688:
1689: //�������������������������������������������������������������������������������
1690: // Routine: GetNextFileControlBlock from Asm: GtNxtFCB
1691: //
1692: // Function: Increment to the next FCB
1693: // Check if we've hit the end fcb yet
1694: //
1695: // Result: Return true if end was reached
1696: //�������������������������������������������������������������������������������
1697: Boolean GetNextFileControlBlock( UInt16 *index, Ptr fcbsP )
1698: {
1699:
1700: *index += LMGetFSFCBLen();
1701:
1702: return ( *index == *((UInt16 *)fcbsP) ); // first word is length
1703: }
1704:
1705: #endif /* TARGET_OS_MAC */
1706:
1707:
1708: //�������������������������������������������������������������������������������
1709: // Routine: DivUp from Asm: DivUp
1710: //
1711: // Function: Given a number of bytes and block size, calculate the number of
1712: // blocks needd to hold all the bytes.
1713: //
1714: // Result: Number of physical blocks needed
1715: //�������������������������������������������������������������������������������
1716: UInt16 DivUp( UInt32 byteRun, UInt32 blockSize )
1717: {
1718: UInt32 blocks;
1719:
1720: blocks = (byteRun + blockSize - 1) / blockSize; // Divide up, remember this is integer math.
1721:
1722: if ( blocks > 0xffff ) // maximum 16 bit value
1723: blocks = 0xffff;
1724:
1725: return( (UInt16) blocks );
1726: }
1727:
1728:
1729:
1730:
1731: //�������������������������������������������������������������������������������
1732: // Routine: HFSBlocksFromTotalSectors
1733: //
1734: // Function: Given the total number of sectors on the volume, calculate
1735: // the 16Bit number of allocation blocks, and allocation block size.
1736: //
1737: // Result: none
1738: //�������������������������������������������������������������������������������
1739: void HFSBlocksFromTotalSectors( UInt32 totalSectors, UInt32 *blockSize, UInt16 *blockCount )
1740: {
1741: UInt16 newBlockSizeInSectors = 1;
1742: UInt32 newBlockCount = totalSectors;
1743:
1744: while ( newBlockCount > 0XFFFF )
1745: {
1746: newBlockSizeInSectors++;
1747: newBlockCount = totalSectors / newBlockSizeInSectors;
1748: }
1749:
1750: *blockSize = newBlockSizeInSectors * 512;
1751: *blockCount = newBlockCount;
1752: }
1753:
1754:
1755:
1756:
1757: //�������������������������������������������������������������������������������
1758: // Routine: ValidMasterDirectoryBlock
1759: //
1760: // Function: Run some sanity checks to make sure the MDB is valid
1761: //
1762: // Result: error
1763: //�������������������������������������������������������������������������������
1764: OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb )
1765: {
1766: OSErr err;
1767:
1768: if ( (mdb->drSigWord == kHFSPlusSigWord) || (mdb->drSigWord == kHFSSigWord) ) // if HFS or HFS Plus volume
1769: {
1770: if ( (mdb->drAlBlkSiz != 0) && ((mdb->drAlBlkSiz & 0x01FF) == 0) ) // non zero multiple of 512
1771: err = noErr;
1772: else
1773: err = badMDBErr;
1774: }
1775: else
1776: {
1777: err = noMacDskErr;
1778: }
1779:
1780: return( err );
1781: }
1782:
1783:
1784: //�������������������������������������������������������������������������������
1785: // Routine: ValidVolumeHeader
1786: //
1787: // Function: Run some sanity checks to make sure the VolumeHeader is valid
1788: //
1789: // Result: error
1790: //�������������������������������������������������������������������������������
1791: OSErr ValidVolumeHeader( HFSPlusVolumeHeader *volumeHeader )
1792: {
1793: OSErr err;
1794:
1795: if ( volumeHeader->signature == kHFSPlusSigWord && volumeHeader->version == kHFSPlusVersion )
1796: {
1797: if ( (volumeHeader->blockSize != 0) && ((volumeHeader->blockSize & 0x01FF) == 0) ) // non zero multiple of 512
1798: err = noErr;
1799: else
1800: err = badMDBErr; //�� I want badVolumeHeaderErr in Errors.i
1801: }
1802: else
1803: {
1804: err = noMacDskErr;
1805: }
1806:
1807: return( err );
1808: }
1809:
1810:
1811: #if TARGET_OS_MAC
1812:
1813: //�������������������������������������������������������������������������������
1814: // Routine: FindDrive from Asm: FindDrive
1815: //
1816: // Function: Given a drive number, this routine returns the RefNum
1817: // for the driver by searching the system drive queue.
1818: //
1819: // Result: error
1820: //�������������������������������������������������������������������������������
1821: OSErr FindDrive( short *driverRefNum, DrvQEl **dqe, short driveNumber )
1822: {
1823: OSErr err = nsDrvErr; // initialize as "drive not found"
1824:
1825: *dqe = ((DrvQEl*)LMGetDrvQHdr()->qHead); // get first DQE
1826: while ( *dqe != 0 ) // end of list?
1827: {
1828: if ( (**dqe).dQDrive != driveNumber ) // find the drive we're looking for?
1829: {
1830: *dqe = (DrvQEl*)(**dqe).qLink; // get ptr to next
1831: }
1832: else
1833: {
1834: *driverRefNum = (**dqe).dQRefNum; // return driver refnum
1835: if ( (**dqe).dQFSID == 0 ) // is this a Mac Filesystem?
1836: err = noErr;
1837: else
1838: err = extFSErr; // no, return error
1839: break;
1840: }
1841: }
1842:
1843: return( err );
1844: }
1845:
1846:
1847: //�������������������������������������������������������������������������������
1848: // Routine: GetVCBDriveNum from Asm: GetVCBDrv
1849: //
1850: // Function: Determine VCB from DriveNum/VRefNum field
1851: //
1852: // Result: error
1853: //�������������������������������������������������������������������������������
1854: OSErr GetVCBDriveNum( ExtendedVCB **vcbResult, short driveNumber )
1855: {
1856: ExtendedVCB *vcb;
1857:
1858: for ( vcb = (ExtendedVCB*)((LMGetVCBQHdr())->qHead) ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink ) // search the queue of VCBs
1859: {
1860: if ( vcb->vcbDrvNum == driveNumber ) // success!
1861: break;
1862: if ( vcb->vcbDrvNum == 0 ) // offline
1863: {
1864: if ( vcb->vcbDRefNum == driveNumber * (-1) ) // offline match
1865: break;
1866: }
1867: }
1868:
1869: *vcbResult = vcb;
1870:
1871: if ( vcb == nil )
1872: return( nsvErr );
1873: else
1874: return( noErr );
1875: }
1876:
1877:
1878: //�������������������������������������������������������������������������������
1879: // Routine: GetVCBRefNum from Asm: GetVCBRfn
1880: //
1881: // Function: Determine VCB from DriveNum/VRefNum field
1882: //
1883: // Result: error
1884: //�������������������������������������������������������������������������������
1885: OSErr GetVCBRefNum( ExtendedVCB **vcbResult, short vRefNum )
1886: {
1887: ExtendedVCB *vcb;
1888:
1889: for ( vcb = (ExtendedVCB*)((LMGetVCBQHdr())->qHead) ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink ) // search the queue of VCBs
1890: {
1891: if ( vcb->vcbVRefNum == vRefNum ) // success!
1892: {
1893: *vcbResult = vcb;
1894: return( noErr );
1895: }
1896: }
1897:
1898: return( nsvErr );
1899: }
1900:
1901: #endif /* TARGET_OS_MAC */
1902:
1903:
1904: //�������������������������������������������������������������������������������
1905: // Routine: IsARamDiskDriver from Asm: IsRAMDiskDriver
1906: //
1907: // Function: Test if disk driver is a RAM disk
1908: //
1909: // Result: true if RAM disk
1910: //�������������������������������������������������������������������������������
1911: Boolean IsARamDiskDriver( void )
1912: {
1913: #if TARGET_OS_MAC
1914: OSErr err;
1915: ParamBlockRec *pb;
1916: Byte diskType;
1917:
1918: pb = (ParamBlockRec *) LMParamBlock; // general purpose I/O param block
1919: pb->ioParam.ioCompletion = 0; // no completion routine
1920: pb->cntrlParam.csCode = infoCC; // pass control code
1921: pb->cntrlParam.csParam[0] = 0; // start out clean
1922: pb->cntrlParam.csParam[1] = 0;
1923:
1924: err = PBControlSync( pb ); // get driver info�
1925:
1926: if ( err == noErr ) // this control call supported
1927: {
1928: diskType = ((Byte *)(pb->cntrlParam.csParam))[3];
1929: if ( (diskType == ramDiskType) || (diskType == romDiskType) )
1930: return( true );
1931: }
1932:
1933: return( false );
1934: #else
1935: return( false );
1936: #endif /* TARGET_OS_MAC */
1937: }
1938:
1939:
1940: #if TARGET_OS_MAC
1941:
1942: OSErr MakeVCBsExtendedVCBs( void )
1943: {
1944: VCB *oVCB;
1945: VCB *nextVCB;
1946: ExtendedVCB *exVCB;
1947: ExtendedVCB *firstNewVCBInQueue = nil;
1948: QHdr *vcbQHdr;
1949: UInt16 fcbIndex;
1950: UInt16 i;
1951: Ptr fcbs;
1952: FCB *fcb;
1953: WDCBArray *wdcbsAry;
1954: OSErr err;
1955:
1956: vcbQHdr = LMGetVCBQHdr(); // search the queue of VCBs
1957:
1958: for ( oVCB = (VCB *)vcbQHdr->qHead ; (oVCB != nil) && (oVCB != (VCB *)firstNewVCBInQueue) ; )
1959: {
1960: nextVCB = (VCB *) oVCB->qLink;
1961:
1962: if ( (oVCB->vcbSigWord != kHFSPlusSigWord) && (oVCB->vcbFSID == 0) ) // if it's an HFS Plus VCB, assume it is already of ExtendedVCB type
1963: {
1964: exVCB = (ExtendedVCB *) NewPtrSysClear( sizeof(ExtendedVCB) ); // allocate space for the new ExtendedVCB
1965: ReturnIfError( MemError() );
1966: BlockMoveData( oVCB, exVCB, sizeof(VCB) ); // copy the original VCB over
1967:
1968: if ( firstNewVCBInQueue == nil )
1969: firstNewVCBInQueue = exVCB;
1970:
1971: //-- Set up the Extended fields, used internally in the HFS source
1972: exVCB->totalBlocks = exVCB->vcbNmAlBlks;
1973: exVCB->freeBlocks = exVCB->vcbFreeBks;
1974: exVCB->blockSize = exVCB->vcbAlBlkSiz;
1975: exVCB->nextAllocation = (UInt16)exVCB->vcbAllocPtr; // Almost certain to be zero
1976: // Note: SuperMario ROMs clear vcbAllocPtr and then flush the MDB.
1977: // So, when an HFS disk gets mounted, the allocation pointer is cleared both in
1978: // memory and on disk. The only way to fix this is to put HFS Plus in ROM.
1979:
1980: //-- Set up the caches for this volume
1981: err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(exVCB->hintCachePtr) );
1982: ReturnIfError( err );
1983:
1984: err = CreateVolumeCatalogCache(exVCB);
1985: ReturnIfError( err );
1986:
1987: //-- If we are dealing with the default VCB, set the corresponding ExtendedVCB as the default
1988: if ( oVCB == (VCB*) LMGetDefVCBPtr() )
1989: LMSetDefVCBPtr( (Ptr) exVCB );
1990:
1991: //-- Remove and deallocate the original VCB
1992: err = Dequeue( (QElemPtr) oVCB, (QHdrPtr) vcbQHdr ); // Dequeue the VCB from the VCB Queue
1993: ReturnIfError( err );
1994:
1995: //-- Search the FCB list for refs to the old VCB pointer and update them
1996: Get1stFileControlBlock( &fcbIndex, &fcbs );
1997: do
1998: {
1999: fcb = GetFileControlBlock( fcbIndex );
2000: if ( fcb->fcbVPtr == (ExtendedVCB *) oVCB )
2001: fcb->fcbVPtr = exVCB;
2002: } while ( GetNextFileControlBlock( &fcbIndex, fcbs ) == false );// while there's still some left
2003:
2004: //-- Search the WDCB list for refs to the old VCB pointer and update them
2005: wdcbsAry = (WDCBArray*)LMGetWDCBsPtr(); // Point to WDCB array
2006: for ( i=0 ; i< (wdcbsAry->count / sizeof(WDCBRec)) ; i++ )
2007: {
2008: if ( wdcbsAry->wdcb[i].wdVCBPtr == oVCB )
2009: wdcbsAry->wdcb[i].wdVCBPtr = (VCB *) exVCB;
2010: }
2011:
2012: //-- Deallocate memory used by the old VCB
2013: DisposePtr( (Ptr) oVCB );
2014:
2015: //-- Insert the new extended vcb in the queue
2016: Enqueue( (QElemPtr) exVCB, (QHdrPtr) vcbQHdr );
2017: }
2018: oVCB = nextVCB;
2019: }
2020:
2021: return( noErr );
2022: }
2023:
2024:
2025: //�������������������������������������������������������������������������������
2026: // Routine: RemountWrappedVolumes
2027: //
2028: // Function: Called by InitHFSPlus, Attempt to re-mount all HFS+ volumes
2029: // previously mounted as HFS wrappers.
2030: //
2031: // Note: This routine assumes vcbEmbedSigWord is cleared during mount.
2032: //
2033: //�������������������������������������������������������������������������������
2034: extern void RemountWrappedVolumes( void )
2035: {
2036: ExtendedVCB *vcb;
2037: ExtendedVCB *nextVCB;
2038: OSErr err;
2039:
2040: for ( vcb = (ExtendedVCB *) ((QHdr*)LMGetVCBQHdr())->qHead ; vcb != nil ; )
2041: {
2042: // PBMountVol and UnmountVol modify the vcb queue, so save the link
2043: nextVCB = (ExtendedVCB *) vcb->qLink;
2044:
2045: if ( (vcb->vcbEmbedSigWord == kHFSPlusSigWord) && ( vcb->vcbFSID == 0) )
2046: {
2047: err = UnmountVol( nil, vcb->vcbVRefNum );
2048: if ( err == noErr )
2049: {
2050: ParamBlockRec theParam;
2051:
2052: theParam.ioParam.ioCompletion = nil;
2053: theParam.ioParam.ioNamePtr = nil;
2054: theParam.ioParam.ioVRefNum = vcb->vcbDrvNum;
2055: (void) PBMountVol( &theParam );
2056: }
2057: }
2058:
2059: vcb = nextVCB;
2060: }
2061: }
2062:
2063:
2064: //�������������������������������������������������������������������������������
2065: // Routine: FillHFSStack
2066: //
2067: // Function: Called by HFSInit. Fills the newly created HFS stack so we
2068: // can identify how much of the stack is actually being used.
2069: //
2070: //�������������������������������������������������������������������������������
2071: extern void FillHFSStack( void )
2072: {
2073: Ptr p;
2074: SInt16 len = 0;
2075: char *s = "HFS+ By Don Brady, Mark Day, and Deric Horn. ";
2076:
2077: while ( s[len] != '\0' )
2078: ++len;
2079:
2080: for ( p = LMGetHFSStkTop() - kFileSystemStackSize ; p + len < LMGetHFSStkTop() ; p += len )
2081: {
2082: BlockMoveData( s, p, len );
2083: }
2084: }
2085:
2086:
2087: //�������������������������������������������������������������������������������
2088: // Routine: CheckVolumeOffLine from Asm: ExtOffLinCk
2089: //
2090: // Function: Simple routine to separate out calls to be handled by an
2091: // external file system.
2092: //
2093: // Result: noErr if we handle it
2094: //�������������������������������������������������������������������������������
2095: //�� Same function appears in CatSearch.c as ExtOffLineCheck(), but the code is slightly different
2096: //�� we should delete one copy.
2097: OSErr CheckVolumeOffLine( ExtendedVCB *vcb )
2098: {
2099: OSErr err;
2100:
2101: err = CheckExternalFileSystem( vcb );
2102: if ( err == noErr && vcb->vcbDrvNum == 0 )
2103: err = volOffLinErr;
2104:
2105: LMSetReqstVol( (Ptr)vcb );
2106:
2107: return( err );
2108: }
2109:
2110: #endif /* TARGET_OS_MAC */
2111:
2112:
2113:
2114:
2115: //_______________________________________________________________________
2116: //
2117: // Routine: CountRootFiles
2118: //
2119: // Input: pointer to VCB
2120: //
2121: // Function: Return a count of the number of files and folders in
2122: // the root directory of a volume. For HFS volumes, this
2123: // is maintained in the VCB (and MDB). For HFS Plus volumes,
2124: // we get the valence of the root directory from its catalog
2125: // record.
2126: //_______________________________________________________________________
2127: UInt16 CountRootFiles(ExtendedVCB *vcb)
2128: {
2129: OSErr err;
2130: FSSpec spec;
2131: CatalogNodeData catNodeData;
2132: UInt32 hint;
2133: UInt16 rootCount;
2134:
2135: // if (vcb->vcbSigWord == kHFSSigWord || vcb->vcbFSID != 0) {
2136: // return vcb->vcbNmFls;
2137: // }
2138:
2139: // Here, it's an HFS Plus volume, so get the valence from the root
2140: // directory's catalog record.
2141:
2142: rootCount = 0;
2143:
2144: err = GetCatalogNode( vcb, kHFSRootFolderID, nil, kNoHint, &spec, &catNodeData, &hint );
2145: if ( err == noErr ) {
2146: if (catNodeData.valence < 65536)
2147: rootCount = catNodeData.valence;
2148: else
2149: rootCount = 65535; // if the value is too large, pin it
2150: }
2151:
2152: return rootCount;
2153: }
2154:
2155: #if TARGET_OS_MAC
2156:
2157: //_______________________________________________________________________
2158: //
2159: // Routine: GetVolumeInformation : GetVolInfo
2160: // Arguments: HVolumeParam *volume
2161: // Output: WDCBRec **wdcb (Needed for ExtFsHook in CmdDone)
2162: // OSErr err
2163: //
2164: // Function: Return information about the volume in a mounted drive.
2165: // If the IOVolIndex field is 0, the name of the default
2166: // volume is returned; if non-zero, the name of the nth
2167: // mounted volume is returned. The maximum length of a
2168: // volume name is 27 bytes. The drive number for the
2169: // volume is also returned.
2170: //_______________________________________________________________________
2171:
2172: OSErr GetVolumeInformation( HVolumeParam *volume, WDCBRecPtr *wdcb )
2173: {
2174: FSSpec spec;
2175: UInt32 maxBlocks;
2176: SInt16 nameLength;
2177: SInt16 volumeIndex;
2178: FileReference vRefNum;
2179: OSErr err;
2180: Ptr fcbs;
2181: FCB *fcb;
2182: ExtendedVCB *vcb;
2183: unsigned char *pathName;
2184: CatalogNodeData catNodeData;
2185: Boolean doneSearching;
2186: Boolean nameSpecified;
2187: WDCBArray *wdcbsAry;
2188: UInt16 fcbIndex;
2189:
2190: volumeIndex = volume->ioVolIndex;
2191: if ( volumeIndex == 0 )
2192: {
2193: err = DeturmineVolume1( (VolumeParam*)volume, &nameLength, &nameSpecified, (ExtendedVCB **)&vcb, wdcb, &pathName );
2194: if ( err != noErr ) goto CmdDone;
2195: }
2196: else if ( volume->ioVolIndex < 0 )
2197: {
2198: err = DeturmineVolume3( (VolumeParam*)volume, &nameLength, &nameSpecified, (ExtendedVCB **)&vcb, wdcb, &pathName );
2199: if ( err != noErr ) goto CmdDone;
2200: }
2201: else
2202: {
2203: nameSpecified = false; // Never any name specified (ioNamePtr is output arg)
2204: volume->ioVRefNum = 0;
2205:
2206: for ( vcb = (ExtendedVCB*)((LMGetVCBQHdr())->qHead) ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink ) // search the queue of VCBs
2207: {
2208: if ( --volumeIndex == 0 )
2209: break;
2210: }
2211: if ( vcb == nil )
2212: {
2213: err = nsvErr;
2214: goto CmdDone;
2215: }
2216: }
2217:
2218: // first copy the heart of the VCB into the parameter block
2219: volume->ioVCrDate = vcb->vcbCrDate;
2220: volume->ioVLsMod = vcb->vcbLsMod;
2221: volume->ioVAtrb = vcb->vcbAtrb;
2222: volume->ioVNmFls = vcb->vcbNmFls; // don't call CountRootFiles(vcb) anymore
2223: volume->ioVBitMap = vcb->vcbVBMSt;
2224: volume->ioVNmAlBlks = vcb->vcbNmAlBlks; // we return the HFS volume format equivalents cuz ioVNmAlBlks is a short
2225: volume->ioVAlBlkSiz = vcb->vcbAlBlkSiz;
2226: volume->ioVClpSiz = vcb->vcbClpSiz;
2227: volume->ioAlBlSt = vcb->vcbAlBlSt;
2228: volume->ioVNxtCNID = vcb->vcbNxtCNID;
2229: volume->ioVFrBlk = vcb->vcbFreeBks;
2230:
2231: if ( vcb->vcbFSID != 0 )
2232: volume->ioAllocPtr = vcb->vcbAllocPtr; // external file system
2233: else if ( vcb->nextAllocation < 0xFFFF )
2234: volume->ioAllocPtr = vcb->nextAllocation;
2235: else
2236: volume->ioAllocPtr = 0xFFFF;
2237:
2238:
2239: Get1stFileControlBlock( &fcbIndex, &fcbs );
2240: doneSearching = false;
2241:
2242: do
2243: {
2244: fcb = GetFileControlBlock( fcbIndex );
2245: if ( fcb->fcbVPtr == (ExtendedVCB *) vcb ) // The file is currently open and on this volume
2246: {
2247: if ( fcb->fcbFlNm >= fsUsrCNID )
2248: break;
2249: }
2250: doneSearching = GetNextFileControlBlock( &fcbIndex, fcbs );
2251: } while ( doneSearching == false );
2252:
2253: if ( doneSearching == true )
2254: volume->ioVAtrb &= ~kFilesOpenMask; // Clear if no open files match
2255: else
2256: volume->ioVAtrb |= kFilesOpenMask; // Set if any files are opened
2257:
2258: if ( vcb == (ExtendedVCB *) LMGetDefVCBPtr() ) // Are we supposedly the default?
2259: volume->ioVAtrb |= kDefaultVolumeMask; // Set volume as the default
2260: else
2261: volume->ioVAtrb &= ~kDefaultVolumeMask; // Clear volume as the default
2262:
2263: *wdcb = nil;
2264:
2265: if ( (volume->ioVolIndex <= 0) && (nameSpecified == 0) )
2266: {
2267: vRefNum = volume->ioVRefNum;
2268: if ( vRefNum > 0 ) // If driveNum, ignore it
2269: {
2270: goto retVRef;
2271: }
2272: else if ( vRefNum == 0 )
2273: {
2274: vRefNum = 2;
2275: }
2276: else if ( vRefNum <= WDRfnMax )
2277: {
2278: // a WDRefNum was supplied as VRefNum: change the number of files to be the <21Sep85>
2279: // valence of the directory in question: <21Sep85>
2280: vRefNum -= WDRfnMin; // Change WDRefNum to index
2281: }
2282: else
2283: {
2284: goto retVRef;
2285: }
2286:
2287: wdcbsAry = (WDCBArray*)LMGetWDCBsPtr(); // Point to WDCB array
2288: *wdcb = (WDCBRec*)((Ptr)wdcbsAry + vRefNum);
2289:
2290: err = CheckVolumeOffLine( vcb ); // check external FS err
2291: if ( err == noErr )
2292: {
2293: if ( (**wdcb).wdDirID != fsRtDirID )
2294: {
2295: //�� This will change to handle Don's meta struct
2296: err = GetCatalogNode( (ExtendedVCB*)vcb, (**wdcb).wdDirID, nil, (**wdcb).wdCatHint, &spec, &catNodeData, (UInt32*)&((**wdcb).wdCatHint) );
2297: if ( err == noErr )
2298: {
2299: volume->ioVNmFls = (UInt16) catNodeData.valence;
2300: }
2301: }
2302: }
2303: }
2304:
2305: // Do some hairy checking: if a working directory was specified, it shouldn't
2306: // be overwritten by the volRefNum. However, if a volume NAME was used, the
2307: // volRefNum field is ignored, and SHOULD be filled in with the volume's VRefNum.
2308: retVRef:
2309: if( (nameSpecified != 0) || (volume->ioVRefNum >= 0) )
2310: {
2311: volume->ioVRefNum = vcb->vcbVRefNum;
2312: }
2313: // Copy the volume name field if specified.
2314: if ( volume->ioNamePtr != 0 )
2315: BlockMoveData( vcb->vcbVN, volume->ioNamePtr, vcb->vcbVN[0]+1 );
2316:
2317:
2318: // Many applications call GetVolInfo for preflighting when saving files. However,
2319: // they tend to use signed integers when calculating the volume's free space
2320: // (vcbFreeBlks * vcbAlBlkSize). If the free space is greater than 2 gigabytes they
2321: // get a negative result and think there is not enough space left on the volume.
2322: //
2323: // To fix this problem we high water mark vcbFreeBlks and vcbNmAlBlks so that when
2324: // multiplied by vcbAlBlkSiz the result is always less than or equal to 2GB.
2325:
2326: if ( volume->ioVAlBlkSiz > 0x8000 ) // Do the mock up
2327: {
2328: // Calculate the maximum number of allocation blocks that can fit within 2 gigabytes� <LgVol>
2329: // Divide 2 gig by block allocation size
2330: maxBlocks = 0x7FFFFFFF / volume->ioVAlBlkSiz;
2331:
2332: // Clip total and free to the maximum�
2333: if ( volume->ioVNmAlBlks > maxBlocks )
2334: {
2335: volume->ioVNmAlBlks = maxBlocks; // pin the value limit
2336:
2337: if ( volume->ioVFrBlk > maxBlocks )
2338: {
2339: volume->ioVFrBlk = maxBlocks;
2340: }
2341: }
2342: }
2343:
2344: // Subtract the physical sizes of the extent B*-Tree and the catalog B*-Tree <21Sep85>
2345: // from the volume size, so that the difference between the volume size and <21Sep85>
2346: // the free space reflects only the user's allocations: <21Sep85>
2347: volume->ioVNmAlBlks -= vcb->vcbXTAlBlks; // Take out XT allocation
2348: volume->ioVNmAlBlks -= vcb->vcbCTAlBlks; // Take out CT allocation
2349:
2350: if ( !(volume->ioTrap & kHFSMask) ) // TFGetVolInfo vs. plain GetVolInfo?
2351: { // GetVolInfo
2352: if ( volume->ioVNmAlBlks > kMaxHFSAllocationBlocks )
2353: volume->ioVNmAlBlks = kMaxHFSAllocationBlocks;
2354:
2355: if ( volume->ioVFrBlk > kMaxHFSAllocationBlocks )
2356: volume->ioVFrBlk = kMaxHFSAllocationBlocks;
2357: }
2358: else // Return some additional information for TGetVolInfo requests:
2359: {
2360: volume->ioVRefNum = vcb->vcbVRefNum; // ALWAYS return VRefNum
2361: volume->ioVDrvInfo = vcb->vcbDrvNum; // Driver number
2362: volume->ioVDRefNum = vcb->vcbDRefNum; // Driver RefNum
2363: volume->ioVFSID = vcb->vcbFSID; // File System ID
2364:
2365: // We return kHFSSigWord for HFS+ volumes for copatability with
2366: // existing applications. All StuffIt products, AppleShare, FileSharing,
2367: // and others incorrectly assume the volume is unsupported or MFS if the
2368: // sigWord is not 'BD'. GetXVolInfo() returns the "real" value.
2369: volume->ioVSigWord = vcb->vcbSigWord == kHFSPlusSigWord ? kHFSSigWord : vcb->vcbSigWord;
2370:
2371:
2372: //volume->ioVFilCnt = 0; // Clear
2373: //volume->ioVFilCnt = vcb->vcbNmFls; // Stuff low word as if MFS
2374:
2375: volume->ioVBkUp = vcb->vcbVolBkUp; // Last backup date
2376: volume->ioVSeqNum = vcb->vcbVSeqNum; // Volume sequence number
2377: volume->ioVWrCnt = vcb->vcbWrCnt; // Volume write count
2378: volume->ioVFilCnt = vcb->vcbFilCnt; // Files count for volume
2379: volume->ioVDirCnt = vcb->vcbDirCnt; // Directory count for volume
2380:
2381: BlockMoveData( vcb->vcbFndrInfo, volume->ioVFndrInfo, sizeof( SInt32 ) * 8 );
2382: }
2383:
2384: GVIDone:
2385: LMSetReqstVol( (Ptr)vcb );
2386:
2387: err = CheckExternalFileSystem( vcb );
2388:
2389: CmdDone:
2390: return( err );
2391:
2392: }
2393:
2394:
2395:
2396:
2397: //_______________________________________________________________________
2398: //
2399: // Routine: GetXVolumeInformation : GetXVolInfo
2400: // Arguments: XVolumeParam *volume
2401: // Output: WDCBRecPtr *wdcb (Needed for ExtFsHook in CmdDone)
2402: // OSErr err
2403: //
2404: // Function: Return information about the volume in a mounted drive.
2405: // If the IOVolIndex field is 0, the name of the default
2406: // volume is returned; if non-zero, the name of the nth
2407: // mounted volume is returned. The maximum length of a
2408: // volume name is 27 bytes. The drive number for the
2409: // volume is also returned.
2410: //_______________________________________________________________________
2411:
2412: OSErr GetXVolumeInformation( XVolumeParam *volume, WDCBRecPtr *wdcb )
2413: {
2414: FSSpec spec;
2415: SInt16 nameLength;
2416: SInt16 volumeIndex;
2417: FileReference vRefNum;
2418: OSErr err;
2419: Ptr fcbs;
2420: FCB *fcb;
2421: ExtendedVCB *vcb;
2422: unsigned char *pathName;
2423: CatalogNodeData catNodeData;
2424: Boolean doneSearching;
2425: Boolean nameSpecified;
2426: WDCBArray *wdcbsAry;
2427: UInt16 fcbIndex;
2428:
2429: // The Installer doesn't setup ioXVersion (radar #1666217)
2430: #if 0
2431: if (volume->ioXVersion != 0)
2432: return paramErr;
2433: #endif
2434:
2435: err = noErr; // Assume things will work
2436:
2437: volumeIndex = volume->ioVolIndex;
2438: if ( volumeIndex == 0 )
2439: {
2440: err = DeturmineVolume1( (VolumeParam*)volume, &nameLength, &nameSpecified, (ExtendedVCB **)&vcb, wdcb, &pathName );
2441: if ( err != noErr ) goto CmdDone;
2442: }
2443: else if ( volume->ioVolIndex < 0 )
2444: {
2445: err = DeturmineVolume3( (VolumeParam*)volume, &nameLength, &nameSpecified, (ExtendedVCB **)&vcb, wdcb, &pathName );
2446: if ( err != noErr ) goto CmdDone;
2447: }
2448: else
2449: {
2450: nameSpecified = false; // Never any name specified (ioNamePtr is output arg)
2451: volume->ioVRefNum = 0;
2452:
2453: for ( vcb = (ExtendedVCB*)((LMGetVCBQHdr())->qHead) ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink ) // search the queue of VCBs
2454: {
2455: if ( --volumeIndex == 0 )
2456: break;
2457: }
2458: if ( vcb == nil )
2459: {
2460: err = nsvErr;
2461: goto CmdDone;
2462: }
2463: }
2464:
2465: // first copy the heart of the VCB into the parameter block
2466: volume->ioVCrDate = vcb->vcbCrDate;
2467: volume->ioVLsMod = vcb->vcbLsMod;
2468: volume->ioVAtrb = vcb->vcbAtrb;
2469: volume->ioVBitMap = vcb->vcbVBMSt;
2470: volume->ioVNmAlBlks = vcb->vcbNmAlBlks; // 16 bit value
2471: volume->ioVClpSiz = vcb->vcbClpSiz;
2472: volume->ioAlBlSt = vcb->vcbAlBlSt;
2473: volume->ioVNxtCNID = vcb->vcbNxtCNID;
2474: volume->ioVFrBlk = vcb->vcbFreeBks;
2475: volume->ioVNmFls = vcb->vcbNmFls; // don't call CountRootFiles(vcb) anymore
2476:
2477: if ( vcb->vcbFSID == 0 ) // an HFS or HFS Plus disk
2478: {
2479: volume->ioVAlBlkSiz = vcb->blockSize; // return true allocation blocks
2480:
2481: if ( vcb->nextAllocation < 0xFFFF )
2482: volume->ioAllocPtr = vcb->nextAllocation;
2483: else
2484: volume->ioAllocPtr = 0xFFFF;
2485: }
2486: else // an external file system
2487: {
2488: volume->ioVAlBlkSiz = vcb->vcbAlBlkSiz;
2489: volume->ioAllocPtr = vcb->vcbAllocPtr;
2490: }
2491:
2492:
2493: Get1stFileControlBlock( &fcbIndex, &fcbs );
2494: doneSearching = false;
2495:
2496: do
2497: {
2498: fcb = GetFileControlBlock( fcbIndex );
2499: if ( fcb->fcbVPtr == vcb ) // The file is currently open and on this volume
2500: {
2501: if ( fcb->fcbFlNm >= fsUsrCNID )
2502: break;
2503: }
2504: doneSearching = GetNextFileControlBlock( &fcbIndex, fcbs );
2505: } while ( doneSearching == false );
2506:
2507: if ( doneSearching == true )
2508: volume->ioVAtrb &= ~kFilesOpenMask; // Clear if no open files match
2509: else
2510: volume->ioVAtrb |= kFilesOpenMask; // Set if any files are opened
2511:
2512: if ( vcb == (ExtendedVCB *) LMGetDefVCBPtr() ) // Are we supposedly the default?
2513: volume->ioVAtrb |= kDefaultVolumeMask; // Set volume as the default
2514: else
2515: volume->ioVAtrb &= ~kDefaultVolumeMask; // Clear volume as the default
2516:
2517:
2518: *wdcb = nil;
2519:
2520: if ( (volume->ioVolIndex <= 0) && (nameSpecified == 0) )
2521: {
2522: vRefNum = volume->ioVRefNum;
2523: if ( vRefNum > 0 ) // If driveNum, ignore it
2524: {
2525: goto retVRef;
2526: }
2527: else if ( vRefNum == 0 )
2528: {
2529: vRefNum = 2;
2530: }
2531: else if ( vRefNum <= WDRfnMax )
2532: {
2533: // a WDRefNum was supplied as VRefNum: change the number of files to be the <21Sep85>
2534: // valence of the directory in question: <21Sep85>
2535: vRefNum -= WDRfnMin; // Change WDRefNum to index
2536: }
2537: else
2538: {
2539: goto retVRef;
2540: }
2541:
2542: wdcbsAry = (WDCBArray*)LMGetWDCBsPtr(); // Point to WDCB array
2543: *wdcb = (WDCBRec*)((Ptr)wdcbsAry + vRefNum);
2544:
2545: err = CheckVolumeOffLine( (ExtendedVCB*)vcb ); // check external FS err
2546: if ( err == noErr )
2547: {
2548: if ( (**wdcb).wdDirID != fsRtDirID )
2549: {
2550: //�� This will change to handle Don's meta struct
2551: err = GetCatalogNode( (ExtendedVCB*)vcb, (**wdcb).wdDirID, nil, (**wdcb).wdCatHint, &spec, &catNodeData, (UInt32*)&((**wdcb).wdCatHint) );
2552: if ( err == noErr )
2553: {
2554: volume->ioVNmFls = (UInt16) catNodeData.valence;
2555: }
2556: }
2557: }
2558: }
2559:
2560: // If a working directory was specified, it shouldn't be overwritten by
2561: // the volRefNum. However, if a volume NAME was used, the volRefNum
2562: // field is ignored, and SHOULD be filled in with the volume's VRefNum.
2563: retVRef:
2564: if( (nameSpecified != 0) || (volume->ioVRefNum >= 0) )
2565: {
2566: volume->ioVRefNum = vcb->vcbVRefNum;
2567: }
2568: // Copy the volume name field if specified.
2569: if ( volume->ioNamePtr != 0 )
2570: BlockMoveData( vcb->vcbVN, volume->ioNamePtr, vcb->vcbVN[0]+1 );
2571:
2572:
2573: // Calculate the total and free bytes available on the volume as a 64 bit integer:
2574:
2575: if ( vcb->vcbSigWord == kHFSPlusSigWord )
2576: {
2577: //-- Change to use ExtendedVCB fields for HFS Plus
2578: MultiplyUInt32IntoUInt64( &(volume->ioVTotalBytes), vcb->totalBlocks, vcb->blockSize );
2579: MultiplyUInt32IntoUInt64( &(volume->ioVFreeBytes), vcb->freeBlocks, vcb->blockSize );
2580: }
2581: else
2582: {
2583: //-- It's just an HFS volume or some other external file system
2584: MultiplyUInt32IntoUInt64( &(volume->ioVTotalBytes), volume->ioVNmAlBlks, volume->ioVAlBlkSiz );
2585: MultiplyUInt32IntoUInt64( &(volume->ioVFreeBytes), volume->ioVFrBlk, volume->ioVAlBlkSiz );
2586: }
2587:
2588:
2589: volume->ioVRefNum = vcb->vcbVRefNum; // VRefNum
2590: volume->ioVSigWord = vcb->vcbSigWord; // Volume signature
2591: volume->ioVDrvInfo = vcb->vcbDrvNum; // Driver number
2592: volume->ioVDRefNum = vcb->vcbDRefNum; // Driver RefNum
2593: volume->ioVFSID = vcb->vcbFSID; // File System ID
2594: volume->ioVBkUp = vcb->vcbVolBkUp; // Last backup date
2595: volume->ioVSeqNum = vcb->vcbVSeqNum; // Volume sequence number
2596: volume->ioVWrCnt = vcb->vcbWrCnt; // Volume write count
2597: volume->ioVFilCnt = vcb->vcbFilCnt; // Files count for volume
2598: volume->ioVDirCnt = vcb->vcbDirCnt; // Directory count for volume
2599:
2600: BlockMoveData( vcb->vcbFndrInfo, volume->ioVFndrInfo, sizeof( SInt32 ) * 8 );
2601:
2602: CmdDone:
2603: if ( err == noErr && volume->ioVFSID != 0)
2604: {
2605: LMSetReqstVol((Ptr) vcb);
2606: err = extFSErr; // not an HFS or HFS Plus volume, let others have a crack at this call...
2607: }
2608:
2609: return( err );
2610: }
2611:
2612: #endif /* TARGET_OS_MAC */
2613:
2614:
2615: //_______________________________________________________________________
2616: //
2617: // Routine: FlushVolumeControlBlock
2618: // Arguments: ExtendedVCB *vcb
2619: // Output: OSErr err
2620: //
2621: // Function: Flush volume information to either the VolumeHeader of the Master Directory Block
2622: //_______________________________________________________________________
2623:
2624: OSErr FlushVolumeControlBlock( ExtendedVCB *vcb )
2625: {
2626: OSErr err;
2627: #if TARGET_OS_MAC
2628: HFSPlusVolumeHeader *volumeHeader;
2629: FileReference index;
2630: FCB *fcb;
2631: ExtendedFCB *extendedFCB;
2632: #endif
2633: if ( ! IsVCBDirty( vcb ) ) // if it's not dirty
2634: return( noErr );
2635:
2636: if ( vcb->vcbSigWord == kHFSPlusSigWord )
2637: {
2638: #if TARGET_OS_MAC
2639: err = GetBlock_glue( gbDefault, (vcb->hfsPlusIOPosOffset / 512) + kIDSectorOffset, (Ptr*)&volumeHeader, vcb->vcbVRefNum, vcb ); // no Flags, VH is always block #0, vcb->vcbBufAdr == CacheQueueHeader
2640: #if( DEBUG_BUILD )
2641: if ( volumeHeader->signature != vcb->vcbSigWord )
2642: DebugStr("\p Bad VolumeHeader, signature does not match vcb" );
2643: #endif
2644: ReturnIfError( err );
2645:
2646: // 2005507, Keep the MDB creation date and VolumeHeader creation date in sync.
2647: if ( vcb->hfsPlusIOPosOffset != 0 ) // It's a wrapped HFS+ volume
2648: {
2649: HFSMasterDirectoryBlock *mdb;
2650:
2651: err = GetBlock_glue( gbDefault,
2652: kIDSectorOffset,
2653: (Ptr*)&mdb,
2654: vcb->vcbVRefNum,
2655: vcb );
2656: if ( err == noErr )
2657: {
2658: if ( mdb->drCrDate != vcb->vcbCrDate ) // The creation date changed
2659: {
2660: mdb->drCrDate = vcb->vcbCrDate;
2661: err = RelBlock_glue( (Ptr)mdb, rbWriteMask ); // Force it to be written
2662: }
2663: else
2664: {
2665: err = RelBlock_glue( (Ptr)mdb, rbFreeMask ); // Just release it
2666: }
2667: }
2668: }
2669:
2670: // volumeHeader->signature = vcb->signature;
2671: // volumeHeader->version =
2672: volumeHeader->attributes = vcb->vcbAtrb; // VCB uses 16 bits, next 16 are for future API changes
2673: volumeHeader->lastMountedVersion= kHFSPlusMountVersion; // Let others know we've mounted volume for writing
2674: //�� volumeName
2675: volumeHeader->createDate = vcb->vcbCrDate; // NOTE: local time, not GMT!
2676: volumeHeader->modifyDate = LocalToUTC(vcb->vcbLsMod);
2677: volumeHeader->backupDate = LocalToUTC(vcb->vcbVolBkUp);
2678: volumeHeader->checkedDate = vcb->checkedDate;
2679: volumeHeader->fileCount = vcb->vcbFilCnt;
2680: volumeHeader->folderCount = vcb->vcbDirCnt;
2681: volumeHeader->blockSize = vcb->blockSize;
2682: volumeHeader->totalBlocks = vcb->totalBlocks;
2683: volumeHeader->freeBlocks = vcb->freeBlocks;
2684: volumeHeader->nextAllocation = vcb->nextAllocation;
2685: volumeHeader->rsrcClumpSize = vcb->vcbClpSiz;
2686: volumeHeader->dataClumpSize = vcb->vcbClpSiz;
2687: volumeHeader->nextCatalogID = vcb->vcbNxtCNID;
2688: volumeHeader->writeCount = vcb->vcbWrCnt;
2689: volumeHeader->encodingsBitmap = vcb->encodingsBitmap;
2690:
2691: //���should we use the vcb or fcb clumpSize values ????? -djb
2692: volumeHeader->allocationFile.clumpSize = vcb->allocationsClumpSize;
2693: volumeHeader->extentsFile.clumpSize = vcb->vcbXTClpSiz;
2694: volumeHeader->catalogFile.clumpSize = vcb->vcbCTClpSiz;
2695:
2696: BlockMoveData( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
2697:
2698: index = vcb->extentsRefNum;
2699: extendedFCB = GetParallelFCB( index );
2700: BlockMoveData( extendedFCB->extents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) );
2701: fcb = GetFileControlBlock( index );
2702: volumeHeader->extentsFile.logicalSize.lo = fcb->fcbEOF;
2703: volumeHeader->extentsFile.logicalSize.hi = 0;
2704: volumeHeader->extentsFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
2705:
2706: index = vcb->catalogRefNum;
2707: extendedFCB = GetParallelFCB( index );
2708: BlockMoveData( extendedFCB->extents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) );
2709: fcb = GetFileControlBlock( index );
2710: volumeHeader->catalogFile.logicalSize.lo = fcb->fcbPLen;
2711: volumeHeader->catalogFile.logicalSize.hi = 0;
2712: volumeHeader->catalogFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
2713:
2714: index = vcb->allocationsRefNum;
2715: extendedFCB = GetParallelFCB( index );
2716: BlockMoveData( extendedFCB->extents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) );
2717: fcb = GetFileControlBlock( index );
2718: volumeHeader->allocationFile.logicalSize.lo = fcb->fcbPLen;
2719: volumeHeader->allocationFile.logicalSize.hi = 0;
2720: volumeHeader->allocationFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
2721:
2722: index = vcb->attributesRefNum;
2723: if (index != 0) // Only update fields if an attributes file existed and was open
2724: {
2725: extendedFCB = GetParallelFCB( index );
2726: BlockMoveData( extendedFCB->extents, volumeHeader->attributesFile.extents, sizeof(HFSPlusExtentRecord) );
2727: fcb = GetFileControlBlock( index );
2728: volumeHeader->attributesFile.logicalSize.lo = fcb->fcbPLen;
2729: volumeHeader->attributesFile.logicalSize.hi = 0;
2730: volumeHeader->attributesFile.clumpSize = fcb->fcbClmpSize;
2731: volumeHeader->attributesFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
2732: }
2733:
2734: //-- Write the MDB out by releasing the block dirty
2735:
2736: err = RelBlock_glue( (Ptr)volumeHeader, rbWriteMask ); // force it to be written
2737:
2738: #if( hasHFSManualEject )
2739: // The critical volume info that needs to be maintained
2740: // for volumes in manual-eject drives has just been flushed.
2741: if (err == noErr)
2742: vcb->vcbFlags &= ~vcbFlushCriticalInfoMask;
2743: #endif
2744:
2745: MarkVCBClean( vcb );
2746: #else
2747: // This does now what above does also, so lets keep it all together in a single place
2748: err = C_FlushMDB( vcb ); // Go flush the VCB info BEFORE close
2749: #endif
2750: }
2751: else
2752: {
2753: // This routine doesn't really return an error!!!
2754: // So for now, we will just return noErr
2755: err = C_FlushMDB( vcb ); // Go flush the VCB info BEFORE close
2756: return( noErr );
2757: }
2758:
2759: return( err );
2760: }
2761:
2762:
2763: ExtendedFCB* GetParallelFCB(FileReference fref)
2764: {
2765: #if TARGET_OS_MAC
2766: ParallelFCB* pfcbArray;
2767: FSVarsRec* fsVars;
2768: short index;
2769:
2770: index = fref / sizeof(FCB);
2771:
2772: fsVars = (FSVarsRec*) LMGetFSMVars();
2773:
2774: pfcbArray = (ParallelFCB*) fsVars->fcbPBuf;
2775:
2776: return &pfcbArray->extendedFCB[index];
2777: #else
2778: return &VTOH(fref)->h_xfcb->fcb_extFCB;
2779: #endif /* TARGET_OS_MAC */
2780: }
2781:
2782:
2783: //_______________________________________________________________________
2784: //
2785: // Routine: FlushAlternateVolumeControlBlock
2786: // Arguments: ExtendedVCB *vcb
2787: // Boolean ifHFSPlus
2788: // Output: OSErr err
2789: //
2790: // Function: Flush volume information to either the Alternate VolumeHeader of the
2791: // Alternate Master Directory Block. Called by the BTree when the catalog
2792: // or extent files grow. Simply BlockMoves the original to the alternate
2793: // location.
2794: //_______________________________________________________________________
2795:
2796: OSErr FlushAlternateVolumeControlBlock( ExtendedVCB *vcb, Boolean isHFSPlus )
2797: {
2798: OSErr err;
2799: UInt32 alternateBlockLocation;
2800:
2801: err = FlushVolumeControlBlock( vcb );
2802:
2803: if ( isHFSPlus ) // Flush the VolumeHeader
2804: {
2805: HFSPlusVolumeHeader *volumeHeader;
2806: HFSPlusVolumeHeader *alternateVolumeHeader;
2807:
2808: //-- Get the VolumeHeader Block, 1st block in the HFS Plus partition
2809: #if TARGET_OS_MAC
2810: err = GetBlock_glue( gbDefault, (vcb->hfsPlusIOPosOffset / 512) + kIDSectorOffset, (Ptr*)&volumeHeader, vcb->vcbVRefNum, vcb ); // VH is always 1st sector of HFS Plus partition
2811: #else
2812: err = GetBlock_glue( gbDefault, (vcb->hfsPlusIOPosOffset / 512) + kIDSectorOffset, (Ptr*)&volumeHeader, kNoFileReference, vcb ); // VH is always 1st sector of HFS Plus partition
2813: #endif
2814: ReturnIfError( err );
2815:
2816: //-- Get the Alternate VolumeHeader Block, last sector in the HFS Plus partition
2817: alternateBlockLocation = (vcb->hfsPlusIOPosOffset / 512) + vcb->totalBlocks * (vcb->blockSize / 512) - 2;
2818: #if TARGET_OS_MAC
2819: err = GetBlock_glue( gbDefault, alternateBlockLocation, (Ptr*)&alternateVolumeHeader, vcb->vcbVRefNum, vcb ); // Alt VH is always 2nd to last sector of HFS Plus partition
2820: #else
2821: err = GetBlock_glue( gbDefault, alternateBlockLocation, (Ptr*)&alternateVolumeHeader, kNoFileReference, vcb ); // Alt VH is always 2nd to last sector of HFS Plus partition
2822: #endif
2823: if ( err == noErr )
2824: {
2825: //-- Copy the VolumeHeader to the alternate location
2826: BlockMoveData( volumeHeader, alternateVolumeHeader, sizeof(HFSPlusVolumeHeader) );
2827:
2828: //-- And write it back to the disk, NOW!
2829: err = RelBlock_glue( (Ptr)volumeHeader, rbFreeMask ); // free the MDB
2830: err = RelBlock_glue( (Ptr)alternateVolumeHeader, rbWriteMask ); // force it to be written
2831: }
2832: else
2833: {
2834: err = RelBlock_glue( (Ptr)volumeHeader, rbFreeMask ); // free the VH
2835: }
2836: }
2837: else // Flush the MasterDirectoryBlock
2838: {
2839: HFSMasterDirectoryBlock *mdb;
2840: HFSMasterDirectoryBlock *alternateMDB;
2841: UInt32 numBlocks;
2842:
2843:
2844: err = GetDiskBlocks( vcb, &numBlocks );
2845: ReturnIfError( err );
2846:
2847: //-- Get the MDB, 2nd block on HFS disk
2848: #if TARGET_OS_MAC
2849: err = GetBlock_glue( gbDefault, kIDSectorOffset, (Ptr*)&mdb, vcb->vcbVRefNum, vcb ); // no Flags, MDB is always block
2850: #else
2851: err = GetBlock_glue( gbDefault, kIDSectorOffset, (Ptr*)&mdb, kNoFileReference, vcb ); // no Flags, MDB is always block
2852: #endif
2853: ReturnIfError( err );
2854:
2855: //-- Get the Alternate MDB, 2nd to last block on disk
2856: alternateBlockLocation = numBlocks - 2;
2857: #if TARGET_OS_MAC
2858: err = GetBlock_glue( gbDefault, alternateBlockLocation, (Ptr*)&alternateMDB, vcb->vcbVRefNum, vcb ); // no Flags, VH is always block #0, vcb->vcbBufAdr == CacheQueueHeader
2859: #else
2860: err = GetBlock_glue( gbDefault, alternateBlockLocation, (Ptr*)&alternateMDB, kNoFileReference, vcb ); // no Flags, VH is always block #0, vcb->vcbBufAdr == CacheQueueHeader
2861: #endif
2862: if ( err == noErr )
2863: {
2864: //-- Copy the MDB to the alternate location
2865: BlockMoveData( mdb, alternateMDB, sizeof(HFSMasterDirectoryBlock) );
2866:
2867: //-- And write it back to the disk, NOW!
2868: err = RelBlock_glue( (Ptr)mdb, rbFreeMask ); // free the MDB
2869: err = RelBlock_glue( (Ptr)alternateMDB, rbWriteMask ); // force it to be written
2870: }
2871: else
2872: {
2873: err = RelBlock_glue( (Ptr)mdb, rbFreeMask ); // free the MDB
2874: }
2875: }
2876:
2877: return( err );
2878: }
2879:
2880:
2881:
2882: //_______________________________________________________________________
2883: //
2884: // Routine: TrashAllFSCaches
2885: // Arguments: ExtendedVCB *vcb
2886: // Output: OSErr err
2887: //
2888: // Function: Trash all file system related caches as well as the disk cache.
2889: // This allows applications such as Disk First Aid or Norton Utilities
2890: // to be able to repair disks without first unmounting the volume.
2891: //
2892: // All file system caches should also have a call to the cache
2893: // trashing routine here!
2894: //_______________________________________________________________________
2895: #if TARGET_OS_MAC
2896: OSErr TrashAllFSCaches( ExtendedVCB *vcb )
2897: {
2898: OSErr err;
2899: FSVarsRec* fsVars = (FSVarsRec*) LMGetFSMVars();
2900:
2901: InvalidateCatalogCache( vcb ); // Calls TrashCatalogIterator
2902: TrashCatalogNodeCache( ); // Trash Catalog node cache, gCatalogFSSpec
2903: err = TrashCacheBlocks( 0 ); // Trash BTree node cache
2904: TrashMRUCache( vcb->hintCachePtr ); // Trash the heuristic hint cache
2905: ClearMemory( fsVars->gAttributesBuffer, fsVars->gAttributesBufferSize ); // Clear the buffer used by MountCheck and CatSearch
2906: TrashVolumeDiskCache( vcb ); // Trash the disk cache, calls TRASHVBLKSA7
2907:
2908: return( err );
2909: }
2910: #endif /* TARGET_OS_MAC */
2911:
2912:
2913: #if TARGET_OS_MAC
2914: OSErr GetDiskBlocks( ExtendedVCB *vcb, unsigned long *numBlocks)
2915: {
2916: /* Various constants for GetDiskBlocks() */
2917: enum
2918: {
2919: /* return format list status code */
2920: kFmtLstCode = 6,
2921:
2922: /* reference number of .SONY driver */
2923: kSonyRefNum = 0xfffb,
2924:
2925: /* values returned by DriveStatus in DrvSts.twoSideFmt */
2926: kSingleSided = 0,
2927: kDoubleSided = -1,
2928: kSingleSidedSize = 800, /* 400K */
2929: kDoubleSidedSize = 1600, /* 800K */
2930:
2931: /* values in DrvQEl.qType */
2932: kWordDrvSiz = 0,
2933: kLongDrvSiz = 1,
2934:
2935: /* more than enough formatListRecords */
2936: kMaxFormatListRecs = 16
2937: };
2938:
2939: DrvQEl *driveQElementPtr;
2940: unsigned long blocks;
2941: ParamBlockRec pb;
2942: DrvSts status;
2943: FormatListRec formatListRecords[kMaxFormatListRecs];
2944: short formatListRecIndex;
2945: OSErr err;
2946: short driverRefNum;
2947:
2948: blocks = 0;
2949:
2950: // Find the drive queue element for this volume
2951: err = FindDrive( &driverRefNum, &driveQElementPtr, vcb->vcbDrvNum );
2952: ReturnIfError( err );
2953:
2954: // Make sure this is a real driver (dQRefNum < 0).
2955: // AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause
2956: // problems if you try to use it as a driver refNum.
2957:
2958: if ( driveQElementPtr->dQRefNum >= 0 )
2959: {
2960: err = paramErr;
2961: }
2962: else
2963: {
2964: // Attempt to get the drive's format list.
2965: // (see the Technical Note "What Your Sony Drives For You")
2966:
2967: pb.cntrlParam.ioVRefNum = driveQElementPtr->dQDrive;
2968: pb.cntrlParam.ioCRefNum = driveQElementPtr->dQRefNum;
2969: pb.cntrlParam.csCode = kFmtLstCode;
2970: pb.cntrlParam.csParam[0] = kMaxFormatListRecs;
2971: *(long *)&pb.cntrlParam.csParam[1] = (long)&formatListRecords[0];
2972:
2973: err = PBStatusSync(&pb);
2974:
2975: if ( err == noErr )
2976: {
2977: // The drive supports ReturnFormatList status call.
2978:
2979: // Get the current disk's size.
2980: for( formatListRecIndex = 0;
2981: formatListRecIndex < pb.cntrlParam.csParam[0];
2982: ++formatListRecIndex )
2983: {
2984: if ( (formatListRecords[formatListRecIndex].formatFlags &
2985: diCIFmtFlagsCurrentMask) != 0 )
2986: {
2987: blocks = formatListRecords[formatListRecIndex].volSize;
2988: }
2989: }
2990: if ( blocks == 0 )
2991: {
2992: // This should never happen
2993: err = paramErr;
2994: }
2995: }
2996: else if ( driveQElementPtr->dQRefNum == (short)kSonyRefNum )
2997: {
2998: // The drive is a non-SuperDrive floppy which only supports 400K and 800K disks
2999:
3000: err = DriveStatus(driveQElementPtr->dQDrive, &status);
3001: if ( err == noErr )
3002: {
3003: switch ( status.twoSideFmt )
3004: {
3005: case kSingleSided:
3006: blocks = kSingleSidedSize;
3007: break;
3008: case kDoubleSided:
3009: blocks = kDoubleSidedSize;
3010: break;
3011: default:
3012: // This should never happen
3013: err = paramErr;
3014: break;
3015: }
3016: }
3017: }
3018: else
3019: {
3020: // The drive is not a floppy and it doesn't support ReturnFormatList
3021: // so use the dQDrvSz field(s)
3022:
3023: err = noErr; // reset err
3024: switch ( driveQElementPtr->qType )
3025: {
3026: case kWordDrvSiz:
3027: blocks = driveQElementPtr->dQDrvSz;
3028: break;
3029: case kLongDrvSiz:
3030: blocks = ((unsigned long)driveQElementPtr->dQDrvSz2 << 16) +
3031: driveQElementPtr->dQDrvSz;
3032: break;
3033: default:
3034: // This should never happen
3035: err = paramErr;
3036: break;
3037: }
3038: }
3039: }
3040:
3041: *numBlocks = blocks;
3042:
3043: return ( err );
3044: }
3045: #endif /* TARGET_OS_MAC */
3046:
3047:
3048: //
3049: // Sets up a VCB for calls to GetBlock()
3050: //
3051: void AddVCB( ExtendedVCB *vcb, short driveNumber, short ioRefNum )
3052: {
3053: #if TARGET_OS_MAC
3054: OSErr err = noErr;
3055: WDCBArray *wdcbsAry;
3056: QHdr *vcbQHdr;
3057: WDCBRecPtr wdcb;
3058:
3059: vcbQHdr = LMGetVCBQHdr();
3060: if ( vcbQHdr->qHead == nil )
3061: { // Queue is empty, new vcb is the default now
3062: LMSetDefVCBPtr( (Ptr) vcb );
3063: wdcbsAry = (WDCBArray*)LMGetWDCBsPtr(); // Point to WDCB array
3064:
3065: wdcb = &(wdcbsAry->wdcb[0]);
3066: wdcb->wdVCBPtr = (VCB *) vcb; // Set default VCB pointer in default WDCB
3067: wdcb->wdDirID = fsRtDirID; // Default to root directory
3068: wdcb->wdCatHint = 0; // Clear catalog hint
3069: wdcb->wdProcID = 0; // And procID of WDCB 'owner'
3070: vcbQHdr = LMGetVCBQHdr(); // Reset for VCB insertion
3071: }
3072:
3073:
3074: Enqueue( (QElemPtr)vcb, (QHdrPtr)vcbQHdr ); // Insert the new VCB in the queue
3075:
3076: vcb->vcbDrvNum = driveNumber;
3077: vcb->vcbDRefNum = ioRefNum;
3078:
3079: #if ( hasHFSManualEject )
3080: SetVCBManEject(vcb); // set vcb maneject flag appropriately <SM7> <BH 03Aug93>
3081: #endif
3082:
3083:
3084: vcb->vcbBufAdr = LMGetSysVolCPtr(); // always use system-wide cache �
3085:
3086: vcb->vcbVRefNum = GetNewVRefNum(); // Assign a refNum to this new volume.
3087:
3088: if ( vcb == (ExtendedVCB *) LMGetDefVCBPtr() ) // Are we supposedly the default?
3089: {
3090: LMSetDefVRefNum( vcb->vcbVRefNum );
3091: }
3092: #else
3093: #pragma unused(vcb,driveNumber,ioRefNum,wdcbH)
3094: #endif /* TARGET_OS_MAC */
3095: }
3096:
3097:
3098: //--------------------------------------------------------------------------------------
3099: // Routine: SetVCBManEject
3100: // Input: VCB ptr
3101: // Called by: MountVol
3102: // Function: Sets or clears the manual-eject bit in the flags word of the input VCB
3103: // based on the type of the drive indicated by vcbDrvNum. All registers
3104: // are preserved. The manual-eject flag should only be changed at MountVol
3105: // time.
3106: //--------------------------------------------------------------------------------------
3107:
3108: #if ( hasHFSManualEject )
3109:
3110: static void SetVCBManEject(ExtendedVCB *vcb)
3111: {
3112: DrvQEl *driveQElementPtr;
3113: DrvSts *driveStatsPtr;
3114: short driverRefNum;
3115: OSErr err;
3116:
3117: // Find the drive queue element for this volume
3118: err = FindDrive( &driverRefNum, &driveQElementPtr, vcb->vcbDrvNum );
3119:
3120: if (err) return;
3121:
3122: driveStatsPtr = (DrvSts*) ((Ptr) driveQElementPtr - offsetof(DrvSts, qLink));
3123:
3124: if ( driveStatsPtr->installed & (1 << kdqManualEjectBit) ) // manual eject drive asserted?
3125: vcb->vcbFlags |= vcbManualEjectMask;
3126: else
3127: vcb->vcbFlags &= ~vcbManualEjectMask;
3128: }
3129:
3130: #endif
3131:
3132:
3133: //
3134: // Simple utility function to deturmine if a keyboard key is pressed.
3135: //
3136: short IsPressed( UInt16 k ) // k = any keyboard scan code, 0-127
3137: {
3138: #if TARGET_OS_MAC
3139: unsigned char km[16];
3140:
3141: GetKeys( *( (KeyMap*) &km ) ); // Ugly casting to compile with MPWC & SC
3142: return ( ( km[k>>3] >> (k & 7) ) & 1);
3143: #else
3144: #pragma unused(k)
3145: return( 0 );
3146: #endif /* TARGET_OS_MAC */
3147: }
3148:
3149:
3150: #if TARGET_OS_MAC
3151: //
3152: // Utility function to allocate a new vRefNum.
3153: // This function cycles through all vRefNums, rather than reuse them.
3154: //
3155: FileReference GetNewVRefNum()
3156: {
3157: FileReference refNum;
3158: ExtendedVCB *tempVCB;
3159: OSErr err = noErr;
3160:
3161: #if (0) // See bug 1664445
3162: {
3163: FSVarsRec *fsVars;
3164:
3165: fsVars = (FSVarsRec*)LMGetFSMVars();
3166: for ( refNum = fsVars->nextVRefNum ; err == noErr ; refNum-- )
3167: {
3168: if ( refNum >= 0x8001 ) // if we've cycled through all the possible vRef nums, start over
3169: refNum = -1;
3170:
3171: err = GetVCBRefNum( &tempVCB, refNum ); // Check if already assigned
3172: }
3173:
3174: fsVars->nextVRefNum = refNum;
3175: return( ++refNum ); // for loop post decrements
3176: }
3177: #else
3178: {
3179: for ( refNum = -1 ; err == noErr ; refNum-- )
3180: {
3181: err = GetVCBRefNum( &tempVCB, refNum ); // Check if already assigned
3182: }
3183: return( ++refNum ); // for loop post decrements
3184: }
3185: #endif
3186: }
3187: #endif /* TARGET_OS_MAC */
3188:
3189: //�������������������������������������������������������������������������������
3190:
3191: OSErr GetVolumeNameFromCatalog( ExtendedVCB *vcb )
3192: {
3193: FSSpec spec;
3194: CatalogNodeData nodeData;
3195: UInt32 hint;
3196: OSErr err;
3197: #if TARGET_OS_MAC
3198: FSVarsRec *fsVars;
3199:
3200: fsVars = (FSVarsRec*) LMGetFSMVars();
3201: if ( fsVars->gIsUnicodeInstalled )
3202: #else
3203: if ( true )
3204: #endif /*TARGET_OS_MAC */
3205: {
3206: err = GetCatalogNode( vcb, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint );
3207:
3208: if ( err == noErr )
3209: {
3210: #if TARGET_OS_MAC
3211: BlockMoveData( spec.name, vcb->vcbVN, sizeof(Str27) );
3212: #else
3213: vcb->vcbVN[0] = strlen(spec.name);
3214: BlockMoveData( spec.name, &vcb->vcbVN[1], sizeof(Str27)-1 );
3215: #endif
3216: vcb->volumeNameEncodingHint = nodeData.textEncoding; // save encoding for FSFindTextEncodingForVolume
3217: }
3218: }
3219: else
3220: {
3221: err = paramErr;
3222: }
3223:
3224: return err;
3225: }
3226:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.