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