]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/CatalogUtilities.c
3538b8ce13e015ae20ad19d58d2f5f42dd587f38
[apple/xnu.git] / bsd / hfs / hfscommon / Catalog / CatalogUtilities.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 #include <sys/param.h>
31 #include <sys/utfconv.h>
32 #include <sys/stat.h>
33
34 #include "../headers/FileMgrInternal.h"
35 #include "../headers/BTreesInternal.h"
36 #include "../headers/CatalogPrivate.h"
37 #include "../headers/HFSUnicodeWrappers.h"
38 #include <string.h>
39
40
41 //*******************************************************************************
42 // Routine: LocateCatalogNode
43 //
44 // Function: Locates the catalog record for an existing folder or file
45 // CNode and returns pointers to the key and data records.
46 //
47 //*******************************************************************************
48
49 OSErr
50 LocateCatalogNode(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
51 UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
52 {
53 OSErr result;
54 CatalogName *nodeName = NULL; /* To ward off uninitialized use warnings from compiler */
55 HFSCatalogNodeID threadParentID;
56
57
58 result = LocateCatalogRecord(volume, folderID, name, hint, keyPtr, dataPtr, newHint);
59 ReturnIfError(result);
60
61 // if we got a thread record, then go look up real record
62 switch ( dataPtr->recordType )
63 {
64 case kHFSFileThreadRecord:
65 case kHFSFolderThreadRecord:
66 threadParentID = dataPtr->hfsThread.parentID;
67 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
68 break;
69
70 case kHFSPlusFileThreadRecord:
71 case kHFSPlusFolderThreadRecord:
72 threadParentID = dataPtr->hfsPlusThread.parentID;
73 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
74 break;
75
76 default:
77 threadParentID = 0;
78 break;
79 }
80
81 if ( threadParentID ) // found a thread
82 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
83
84 return result;
85 }
86
87 //
88 // Routine: LocateCatalogNodeByKey
89 //
90 // Function: Locates the catalog record for an existing folder or file
91 // CNode and returns the key and data records.
92 //
93
94 OSErr
95 LocateCatalogNodeByKey(const ExtendedVCB *volume, UInt32 hint, CatalogKey *keyPtr,
96 CatalogRecord *dataPtr, UInt32 *newHint)
97 {
98 OSErr result;
99 CatalogName *nodeName = NULL;
100 HFSCatalogNodeID threadParentID;
101 UInt16 tempSize;
102 FSBufferDescriptor btRecord;
103 BTreeIterator searchIterator = {0};
104 FCB *fcb;
105
106 fcb = GetFileControlBlock(volume->catalogRefNum);
107
108 btRecord.bufferAddress = dataPtr;
109 btRecord.itemCount = 1;
110 btRecord.itemSize = sizeof(CatalogRecord);
111
112 searchIterator.hint.nodeNum = hint;
113
114 bcopy(keyPtr, &searchIterator.key, sizeof(CatalogKey));
115
116 result = BTSearchRecord( fcb, &searchIterator, &btRecord, &tempSize, &searchIterator );
117
118 if (result == noErr)
119 {
120 *newHint = searchIterator.hint.nodeNum;
121
122 BlockMoveData(&searchIterator.key, keyPtr, sizeof(CatalogKey));
123 }
124
125 if (result == btNotFound)
126 result = cmNotFound;
127 ReturnIfError(result);
128
129 // if we got a thread record, then go look up real record
130 switch ( dataPtr->recordType )
131 {
132 case kHFSFileThreadRecord:
133 case kHFSFolderThreadRecord:
134 threadParentID = dataPtr->hfsThread.parentID;
135 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
136 break;
137
138 case kHFSPlusFileThreadRecord:
139 case kHFSPlusFolderThreadRecord:
140 threadParentID = dataPtr->hfsPlusThread.parentID;
141 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
142 break;
143
144 default:
145 threadParentID = 0;
146 break;
147 }
148
149 if ( threadParentID ) // found a thread
150 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
151
152 return result;
153 }
154
155
156
157 //*******************************************************************************
158 // Routine: LocateCatalogRecord
159 //
160 // Function: Locates the catalog record associated with folderID and name
161 //
162 //*******************************************************************************
163
164 OSErr
165 LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
166 UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
167 {
168 OSErr result;
169 CatalogKey tempKey; // 518 bytes
170 UInt16 tempSize;
171
172 BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), &tempKey);
173
174 if ( name == NULL )
175 hint = kNoHint; // no CName given so clear the hint
176
177 result = SearchBTreeRecord(volume->catalogRefNum, &tempKey, hint, keyPtr, dataPtr, &tempSize, newHint);
178
179 return (result == btNotFound ? cmNotFound : result);
180 }
181
182
183
184 /*
185 * Routine: BuildCatalogKey
186 *
187 * Function: Constructs a catalog key record (ckr) given the parent
188 * folder ID and CName. Works for both classic and extended
189 * HFS volumes.
190 *
191 */
192
193 void
194 BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
195 {
196 if ( isHFSPlus )
197 {
198 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
199 key->hfsPlus.parentID = parentID; // set parent ID
200 key->hfsPlus.nodeName.length = 0; // null CName length
201 if ( cName != NULL )
202 {
203 CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
204 key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
205 }
206 }
207 else
208 {
209 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
210 key->hfs.reserved = 0; // clear unused byte
211 key->hfs.parentID = parentID; // set parent ID
212 key->hfs.nodeName[0] = 0; // null CName length
213 if ( cName != NULL )
214 {
215 UpdateCatalogName(cName->pstr, key->hfs.nodeName);
216 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
217 }
218 }
219 }
220
221 OSErr
222 BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const char *name, UInt32 nameLength,
223 CatalogKey *key, UInt32 *textEncoding)
224 {
225 OSErr err = 0;
226
227 if ( name == NULL)
228 nameLength = 0;
229 else if (nameLength == kUndefinedStrLen)
230 nameLength = strlen(name);
231
232 if ( volume->vcbSigWord == kHFSPlusSigWord ) {
233 size_t unicodeBytes = 0;
234
235 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
236 key->hfsPlus.parentID = parentID; // set parent ID
237 key->hfsPlus.nodeName.length = 0; // null CName length
238 if ( nameLength > 0 ) {
239 err = utf8_decodestr(name, nameLength, key->hfsPlus.nodeName.unicode,
240 &unicodeBytes, sizeof(key->hfsPlus.nodeName.unicode), ':', UTF_DECOMPOSED);
241 key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar);
242 key->hfsPlus.keyLength += unicodeBytes;
243 }
244
245 if (textEncoding && (*textEncoding != kTextEncodingMacUnicode))
246 *textEncoding = hfs_pickencoding(key->hfsPlus.nodeName.unicode,
247 key->hfsPlus.nodeName.length);
248 }
249 else {
250 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
251 key->hfs.reserved = 0; // clear unused byte
252 key->hfs.parentID = parentID; // set parent ID
253 key->hfs.nodeName[0] = 0; // null CName length
254 if ( nameLength > 0 ) {
255 err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
256 /*
257 * Retry with MacRoman in case that's how it was exported.
258 * When textEncoding != NULL we know that this is a create
259 * or rename call and can skip the retry (ugly but it works).
260 */
261 if (err && (textEncoding == NULL))
262 err = utf8_to_mac_roman(nameLength, name, &key->hfs.nodeName[0]);
263 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
264 }
265 if (textEncoding)
266 *textEncoding = 0;
267 }
268
269 if (err) {
270 if (err == ENAMETOOLONG)
271 err = bdNamErr; /* name is too long */
272 else
273 err = paramErr; /* name has invalid characters */
274 }
275
276 return err;
277 }
278
279
280 //*******************************************************************************
281 // Routine: FlushCatalog
282 //
283 // Function: Flushes the catalog for a specified volume.
284 //
285 //*******************************************************************************
286
287 OSErr
288 FlushCatalog(ExtendedVCB *volume)
289 {
290 FCB * fcb;
291 OSErr result;
292
293 fcb = GetFileControlBlock(volume->catalogRefNum);
294 result = BTFlushPath(fcb);
295
296 if (result == noErr)
297 {
298 //--- check if catalog's fcb is dirty...
299
300 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
301 {
302 HFS_MOUNT_LOCK(volume, TRUE);
303 volume->vcbFlags |= 0xFF00; // Mark the VCB dirty
304 volume->vcbLsMod = GetTimeUTC(); // update last modified date
305 HFS_MOUNT_UNLOCK(volume, TRUE);
306
307 // result = FlushVolumeControlBlock(volume);
308 }
309 }
310
311 return result;
312 }
313
314
315 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
316 // Routine: UpdateCatalogName
317 //
318 // Function: Updates a CName.
319 //
320 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
321
322 void
323 UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
324 {
325 Size length = srcName[0];
326
327 if (length > CMMaxCName)
328 length = CMMaxCName; // truncate to max
329
330 destName[0] = length; // set length byte
331
332 BlockMoveData(&srcName[1], &destName[1], length);
333 }
334
335 //_______________________________________________________________________
336
337 void
338 CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus)
339 {
340 UInt32 length;
341
342 if ( srcName == NULL )
343 {
344 if ( dstName != NULL )
345 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
346 return;
347 }
348
349 if (isHFSPLus)
350 length = sizeof(UniChar) * (srcName->ustr.length + 1);
351 else
352 length = sizeof(UInt8) + srcName->pstr[0];
353
354 if ( length > 1 )
355 BlockMoveData(srcName, dstName, length);
356 else
357 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
358 }
359