|
|
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: Attributes.c ! 27: ! 28: Contains: Extended Attributes Manager ! 29: Routines for managing attributes (additional catalog-like data) associated ! 30: with files or folders on HFS Plus volumes. ! 31: ! 32: Version: HFS Plus 1.0 ! 33: ! 34: Copyright: � 1997-1998 by Apple Computer, Inc., all rights reserved. ! 35: ! 36: File Ownership: ! 37: ! 38: DRI: Mark Day ! 39: ! 40: Other Contact: Greg Parks ! 41: ! 42: Technology: HFS Plus ! 43: ! 44: Writers: ! 45: ! 46: (djb) Don Brady ! 47: (DSH) Deric Horn ! 48: (msd) Mark Day ! 49: ! 50: Change History (most recent first): ! 51: <Rhap> 4/17/98 djb Add VCB locking. ! 52: <Rhap> 3/31/98 djb Sync up with final HFSVolumes.h header file. ! 53: ! 54: <CS13> 11/7/97 msd Change calls to the wrapper routine CompareUnicodeNames() to use ! 55: the underlying routine FastUnicodeCompare() instead. ! 56: <CS12> 10/17/97 msd Remove DebugStrs. ! 57: <CS11> 10/13/97 DSH Added InitBTreeHeader() fileSize parameter. ! 58: <CS10> 9/4/97 msd Remove unneeded/unused routines. ! 59: <CS9> 8/22/97 djb Add readFromDisk flag to GetCacheBlock. ! 60: <CS8> 7/25/97 DSH Pass kInvalidMRUCacheKey to BTSearchRecord as the heuristicHint. ! 61: <CS7> 7/24/97 djb SetEndOfForkProc takes a refNum instead of an FCB. ! 62: <CS6> 7/18/97 msd Include LowMemPriv.h. ! 63: <CS5> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name ! 64: collision ! 65: <CS4> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line ! 66: <CS3> 6/2/97 DSH On creation make sure we call through the SetEndOfFileProc so ! 67: the AlternateVolumeHeader is updated. ! 68: <CS2> 5/28/97 msd Change keys to {cnid, flags, creator, selector}. Prototype an ! 69: SPI for testing. ! 70: <CS1> 4/24/97 djb first checked in ! 71: <HFS5> 4/10/97 msd In PropertyDeleteObject, use the global buffer instead of an ! 72: automatic variable. ! 73: <HFS4> 4/8/97 msd Add AttributesOpenVolume to allocate appropriate buffer space. ! 74: <HFS3> 4/7/97 msd Start adding real code. Removed PropertyOpenVolume; that code ! 75: now resides in Volumes.c. ! 76: <HFS2> 3/17/97 DSH SC needs parameters to the stub functions. ! 77: <HFS1> 3/5/97 msd first checked in ! 78: */ ! 79: ! 80: /* ! 81: Public routines: ! 82: AttributesCloseVolume ! 83: Clean up and finalize for a given volume. Close a property database ! 84: file if needed. In general, clean up after PropertyOpenVolume. ! 85: This routine should be called before closing the Catalog and Extents ! 86: files on the volume. ! 87: */ ! 88: ! 89: #if ( PRAGMA_LOAD_SUPPORTED ) ! 90: #pragma load PrecompiledHeaders ! 91: #else ! 92: #if TARGET_OS_MAC ! 93: #include <Types.h> ! 94: #include <LowMemPriv.h> ! 95: #else ! 96: #include "../headers/system/MacOSStubs.h" ! 97: #endif /* TARGET_OS_MAC */ ! 98: #endif /* PRAGMA_LOAD_SUPPORTED */ ! 99: ! 100: #include "../headers/HFSVolumes.h" ! 101: #include "../headers/FileMgrInternal.h" ! 102: #include "../headers/BTreesInternal.h" ! 103: #include "../headers/HFSBtreesPriv.h" ! 104: #include "../headers/system/HFSUnicodeWrappers.h" ! 105: ! 106: #if HFSInstrumentation ! 107: #include "Instrumentation.h" ! 108: #endif ! 109: ! 110: #define min(x,y) ((x < y) ? x : y) ! 111: ! 112: // ! 113: // Values for flags in AttributesKey.flags ! 114: // ! 115: enum { ! 116: kAttributeNodeSize = 4096 // Size of our Btree node ! 117: }; ! 118: ! 119: ! 120: #if TARGET_OS_MAC ! 121: OSErr AttributesCloseVolume(ExtendedVCB * vcb) ! 122: { ! 123: OSErr err; ! 124: ! 125: err = noErr; ! 126: ! 127: if (vcb->vcbSigWord == kHFSPlusSigWord && vcb->attributesRefNum != 0) { ! 128: err = CloseFile( vcb, vcb->attributesRefNum, LMGetFCBSPtr() ); ! 129: vcb->attributesRefNum = 0; ! 130: } ! 131: ! 132: return err; ! 133: } ! 134: #endif /* TARGET_OS_MAC */ ! 135: ! 136: SInt32 CompareAttributeKeys( const void *inSearchKey, const void *inTrialKey ) ! 137: { ! 138: const AttributeKey *searchKey = inSearchKey; ! 139: const AttributeKey *trialKey = inTrialKey; ! 140: SInt32 temp; ! 141: ! 142: // ! 143: // First, compare the CNID's ! 144: // ! 145: if (searchKey->cnid != trialKey->cnid) { ! 146: return searchKey->cnid < trialKey->cnid ? -1 : 1; ! 147: } ! 148: ! 149: // ! 150: // CNID's are equal; compare names ! 151: // ! 152: if (searchKey->attributeName.length == 0 || trialKey->attributeName.length == 0) ! 153: return searchKey->attributeName.length < trialKey->attributeName.length ? -1 : 1; ! 154: temp = FastUnicodeCompare(&searchKey->attributeName.unicode[0], searchKey->attributeName.length, ! 155: &trialKey->attributeName.unicode[0], trialKey->attributeName.length); ! 156: if (temp != 0) ! 157: return temp; ! 158: ! 159: // ! 160: // Names are equal; compare startBlock ! 161: // ! 162: if (searchKey->startBlock == trialKey->startBlock) ! 163: return 0; ! 164: else ! 165: return searchKey->startBlock < trialKey->startBlock ? -1 : 1; ! 166: } ! 167: ! 168: ! 169: #if TARGET_OS_MAC ! 170: static OSErr CreateAndOpenBtree(ExtendedVCB *vcb) ! 171: { ! 172: OSStatus err; ! 173: UInt16 refnum; // attribute file's refnum ! 174: Ptr fcbHeader; // points to start of FCBs (unused) ! 175: FCB *fcb; // attribute file's FCB ! 176: ExtendedFCB *extendedFCB; // attribute file's extended FCB ! 177: UInt32 clumpSize; ! 178: UInt32 mapNodes; ! 179: LogicalAddress header; ! 180: Boolean readFromDisk; ! 181: ! 182: clumpSize = 32 * vcb->blockSize; //�� Need a better value. ! 183: ! 184: // Find a free FCB for the attributes file ! 185: #if TARGET_OS_MAC ! 186: err = FindFileControlBlock(&refnum, &fcbHeader); ! 187: #else /* TARGET_OS_MAC */ ! 188: err = GetNewFCB(vcb, &refnum ); ! 189: #endif /* TARGET_OS_MAC */ ! 190: ! 191: ReturnIfError(err); ! 192: // fcb = GetFileControlBlock(refnum); ! 193: fcb = SetupFCB(vcb, refnum, kHFSAttributesFileID, clumpSize); ! 194: ! 195: // Mark file as empty. ! 196: fcb->fcbEOF = 0; ! 197: fcb->fcbPLen = 0; ! 198: vcb->attributesRefNum = refnum; ! 199: ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) ); ! 200: /* XXX PPD: Is there any reason this isn't the same for EVERY platform? */ ! 201: #if TARGET_OS_MAC ! 202: extendedFCB = ParallelFCBFromRefnum( refnum ); ! 203: #else ! 204: extendedFCB = GetParallelFCB( refnum ); ! 205: #endif ! 206: ClearMemory( (Ptr)extendedFCB->extents, sizeof(HFSPlusExtentRecord) ); ! 207: ! 208: // Allocate some space to the file ! 209: err = SetEndOfForkProc(refnum, clumpSize, clumpSize); ! 210: if (err) { ! 211: ClearMemory(fcb, sizeof(FCB)); ! 212: goto ErrorExit; ! 213: } ! 214: fcb->fcbEOF = fcb->fcbPLen; // grow the file to include the allocated space ! 215: ! 216: // Initialize the b-tree. Write out the header. ! 217: err = GetCacheBlock(refnum, 0, kAttributeNodeSize, gbDefault, &header, &readFromDisk); ! 218: ClearMemory(header, kAttributeNodeSize); ! 219: InitBTreeHeader(fcb->fcbEOF, clumpSize, kAttributeNodeSize, 0, kAttributeKeyMaximumLength, kBTBigKeysMask, &mapNodes, header); ! 220: err = ReleaseCacheBlock(header, rbWriteMask); ! 221: ! 222: // Finally, prepare for using the B-tree ! 223: err = OpenBTree( refnum, (KeyCompareProcPtr) CompareAttributeKeys ); ! 224: if (err) { ! 225: ClearMemory(fcb, sizeof(FCB)); ! 226: goto ErrorExit; ! 227: } ! 228: ! 229: //�� Should we update the volume header and alternate volume header? ! 230: ! 231: ErrorExit: ! 232: return err; ! 233: } ! 234: #endif /* #if TARGET_OS_MAC */ ! 235: ! 236: #if TARGET_OS_MAC ! 237: static OSErr PreflightAttributeCall(AttributeParam *pb, FindFileNameGlueRec *fileInfo, Boolean needsWrite) ! 238: { ! 239: OSErr err; ! 240: ExtendedVCB *vcb; ! 241: ! 242: // ! 243: // See if the file exists. Get its FileID. ! 244: // ! 245: err = FindFileName((ParamBlockRec *) pb, fileInfo); ! 246: ReturnIfError( err ); ! 247: ! 248: // ! 249: // Make sure the volume is on-line and writable. ! 250: // ! 251: vcb = fileInfo->vcb; ! 252: ! 253: if (needsWrite) { ! 254: err = VolumeWritable( vcb ); ! 255: ReturnIfError( err ); ! 256: } ! 257: ! 258: err = CheckVolumeOffLine( vcb ); ! 259: ReturnIfError( err ); ! 260: ! 261: // ! 262: // And make sure it is HFS Plus. ! 263: // ! 264: if (vcb->vcbSigWord != kHFSPlusSigWord) ! 265: return wrgVolTypErr; ! 266: ! 267: // ! 268: //�� Make sure there is an attribute file. Create and open it if needed. ! 269: // ! 270: if (vcb->attributesRefNum == 0) { ! 271: ! 272: if (needsWrite == false) // If we only wanted to read, ! 273: return notBTree; // tell caller there is no b-tree ! 274: // ! 275: // Create and open b-tree ! 276: // ! 277: err = CreateAndOpenBtree(vcb); ! 278: } ! 279: ! 280: return err; ! 281: } ! 282: #endif /* TARGET_OS_MAC */ ! 283: ! 284: ! 285: #if TARGET_OS_MAC ! 286: OSErr CreateAttribute(AttributeParam *pb) ! 287: { ! 288: OSErr err; ! 289: ExtendedVCB *vcb; ! 290: UInt32 length; ! 291: UInt32 numberOfExtents; ! 292: UInt32 i,extentsThisRecord; ! 293: UInt32 blocksAllocated = 0; ! 294: UInt32 hint; ! 295: AttributeKey key; ! 296: FindFileNameGlueRec fileInfo; ! 297: ! 298: err = PreflightAttributeCall(pb, &fileInfo, true); ! 299: ReturnIfError( err ); ! 300: ! 301: vcb = fileInfo.vcb; ! 302: ! 303: // ! 304: // Set up the first key ! 305: // ! 306: length = sizeof(UniChar) * (pb->ioAttributeName->length+1); // length in bytes of Unicode name ! 307: ! 308: key.keyLength = length + offsetof(AttributeKey, attributeName); ! 309: key.pad = 0; ! 310: key.cnid = fileInfo.data->nodeID; ! 311: key.startBlock = 0; ! 312: BlockMoveData(pb->ioAttributeName, &key.attributeName, length); // copy attributeName ! 313: ! 314: // ! 315: // Determine the first record type based on the number of extents ! 316: // ! 317: numberOfExtents = pb->filler1; ! 318: if (numberOfExtents == 0) { ! 319: AttributeInlineData record; ! 320: ! 321: record.recordType = kAttributeInlineData; ! 322: record.logicalSize = 0; ! 323: length = offsetof(AttributeInlineData, userData); ! 324: err = InsertBTreeRecord(vcb->attributesRefNum, &key, &record, length, &hint); ! 325: } ! 326: else { ! 327: { ! 328: AttributeForkData record; ! 329: ! 330: // Set up first record, with ForkData ! 331: ClearMemory(&record, sizeof(record)); ! 332: record.recordType = kAttributeForkData; ! 333: record.theFork.logicalSize.lo = numberOfExtents * vcb->blockSize; // each extent is one block ! 334: record.theFork.logicalSize.hi = 0; ! 335: record.theFork.clumpSize = vcb->attributesClumpSize; ! 336: record.theFork.totalBlocks = numberOfExtents; // one block per extent ! 337: extentsThisRecord = min(numberOfExtents, kHFSPlusExtentDensity); ! 338: for (i=0; i<extentsThisRecord; i++) { ! 339: err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, 1, &record.theFork.extents[i].startBlock, ! 340: &record.theFork.extents[i].blockCount); ! 341: ReturnIfError(err); ! 342: ++blocksAllocated; ! 343: } ! 344: err = InsertBTreeRecord(vcb->attributesRefNum, &key, &record, sizeof(record), &hint); ! 345: ReturnIfError(err); ! 346: } ! 347: ! 348: { ! 349: AttributeExtents record; ! 350: ! 351: // Handle overflow extent records ! 352: ClearMemory(&record, sizeof(record)); ! 353: numberOfExtents -= extentsThisRecord; ! 354: record.recordType = kAttributeExtents; ! 355: while (numberOfExtents) { ! 356: extentsThisRecord = min(numberOfExtents, kHFSPlusExtentDensity); ! 357: key.startBlock += kHFSPlusExtentDensity; ! 358: for (i=0; i<extentsThisRecord; i++) { ! 359: err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, 1, &record.extents[i].startBlock, ! 360: &record.extents[i].blockCount); ! 361: ReturnIfError(err); ! 362: ++blocksAllocated; ! 363: } ! 364: for (; i<kHFSPlusExtentDensity; i++) { ! 365: record.extents[i].startBlock = 0; ! 366: record.extents[i].blockCount = 0; ! 367: } ! 368: err = InsertBTreeRecord(vcb->attributesRefNum, &key, &record, sizeof(record), &hint); ! 369: ReturnIfError(err); ! 370: numberOfExtents -= extentsThisRecord; ! 371: } ! 372: } ! 373: } ! 374: ! 375: if (blocksAllocated) { ! 376: VCB_LOCK(vcb); ! 377: vcb->freeBlocks -= blocksAllocated; ! 378: VCB_UNLOCK(vcb); ! 379: UpdateVCBFreeBlks( vcb ); ! 380: MarkVCBDirty(vcb); ! 381: } ! 382: ! 383: if (err == fsBTDuplicateRecordErr) ! 384: err = btDupRecErr; ! 385: ! 386: return err; ! 387: } ! 388: #endif /* TARGET_OS_MAC */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.