]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfscommon/Catalog/CatalogUtilities.c
xnu-1228.7.58.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Catalog / CatalogUtilities.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2002, 2004-2005 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b
A
28#include <sys/param.h>
29#include <sys/utfconv.h>
0b4e3aa0 30#include <sys/stat.h>
1c79356b
A
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
1c79356b
A
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
47OSErr
48LocateCatalogNode(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
2d21ac55 49 u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint)
1c79356b
A
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
92OSErr
2d21ac55
A
93LocateCatalogNodeByKey(const ExtendedVCB *volume, u_int32_t hint, CatalogKey *keyPtr,
94 CatalogRecord *dataPtr, u_int32_t *newHint)
1c79356b
A
95{
96 OSErr result;
9bccf70c 97 CatalogName *nodeName = NULL;
1c79356b 98 HFSCatalogNodeID threadParentID;
2d21ac55 99 u_int16_t tempSize;
9bccf70c 100 FSBufferDescriptor btRecord;
2d21ac55 101 BTreeIterator searchIterator;
9bccf70c
A
102 FCB *fcb;
103
2d21ac55
A
104 bzero(&searchIterator, sizeof(searchIterator));
105
9bccf70c 106 fcb = GetFileControlBlock(volume->catalogRefNum);
1c79356b 107
9bccf70c
A
108 btRecord.bufferAddress = dataPtr;
109 btRecord.itemCount = 1;
110 btRecord.itemSize = sizeof(CatalogRecord);
111
112 searchIterator.hint.nodeNum = hint;
113
114 bcopy(keyPtr, &searchIterator.key, sizeof(CatalogKey));
115
116 result = BTSearchRecord( fcb, &searchIterator, &btRecord, &tempSize, &searchIterator );
117
118 if (result == noErr)
119 {
120 *newHint = searchIterator.hint.nodeNum;
121
122 BlockMoveData(&searchIterator.key, keyPtr, sizeof(CatalogKey));
123 }
1c79356b 124
1c79356b
A
125 if (result == btNotFound)
126 result = cmNotFound;
127 ReturnIfError(result);
128
129 // if we got a thread record, then go look up real record
130 switch ( dataPtr->recordType )
131 {
132 case kHFSFileThreadRecord:
133 case kHFSFolderThreadRecord:
134 threadParentID = dataPtr->hfsThread.parentID;
135 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
136 break;
137
138 case kHFSPlusFileThreadRecord:
139 case kHFSPlusFolderThreadRecord:
140 threadParentID = dataPtr->hfsPlusThread.parentID;
141 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;
142 break;
143
144 default:
145 threadParentID = 0;
146 break;
147 }
148
149 if ( threadParentID ) // found a thread
150 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
151
152 return result;
153}
154
155
1c79356b
A
156
157//*******************************************************************************
158// Routine: LocateCatalogRecord
159//
160// Function: Locates the catalog record associated with folderID and name
161//
162//*******************************************************************************
163
164OSErr
165LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
2d21ac55 166 u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint)
1c79356b
A
167{
168 OSErr result;
169 CatalogKey tempKey; // 518 bytes
2d21ac55 170 u_int16_t tempSize;
1c79356b
A
171
172 BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), &tempKey);
173
174 if ( name == NULL )
175 hint = kNoHint; // no CName given so clear the hint
176
177 result = SearchBTreeRecord(volume->catalogRefNum, &tempKey, hint, keyPtr, dataPtr, &tempSize, newHint);
178
179 return (result == btNotFound ? cmNotFound : result);
180}
181
182
1c79356b
A
183
184/*
185 * Routine: BuildCatalogKey
186 *
187 * Function: Constructs a catalog key record (ckr) given the parent
188 * folder ID and CName. Works for both classic and extended
189 * HFS volumes.
190 *
191 */
192
193void
194BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
195{
196 if ( isHFSPlus )
197 {
198 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
199 key->hfsPlus.parentID = parentID; // set parent ID
200 key->hfsPlus.nodeName.length = 0; // null CName length
201 if ( cName != NULL )
202 {
203 CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
204 key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
205 }
206 }
207 else
208 {
209 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
210 key->hfs.reserved = 0; // clear unused byte
211 key->hfs.parentID = parentID; // set parent ID
212 key->hfs.nodeName[0] = 0; // null CName length
213 if ( cName != NULL )
214 {
215 UpdateCatalogName(cName->pstr, key->hfs.nodeName);
216 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
217 }
218 }
219}
220
1c79356b 221OSErr
2d21ac55
A
222BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const unsigned char *name, u_int32_t nameLength,
223 CatalogKey *key, u_int32_t *textEncoding)
1c79356b
A
224{
225 OSErr err = 0;
226
227 if ( name == NULL)
228 nameLength = 0;
229 else if (nameLength == kUndefinedStrLen)
2d21ac55 230 nameLength = strlen((const char *)name);
1c79356b
A
231
232 if ( volume->vcbSigWord == kHFSPlusSigWord ) {
233 size_t unicodeBytes = 0;
234
235 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
236 key->hfsPlus.parentID = parentID; // set parent ID
237 key->hfsPlus.nodeName.length = 0; // null CName length
238 if ( nameLength > 0 ) {
239 err = utf8_decodestr(name, nameLength, key->hfsPlus.nodeName.unicode,
240 &unicodeBytes, sizeof(key->hfsPlus.nodeName.unicode), ':', UTF_DECOMPOSED);
241 key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar);
242 key->hfsPlus.keyLength += unicodeBytes;
243 }
244
0b4e3aa0
A
245 if (textEncoding && (*textEncoding != kTextEncodingMacUnicode))
246 *textEncoding = hfs_pickencoding(key->hfsPlus.nodeName.unicode,
247 key->hfsPlus.nodeName.length);
1c79356b
A
248 }
249 else {
250 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
251 key->hfs.reserved = 0; // clear unused byte
252 key->hfs.parentID = parentID; // set parent ID
253 key->hfs.nodeName[0] = 0; // null CName length
254 if ( nameLength > 0 ) {
255 err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
256 /*
257 * Retry with MacRoman in case that's how it was exported.
258 * When textEncoding != NULL we know that this is a create
259 * or rename call and can skip the retry (ugly but it works).
260 */
261 if (err && (textEncoding == NULL))
262 err = utf8_to_mac_roman(nameLength, name, &key->hfs.nodeName[0]);
263 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
264 }
265 if (textEncoding)
266 *textEncoding = 0;
267 }
268
269 if (err) {
270 if (err == ENAMETOOLONG)
271 err = bdNamErr; /* name is too long */
272 else
273 err = paramErr; /* name has invalid characters */
274 }
275
276 return err;
277}
278
279
1c79356b
A
280//*******************************************************************************
281// Routine: FlushCatalog
282//
283// Function: Flushes the catalog for a specified volume.
284//
285//*******************************************************************************
286
287OSErr
288FlushCatalog(ExtendedVCB *volume)
289{
290 FCB * fcb;
291 OSErr result;
292
293 fcb = GetFileControlBlock(volume->catalogRefNum);
294 result = BTFlushPath(fcb);
295
296 if (result == noErr)
297 {
298 //--- check if catalog's fcb is dirty...
299
9bccf70c 300 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
1c79356b 301 {
91447636 302 HFS_MOUNT_LOCK(volume, TRUE);
2d21ac55 303 MarkVCBDirty(volume); // Mark the VCB dirty
1c79356b 304 volume->vcbLsMod = GetTimeUTC(); // update last modified date
91447636 305 HFS_MOUNT_UNLOCK(volume, TRUE);
1c79356b 306
9bccf70c 307 // result = FlushVolumeControlBlock(volume);
1c79356b
A
308 }
309 }
310
311 return result;
312}
313
314
315