2 * Copyright (c) 2000-2002, 2004-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <sys/param.h>
29 #include <sys/utfconv.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <libkern/libkern.h>
35 #include "../headers/FileMgrInternal.h"
36 #include "../headers/BTreesInternal.h"
37 #include "../headers/CatalogPrivate.h"
38 #include "../headers/HFSUnicodeWrappers.h"
39 #include "../headers/BTreesPrivate.h"
43 // Routine: LocateCatalogNodeByKey
45 // Function: Locates the catalog record for an existing folder or file
46 // CNode and returns the key and data records.
50 LocateCatalogNodeByKey(const ExtendedVCB
*volume
, u_int32_t hint
, CatalogKey
*keyPtr
,
51 CatalogRecord
*dataPtr
, u_int32_t
*newHint
)
54 CatalogName
*nodeName
= NULL
;
55 HFSCatalogNodeID threadParentID
;
57 FSBufferDescriptor btRecord
;
58 struct BTreeIterator
*searchIterator
;
61 MALLOC (searchIterator
, struct BTreeIterator
*, sizeof(struct BTreeIterator
), M_TEMP
, M_WAITOK
);
62 if (searchIterator
== NULL
) {
63 return memFullErr
; // translates to ENOMEM
66 bzero(searchIterator
, sizeof(*searchIterator
));
68 fcb
= GetFileControlBlock(volume
->catalogRefNum
);
70 btRecord
.bufferAddress
= dataPtr
;
71 btRecord
.itemCount
= 1;
72 btRecord
.itemSize
= sizeof(CatalogRecord
);
74 searchIterator
->hint
.nodeNum
= hint
;
76 bcopy(keyPtr
, &searchIterator
->key
, sizeof(CatalogKey
));
78 result
= BTSearchRecord( fcb
, searchIterator
, &btRecord
, &tempSize
, searchIterator
);
82 *newHint
= searchIterator
->hint
.nodeNum
;
84 BlockMoveData(&searchIterator
->key
, keyPtr
, sizeof(CatalogKey
));
87 if (result
== btNotFound
) {
92 FREE(searchIterator
, M_TEMP
);
96 // if we got a thread record, then go look up real record
97 switch ( dataPtr
->recordType
)
101 case kHFSFileThreadRecord
:
102 case kHFSFolderThreadRecord
:
103 threadParentID
= dataPtr
->hfsThread
.parentID
;
104 nodeName
= (CatalogName
*) &dataPtr
->hfsThread
.nodeName
;
108 case kHFSPlusFileThreadRecord
:
109 case kHFSPlusFolderThreadRecord
:
110 threadParentID
= dataPtr
->hfsPlusThread
.parentID
;
111 nodeName
= (CatalogName
*) &dataPtr
->hfsPlusThread
.nodeName
;
119 if ( threadParentID
) // found a thread
120 result
= LocateCatalogRecord(volume
, threadParentID
, nodeName
, kNoHint
, keyPtr
, dataPtr
, newHint
);
122 FREE (searchIterator
, M_TEMP
);
128 //*******************************************************************************
129 // Routine: LocateCatalogRecord
131 // Function: Locates the catalog record associated with folderID and name
133 //*******************************************************************************
136 LocateCatalogRecord(const ExtendedVCB
*volume
, HFSCatalogNodeID folderID
, const CatalogName
*name
,
137 __unused u_int32_t hint
, CatalogKey
*keyPtr
, CatalogRecord
*dataPtr
, u_int32_t
*newHint
)
141 FSBufferDescriptor btRecord
;
142 struct BTreeIterator
*searchIterator
= NULL
;
144 BTreeControlBlock
*btcb
;
146 MALLOC (searchIterator
, struct BTreeIterator
*, sizeof(struct BTreeIterator
), M_TEMP
, M_WAITOK
);
147 if (searchIterator
== NULL
) {
148 return memFullErr
; // translates to ENOMEM
151 bzero(searchIterator
, sizeof(*searchIterator
));
154 fcb
= GetFileControlBlock(volume
->catalogRefNum
);
155 btcb
= (BTreeControlBlock
*)fcb
->fcbBTCBPtr
;
157 btRecord
.bufferAddress
= dataPtr
;
158 btRecord
.itemCount
= 1;
159 btRecord
.itemSize
= sizeof(CatalogRecord
);
161 BuildCatalogKey(folderID
, name
, (volume
->vcbSigWord
== kHFSPlusSigWord
), (CatalogKey
*)&searchIterator
->key
);
163 result
= BTSearchRecord(fcb
, searchIterator
, &btRecord
, &tempSize
, searchIterator
);
164 if (result
== noErr
) {
165 *newHint
= searchIterator
->hint
.nodeNum
;
166 BlockMoveData(&searchIterator
->key
, keyPtr
, CalcKeySize(btcb
, &searchIterator
->key
));
169 FREE (searchIterator
, M_TEMP
);
170 return (result
== btNotFound
? cmNotFound
: result
);
176 * Routine: BuildCatalogKey
178 * Function: Constructs a catalog key record (ckr) given the parent
179 * folder ID and CName. Works for both classic and extended
185 BuildCatalogKey(HFSCatalogNodeID parentID
, const CatalogName
*cName
, Boolean isHFSPlus
, CatalogKey
*key
)
189 key
->hfsPlus
.keyLength
= kHFSPlusCatalogKeyMinimumLength
; // initial key length (4 + 2)
190 key
->hfsPlus
.parentID
= parentID
; // set parent ID
191 key
->hfsPlus
.nodeName
.length
= 0; // null CName length
194 CopyCatalogName(cName
, (CatalogName
*) &key
->hfsPlus
.nodeName
, isHFSPlus
);
195 key
->hfsPlus
.keyLength
+= sizeof(UniChar
) * cName
->ustr
.length
; // add CName size to key length
201 key
->hfs
.keyLength
= kHFSCatalogKeyMinimumLength
; // initial key length (1 + 4 + 1)
202 key
->hfs
.reserved
= 0; // clear unused byte
203 key
->hfs
.parentID
= parentID
; // set parent ID
204 key
->hfs
.nodeName
[0] = 0; // null CName length
207 UpdateCatalogName(cName
->pstr
, key
->hfs
.nodeName
);
208 key
->hfs
.keyLength
+= key
->hfs
.nodeName
[0]; // add CName size to key length
216 BuildCatalogKeyUTF8(ExtendedVCB
*volume
, HFSCatalogNodeID parentID
, const unsigned char *name
, u_int32_t nameLength
,
217 CatalogKey
*key
, u_int32_t
*textEncoding
)
223 else if (nameLength
== kUndefinedStrLen
)
224 nameLength
= strlen((const char *)name
);
226 if ( volume
->vcbSigWord
== kHFSPlusSigWord
) {
227 size_t unicodeBytes
= 0;
229 key
->hfsPlus
.keyLength
= kHFSPlusCatalogKeyMinimumLength
; // initial key length (4 + 2)
230 key
->hfsPlus
.parentID
= parentID
; // set parent ID
231 key
->hfsPlus
.nodeName
.length
= 0; // null CName length
232 if ( nameLength
> 0 ) {
233 err
= utf8_decodestr(name
, nameLength
, key
->hfsPlus
.nodeName
.unicode
,
234 &unicodeBytes
, sizeof(key
->hfsPlus
.nodeName
.unicode
), ':', UTF_DECOMPOSED
);
235 key
->hfsPlus
.nodeName
.length
= unicodeBytes
/ sizeof(UniChar
);
236 key
->hfsPlus
.keyLength
+= unicodeBytes
;
239 if (textEncoding
&& (*textEncoding
!= kTextEncodingMacUnicode
))
240 *textEncoding
= hfs_pickencoding(key
->hfsPlus
.nodeName
.unicode
,
241 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
266 if (err
== ENAMETOOLONG
)
267 err
= bdNamErr
; /* name is too long */
269 err
= paramErr
; /* name has invalid characters */
276 //*******************************************************************************
277 // Routine: FlushCatalog
279 // Function: Flushes the catalog for a specified volume.
281 //*******************************************************************************
284 FlushCatalog(ExtendedVCB
*volume
)
288 struct hfsmount
*hfsmp
= VCBTOHFS (volume
);
290 fcb
= GetFileControlBlock(volume
->catalogRefNum
);
291 result
= BTFlushPath(fcb
);
295 //--- check if catalog's fcb is dirty...
297 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
299 hfs_lock_mount (hfsmp
);
300 MarkVCBDirty(volume
); // Mark the VCB dirty
301 volume
->vcbLsMod
= GetTimeUTC(); // update last modified date
302 hfs_unlock_mount (hfsmp
);
304 // result = FlushVolumeControlBlock(volume);
312 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
313 // Routine: UpdateCatalogName
315 // Function: Updates a CName.
317 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
320 UpdateCatalogName(ConstStr31Param srcName
, Str31 destName
)
322 Size length
= srcName
[0];
324 if (length
> CMMaxCName
)
325 length
= CMMaxCName
; // truncate to max
327 destName
[0] = length
; // set length byte
329 BlockMoveData(&srcName
[1], &destName
[1], length
);
332 //_______________________________________________________________________
335 CopyCatalogName(const CatalogName
*srcName
, CatalogName
*dstName
, Boolean isHFSPlus
)
337 u_int32_t length
= 0;
339 if ( srcName
== NULL
)
341 if ( dstName
!= NULL
)
342 dstName
->ustr
.length
= 0; // set length byte to zero (works for both unicode and pascal)
347 length
= sizeof(UniChar
) * (srcName
->ustr
.length
+ 1);
351 length
= sizeof(u_int8_t
) + srcName
->pstr
[0];
356 BlockMoveData(srcName
, dstName
, length
);
358 dstName
->ustr
.length
= 0; // set length byte to zero (works for both unicode and pascal)