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