2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/param.h>
26 #include <sys/utfconv.h>
29 #include "../headers/FileMgrInternal.h"
30 #include "../headers/BTreesInternal.h"
31 #include "../headers/CatalogPrivate.h"
32 #include "../headers/HFSUnicodeWrappers.h"
36 //*******************************************************************************
37 // Routine: LocateCatalogNode
39 // Function: Locates the catalog record for an existing folder or file
40 // CNode and returns pointers to the key and data records.
42 //*******************************************************************************
45 LocateCatalogNode(const ExtendedVCB
*volume
, HFSCatalogNodeID folderID
, const CatalogName
*name
,
46 UInt32 hint
, CatalogKey
*keyPtr
, CatalogRecord
*dataPtr
, UInt32
*newHint
)
49 CatalogName
*nodeName
= NULL
; /* To ward off uninitialized use warnings from compiler */
50 HFSCatalogNodeID threadParentID
;
53 result
= LocateCatalogRecord(volume
, folderID
, name
, hint
, keyPtr
, dataPtr
, newHint
);
54 ReturnIfError(result
);
56 // if we got a thread record, then go look up real record
57 switch ( dataPtr
->recordType
)
59 case kHFSFileThreadRecord
:
60 case kHFSFolderThreadRecord
:
61 threadParentID
= dataPtr
->hfsThread
.parentID
;
62 nodeName
= (CatalogName
*) &dataPtr
->hfsThread
.nodeName
;
65 case kHFSPlusFileThreadRecord
:
66 case kHFSPlusFolderThreadRecord
:
67 threadParentID
= dataPtr
->hfsPlusThread
.parentID
;
68 nodeName
= (CatalogName
*) &dataPtr
->hfsPlusThread
.nodeName
;
76 if ( threadParentID
) // found a thread
77 result
= LocateCatalogRecord(volume
, threadParentID
, nodeName
, kNoHint
, keyPtr
, dataPtr
, newHint
);
83 // Routine: LocateCatalogNodeByKey
85 // Function: Locates the catalog record for an existing folder or file
86 // CNode and returns the key and data records.
90 LocateCatalogNodeByKey(const ExtendedVCB
*volume
, UInt32 hint
, CatalogKey
*keyPtr
,
91 CatalogRecord
*dataPtr
, UInt32
*newHint
)
94 CatalogName
*nodeName
= NULL
;
95 HFSCatalogNodeID threadParentID
;
97 FSBufferDescriptor btRecord
;
98 BTreeIterator searchIterator
= {0};
101 fcb
= GetFileControlBlock(volume
->catalogRefNum
);
103 btRecord
.bufferAddress
= dataPtr
;
104 btRecord
.itemCount
= 1;
105 btRecord
.itemSize
= sizeof(CatalogRecord
);
107 searchIterator
.hint
.nodeNum
= hint
;
109 bcopy(keyPtr
, &searchIterator
.key
, sizeof(CatalogKey
));
111 result
= BTSearchRecord( fcb
, &searchIterator
, &btRecord
, &tempSize
, &searchIterator
);
115 *newHint
= searchIterator
.hint
.nodeNum
;
117 BlockMoveData(&searchIterator
.key
, keyPtr
, sizeof(CatalogKey
));
120 if (result
== btNotFound
)
122 ReturnIfError(result
);
124 // if we got a thread record, then go look up real record
125 switch ( dataPtr
->recordType
)
127 case kHFSFileThreadRecord
:
128 case kHFSFolderThreadRecord
:
129 threadParentID
= dataPtr
->hfsThread
.parentID
;
130 nodeName
= (CatalogName
*) &dataPtr
->hfsThread
.nodeName
;
133 case kHFSPlusFileThreadRecord
:
134 case kHFSPlusFolderThreadRecord
:
135 threadParentID
= dataPtr
->hfsPlusThread
.parentID
;
136 nodeName
= (CatalogName
*) &dataPtr
->hfsPlusThread
.nodeName
;
144 if ( threadParentID
) // found a thread
145 result
= LocateCatalogRecord(volume
, threadParentID
, nodeName
, kNoHint
, keyPtr
, dataPtr
, newHint
);
152 //*******************************************************************************
153 // Routine: LocateCatalogRecord
155 // Function: Locates the catalog record associated with folderID and name
157 //*******************************************************************************
160 LocateCatalogRecord(const ExtendedVCB
*volume
, HFSCatalogNodeID folderID
, const CatalogName
*name
,
161 UInt32 hint
, CatalogKey
*keyPtr
, CatalogRecord
*dataPtr
, UInt32
*newHint
)
164 CatalogKey tempKey
; // 518 bytes
167 BuildCatalogKey(folderID
, name
, (volume
->vcbSigWord
== kHFSPlusSigWord
), &tempKey
);
170 hint
= kNoHint
; // no CName given so clear the hint
172 result
= SearchBTreeRecord(volume
->catalogRefNum
, &tempKey
, hint
, keyPtr
, dataPtr
, &tempSize
, newHint
);
174 return (result
== btNotFound
? cmNotFound
: result
);
180 * Routine: BuildCatalogKey
182 * Function: Constructs a catalog key record (ckr) given the parent
183 * folder ID and CName. Works for both classic and extended
189 BuildCatalogKey(HFSCatalogNodeID parentID
, const CatalogName
*cName
, Boolean isHFSPlus
, CatalogKey
*key
)
193 key
->hfsPlus
.keyLength
= kHFSPlusCatalogKeyMinimumLength
; // initial key length (4 + 2)
194 key
->hfsPlus
.parentID
= parentID
; // set parent ID
195 key
->hfsPlus
.nodeName
.length
= 0; // null CName length
198 CopyCatalogName(cName
, (CatalogName
*) &key
->hfsPlus
.nodeName
, isHFSPlus
);
199 key
->hfsPlus
.keyLength
+= sizeof(UniChar
) * cName
->ustr
.length
; // add CName size to key length
204 key
->hfs
.keyLength
= kHFSCatalogKeyMinimumLength
; // initial key length (1 + 4 + 1)
205 key
->hfs
.reserved
= 0; // clear unused byte
206 key
->hfs
.parentID
= parentID
; // set parent ID
207 key
->hfs
.nodeName
[0] = 0; // null CName length
210 UpdateCatalogName(cName
->pstr
, key
->hfs
.nodeName
);
211 key
->hfs
.keyLength
+= key
->hfs
.nodeName
[0]; // add CName size to key length
217 BuildCatalogKeyUTF8(ExtendedVCB
*volume
, HFSCatalogNodeID parentID
, const char *name
, UInt32 nameLength
,
218 CatalogKey
*key
, UInt32
*textEncoding
)
224 else if (nameLength
== kUndefinedStrLen
)
225 nameLength
= strlen(name
);
227 if ( volume
->vcbSigWord
== kHFSPlusSigWord
) {
228 size_t unicodeBytes
= 0;
230 key
->hfsPlus
.keyLength
= kHFSPlusCatalogKeyMinimumLength
; // initial key length (4 + 2)
231 key
->hfsPlus
.parentID
= parentID
; // set parent ID
232 key
->hfsPlus
.nodeName
.length
= 0; // null CName length
233 if ( nameLength
> 0 ) {
234 err
= utf8_decodestr(name
, nameLength
, key
->hfsPlus
.nodeName
.unicode
,
235 &unicodeBytes
, sizeof(key
->hfsPlus
.nodeName
.unicode
), ':', UTF_DECOMPOSED
);
236 key
->hfsPlus
.nodeName
.length
= unicodeBytes
/ sizeof(UniChar
);
237 key
->hfsPlus
.keyLength
+= unicodeBytes
;
240 if (textEncoding
&& (*textEncoding
!= kTextEncodingMacUnicode
))
241 *textEncoding
= hfs_pickencoding(key
->hfsPlus
.nodeName
.unicode
,
242 key
->hfsPlus
.nodeName
.length
);
245 key
->hfs
.keyLength
= kHFSCatalogKeyMinimumLength
; // initial key length (1 + 4 + 1)
246 key
->hfs
.reserved
= 0; // clear unused byte
247 key
->hfs
.parentID
= parentID
; // set parent ID
248 key
->hfs
.nodeName
[0] = 0; // null CName length
249 if ( nameLength
> 0 ) {
250 err
= utf8_to_hfs(volume
, nameLength
, name
, &key
->hfs
.nodeName
[0]);
252 * Retry with MacRoman in case that's how it was exported.
253 * When textEncoding != NULL we know that this is a create
254 * or rename call and can skip the retry (ugly but it works).
256 if (err
&& (textEncoding
== NULL
))
257 err
= utf8_to_mac_roman(nameLength
, name
, &key
->hfs
.nodeName
[0]);
258 key
->hfs
.keyLength
+= key
->hfs
.nodeName
[0]; // add CName size to key length
265 if (err
== ENAMETOOLONG
)
266 err
= bdNamErr
; /* name is too long */
268 err
= paramErr
; /* name has invalid characters */
275 //*******************************************************************************
276 // Routine: FlushCatalog
278 // Function: Flushes the catalog for a specified volume.
280 //*******************************************************************************
283 FlushCatalog(ExtendedVCB
*volume
)
288 fcb
= GetFileControlBlock(volume
->catalogRefNum
);
289 result
= BTFlushPath(fcb
);
293 //--- check if catalog's fcb is dirty...
295 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
298 volume
->vcbFlags
|= 0xFF00; // Mark the VCB dirty
299 volume
->vcbLsMod
= GetTimeUTC(); // update last modified date
302 // result = FlushVolumeControlBlock(volume);
310 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
311 // Routine: UpdateCatalogName
313 // Function: Updates a CName.
315 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
318 UpdateCatalogName(ConstStr31Param srcName
, Str31 destName
)
320 Size length
= srcName
[0];
322 if (length
> CMMaxCName
)
323 length
= CMMaxCName
; // truncate to max
325 destName
[0] = length
; // set length byte
327 BlockMoveData(&srcName
[1], &destName
[1], length
);
330 //_______________________________________________________________________
333 CopyCatalogName(const CatalogName
*srcName
, CatalogName
*dstName
, Boolean isHFSPLus
)
337 if ( srcName
== NULL
)
339 if ( dstName
!= NULL
)
340 dstName
->ustr
.length
= 0; // set length byte to zero (works for both unicode and pascal)
345 length
= sizeof(UniChar
) * (srcName
->ustr
.length
+ 1);
347 length
= sizeof(UInt8
) + srcName
->pstr
[0];
350 BlockMoveData(srcName
, dstName
, length
);
352 dstName
->ustr
.length
= 0; // set length byte to zero (works for both unicode and pascal)