|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: File: CatalogUtilities.c
24:
25: Contains: Private Catalog Manager support routines.
26:
27: Version: HFS Plus 1.0
28:
29: Copyright: � 1997-2000 by Apple Computer, Inc., all rights reserved.
30:
31: File Ownership:
32:
33: DRI: Don Brady
34:
35: Other Contact: Mark Day
36:
37: Technology: xxx put technology here xxx
38:
39: Writers:
40:
41: (DSH) Deric Horn
42: (msd) Mark Day
43: (djb) Don Brady
44:
45: Change History (most recent first):
46: <MacOSX> 1/8/99 djb Fixing LocateCatalogNodeByMangledName...
47: <MacOSX> 1/7/99 djb In BuildCatalogKeyUTF8 check name length against NAME_MAX.
48: <MacOSX> 12/7/98 djb Add ExtractTextEncoding routine to get text encodings.
49: <MacOSX> 11/20/98 djb Add support for UTF-8 names.
50: <MacOSX> 8/31/98 djb GetTimeLocal now takes an input.
51: <MacOSX> 4/17/98 djb Add VCB locking.
52: <MacOSX> 4/3/98 djb Removed last name conversion cache from LocateCatalogNodeWithRetry.
53: <MacOSX> 4/2/98 djb InvalidateCatalogNodeCache and TrashCatalogNodeCache are not used in MacOS X.
54: <MacOSX> 03/31/98 djb Sync up with final HFSVolumes.h header file.
55:
56: <CS24> 1/29/98 DSH Add TrashCatalogNodeCache for TrashAllFSCaches API support.
57: <CS23> 12/15/97 djb Radar #2202860, In LocateCatalogNodeByMangledName remap
58: cmParentNotFound error code to cmNotFound.
59: <CS22> 12/10/97 DSH 2201501, Pin the leof and peof to multiple of allocation blocks
60: under 2 Gig.
61: <CS21> 12/9/97 DSH 2201501, Pin returned leof values to 2^31-1 (SInt32), instead of
62: 2^32-1
63: <CS20> 11/26/97 djb Radar #2005688, 2005461 - need to handle kTextMalformedInputErr.
64: <CS19> 11/25/97 djb Radar #2002357 (again) fix new bug introduced in <CS18>.
65: <CS18> 11/17/97 djb PrepareInputName routine now returns an error.
66: <CS17> 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate.
67: <CS16> 10/17/97 djb Add ConvertInputNameToUnicode for Catalog Create/Rename.
68: <CS15> 10/14/97 djb Fix LocateCatalogNode's MakeFSSpec optimization (radar #1683166)
69: <CS14> 10/13/97 djb Copy text encoding in CopyCatalogNodeData. Fix cut/paste error
70: in VolumeHasEncodings macro. When accessing encoding bitmap use
71: the MapEncodingToIndex and MapIndexToEncoding macros.
72: <CS13> 10/1/97 djb Remove old Catalog Iterator code...
73: <CS12> 9/8/97 msd Make sure a folder's modifyDate is set whenever its
74: contentModDate is set.
75: <CS11> 9/4/97 djb Add MakeFSSpec optimization.
76: <CS10> 9/4/97 msd In CatalogNodeData, change attributeModDate to modifyDate.
77: <CS9> 8/26/97 djb Back out <CS4> (UpdateFolderCount must maintain vcbNmFls for HFS
78: Plus volumes too).
79: <CS8> 8/14/97 djb Remove hard link support.
80: <CS7> 7/18/97 msd Include LowMemPriv.h.
81: <CS6> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
82: collision
83: <CS5> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
84: <CS4> 6/27/97 msd UpdateFolderCount should update number of root files/folders for
85: HFS volumes, not HFS Plus.
86: <CS3> 6/24/97 djb LocateCatalogNodeWithRetry did not always set result code.
87: <CS2> 6/24/97 djb Add LocateCatalogNodeByMangledName routine
88: <CS1> 6/24/97 djb first checked in
89: */
90:
91: #include "../headers/FileMgrInternal.h"
92: #include "../headers/BTreesInternal.h"
93: #include "../headers/CatalogPrivate.h"
94: #include "../headers/HFSUnicodeWrappers.h"
95: #include <string.h>
96:
97: static void ExtractTextEncoding (ItemCount length, ConstUniCharArrayPtr string, UInt32 * textEncoding);
98:
99: //*******************************************************************************
100: // Routine: LocateCatalogNode
101: //
102: // Function: Locates the catalog record for an existing folder or file
103: // CNode and returns pointers to the key and data records.
104: //
105: //*******************************************************************************
106:
107: OSErr
108: LocateCatalogNode(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
109: UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
110: {
111: OSErr result;
112: CatalogName *nodeName = NULL; /* To ward off uninitialized use warnings from compiler */
113: HFSCatalogNodeID threadParentID;
114:
115:
116: result = LocateCatalogRecord(volume, folderID, name, hint, keyPtr, dataPtr, newHint);
117: ReturnIfError(result);
118:
119: // if we got a thread record, then go look up real record
120: switch ( dataPtr->recordType )
121: {
122: case kHFSFileThreadRecord:
123: case kHFSFolderThreadRecord:
124: threadParentID = dataPtr->hfsThread.parentID;
125: nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
126: break;
127:
128: case kHFSPlusFileThreadRecord:
129: case kHFSPlusFolderThreadRecord:
130: threadParentID = dataPtr->hfsPlusThread.parentID;
131: nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
132: break;
133:
134: default:
135: threadParentID = 0;
136: break;
137: }
138:
139: if ( threadParentID ) // found a thread
140: result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
141:
142: return result;
143: }
144:
145: //
146: // Routine: LocateCatalogNodeByKey
147: //
148: // Function: Locates the catalog record for an existing folder or file
149: // CNode and returns the key and data records.
150: //
151:
152: OSErr
153: LocateCatalogNodeByKey(const ExtendedVCB *volume, UInt32 hint, CatalogKey *keyPtr,
154: CatalogRecord *dataPtr, UInt32 *newHint)
155: {
156: OSErr result;
157: CatalogName *nodeName = NULL; /* To ward off uninitialized use warnings from compiler */
158: HFSCatalogNodeID threadParentID;
159: UInt16 tempSize;
160:
161:
162: result = SearchBTreeRecord(volume->catalogRefNum, keyPtr, hint, keyPtr,
163: dataPtr, &tempSize, newHint);
164: if (result == btNotFound)
165: result = cmNotFound;
166: ReturnIfError(result);
167:
168: // if we got a thread record, then go look up real record
169: switch ( dataPtr->recordType )
170: {
171: case kHFSFileThreadRecord:
172: case kHFSFolderThreadRecord:
173: threadParentID = dataPtr->hfsThread.parentID;
174: nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
175: break;
176:
177: case kHFSPlusFileThreadRecord:
178: case kHFSPlusFolderThreadRecord:
179: threadParentID = dataPtr->hfsPlusThread.parentID;
180: nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
181: break;
182:
183: default:
184: threadParentID = 0;
185: break;
186: }
187:
188: if ( threadParentID ) // found a thread
189: result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
190:
191: return result;
192: }
193:
194:
195: #if 0
196: //*******************************************************************************
197: // Routine: LocateCatalogNodeWithRetry
198: //
199: // Function: Locates the catalog record for an existing folder or file node.
200: // For HFS Plus volumes a retry is performed when a catalog node is
201: // not found and the volume contains more than one text encoding.
202: //
203: //�������������������������������������������������������������������������������
204:
205: #define VolumeHasEncodings(v) \
206: ( ((v)->encodingsBitmap != 0 )
207:
208: #define EncodingInstalled(i) \
209: ( (fsVars)->gConversionContext[(i)].toUnicode != 0 )
210:
211: #define EncodingUsedByVolume(v,i) \
212: ( ((v)->encodingsBitmap & (1 << (i))) )
213:
214:
215: OSErr
216: LocateCatalogNodeWithRetry (const ExtendedVCB *volume, HFSCatalogNodeID folderID, ConstStr31Param pascalName, CatalogName *unicodeName,
217: UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
218: {
219: TextEncoding defaultEncoding;
220: TextEncoding encoding;
221: ItemCount encodingsToTry;
222: FSVarsRec *fsVars;
223: OSErr result = cmNotFound;
224:
225: fsVars = (FSVarsRec*) LMGetFSMVars(); // used by macros
226:
227: defaultEncoding = GetDefaultTextEncoding();
228: encodingsToTry = CountInstalledEncodings();
229:
230: // 1. Try finding file using default encoding (typical case)
231:
232: {
233: --encodingsToTry;
234: result = PrepareInputName(pascalName, true, defaultEncoding, unicodeName);
235: if (result == noErr)
236: result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint);
237: else
238: result = cmNotFound;
239:
240: if ( result != cmNotFound || encodingsToTry == 0)
241: return result;
242: }
243:
244: //
245: // XXX if the pascal string contains all 7-bit ascii then we don't need to do anymore retries
246: //
247:
248: // 2. Try finding file using Mac Roman (if not already tried above)
249:
250: if ( defaultEncoding != kTextEncodingMacRoman )
251: {
252: --encodingsToTry;
253: result = PrepareInputName(pascalName, true, kTextEncodingMacRoman, unicodeName);
254: if (result == noErr)
255: result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint);
256: else
257: result = cmNotFound;
258:
259: if ( result != cmNotFound || encodingsToTry == 0 )
260: return result;
261: }
262:
263: // 3. Try with encodings from disk (if any)
264:
265: if ( VolumeHasEncodings(volume) ) // any left to try?
266: {
267: UInt32 index;
268:
269: index = 0; // since we pre increment this will skip MacRoman (which was already tried above)
270:
271: while ( index < kMacBaseEncodingCount )
272: {
273: ++index;
274:
275: encoding = MapIndexToEncoding(index);
276:
277: if ( encoding == defaultEncoding )
278: continue; // we did this one already
279:
280: if ( EncodingInstalled(index) && EncodingUsedByVolume(volume, index) )
281: {
282: --encodingsToTry;
283: result = PrepareInputName(pascalName, true, encoding, unicodeName);
284: if (result == noErr)
285: result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint);
286: else
287: result = cmNotFound;
288:
289: if ( result != cmNotFound || encodingsToTry == 0 )
290: return result;
291: }
292: }
293: }
294:
295: // 4. Try any remaining encodings (if any)
296:
297: {
298: UInt32 index;
299:
300: index = 0; // since we pre increment this will skip MacRoman (which was already tried above)
301:
302: while ( (encodingsToTry > 0) && (index < kMacBaseEncodingCount) )
303: {
304: ++index;
305:
306: encoding = MapIndexToEncoding(index);
307:
308: if ( encoding == defaultEncoding )
309: continue; // we did this one already
310:
311: if ( EncodingInstalled(index) && EncodingUsedByVolume(volume, index) == false )
312: {
313: --encodingsToTry;
314: result = PrepareInputName(pascalName, true, encoding, unicodeName);
315: if (result == noErr)
316: result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint);
317: else
318: result = cmNotFound;
319:
320: if ( result != cmNotFound || encodingsToTry == 0 )
321: return result;
322: }
323: }
324: }
325:
326: return cmNotFound;
327: }
328: #endif
329:
330: //*******************************************************************************
331: // Routine: LocateCatalogNodeByMangledName
332: //
333: // Function: Locates the catalog record associated with a mangled name (if any)
334: //
335: //*******************************************************************************
336:
337: OSErr
338: LocateCatalogNodeByMangledName( const ExtendedVCB *volume, HFSCatalogNodeID folderID,
339: const unsigned char * name, UInt32 length, CatalogKey *keyPtr,
340: CatalogRecord *dataPtr, UInt32 *hintPtr )
341: {
342: HFSCatalogNodeID fileID;
343: unsigned char nodeName[64];
344: OSErr result;
345: ByteCount actualDstLen;
346: ByteCount prefixlen;
347:
348:
349: if (name == NULL || name[0] == '\0')
350: return cmNotFound;
351:
352: fileID = GetEmbeddedFileID(name, length, &prefixlen);
353:
354: if ( fileID < kHFSFirstUserCatalogNodeID )
355: return cmNotFound;
356:
357: result = LocateCatalogNode(volume, fileID, NULL, kNoHint, keyPtr, dataPtr, hintPtr);
358: if ( result == cmParentNotFound ) // GetCatalogNode already handled cmParentNotFound case <CS23>
359: result = cmNotFound; // so remap <CS23>
360: ReturnIfError(result);
361:
362: // first make sure that the parents match
363: if ( folderID != keyPtr->hfsPlus.parentID )
364: return cmNotFound; // not the same folder so this is a false match
365:
366: result = ConvertUnicodeToUTF8( keyPtr->hfsPlus.nodeName.length * sizeof (UniChar),
367: keyPtr->hfsPlus.nodeName.unicode,
368: 64,
369: &actualDstLen,
370: nodeName);
371:
372: if ( (actualDstLen < prefixlen) || bcmp(nodeName, name, prefixlen) != 0)
373: return cmNotFound; // mangled names didn't match so this is a false match
374:
375: return noErr; // we found it
376: }
377:
378:
379: //*******************************************************************************
380: // Routine: LocateCatalogRecord
381: //
382: // Function: Locates the catalog record associated with folderID and name
383: //
384: //*******************************************************************************
385:
386: OSErr
387: LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
388: UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
389: {
390: OSErr result;
391: CatalogKey tempKey; // 518 bytes
392: UInt16 tempSize;
393:
394: BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), &tempKey);
395:
396: if ( name == NULL )
397: hint = kNoHint; // no CName given so clear the hint
398:
399: result = SearchBTreeRecord(volume->catalogRefNum, &tempKey, hint, keyPtr, dataPtr, &tempSize, newHint);
400:
401: return (result == btNotFound ? cmNotFound : result);
402: }
403:
404:
405: //*******************************************************************************
406: // Routine: LocateCatalogThread
407: //
408: // Function: Locates a catalog thread record in the catalog BTree file and
409: // returns a pointer to the data record.
410: //
411: //*******************************************************************************
412:
413: OSErr
414: LocateCatalogThread(const ExtendedVCB *volume, HFSCatalogNodeID nodeID, CatalogRecord *threadData, UInt16 *threadSize, UInt32 *threadHint)
415: {
416: CatalogKey threadKey; // 518 bytes
417: OSErr result;
418:
419: //--- build key record
420:
421: BuildCatalogKey(nodeID, NULL, (volume->vcbSigWord == kHFSPlusSigWord), &threadKey);
422:
423: //--- locate thread record in BTree
424:
425: result = SearchBTreeRecord( volume->catalogRefNum, &threadKey, kNoHint, &threadKey,
426: threadData, threadSize, threadHint);
427:
428: return (result == btNotFound ? cmNotFound : result);
429: }
430:
431:
432: /*
433: * Routine: BuildCatalogKey
434: *
435: * Function: Constructs a catalog key record (ckr) given the parent
436: * folder ID and CName. Works for both classic and extended
437: * HFS volumes.
438: *
439: */
440:
441: void
442: BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
443: {
444: if ( isHFSPlus )
445: {
446: key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
447: key->hfsPlus.parentID = parentID; // set parent ID
448: key->hfsPlus.nodeName.length = 0; // null CName length
449: if ( cName != NULL )
450: {
451: CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
452: key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
453: }
454: }
455: else
456: {
457: key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
458: key->hfs.reserved = 0; // clear unused byte
459: key->hfs.parentID = parentID; // set parent ID
460: key->hfs.nodeName[0] = 0; // null CName length
461: if ( cName != NULL )
462: {
463: UpdateCatalogName(cName->pstr, key->hfs.nodeName);
464: key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
465: }
466: }
467: }
468:
469: /*
470: * for HFS, only MacRoman is supported. If a non-MacRoman character is found, an error is returned
471: */
472: OSErr
473: BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const char *name, UInt32 nameLength,
474: CatalogKey *key, UInt32 *textEncoding)
475: {
476: OSErr err = 0;
477:
478: if ( name == NULL)
479: nameLength = 0;
480: else if (nameLength == kUndefinedStrLen)
481: nameLength = strlen(name);
482:
483: if ( volume->vcbSigWord == kHFSPlusSigWord ) {
484: ByteCount unicodeBytes = 0;
485:
486: key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
487: key->hfsPlus.parentID = parentID; // set parent ID
488: key->hfsPlus.nodeName.length = 0; // null CName length
489: if ( nameLength > 0 ) {
490: err = ConvertUTF8ToUnicode(nameLength, name, sizeof(key->hfsPlus.nodeName.unicode),
491: &unicodeBytes, key->hfsPlus.nodeName.unicode);
492: key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar);
493: key->hfsPlus.keyLength += unicodeBytes;
494: }
495:
496: if (textEncoding)
497: ExtractTextEncoding(key->hfsPlus.nodeName.length, key->hfsPlus.nodeName.unicode, textEncoding);
498: }
499: else {
500: key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
501: key->hfs.reserved = 0; // clear unused byte
502: key->hfs.parentID = parentID; // set parent ID
503: key->hfs.nodeName[0] = 0; // null CName length
504: if ( nameLength > 0 ) {
505: err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
506: key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
507: }
508: if (textEncoding)
509: *textEncoding = 0;
510: }
511:
512: if (err) {
513: if (err == kTECOutputBufferFullStatus)
514: err = bdNamErr; /* name is too long */
515: else
516: err = paramErr; /* name has invalid characters */
517: }
518:
519: return err;
520: }
521:
522:
523: /*
524: * make a guess at the text encoding value that coresponds to the Unicode characters
525: */
526: static void
527: ExtractTextEncoding(ItemCount length, ConstUniCharArrayPtr string, UInt32 * textEncoding)
528: {
529: int i;
530: UniChar ch;
531:
532: *textEncoding = 0;
533:
534: for (i = 0; i < length; ++i) {
535: ch = string[i];
536: /* CJK codepoints are 0x3000 thru 0x9FFF */
537: if (ch >= 0x3000) {
538: if (ch < 0xa000) {
539: *textEncoding = kTextEncodingMacJapanese;
540: break;
541: }
542:
543: /* fullwidth character codepoints are 0xFF00 thru 0xFFEF */
544: if (ch >= 0xff00 && ch <= 0xffef) {
545: *textEncoding = kTextEncodingMacJapanese;
546: break;
547: }
548: }
549: }
550: }
551:
552:
553: //*******************************************************************************
554: // Routine: FlushCatalog
555: //
556: // Function: Flushes the catalog for a specified volume.
557: //
558: //*******************************************************************************
559:
560: OSErr
561: FlushCatalog(ExtendedVCB *volume)
562: {
563: FCB * fcb;
564: OSErr result;
565:
566: fcb = GetFileControlBlock(volume->catalogRefNum);
567: result = BTFlushPath(fcb);
568:
569: if (result == noErr)
570: {
571: //--- check if catalog's fcb is dirty...
572:
573: if ( fcb->fcbFlags & fcbModifiedMask )
574: {
575: VCB_LOCK(volume);
576: volume->vcbFlags |= 0xFF00; // Mark the VCB dirty
577: volume->vcbLsMod = GetTimeUTC(); // update last modified date
578: VCB_UNLOCK(volume);
579:
580: result = FlushVolumeControlBlock(volume);
581: }
582: }
583:
584: return result;
585: }
586:
587:
588: //�������������������������������������������������������������������������������
589: // Routine: UpdateCatalogName
590: //
591: // Function: Updates a CName.
592: //
593: //�������������������������������������������������������������������������������
594:
595: void
596: UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
597: {
598: Size length = srcName[0];
599:
600: if (length > CMMaxCName)
601: length = CMMaxCName; // truncate to max
602:
603: destName[0] = length; // set length byte
604:
605: BlockMoveData(&srcName[1], &destName[1], length);
606: }
607:
608:
609: //*******************************************************************************
610: // Routine: AdjustVolumeCounts
611: //
612: // Function: Adjusts the folder and file counts in the VCB
613: //
614: //*******************************************************************************
615:
616: void
617: AdjustVolumeCounts(ExtendedVCB *volume, SInt16 type, SInt16 delta)
618: {
619: //�� also update extended VCB fields...
620:
621: VCB_LOCK(volume);
622:
623: if (type == kHFSFolderRecord || type == kHFSPlusFolderRecord)
624: volume->vcbDirCnt += delta; // adjust volume folder count, �� worry about overflow?
625: else
626: volume->vcbFilCnt += delta; // adjust volume file count
627:
628: volume->vcbFlags |= 0xFF00; // Mark the VCB dirty
629: volume->vcbLsMod = GetTimeUTC(); // update last modified date
630:
631: VCB_UNLOCK(volume);
632: }
633:
634:
635: //*******************************************************************************
636:
637: void
638: UpdateVolumeEncodings(ExtendedVCB *volume, TextEncoding encoding)
639: {
640: UInt32 index;
641:
642: encoding &= 0x7F;
643:
644: index = MapEncodingToIndex(encoding);
645:
646: VCB_LOCK(volume);
647:
648: volume->encodingsBitmap |= (1 << index);
649:
650: VCB_UNLOCK(volume);
651:
652: // vcb should already be marked dirty
653: }
654:
655:
656: //*******************************************************************************
657:
658: OSErr
659: UpdateFolderCount( ExtendedVCB *volume, HFSCatalogNodeID parentID, const CatalogName *name, SInt16 newType,
660: UInt32 hint, SInt16 valenceDelta)
661: {
662: CatalogKey tempKey; // 518 bytes
663: CatalogRecord tempData; // 520 bytes
664: UInt32 tempHint;
665: HFSCatalogNodeID folderID;
666: UInt16 recordSize;
667: OSErr result;
668:
669: #if 0
670: result = SearchBTreeRecord(volume->catalogRefNum, parentKey, hint,
671: &tempKey, &tempData, &recordSize, &tempHint);
672: if (result)
673: return (result == btNotFound ? cmNotFound : result);
674: #else
675:
676: result = LocateCatalogNode(volume, parentID, name, hint, &tempKey, &tempData, &tempHint);
677: ReturnIfError(result);
678: #endif
679:
680: if ( volume->vcbSigWord == kHFSPlusSigWord ) // HFS Plus
681: {
682: UInt32 timeStamp;
683:
684: if ( DEBUG_BUILD && tempData.recordType != kHFSPlusFolderRecord )
685: DebugStr("\p UpdateFolder: found HFS folder on HFS+ volume!");
686:
687: timeStamp = GetTimeUTC();
688: tempData.hfsPlusFolder.valence += valenceDelta; // adjust valence
689: tempData.hfsPlusFolder.contentModDate = timeStamp; // set date/time last modified
690: folderID = tempData.hfsPlusFolder.folderID;
691: recordSize = sizeof(tempData.hfsPlusFolder);
692: }
693: else // classic HFS
694: {
695: if ( DEBUG_BUILD && tempData.recordType != kHFSFolderRecord )
696: DebugStr("\p UpdateFolder: found HFS+ folder on HFS volume!");
697:
698: tempData.hfsFolder.valence += valenceDelta; // adjust valence
699: tempData.hfsFolder.modifyDate = GetTimeLocal(true); // set date/time last modified
700: folderID = tempData.hfsFolder.folderID;
701: recordSize = sizeof(tempData.hfsFolder);
702: }
703:
704: result = ReplaceBTreeRecord(volume->catalogRefNum, &tempKey, tempHint,
705: &tempData, recordSize, &tempHint);
706: ReturnIfError(result);
707:
708: if ( folderID == kHFSRootFolderID )
709: {
710: if (newType == kHFSFolderRecord || newType == kHFSPlusFolderRecord)
711: {
712: VCB_LOCK(volume);
713: volume->vcbNmRtDirs += valenceDelta; // adjust root folder count (undefined for HFS Plus)
714: VCB_UNLOCK(volume);
715: }
716: else
717: {
718: VCB_LOCK(volume);
719: volume->vcbNmFls += valenceDelta; // adjust root file count (used by GetVolInfo)
720: VCB_UNLOCK(volume);
721: }
722: }
723:
724: //XXX also update extended VCB fields...
725:
726: return result;
727: }
728:
729:
730: //*******************************************************************************
731:
732: UInt16
733: GetCatalogRecordSize(const CatalogRecord *dataRecord)
734: {
735: switch (dataRecord->recordType)
736: {
737: case kHFSFileRecord:
738: return sizeof(HFSCatalogFile);
739:
740: case kHFSFolderRecord:
741: return sizeof(HFSCatalogFolder);
742:
743: case kHFSPlusFileRecord:
744: return sizeof(HFSPlusCatalogFile);
745:
746: case kHFSPlusFolderRecord:
747: return sizeof(HFSPlusCatalogFolder);
748:
749: case kHFSFolderThreadRecord:
750: case kHFSFileThreadRecord:
751: return sizeof(HFSCatalogThread);
752:
753: case kHFSPlusFolderThreadRecord:
754: case kHFSPlusFileThreadRecord:
755: return sizeof(HFSPlusCatalogThread);
756:
757: default:
758: return 0;
759: }
760: }
761:
762:
763: //*******************************************************************************
764:
765: void
766: CopyCatalogNodeData(const ExtendedVCB *volume, const CatalogRecord *dataPtr, CatalogNodeData *nodeData)
767: {
768: /* convert classic hfs records to hfs plus format */
769:
770: if (dataPtr->recordType == kHFSFolderRecord) {
771: nodeData->cnd_type = kCatalogFolderNode;
772: nodeData->cnd_flags = dataPtr->hfsFolder.flags;
773: nodeData->cnd_nodeID = dataPtr->hfsFolder.folderID;
774: nodeData->cnd_createDate = LocalToUTC(dataPtr->hfsFolder.createDate);
775: nodeData->cnd_contentModDate = LocalToUTC(dataPtr->hfsFolder.modifyDate);
776: nodeData->cnd_backupDate = LocalToUTC(dataPtr->hfsFolder.backupDate);
777: nodeData->cnd_valence = dataPtr->hfsFolder.valence;
778:
779: BlockMoveData(&dataPtr->hfsFolder.userInfo, &nodeData->cnd_finderInfo, 32);
780: } else {
781: UInt32 i;
782:
783: nodeData->cnd_type = kCatalogFileNode;
784: nodeData->cnd_flags = dataPtr->hfsFile.flags;
785: nodeData->cnd_nodeID = dataPtr->hfsFile.fileID;
786: nodeData->cnd_createDate = LocalToUTC(dataPtr->hfsFile.createDate);
787: nodeData->cnd_contentModDate = LocalToUTC(dataPtr->hfsFile.modifyDate);
788: nodeData->cnd_backupDate = LocalToUTC(dataPtr->hfsFile.backupDate);
789: nodeData->cnd_linkCount = 0;
790:
791: BlockMoveData(&dataPtr->hfsFile.userInfo, &nodeData->cnd_finderInfo, 16);
792: BlockMoveData(&dataPtr->hfsFile.finderInfo, (void*)((UInt32)&nodeData->cnd_finderInfo + 16), 16);
793:
794: nodeData->cnd_datafork.logicalSize = dataPtr->hfsFile.dataLogicalSize;
795: nodeData->cnd_datafork.totalBlocks =
796: dataPtr->hfsFile.dataPhysicalSize / volume->blockSize;
797:
798: nodeData->cnd_rsrcfork.logicalSize = dataPtr->hfsFile.rsrcLogicalSize;
799: nodeData->cnd_rsrcfork.totalBlocks =
800: dataPtr->hfsFile.rsrcPhysicalSize / volume->blockSize;
801:
802: for (i = 0; i < kHFSExtentDensity; ++i) {
803: nodeData->cnd_datafork.extents[i].startBlock =
804: (UInt32) (dataPtr->hfsFile.dataExtents[i].startBlock);
805:
806: nodeData->cnd_datafork.extents[i].blockCount =
807: (UInt32) (dataPtr->hfsFile.dataExtents[i].blockCount);
808:
809: nodeData->cnd_rsrcfork.extents[i].startBlock =
810: (UInt32) (dataPtr->hfsFile.rsrcExtents[i].startBlock);
811:
812: nodeData->cnd_rsrcfork.extents[i].blockCount =
813: (UInt32) (dataPtr->hfsFile.rsrcExtents[i].blockCount);
814: }
815: for (i = kHFSExtentDensity; i < kHFSPlusExtentDensity; ++i) {
816: nodeData->cnd_datafork.extents[i].startBlock = 0;
817: nodeData->cnd_datafork.extents[i].blockCount = 0;
818: nodeData->cnd_rsrcfork.extents[i].startBlock = 0;
819: nodeData->cnd_rsrcfork.extents[i].blockCount = 0;
820: }
821: }
822: }
823:
824:
825: //_______________________________________________________________________
826:
827: void
828: CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus)
829: {
830: UInt32 length;
831:
832: if ( srcName == NULL )
833: {
834: if ( dstName != NULL )
835: dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
836: return;
837: }
838:
839: if (isHFSPLus)
840: length = sizeof(UniChar) * (srcName->ustr.length + 1);
841: else
842: length = sizeof(UInt8) + srcName->pstr[0];
843:
844: if ( length > 1 )
845: BlockMoveData(srcName, dstName, length);
846: else
847: dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
848: }
849:
850: //_______________________________________________________________________
851:
852: UInt32
853: CatalogNameLength(const CatalogName *name, Boolean isHFSPlus)
854: {
855: if (isHFSPlus)
856: return name->ustr.length;
857: else
858: return name->pstr[0];
859: }
860:
861:
862:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.