]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/CatalogUtilities.c
xnu-1228.5.20.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
32 #include "../headers/FileMgrInternal.h"
33 #include "../headers/BTreesInternal.h"
34 #include "../headers/CatalogPrivate.h"
35 #include "../headers/HFSUnicodeWrappers.h"
36 #include <string.h>
37
38
39 //*******************************************************************************
40 // Routine: LocateCatalogNode
41 //
42 // Function: Locates the catalog record for an existing folder or file
43 // CNode and returns pointers to the key and data records.
44 //
45 //*******************************************************************************
46
47 OSErr
48 LocateCatalogNode(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
49 u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint)
50 {
51 OSErr result;
52 CatalogName *nodeName = NULL; /* To ward off uninitialized use warnings from compiler */
53 HFSCatalogNodeID threadParentID;
54
55
56 result = LocateCatalogRecord(volume, folderID, name, hint, keyPtr, dataPtr, newHint);
57 ReturnIfError(result);
58
59 // if we got a thread record, then go look up real record
60 switch ( dataPtr->recordType )
61 {
62 case kHFSFileThreadRecord:
63 case kHFSFolderThreadRecord:
64 threadParentID = dataPtr->hfsThread.parentID;
65 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
66 break;
67
68 case kHFSPlusFileThreadRecord:
69 case kHFSPlusFolderThreadRecord:
70 threadParentID = dataPtr->hfsPlusThread.parentID;
71 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
72 break;
73
74 default:
75 threadParentID = 0;
76 break;
77 }
78
79 if ( threadParentID ) // found a thread
80 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
81
82 return result;
83 }
84
85 //
86 // Routine: LocateCatalogNodeByKey
87 //
88 // Function: Locates the catalog record for an existing folder or file
89 // CNode and returns the key and data records.
90 //
91
92 OSErr
93 LocateCatalogNodeByKey(const ExtendedVCB *volume, u_int32_t hint, CatalogKey *keyPtr,
94 CatalogRecord *dataPtr, u_int32_t *newHint)
95 {
96 OSErr result;
97 CatalogName *nodeName = NULL;
98 HFSCatalogNodeID threadParentID;
99 u_int16_t tempSize;
100 FSBufferDescriptor btRecord;
101 BTreeIterator searchIterator;
102 FCB *fcb;
103
104 bzero(&searchIterator, sizeof(searchIterator));
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 u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint)
167 {
168 OSErr result;
169 CatalogKey tempKey; // 518 bytes
170 u_int16_t 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 unsigned char *name, u_int32_t nameLength,
223 CatalogKey *key, u_int32_t *textEncoding)
224 {
225 OSErr err = 0;
226
227 if ( name == NULL)
228 nameLength = 0;
229 else if (nameLength == kUndefinedStrLen)
230 nameLength = strlen((const char *)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 MarkVCBDirty(volume); // 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 u_int32_t 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(u_int8_t) + 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