]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfscommon/Catalog/CatalogUtilities.c
xnu-344.23.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 *
de355530
A
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.
1c79356b 11 *
de355530
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
de355530
A
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.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
1c79356b
A
22#include <sys/param.h>
23#include <sys/utfconv.h>
0b4e3aa0 24#include <sys/stat.h>
1c79356b
A
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
1c79356b
A
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
41OSErr
42LocateCatalogNode(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
86OSErr
87LocateCatalogNodeByKey(const ExtendedVCB *volume, UInt32 hint, CatalogKey *keyPtr,
88 CatalogRecord *dataPtr, UInt32 *newHint)
89{
90 OSErr result;
9bccf70c 91 CatalogName *nodeName = NULL;
1c79356b
A
92 HFSCatalogNodeID threadParentID;
93 UInt16 tempSize;
9bccf70c
A
94 FSBufferDescriptor btRecord;
95 BTreeIterator searchIterator = {0};
96 FCB *fcb;
97
98 fcb = GetFileControlBlock(volume->catalogRefNum);
1c79356b 99
9bccf70c
A
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 }
1c79356b 116
1c79356b
A
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
1c79356b
A
148
149//*******************************************************************************
150// Routine: LocateCatalogRecord
151//
152// Function: Locates the catalog record associated with folderID and name
153//
154//*******************************************************************************
155
156OSErr
157LocateCatalogRecord(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
1c79356b
A
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
185void
186BuildCatalogKey(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
1c79356b
A
213OSErr
214BuildCatalogKeyUTF8(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
0b4e3aa0
A
237 if (textEncoding && (*textEncoding != kTextEncodingMacUnicode))
238 *textEncoding = hfs_pickencoding(key->hfsPlus.nodeName.unicode,
239 key->hfsPlus.nodeName.length);
1c79356b
A
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
1c79356b
A
272//*******************************************************************************
273// Routine: FlushCatalog
274//
275// Function: Flushes the catalog for a specified volume.
276//
277//*******************************************************************************
278
279OSErr
280FlushCatalog(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
9bccf70c 292 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ )
1c79356b
A
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
9bccf70c 299 // result = FlushVolumeControlBlock(volume);
1c79356b
A
300 }
301 }
302
303 return result;
304}
305
306
307