]> git.saurik.com Git - apple/hfs.git/blob - core/CatalogUtilities.c
hfs-556.41.1.tar.gz
[apple/hfs.git] / core / CatalogUtilities.c
1 /*
2 * Copyright (c) 2000-2002, 2004-2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <sys/param.h>
29 #include <sys/utfconv.h>
30 #include <sys/stat.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <libkern/libkern.h>
34
35 #include "FileMgrInternal.h"
36 #include "BTreesInternal.h"
37 #include "CatalogPrivate.h"
38 #include "HFSUnicodeWrappers.h"
39 #include "BTreesPrivate.h"
40 #include <string.h>
41
42 //
43 // Routine: LocateCatalogNodeByKey
44 //
45 // Function: Locates the catalog record for an existing folder or file
46 // CNode and returns the key and data records.
47 //
48
49 OSErr
50 LocateCatalogNodeByKey(const ExtendedVCB *volume, u_int32_t hint, CatalogKey *keyPtr,
51 CatalogRecord *dataPtr, u_int32_t *newHint)
52 {
53 OSErr result;
54 CatalogName *nodeName = NULL;
55 HFSCatalogNodeID threadParentID;
56 u_int16_t tempSize;
57 FSBufferDescriptor btRecord;
58 struct BTreeIterator *searchIterator;
59 FCB *fcb;
60
61 searchIterator = hfs_mallocz(sizeof(struct BTreeIterator));
62
63 fcb = GetFileControlBlock(volume->catalogRefNum);
64
65 btRecord.bufferAddress = dataPtr;
66 btRecord.itemCount = 1;
67 btRecord.itemSize = sizeof(CatalogRecord);
68
69 searchIterator->hint.nodeNum = hint;
70
71 bcopy(keyPtr, &searchIterator->key, sizeof(CatalogKey));
72
73 result = BTSearchRecord( fcb, searchIterator, &btRecord, &tempSize, searchIterator );
74
75 if (result == noErr)
76 {
77 *newHint = searchIterator->hint.nodeNum;
78
79 BlockMoveData(&searchIterator->key, keyPtr, sizeof(CatalogKey));
80 }
81
82 if (result == btNotFound) {
83 result = cmNotFound;
84 }
85
86 if (result) {
87 hfs_free(searchIterator, sizeof(*searchIterator));
88 return result;
89 }
90
91 // if we got a thread record, then go look up real record
92 switch ( dataPtr->recordType )
93 {
94
95 #if CONFIG_HFS_STD
96 case kHFSFileThreadRecord:
97 case kHFSFolderThreadRecord:
98 threadParentID = dataPtr->hfsThread.parentID;
99 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
100 break;
101 #endif
102
103 case kHFSPlusFileThreadRecord:
104 case kHFSPlusFolderThreadRecord:
105 threadParentID = dataPtr->hfsPlusThread.parentID;
106 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
107 break;
108
109 default:
110 threadParentID = 0;
111 break;
112 }
113
114 if ( threadParentID ) // found a thread
115 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
116
117 hfs_free(searchIterator, sizeof(*searchIterator));
118 return result;
119 }
120
121
122
123 //*******************************************************************************
124 // Routine: LocateCatalogRecord
125 //
126 // Function: Locates the catalog record associated with folderID and name
127 //
128 //*******************************************************************************
129
130 OSErr
131 LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
132 __unused u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint)
133 {
134 OSErr result;
135 uint16_t tempSize;
136 FSBufferDescriptor btRecord;
137 struct BTreeIterator *searchIterator = NULL;
138 FCB *fcb;
139 BTreeControlBlock *btcb;
140
141 searchIterator = hfs_mallocz(sizeof(struct BTreeIterator));
142
143 fcb = GetFileControlBlock(volume->catalogRefNum);
144 btcb = (BTreeControlBlock *)fcb->fcbBTCBPtr;
145
146 btRecord.bufferAddress = dataPtr;
147 btRecord.itemCount = 1;
148 btRecord.itemSize = sizeof(CatalogRecord);
149
150 BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), (CatalogKey *)&searchIterator->key);
151
152 result = BTSearchRecord(fcb, searchIterator, &btRecord, &tempSize, searchIterator);
153 if (result == noErr) {
154 *newHint = searchIterator->hint.nodeNum;
155 BlockMoveData(&searchIterator->key, keyPtr, CalcKeySize(btcb, &searchIterator->key));
156 }
157
158 hfs_free(searchIterator, sizeof(*searchIterator));
159 return (result == btNotFound ? cmNotFound : result);
160 }
161
162
163
164 /*
165 * Routine: BuildCatalogKey
166 *
167 * Function: Constructs a catalog key record (ckr) given the parent
168 * folder ID and CName. Works for both classic and extended
169 * HFS volumes.
170 *
171 */
172
173 void
174 BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
175 {
176 if ( isHFSPlus )
177 {
178 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
179 key->hfsPlus.parentID = parentID; // set parent ID
180 key->hfsPlus.nodeName.length = 0; // null CName length
181 if ( cName != NULL )
182 {
183 CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
184 key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
185 }
186 }
187 #if CONFIG_HFS_STD
188 else
189 {
190 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
191 key->hfs.reserved = 0; // clear unused byte
192 key->hfs.parentID = parentID; // set parent ID
193 key->hfs.nodeName[0] = 0; // null CName length
194 if ( cName != NULL )
195 {
196 UpdateCatalogName(cName->pstr, key->hfs.nodeName);
197 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
198 }
199 }
200 #endif
201
202 }
203
204 OSErr
205 BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const unsigned char *name, u_int32_t nameLength,
206 CatalogKey *key)
207 {
208 OSErr err = 0;
209
210 if ( name == NULL)
211 nameLength = 0;
212 else if (nameLength == kUndefinedStrLen)
213 nameLength = strlen((const char *)name);
214
215 if ( volume->vcbSigWord == kHFSPlusSigWord ) {
216 size_t unicodeBytes = 0;
217
218 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
219 key->hfsPlus.parentID = parentID; // set parent ID
220 key->hfsPlus.nodeName.length = 0; // null CName length
221 if ( nameLength > 0 ) {
222 err = utf8_decodestr(name, nameLength, key->hfsPlus.nodeName.unicode,
223 &unicodeBytes, sizeof(key->hfsPlus.nodeName.unicode), ':', UTF_DECOMPOSED);
224 key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar);
225 key->hfsPlus.keyLength += unicodeBytes;
226 }
227 }
228 #if CONFIG_HFS_STD
229 else {
230 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
231 key->hfs.reserved = 0; // clear unused byte
232 key->hfs.parentID = parentID; // set parent ID
233 key->hfs.nodeName[0] = 0; // null CName length
234 if ( nameLength > 0 ) {
235 err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
236 /*
237 * Retry with MacRoman in case that's how it was exported.
238 * When textEncoding != NULL we know that this is a create
239 * or rename call and can skip the retry (ugly but it works).
240 */
241 if (err)
242 err = utf8_to_mac_roman(nameLength, name, &key->hfs.nodeName[0]);
243 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
244 }
245 }
246 #endif
247
248 if (err) {
249 if (err == ENAMETOOLONG)
250 err = bdNamErr; /* name is too long */
251 else
252 err = paramErr; /* name has invalid characters */
253 }
254
255 return err;
256 }
257
258
259 //*******************************************************************************
260 // Routine: FlushCatalog
261 //
262 // Function: Flushes the catalog for a specified volume.
263 //
264 //*******************************************************************************
265
266 OSErr
267 FlushCatalog(ExtendedVCB *volume)
268 {
269 FCB * fcb;
270 OSErr result;
271 struct hfsmount *hfsmp = VCBTOHFS (volume);
272
273 fcb = GetFileControlBlock(volume->catalogRefNum);
274 result = BTFlushPath(fcb);
275
276 if (result == noErr)
277 {
278 //--- check if catalog's fcb is dirty...
279
280 if ( (0) /*fcb->fcbFlags & fcbModifiedMask*/ )
281 {
282 hfs_lock_mount (hfsmp);
283 MarkVCBDirty(volume); // Mark the VCB dirty
284 volume->vcbLsMod = GetTimeUTC(); // update last modified date
285 hfs_unlock_mount (hfsmp);
286
287 // result = FlushVolumeControlBlock(volume);
288 }
289 }
290
291 return result;
292 }
293
294
295 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
296 // Routine: UpdateCatalogName
297 //
298 // Function: Updates a CName.
299 //
300 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
301
302 void
303 UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
304 {
305 Size length = srcName[0];
306
307 if (length > CMMaxCName)
308 length = CMMaxCName; // truncate to max
309
310 destName[0] = length; // set length byte
311
312 BlockMoveData(&srcName[1], &destName[1], length);
313 }
314
315 //_______________________________________________________________________
316
317 void
318 CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPlus)
319 {
320 u_int32_t length = 0;
321
322 if ( srcName == NULL )
323 {
324 if ( dstName != NULL )
325 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
326 return;
327 }
328
329 if (isHFSPlus) {
330 length = sizeof(UniChar) * (srcName->ustr.length + 1);
331 }
332 #if CONFIG_HFS_STD
333 else {
334 length = sizeof(u_int8_t) + srcName->pstr[0];
335 }
336 #endif
337
338 if ( length > 1 )
339 BlockMoveData(srcName, dstName, length);
340 else
341 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
342 }
343