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 27OSErr 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 44OSErr 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 92OSErr 93UpdateFolderCount(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, �� 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 */ 155OSErr 156DeleteCatalogNode(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 244OSErr 245GetCatalogNode(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 269