|
|
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.