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