2 * Copyright (c) 1999-2000, 2002, 2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "Scavenger.h"
27 OSErr
FlushCatalogFile( SVCB
*vcb
)
31 err
= BTFlushPath(vcb
->vcbCatalogFile
);
34 if( ( vcb
->vcbCatalogFile
->fcbFlags
& fcbModifiedMask
) != 0 )
36 (void) MarkVCBDirty( vcb
);
37 err
= FlushVolumeControlBlock( vcb
);
44 OSErr
LocateCatalogNode(SFCB
*fcb
, BTreeIterator
*iterator
, FSBufferDescriptor
*btRecord
, UInt16
*reclen
)
48 CatalogName
* namep
= NULL
;
51 Boolean isHFSPlus
= false;
53 result
= BTSearchRecord(fcb
, iterator
, kInvalidMRUCacheKey
, btRecord
, reclen
, iterator
);
54 if (result
== btNotFound
)
56 ReturnIfError(result
);
58 recp
= (CatalogRecord
*)btRecord
->bufferAddress
;
59 keyp
= (CatalogKey
*)&iterator
->key
;
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
;
70 case kHFSPlusFileThreadRecord
:
71 case kHFSPlusFolderThreadRecord
:
72 threadpid
= recp
->hfsPlusThread
.parentID
;
73 namep
= (CatalogName
*) &recp
->hfsPlusThread
.nodeName
;
83 (void) BTInvalidateHint(iterator
);
84 BuildCatalogKey(threadpid
, namep
, isHFSPlus
, keyp
);
85 result
= BTSearchRecord(fcb
, iterator
, kInvalidMRUCacheKey
, btRecord
, reclen
, iterator
);
93 UpdateFolderCount(SVCB
*vcb
, HFSCatalogNodeID pid
, const CatalogName
*name
, SInt16 newType
,
94 UInt32 hint
, SInt16 valenceDelta
)
96 CatalogRecord tempData
; // 520 bytes
97 HFSCatalogNodeID folderID
;
100 BTreeIterator btIterator
;
101 FSBufferDescriptor btRecord
;
103 btRecord
.bufferAddress
= &tempData
;
104 btRecord
.itemCount
= 1;
105 btRecord
.itemSize
= sizeof(tempData
);
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
);
113 if (vcb
->vcbSignature
== kHFSPlusSigWord
) {
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
;
126 result
= BTReplaceRecord(vcb
->vcbCatalogFile
, &btIterator
, &btRecord
, reclen
);
127 ReturnIfError(result
);
129 if (folderID
== kHFSRootFolderID
) {
130 if (newType
== kHFSFolderRecord
|| newType
== kHFSPlusFolderRecord
)
131 vcb
->vcbNmRtDirs
+= valenceDelta
; // adjust root folder count (undefined for HFS Plus)
133 vcb
->vcbNmFls
+= valenceDelta
; // adjust root file count (used by GetVolInfo)
136 if (newType
== kHFSFolderRecord
|| newType
== kHFSPlusFolderRecord
)
137 vcb
->vcbFolderCount
+= valenceDelta
; // adjust volume folder count, \80\80 worry about overflow?
139 vcb
->vcbFileCount
+= valenceDelta
; // adjust volume file count
141 vcb
->vcbModifyDate
= GetTimeUTC(); // update last modified date
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
156 DeleteCatalogNode(SVCB
*vcb
, UInt32 pid
, const CatalogName
* name
, UInt32 hint
, Boolean for_rename
)
160 BTreeIterator btIterator
;
161 FSBufferDescriptor btRecord
;
163 HFSCatalogNodeID nodeID
;
164 HFSCatalogNodeID nodeParentID
;
168 Boolean isHFSPlus
= (vcb
->vcbSignature
== kHFSPlusSigWord
);
170 btRecord
.bufferAddress
= &rec
;
171 btRecord
.itemCount
= 1;
172 btRecord
.itemSize
= sizeof(rec
);
174 ClearMemory(&btIterator
, sizeof(btIterator
));
175 btIterator
.hint
.nodeNum
= hint
;
176 keyp
= (CatalogKey
*)&btIterator
.key
;
177 BuildCatalogKey(pid
, name
, isHFSPlus
, keyp
);
179 result
= LocateCatalogNode(vcb
->vcbCatalogFile
, &btIterator
, &btRecord
, &reclen
);
180 ReturnIfError(result
);
182 /* establish real parent cnid and cnode type */
183 nodeParentID
= isHFSPlus
? keyp
->hfsPlus
.parentID
: keyp
->hfs
.parentID
;
184 nodeType
= rec
.recordType
;
188 case kHFSFolderRecord
:
189 if ((for_rename
== false) && (rec
.hfsFolder
.valence
!= 0))
192 nodeID
= rec
.hfsFolder
.folderID
;
195 case kHFSPlusFolderRecord
:
196 if ((for_rename
== false) && (rec
.hfsPlusFolder
.valence
!= 0))
199 nodeID
= rec
.hfsPlusFolder
.folderID
;
203 if (rec
.hfsFile
.flags
& kHFSThreadExistsMask
)
204 nodeID
= rec
.hfsFile
.fileID
;
207 case kHFSPlusFileRecord
:
208 nodeID
= rec
.hfsPlusFile
.fileID
;
215 if (nodeID
== kHFSRootFolderID
)
216 return cmRootCN
; /* sorry, you can't delete the root! */
218 /* delete catalog records for CNode and thread */
219 result
= BTDeleteRecord(vcb
->vcbCatalogFile
, &btIterator
);
220 ReturnIfError(result
);
222 (void) BTInvalidateHint(&btIterator
);
225 BuildCatalogKey(nodeID
, NULL
, isHFSPlus
, keyp
);
226 (void) BTDeleteRecord(vcb
->vcbCatalogFile
, &btIterator
);
229 /* update directory and volume stats */
231 result
= UpdateFolderCount(vcb
, nodeParentID
, NULL
, nodeType
, kNoHint
, -1);
232 ReturnIfError(result
);
234 (void) FlushCatalogFile(vcb
);
236 if (((nodeType
== kHFSPlusFileRecord
) || (nodeType
== kHFSFileRecord
)) &&
237 (for_rename
== false))
238 result
= DeallocateFile(vcb
, &rec
);
245 GetCatalogNode(SVCB
*vcb
, UInt32 pid
, const CatalogName
* name
, UInt32 hint
, CatalogRecord
*data
)
248 BTreeIterator btIterator
;
249 FSBufferDescriptor btRecord
;
253 Boolean isHFSPlus
= (vcb
->vcbSignature
== kHFSPlusSigWord
);
255 btRecord
.bufferAddress
= data
;
256 btRecord
.itemCount
= 1;
257 btRecord
.itemSize
= sizeof(CatalogRecord
);
259 ClearMemory(&btIterator
, sizeof(btIterator
));
260 btIterator
.hint
.nodeNum
= hint
;
261 keyp
= (CatalogKey
*)&btIterator
.key
;
262 BuildCatalogKey(pid
, name
, isHFSPlus
, keyp
);
264 result
= LocateCatalogNode(vcb
->vcbCatalogFile
, &btIterator
, &btRecord
, &reclen
);