]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/CatalogUtilities.c
xnu-2422.115.4.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Catalog / CatalogUtilities.c
1 /*
2 * Copyright (c) 2000-2002, 2004-2005 Apple Computer, 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 "../headers/FileMgrInternal.h"
36 #include "../headers/BTreesInternal.h"
37 #include "../headers/CatalogPrivate.h"
38 #include "../headers/HFSUnicodeWrappers.h"
39 #include "../headers/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 MALLOC (searchIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
62 if (searchIterator == NULL) {
63 return memFullErr; // translates to ENOMEM
64 }
65
66 bzero(searchIterator, sizeof(*searchIterator));
67
68 fcb = GetFileControlBlock(volume->catalogRefNum);
69
70 btRecord.bufferAddress = dataPtr;
71 btRecord.itemCount = 1;
72 btRecord.itemSize = sizeof(CatalogRecord);
73
74 searchIterator->hint.nodeNum = hint;
75
76 bcopy(keyPtr, &searchIterator->key, sizeof(CatalogKey));
77
78 result = BTSearchRecord( fcb, searchIterator, &btRecord, &tempSize, searchIterator );
79
80 if (result == noErr)
81 {
82 *newHint = searchIterator->hint.nodeNum;
83
84 BlockMoveData(&searchIterator->key, keyPtr, sizeof(CatalogKey));
85 }
86
87 if (result == btNotFound) {
88 result = cmNotFound;
89 }
90
91 if (result) {
92 FREE(searchIterator, M_TEMP);
93 return result;
94 }
95
96 // if we got a thread record, then go look up real record
97 switch ( dataPtr->recordType )
98 {
99
100 #if CONFIG_HFS_STD
101 case kHFSFileThreadRecord:
102 case kHFSFolderThreadRecord:
103 threadParentID = dataPtr->hfsThread.parentID;
104 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
105 break;
106 #endif
107
108 case kHFSPlusFileThreadRecord:
109 case kHFSPlusFolderThreadRecord:
110 threadParentID = dataPtr->hfsPlusThread.parentID;
111 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
112 break;
113
114 default:
115 threadParentID = 0;
116 break;
117 }
118
119 if ( threadParentID ) // found a thread
120 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
121
122 FREE (searchIterator, M_TEMP);
123 return result;
124 }
125
126
127
128 //*******************************************************************************
129 // Routine: LocateCatalogRecord
130 //
131 // Function: Locates the catalog record associated with folderID and name
132 //
133 //*******************************************************************************
134
135 OSErr
136 LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
137 __unused u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint)
138 {
139 OSErr result;
140 uint16_t tempSize;
141 FSBufferDescriptor btRecord;
142 struct BTreeIterator *searchIterator = NULL;
143 FCB *fcb;
144 BTreeControlBlock *btcb;
145
146 MALLOC (searchIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
147 if (searchIterator == NULL) {
148 return memFullErr; // translates to ENOMEM
149 }
150
151 bzero(searchIterator, sizeof(*searchIterator));
152
153
154 fcb = GetFileControlBlock(volume->catalogRefNum);
155 btcb = (BTreeControlBlock *)fcb->fcbBTCBPtr;
156
157 btRecord.bufferAddress = dataPtr;
158 btRecord.itemCount = 1;
159 btRecord.itemSize = sizeof(CatalogRecord);
160
161 BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), (CatalogKey *)&searchIterator->key);
162
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));
167 }
168
169 FREE (searchIterator, M_TEMP);
170 return (result == btNotFound ? cmNotFound : result);
171 }
172
173
174
175 /*
176 * Routine: BuildCatalogKey
177 *
178 * Function: Constructs a catalog key record (ckr) given the parent
179 * folder ID and CName. Works for both classic and extended
180 * HFS volumes.
181 *
182 */
183
184 void
185 BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
186 {
187 if ( isHFSPlus )
188 {
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
192 if ( cName != NULL )
193 {
194 CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
195 key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
196 }
197 }
198 #if CONFIG_HFS_STD
199 else
200 {
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
205 if ( cName != NULL )
206 {
207 UpdateCatalogName(cName->pstr, key->hfs.nodeName);
208 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
209 }
210 }
211 #endif
212
213 }
214
215 OSErr
216 BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const unsigned char *name, u_int32_t nameLength,
217 CatalogKey *key, u_int32_t *textEncoding)
218 {
219 OSErr err = 0;
220
221 if ( name == NULL)
222 nameLength = 0;
223 else if (nameLength == kUndefinedStrLen)
224 nameLength = strlen((const char *)name);
225
226 if ( volume->vcbSigWord == kHFSPlusSigWord ) {
227 size_t unicodeBytes = 0;
228
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;
237 }
238
239 if (textEncoding && (*textEncoding != kTextEncodingMacUnicode))
240 *textEncoding = hfs_pickencoding(key->hfsPlus.nodeName.unicode,
241 key->hfsPlus.nodeName.length);
242 }
243 #if CONFIG_HFS_STD
244 else {
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]);
251 /*
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).
255 */
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
259 }
260 if (textEncoding)
261 *textEncoding = 0;
262 }
263 #endif
264
265 if (err) {
266 if (err == ENAMETOOLONG)
267 err = bdNamErr; /* name is too long */
268 else
269 err = paramErr; /* name has invalid characters */
270 }
271
272 return err;
273 }
274
275
276 //*******************************************************************************
277 // Routine: FlushCatalog
278 //
279 // Function: Flushes the catalog for a specified volume.
280 //
281 //*******************************************************************************
282
283 OSErr
284 FlushCatalog(ExtendedVCB *volume)
285 {
286 FCB * fcb;
287 OSErr result;
288 struct hfsmount *hfsmp = VCBTOHFS (volume);
289
290 fcb = GetFileControlBlock(volume->catalogRefNum);
291 result = BTFlushPath(fcb);
292
293 if (result == noErr)
294 {
295 //--- check if catalog's fcb is dirty...
296
297 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
298 {
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);
303
304 // result = FlushVolumeControlBlock(volume);
305 }
306 }
307
308 return result;
309 }
310
311
312 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
313 // Routine: UpdateCatalogName
314 //
315 // Function: Updates a CName.
316 //
317 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
318
319 void
320 UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
321 {
322 Size length = srcName[0];
323
324 if (length > CMMaxCName)
325 length = CMMaxCName; // truncate to max
326
327 destName[0] = length; // set length byte
328
329 BlockMoveData(&srcName[1], &destName[1], length);
330 }
331
332 //_______________________________________________________________________
333
334 void
335 CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPlus)
336 {
337 u_int32_t length = 0;
338
339 if ( srcName == NULL )
340 {
341 if ( dstName != NULL )
342 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
343 return;
344 }
345
346 if (isHFSPlus) {
347 length = sizeof(UniChar) * (srcName->ustr.length + 1);
348 }
349 #if CONFIG_HFS_STD
350 else {
351 length = sizeof(u_int8_t) + srcName->pstr[0];
352 }
353 #endif
354
355 if ( length > 1 )
356 BlockMoveData(srcName, dstName, length);
357 else
358 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
359 }
360