]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/CatalogUtilities.c
114104c6f107812000d58a193964476d2839ebc5
[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 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <libkern/libkern.h>
34
35 #include "../headers/FileMgrInternal.h"
36 #include "../headers/BTreesInternal.h"
37 #include "../headers/CatalogPrivate.h"
38 #include "../headers/HFSUnicodeWrappers.h"
39 #include "../headers/BTreesPrivate.h"
40 #include <string.h>
41
42 //
43 // Routine: LocateCatalogNodeByKey
44 //
45 // Function: Locates the catalog record for an existing folder or file
46 // CNode and returns the key and data records.
47 //
48
49 OSErr
50 LocateCatalogNodeByKey(const ExtendedVCB *volume, u_int32_t hint, CatalogKey *keyPtr,
51 CatalogRecord *dataPtr, u_int32_t *newHint)
52 {
53 OSErr result;
54 CatalogName *nodeName = NULL;
55 HFSCatalogNodeID threadParentID;
56 u_int16_t tempSize;
57 FSBufferDescriptor btRecord;
58 struct BTreeIterator *searchIterator;
59 FCB *fcb;
60
61 MALLOC (searchIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
62 if (searchIterator == NULL) {
63 return memFullErr; // translates to ENOMEM
64 }
65
66 bzero(searchIterator, sizeof(*searchIterator));
67
68 fcb = GetFileControlBlock(volume->catalogRefNum);
69
70 btRecord.bufferAddress = dataPtr;
71 btRecord.itemCount = 1;
72 btRecord.itemSize = sizeof(CatalogRecord);
73
74 searchIterator->hint.nodeNum = hint;
75
76 bcopy(keyPtr, &searchIterator->key, sizeof(CatalogKey));
77
78 result = BTSearchRecord( fcb, searchIterator, &btRecord, &tempSize, searchIterator );
79
80 if (result == noErr)
81 {
82 *newHint = searchIterator->hint.nodeNum;
83
84 BlockMoveData(&searchIterator->key, keyPtr, sizeof(CatalogKey));
85 }
86
87 if (result == btNotFound) {
88 result = cmNotFound;
89 }
90
91 if (result) {
92 FREE(searchIterator, M_TEMP);
93 return result;
94 }
95
96 // if we got a thread record, then go look up real record
97 switch ( dataPtr->recordType )
98 {
99 case kHFSFileThreadRecord:
100 case kHFSFolderThreadRecord:
101 threadParentID = dataPtr->hfsThread.parentID;
102 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
103 break;
104
105 case kHFSPlusFileThreadRecord:
106 case kHFSPlusFolderThreadRecord:
107 threadParentID = dataPtr->hfsPlusThread.parentID;
108 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
109 break;
110
111 default:
112 threadParentID = 0;
113 break;
114 }
115
116 if ( threadParentID ) // found a thread
117 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
118
119 FREE (searchIterator, M_TEMP);
120 return result;
121 }
122
123
124
125 //*******************************************************************************
126 // Routine: LocateCatalogRecord
127 //
128 // Function: Locates the catalog record associated with folderID and name
129 //
130 //*******************************************************************************
131
132 OSErr
133 LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
134 __unused u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint)
135 {
136 OSErr result;
137 uint16_t tempSize;
138 FSBufferDescriptor btRecord;
139 struct BTreeIterator *searchIterator = NULL;
140 FCB *fcb;
141 BTreeControlBlock *btcb;
142
143 MALLOC (searchIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
144 if (searchIterator == NULL) {
145 return memFullErr; // translates to ENOMEM
146 }
147
148 bzero(searchIterator, sizeof(*searchIterator));
149
150
151 fcb = GetFileControlBlock(volume->catalogRefNum);
152 btcb = (BTreeControlBlock *)fcb->fcbBTCBPtr;
153
154 btRecord.bufferAddress = dataPtr;
155 btRecord.itemCount = 1;
156 btRecord.itemSize = sizeof(CatalogRecord);
157
158 BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), (CatalogKey *)&searchIterator->key);
159
160 result = BTSearchRecord(fcb, searchIterator, &btRecord, &tempSize, searchIterator);
161 if (result == noErr) {
162 *newHint = searchIterator->hint.nodeNum;
163 BlockMoveData(&searchIterator->key, keyPtr, CalcKeySize(btcb, &searchIterator->key));
164 }
165
166 FREE (searchIterator, M_TEMP);
167 return (result == btNotFound ? cmNotFound : result);
168 }
169
170
171
172 /*
173 * Routine: BuildCatalogKey
174 *
175 * Function: Constructs a catalog key record (ckr) given the parent
176 * folder ID and CName. Works for both classic and extended
177 * HFS volumes.
178 *
179 */
180
181 void
182 BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
183 {
184 if ( isHFSPlus )
185 {
186 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
187 key->hfsPlus.parentID = parentID; // set parent ID
188 key->hfsPlus.nodeName.length = 0; // null CName length
189 if ( cName != NULL )
190 {
191 CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
192 key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
193 }
194 }
195 else
196 {
197 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
198 key->hfs.reserved = 0; // clear unused byte
199 key->hfs.parentID = parentID; // set parent ID
200 key->hfs.nodeName[0] = 0; // null CName length
201 if ( cName != NULL )
202 {
203 UpdateCatalogName(cName->pstr, key->hfs.nodeName);
204 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
205 }
206 }
207 }
208
209 OSErr
210 BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const unsigned char *name, u_int32_t nameLength,
211 CatalogKey *key, u_int32_t *textEncoding)
212 {
213 OSErr err = 0;
214
215 if ( name == NULL)
216 nameLength = 0;
217 else if (nameLength == kUndefinedStrLen)
218 nameLength = strlen((const char *)name);
219
220 if ( volume->vcbSigWord == kHFSPlusSigWord ) {
221 size_t unicodeBytes = 0;
222
223 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
224 key->hfsPlus.parentID = parentID; // set parent ID
225 key->hfsPlus.nodeName.length = 0; // null CName length
226 if ( nameLength > 0 ) {
227 err = utf8_decodestr(name, nameLength, key->hfsPlus.nodeName.unicode,
228 &unicodeBytes, sizeof(key->hfsPlus.nodeName.unicode), ':', UTF_DECOMPOSED);
229 key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar);
230 key->hfsPlus.keyLength += unicodeBytes;
231 }
232
233 if (textEncoding && (*textEncoding != kTextEncodingMacUnicode))
234 *textEncoding = hfs_pickencoding(key->hfsPlus.nodeName.unicode,
235 key->hfsPlus.nodeName.length);
236 }
237 else {
238 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
239 key->hfs.reserved = 0; // clear unused byte
240 key->hfs.parentID = parentID; // set parent ID
241 key->hfs.nodeName[0] = 0; // null CName length
242 if ( nameLength > 0 ) {
243 err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
244 /*
245 * Retry with MacRoman in case that's how it was exported.
246 * When textEncoding != NULL we know that this is a create
247 * or rename call and can skip the retry (ugly but it works).
248 */
249 if (err && (textEncoding == NULL))
250 err = utf8_to_mac_roman(nameLength, name, &key->hfs.nodeName[0]);
251 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
252 }
253 if (textEncoding)
254 *textEncoding = 0;
255 }
256
257 if (err) {
258 if (err == ENAMETOOLONG)
259 err = bdNamErr; /* name is too long */
260 else
261 err = paramErr; /* name has invalid characters */
262 }
263
264 return err;
265 }
266
267
268 //*******************************************************************************
269 // Routine: FlushCatalog
270 //
271 // Function: Flushes the catalog for a specified volume.
272 //
273 //*******************************************************************************
274
275 OSErr
276 FlushCatalog(ExtendedVCB *volume)
277 {
278 FCB * fcb;
279 OSErr result;
280
281 fcb = GetFileControlBlock(volume->catalogRefNum);
282 result = BTFlushPath(fcb);
283
284 if (result == noErr)
285 {
286 //--- check if catalog's fcb is dirty...
287
288 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
289 {
290 HFS_MOUNT_LOCK(volume, TRUE);
291 MarkVCBDirty(volume); // Mark the VCB dirty
292 volume->vcbLsMod = GetTimeUTC(); // update last modified date
293 HFS_MOUNT_UNLOCK(volume, TRUE);
294
295 // result = FlushVolumeControlBlock(volume);
296 }
297 }
298
299 return result;
300 }
301
302
303 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
304 // Routine: UpdateCatalogName
305 //
306 // Function: Updates a CName.
307 //
308 //ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
309
310 void
311 UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
312 {
313 Size length = srcName[0];
314
315 if (length > CMMaxCName)
316 length = CMMaxCName; // truncate to max
317
318 destName[0] = length; // set length byte
319
320 BlockMoveData(&srcName[1], &destName[1], length);
321 }
322
323 //_______________________________________________________________________
324
325 void
326 CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus)
327 {
328 u_int32_t length;
329
330 if ( srcName == NULL )
331 {
332 if ( dstName != NULL )
333 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
334 return;
335 }
336
337 if (isHFSPLus)
338 length = sizeof(UniChar) * (srcName->ustr.length + 1);
339 else
340 length = sizeof(u_int8_t) + srcName->pstr[0];
341
342 if ( length > 1 )
343 BlockMoveData(srcName, dstName, length);
344 else
345 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
346 }
347