]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfscommon/Catalog/CatalogUtilities.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Catalog / CatalogUtilities.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
1c79356b
A
25#include <sys/param.h>
26#include <sys/utfconv.h>
0b4e3aa0 27#include <sys/stat.h>
1c79356b
A
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
1c79356b
A
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
44OSErr
45LocateCatalogNode(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
89OSErr
90LocateCatalogNodeByKey(const ExtendedVCB *volume, UInt32 hint, CatalogKey *keyPtr,
91 CatalogRecord *dataPtr, UInt32 *newHint)
92{
93 OSErr result;
9bccf70c 94 CatalogName *nodeName = NULL;
1c79356b
A
95 HFSCatalogNodeID threadParentID;
96 UInt16 tempSize;
9bccf70c
A
97 FSBufferDescriptor btRecord;
98 BTreeIterator searchIterator = {0};
99 FCB *fcb;
100
101 fcb = GetFileControlBlock(volume->catalogRefNum);
1c79356b 102
9bccf70c
A
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 }
1c79356b 119
1c79356b
A
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
1c79356b
A
151
152//*******************************************************************************
153// Routine: LocateCatalogRecord
154//
155// Function: Locates the catalog record associated with folderID and name
156//
157//*******************************************************************************
158
159OSErr
160LocateCatalogRecord(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
1c79356b
A
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
188void
189BuildCatalogKey(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
1c79356b
A
216OSErr
217BuildCatalogKeyUTF8(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
0b4e3aa0
A
240 if (textEncoding && (*textEncoding != kTextEncodingMacUnicode))
241 *textEncoding = hfs_pickencoding(key->hfsPlus.nodeName.unicode,
242 key->hfsPlus.nodeName.length);
1c79356b
A
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
1c79356b
A
275//*******************************************************************************
276// Routine: FlushCatalog
277//
278// Function: Flushes the catalog for a specified volume.
279//
280//*******************************************************************************
281
282OSErr
283FlushCatalog(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
9bccf70c 295 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
1c79356b
A
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
9bccf70c 302 // result = FlushVolumeControlBlock(volume);
1c79356b
A
303 }
304 }
305
306 return result;
307}
308
309
310