]> git.saurik.com Git - apple/hfs.git/blob - fsck_hfs/dfalib/SCatalog.c
hfs-366.30.3.tar.gz
[apple/hfs.git] / fsck_hfs / dfalib / SCatalog.c
1 /*
2 * Copyright (c) 1999-2000, 2002, 2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "Scavenger.h"
25
26
27 OSErr FlushCatalogFile( SVCB *vcb )
28 {
29 OSErr err;
30
31 err = BTFlushPath(vcb->vcbCatalogFile);
32 if ( err == noErr )
33 {
34 if( ( vcb->vcbCatalogFile->fcbFlags & fcbModifiedMask ) != 0 )
35 {
36 (void) MarkVCBDirty( vcb );
37 err = FlushVolumeControlBlock( vcb );
38 }
39 }
40
41 return( err );
42 }
43
44 OSErr LocateCatalogNode(SFCB *fcb, BTreeIterator *iterator, FSBufferDescriptor *btRecord, UInt16 *reclen)
45 {
46 CatalogRecord * recp;
47 CatalogKey * keyp;
48 CatalogName * namep = NULL;
49 UInt32 threadpid = 0;
50 OSErr result;
51 Boolean isHFSPlus = false;
52
53 result = BTSearchRecord(fcb, iterator, kInvalidMRUCacheKey, btRecord, reclen, iterator);
54 if (result == btNotFound)
55 result = cmNotFound;
56 ReturnIfError(result);
57
58 recp = (CatalogRecord *)btRecord->bufferAddress;
59 keyp = (CatalogKey*)&iterator->key;
60
61 /* if we got a thread record, then go look up real record */
62 switch (recp->recordType) {
63 case kHFSFileThreadRecord:
64 case kHFSFolderThreadRecord:
65 threadpid = recp->hfsThread.parentID;
66 namep = (CatalogName *) &recp->hfsThread.nodeName;
67 isHFSPlus = false;
68 break;
69
70 case kHFSPlusFileThreadRecord:
71 case kHFSPlusFolderThreadRecord:
72 threadpid = recp->hfsPlusThread.parentID;
73 namep = (CatalogName *) &recp->hfsPlusThread.nodeName;
74 isHFSPlus = true;
75 break;
76
77 default:
78 threadpid = 0;
79 break;
80 }
81
82 if (threadpid) {
83 (void) BTInvalidateHint(iterator);
84 BuildCatalogKey(threadpid, namep, isHFSPlus, keyp);
85 result = BTSearchRecord(fcb, iterator, kInvalidMRUCacheKey, btRecord, reclen, iterator);
86 }
87
88 return result;
89 }
90
91
92 OSErr
93 UpdateFolderCount(SVCB *vcb, HFSCatalogNodeID pid, const CatalogName *name, SInt16 newType,
94 UInt32 hint, SInt16 valenceDelta)
95 {
96 CatalogRecord tempData; // 520 bytes
97 HFSCatalogNodeID folderID;
98 UInt16 reclen;
99 OSErr result;
100 BTreeIterator btIterator;
101 FSBufferDescriptor btRecord;
102
103 btRecord.bufferAddress = &tempData;
104 btRecord.itemCount = 1;
105 btRecord.itemSize = sizeof(tempData);
106
107 ClearMemory(&btIterator, sizeof(btIterator));
108 btIterator.hint.nodeNum = hint;
109 BuildCatalogKey(pid, name, vcb->vcbSignature == kHFSPlusSigWord, (CatalogKey*)&btIterator.key);
110 result = LocateCatalogNode(vcb->vcbCatalogFile, &btIterator, &btRecord, &reclen);
111 ReturnIfError(result);
112
113 if (vcb->vcbSignature == kHFSPlusSigWord) {
114 UInt32 timeStamp;
115
116 timeStamp = GetTimeUTC();
117 tempData.hfsPlusFolder.valence += valenceDelta; // adjust valence
118 tempData.hfsPlusFolder.contentModDate = timeStamp; // set date/time last modified
119 folderID = tempData.hfsPlusFolder.folderID;
120 } else /* kHFSSigWord */ {
121 tempData.hfsFolder.valence += valenceDelta; // adjust valence
122 tempData.hfsFolder.modifyDate = GetTimeLocal(true); // set date/time last modified
123 folderID = tempData.hfsFolder.folderID;
124 }
125
126 result = BTReplaceRecord(vcb->vcbCatalogFile, &btIterator, &btRecord, reclen);
127 ReturnIfError(result);
128
129 if (folderID == kHFSRootFolderID) {
130 if (newType == kHFSFolderRecord || newType == kHFSPlusFolderRecord)
131 vcb->vcbNmRtDirs += valenceDelta; // adjust root folder count (undefined for HFS Plus)
132 else
133 vcb->vcbNmFls += valenceDelta; // adjust root file count (used by GetVolInfo)
134 }
135
136 if (newType == kHFSFolderRecord || newType == kHFSPlusFolderRecord)
137 vcb->vcbFolderCount += valenceDelta; // adjust volume folder count, \80\80 worry about overflow?
138 else
139 vcb->vcbFileCount += valenceDelta; // adjust volume file count
140
141 vcb->vcbModifyDate = GetTimeUTC(); // update last modified date
142 MarkVCBDirty( vcb );
143
144 return result;
145 }
146
147
148 /* Delete the catalog node with given name from given parent directory.
149 * The boolean value for_rename indicates that the caller is interested
150 * in deleting this record as part of rename operation and hence when set
151 * to true, the function does not return error if the directory record
152 * being deleted has non-zero valence and does not deallocate blocks for given
153 * file.
154 */
155 OSErr
156 DeleteCatalogNode(SVCB *vcb, UInt32 pid, const CatalogName * name, UInt32 hint, Boolean for_rename)
157 {
158 CatalogKey * keyp;
159 CatalogRecord rec;
160 BTreeIterator btIterator;
161 FSBufferDescriptor btRecord;
162
163 HFSCatalogNodeID nodeID;
164 HFSCatalogNodeID nodeParentID;
165 UInt16 nodeType;
166 UInt16 reclen;
167 OSErr result;
168 Boolean isHFSPlus = (vcb->vcbSignature == kHFSPlusSigWord);
169
170 btRecord.bufferAddress = &rec;
171 btRecord.itemCount = 1;
172 btRecord.itemSize = sizeof(rec);
173
174 ClearMemory(&btIterator, sizeof(btIterator));
175 btIterator.hint.nodeNum = hint;
176 keyp = (CatalogKey*)&btIterator.key;
177 BuildCatalogKey(pid, name, isHFSPlus, keyp);
178
179 result = LocateCatalogNode(vcb->vcbCatalogFile, &btIterator, &btRecord, &reclen);
180 ReturnIfError(result);
181
182 /* establish real parent cnid and cnode type */
183 nodeParentID = isHFSPlus ? keyp->hfsPlus.parentID : keyp->hfs.parentID;
184 nodeType = rec.recordType;
185 nodeID = 0;
186
187 switch (nodeType) {
188 case kHFSFolderRecord:
189 if ((for_rename == false) && (rec.hfsFolder.valence != 0))
190 return cmNotEmpty;
191
192 nodeID = rec.hfsFolder.folderID;
193 break;
194
195 case kHFSPlusFolderRecord:
196 if ((for_rename == false) && (rec.hfsPlusFolder.valence != 0))
197 return cmNotEmpty;
198
199 nodeID = rec.hfsPlusFolder.folderID;
200 break;
201
202 case kHFSFileRecord:
203 if (rec.hfsFile.flags & kHFSThreadExistsMask)
204 nodeID = rec.hfsFile.fileID;
205 break;
206
207 case kHFSPlusFileRecord:
208 nodeID = rec.hfsPlusFile.fileID;
209 break;
210
211 default:
212 return cmNotFound;
213 }
214
215 if (nodeID == kHFSRootFolderID)
216 return cmRootCN; /* sorry, you can't delete the root! */
217
218 /* delete catalog records for CNode and thread */
219 result = BTDeleteRecord(vcb->vcbCatalogFile, &btIterator);
220 ReturnIfError(result);
221
222 (void) BTInvalidateHint(&btIterator);
223
224 if ( nodeID ) {
225 BuildCatalogKey(nodeID, NULL, isHFSPlus, keyp);
226 (void) BTDeleteRecord(vcb->vcbCatalogFile, &btIterator);
227 }
228
229 /* update directory and volume stats */
230
231 result = UpdateFolderCount(vcb, nodeParentID, NULL, nodeType, kNoHint, -1);
232 ReturnIfError(result);
233
234 (void) FlushCatalogFile(vcb);
235
236 if (((nodeType == kHFSPlusFileRecord) || (nodeType == kHFSFileRecord)) &&
237 (for_rename == false))
238 result = DeallocateFile(vcb, &rec);
239
240 return result;
241 }
242
243
244 OSErr
245 GetCatalogNode(SVCB *vcb, UInt32 pid, const CatalogName * name, UInt32 hint, CatalogRecord *data)
246 {
247 CatalogKey * keyp;
248 BTreeIterator btIterator;
249 FSBufferDescriptor btRecord;
250
251 UInt16 reclen;
252 OSErr result;
253 Boolean isHFSPlus = (vcb->vcbSignature == kHFSPlusSigWord);
254
255 btRecord.bufferAddress = data;
256 btRecord.itemCount = 1;
257 btRecord.itemSize = sizeof(CatalogRecord);
258
259 ClearMemory(&btIterator, sizeof(btIterator));
260 btIterator.hint.nodeNum = hint;
261 keyp = (CatalogKey*)&btIterator.key;
262 BuildCatalogKey(pid, name, isHFSPlus, keyp);
263
264 result = LocateCatalogNode(vcb->vcbCatalogFile, &btIterator, &btRecord, &reclen);
265
266 return result;
267 }
268