]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/CatalogUtilities.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Catalog / CatalogUtilities.c
1 /*
2 * Copyright (c) 2000-2002 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 UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *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, UInt32 hint, CatalogKey *keyPtr,
94 CatalogRecord *dataPtr, UInt32 *newHint)
95 {
96 OSErr result;
97 CatalogName *nodeName = NULL;
98 HFSCatalogNodeID threadParentID;
99 UInt16 tempSize;
100 FSBufferDescriptor btRecord;
101 BTreeIterator searchIterator = {0};
102 FCB *fcb;
103
104 fcb = GetFileControlBlock(volume->catalogRefNum);
105
106 btRecord.bufferAddress = dataPtr;
107 btRecord.itemCount = 1;
108 btRecord.itemSize = sizeof(CatalogRecord);
109
110 searchIterator.hint.nodeNum = hint;
111
112 bcopy(keyPtr, &searchIterator.key, sizeof(CatalogKey));
113
114 result = BTSearchRecord( fcb, &searchIterator, &btRecord, &tempSize, &searchIterator );
115
116 if (result == noErr)
117 {
118 *newHint = searchIterator.hint.nodeNum;
119
120 BlockMoveData(&searchIterator.key, keyPtr, sizeof(CatalogKey));
121 }
122
123 if (result == btNotFound)
124 result = cmNotFound;
125 ReturnIfError(result);
126
127 // if we got a thread record, then go look up real record
128 switch ( dataPtr->recordType )
129 {
130 case kHFSFileThreadRecord:
131 case kHFSFolderThreadRecord:
132 threadParentID = dataPtr->hfsThread.parentID;
133 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
134 break;
135
136 case kHFSPlusFileThreadRecord:
137 case kHFSPlusFolderThreadRecord:
138 threadParentID = dataPtr->hfsPlusThread.parentID;
139 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
140 break;
141
142 default:
143 threadParentID = 0;
144 break;
145 }
146
147 if ( threadParentID ) // found a thread
148 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
149
150 return result;
151 }
152
153
154
155 //*******************************************************************************
156 // Routine: LocateCatalogRecord
157 //
158 // Function: Locates the catalog record associated with folderID and name
159 //
160 //*******************************************************************************
161
162 OSErr
163 LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
164 UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
165 {
166 OSErr result;
167 CatalogKey tempKey; // 518 bytes
168 UInt16 tempSize;
169
170 BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), &tempKey);
171
172 if ( name == NULL )
173 hint = kNoHint; // no CName given so clear the hint
174
175 result = SearchBTreeRecord(volume->catalogRefNum, &tempKey, hint, keyPtr, dataPtr, &tempSize, newHint);
176
177 return (result == btNotFound ? cmNotFound : result);
178 }
179
180
181
182 /*
183 * Routine: BuildCatalogKey
184 *
185 * Function: Constructs a catalog key record (ckr) given the parent
186 * folder ID and CName. Works for both classic and extended
187 * HFS volumes.
188 *
189 */
190
191 void
192 BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
193 {
194 if ( isHFSPlus )
195 {
196 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
197 key->hfsPlus.parentID = parentID; // set parent ID
198 key->hfsPlus.nodeName.length = 0; // null CName length
199 if ( cName != NULL )
200 {
201 CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
202 key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
203 }
204 }
205 else
206 {
207 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
208 key->hfs.reserved = 0; // clear unused byte
209 key->hfs.parentID = parentID; // set parent ID
210 key->hfs.nodeName[0] = 0; // null CName length
211 if ( cName != NULL )
212 {
213 UpdateCatalogName(cName->pstr, key->hfs.nodeName);
214 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
215 }
216 }
217 }
218
219 OSErr
220 BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const char *name, UInt32 nameLength,
221 CatalogKey *key, UInt32 *textEncoding)
222 {
223 OSErr err = 0;
224
225 if ( name == NULL)
226 nameLength = 0;
227 else if (nameLength == kUndefinedStrLen)
228 nameLength = strlen(name);
229
230 if ( volume->vcbSigWord == kHFSPlusSigWord ) {
231 size_t unicodeBytes = 0;
232
233 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
234 key->hfsPlus.parentID = parentID; // set parent ID
235 key->hfsPlus.nodeName.length = 0; // null CName length
236 if ( nameLength > 0 ) {
237 err = utf8_decodestr(name, nameLength, key->hfsPlus.nodeName.unicode,
238 &unicodeBytes, sizeof(key->hfsPlus.nodeName.unicode), ':', UTF_DECOMPOSED);
239 key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar);
240 key->hfsPlus.keyLength += unicodeBytes;
241 }
242
243 if (textEncoding && (*textEncoding != kTextEncodingMacUnicode))
244 *textEncoding = hfs_pickencoding(key->hfsPlus.nodeName.unicode,
245 key->hfsPlus.nodeName.length);
246 }
247 else {
248 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
249 key->hfs.reserved = 0; // clear unused byte
250 key->hfs.parentID = parentID; // set parent ID
251 key->hfs.nodeName[0] = 0; // null CName length
252 if ( nameLength > 0 ) {
253 err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
254 /*
255 * Retry with MacRoman in case that's how it was exported.
256 * When textEncoding != NULL we know that this is a create
257 * or rename call and can skip the retry (ugly but it works).
258 */
259 if (err && (textEncoding == NULL))
260 err = utf8_to_mac_roman(nameLength, name, &key->hfs.nodeName[0]);
261 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
262 }
263 if (textEncoding)
264 *textEncoding = 0;
265 }
266
267 if (err) {
268 if (err == ENAMETOOLONG)
269 err = bdNamErr; /* name is too long */
270 else
271 err = paramErr; /* name has invalid characters */
272 }
273
274 return err;
275 }
276
277
278 //*******************************************************************************
279 // Routine: FlushCatalog
280 //
281 // Function: Flushes the catalog for a specified volume.
282 //
283 //*******************************************************************************
284
285 OSErr
286 FlushCatalog(ExtendedVCB *volume)
287 {
288 FCB * fcb;
289 OSErr result;
290
291 fcb = GetFileControlBlock(volume->catalogRefNum);
292 result = BTFlushPath(fcb);
293
294 if (result == noErr)
295 {
296 //--- check if catalog's fcb is dirty...
297
298 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
299 {
300 HFS_MOUNT_LOCK(volume, TRUE);
301 volume->vcbFlags |= 0xFF00; // Mark the VCB dirty
302 volume->vcbLsMod = GetTimeUTC(); // update last modified date
303 HFS_MOUNT_UNLOCK(volume, TRUE);
304
305 // result = FlushVolumeControlBlock(volume);
306 }
307 }
308
309 return result;
310 }
311
312
313 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
314 // Routine: UpdateCatalogName
315 //
316 // Function: Updates a CName.
317 //
318 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
319
320 void
321 UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
322 {
323 Size length = srcName[0];
324
325 if (length > CMMaxCName)
326 length = CMMaxCName; // truncate to max
327
328 destName[0] = length; // set length byte
329
330 BlockMoveData(&srcName[1], &destName[1], length);
331 }
332
333 //_______________________________________________________________________
334
335 void
336 CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus)
337 {
338 UInt32 length;
339
340 if ( srcName == NULL )
341 {
342 if ( dstName != NULL )
343 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
344 return;
345 }
346
347 if (isHFSPLus)
348 length = sizeof(UniChar) * (srcName->ustr.length + 1);
349 else
350 length = sizeof(UInt8) + srcName->pstr[0];
351
352 if ( length > 1 )
353 BlockMoveData(srcName, dstName, length);
354 else
355 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
356 }
357