1/* 2 * Copyright (c) 2000-2003, 2005, 2007-2008 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 "SRuntime.h" 25#include "Scavenger.h" 26#include "../cache.h" 27 28 29 30extern Cache_t fscache; 31 32 33static OSStatus ReadFragmentedBlock (SFCB *file, UInt32 blockNum, BlockDescriptor *block); 34static OSStatus WriteFragmentedBlock( SFCB *file, 35 BlockDescriptor *block, 36 int age, 37 uint32_t writeOptions ); 38static OSStatus ReleaseFragmentedBlock (SFCB *file, BlockDescriptor *block, int age); 39 40 41void 42InitBlockCache(SVCB *volume) 43{ 44 volume->vcbBlockCache = (void *) &fscache; 45} 46 47 48/* 49 * kGetBlock 50 * kForceReadBlock 51 * kGetEmptyBlock 52 * kSkipEndianSwap 53 */ 54OSStatus 55GetVolumeBlock (SVCB *volume, UInt64 blockNum, GetBlockOptions options, BlockDescriptor *block) 56{ 57 UInt32 blockSize; 58 SInt64 offset; 59 UInt16 signature; 60 OSStatus result; 61 Buf_t * buffer; 62 Cache_t * cache; 63 64 buffer = NULL; 65 cache = (Cache_t *) volume->vcbBlockCache; 66 blockSize = 512; 67 68 offset = (SInt64) ((UInt64) blockNum) << kSectorShift; 69 70 result = CacheRead (cache, offset, blockSize, &buffer); 71 72 if (result == 0) { 73 block->blockHeader = buffer; 74 block->buffer = buffer->Buffer; 75 block->blockNum = blockNum; 76 block->blockSize = blockSize; 77 block->blockReadFromDisk = 0; 78 block->fragmented = 0; 79 } else { 80 block->blockHeader = NULL; 81 block->buffer = NULL; 82 } 83 84 if (!(options & kSkipEndianSwap) && (result == 0)) { 85 HFSMasterDirectoryBlock *mdb; 86 87 mdb = (HFSMasterDirectoryBlock *)block->buffer; 88 signature = SWAP_BE16(mdb->drSigWord); 89 if (signature == kHFSPlusSigWord || signature == kHFSXSigWord) 90 SWAP_HFSPLUSVH(block->buffer); 91 else if (signature == kHFSSigWord) 92 SWAP_HFSMDB(block->buffer); 93 } 94 return (result); 95} 96 97 98/* 99 * kReleaseBlock 100 * kForceWriteBlock 101 * kMarkBlockDirty 102 * kTrashBlock 103 * kSkipEndianSwap 104 */ 105OSStatus 106ReleaseVolumeBlock (SVCB *volume, BlockDescriptor *block, ReleaseBlockOptions options) 107{ 108 OSStatus result = 0; 109 Cache_t * cache; 110 Buf_t * buffer; 111 int age; 112 UInt16 signature; 113 114 cache = (Cache_t *) volume->vcbBlockCache; 115 buffer = (Buf_t *) block->blockHeader; 116 age = ((options & kTrashBlock) != 0); 117 118 /* 119 * Always leave the blocks in the cache in big endian 120 */ 121 if (!(options & kSkipEndianSwap)) { 122 signature = ((HFSMasterDirectoryBlock *)block->buffer)->drSigWord; 123 if (signature == kHFSPlusSigWord || signature == kHFSXSigWord) 124 SWAP_HFSPLUSVH(block->buffer); 125 else if (signature == kHFSSigWord) 126 SWAP_HFSMDB(block->buffer); 127 } 128 129 if (options & (kMarkBlockDirty | kForceWriteBlock)) { 130 result = CacheWrite(cache, buffer, age, 0); 131 } else { /* not dirty */ 132 result = CacheRelease (cache, buffer, age); 133 } 134 return (result); 135} 136 137 138/* 139 * kGetBlock 140 * kForceReadBlock 141 * kGetEmptyBlock 142 */ 143OSStatus 144GetFileBlock (SFCB *file, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block) 145{ 146 UInt64 diskBlock; 147 UInt32 contiguousBytes; 148 SInt64 offset; 149 150 OSStatus result; 151 Buf_t * buffer; 152 Cache_t * cache; 153 154 buffer = NULL; 155 block->buffer = NULL; 156 block->blockHeader = NULL; 157 cache = (Cache_t *)file->fcbVolume->vcbBlockCache; 158 159 /* Map file block to volume block */ 160 result = MapFileBlockC(file->fcbVolume, file, file->fcbBlockSize, 161 (((UInt64)blockNum * (UInt64)file->fcbBlockSize) >> kSectorShift), 162 &diskBlock, &contiguousBytes); 163 if (result) return (result); 164 165 if (contiguousBytes < file->fcbBlockSize) 166 return ( ReadFragmentedBlock(file, blockNum, block) ); 167 168 offset = (SInt64) ((UInt64) diskBlock) << kSectorShift; 169 170 result = CacheRead (cache, offset, file->fcbBlockSize, &buffer); 171 if (result) return (result); 172 173 block->blockHeader = buffer; 174 block->buffer = buffer->Buffer; 175 block->blockNum = blockNum; 176 block->blockSize = file->fcbBlockSize; 177 block->blockReadFromDisk = 0; 178 block->fragmented = 0; 179 180 return (noErr); 181} 182 183 184/* 185 * kReleaseBlock 186 * kForceWriteBlock 187 * kMarkBlockDirty 188 * kTrashBlock 189 */ 190OSStatus 191ReleaseFileBlock (SFCB *file, BlockDescriptor *block, ReleaseBlockOptions options) 192{ 193 OSStatus result = 0; 194 Cache_t * cache; 195 Buf_t * buffer; 196 int age; 197 uint32_t writeOptions = 0; 198 199 cache = (Cache_t *)file->fcbVolume->vcbBlockCache; 200 buffer = (Buf_t *) block->blockHeader; 201 age = ((options & kTrashBlock) != 0); 202 203 if ( (options & kForceWriteBlock) == 0 ) 204 /* only write if we're forced to */ 205 writeOptions |= kLazyWrite; 206 207 if (options & (kMarkBlockDirty | kForceWriteBlock)) { 208 if (block->fragmented) 209 result = WriteFragmentedBlock(file, block, age, writeOptions); 210 else 211 result = CacheWrite(cache, buffer, age, writeOptions); 212 } else { /* not dirty */ 213 214 if (block->fragmented) 215 result = ReleaseFragmentedBlock(file, block, age); 216 else 217 result = CacheRelease (cache, buffer, age); 218 } 219 return (result); 220} 221 222 223/* 224 * 225 */ 226OSStatus 227SetFileBlockSize (SFCB *file, ByteCount blockSize) 228{ 229 file->fcbBlockSize = blockSize; 230 231 return (0); 232} 233 234 235/* 236 * Read a block that is fragmented across 2 or more allocation blocks 237 * 238 * - a block descriptor buffer is allocated here 239 * - the blockHeader field holds a list of Buf_t buffers. 240 * - the fragmented flag is set 241 */ 242static OSStatus 243ReadFragmentedBlock (SFCB *file, UInt32 blockNum, BlockDescriptor *block) 244{ 245 UInt64 sector; 246 UInt32 fragSize, blockSize; 247 UInt64 fileOffset; 248 SInt64 diskOffset; 249 SVCB * volume; 250 int i, maxFrags; 251 OSStatus result; 252 Buf_t ** bufs; /* list of Buf_t pointers */ 253 Cache_t * cache; 254 char * buffer; 255 256 volume = file->fcbVolume; 257 cache = (Cache_t *)volume->vcbBlockCache; 258 259 blockSize = file->fcbBlockSize; 260 maxFrags = blockSize / volume->vcbBlockSize; 261 fileOffset = (UInt64)blockNum * (UInt64)blockSize; 262 263 buffer = (char *) AllocateMemory(blockSize); 264 bufs = (Buf_t **) AllocateClearMemory(maxFrags * sizeof(Buf_t *)); 265 if (buffer == NULL || bufs == NULL) { 266 result = memFullErr; 267 return (result); 268 } 269 270 block->buffer = buffer; 271 block->blockHeader = bufs; 272 block->blockNum = blockNum; 273 block->blockSize = blockSize; 274 block->blockReadFromDisk = false; 275 block->fragmented = true; 276 277 for (i = 0; (i < maxFrags) && (blockSize > 0); ++i) { 278 result = MapFileBlockC (volume, file, blockSize, 279 fileOffset >> kSectorShift, 280 §or, &fragSize); 281 if (result) goto ErrorExit; 282 283 diskOffset = (SInt64) (sector) << kSectorShift; 284 result = CacheRead (cache, diskOffset, fragSize, &bufs[i]); 285 if (result) goto ErrorExit; 286 287 if (bufs[i]->Length != fragSize) { 288 plog("ReadFragmentedBlock: cache failure (Length != fragSize)\n"); 289 result = -1; 290 goto ErrorExit; 291 } 292 293 CopyMemory(bufs[i]->Buffer, buffer, fragSize); 294 buffer += fragSize; 295 fileOffset += fragSize; 296 blockSize -= fragSize; 297 } 298 299 return (noErr); 300 301ErrorExit: 302 i = 0; 303 while (bufs[i] != NULL) { 304 (void) CacheRelease (cache, bufs[i], true); 305 ++i; 306 } 307 308 DisposeMemory(block->buffer); 309 DisposeMemory(block->blockHeader); 310 311 block->blockHeader = NULL; 312 block->buffer = NULL; 313 314 return (result); 315} 316 317 318/* 319 * Write a block that is fragmented across 2 or more allocation blocks 320 * 321 */ 322static OSStatus 323WriteFragmentedBlock( SFCB *file, BlockDescriptor *block, int age, uint32_t writeOptions ) 324{ 325 Cache_t * cache; 326 Buf_t ** bufs; /* list of Buf_t pointers */ 327 char * buffer; 328 char * bufEnd; 329 UInt32 fragSize; 330 OSStatus result; 331 int i = 0; 332 333 result = 0; 334 cache = (Cache_t *) file->fcbVolume->vcbBlockCache; 335 bufs = (Buf_t **) block->blockHeader; 336 buffer = (char *) block->buffer; 337 bufEnd = buffer + file->fcbBlockSize; 338 339 if (bufs == NULL) { 340 plog("WriteFragmentedBlock: NULL bufs list!\n"); 341 return (-1); 342 } 343 344 while ((bufs[i] != NULL) && (buffer < bufEnd)) { 345 fragSize = bufs[i]->Length; 346 347 /* copy data for this fragment */ 348 CopyMemory(buffer, bufs[i]->Buffer, fragSize); 349 350 /* write it back to cache */ 351 result = CacheWrite(cache, bufs[i], age, writeOptions); 352 if (result) break; 353 354 buffer += fragSize; 355 ++i; 356 } 357 358 DisposeMemory(block->buffer); 359 DisposeMemory(block->blockHeader); 360 361 block->buffer = NULL; 362 block->blockHeader = NULL; 363 block->fragmented = false; 364 365 return (result); 366} 367 368 369/* 370 * Release a block that is fragmented across 2 or more allocation blocks 371 * 372 */ 373static OSStatus 374ReleaseFragmentedBlock (SFCB *file, BlockDescriptor *block, int age) 375{ 376 Cache_t * cache; 377 Buf_t ** bufs; /* list of Buf_t pointers */ 378 char *buffer; 379 char *bufEnd; 380 UInt32 fragSize; 381 int i = 0; 382 383 cache = (Cache_t *)file->fcbVolume->vcbBlockCache; 384 bufs = (Buf_t **) block->blockHeader; 385 386 if (bufs == NULL) { 387 plog("ReleaseFragmentedBlock: NULL buf list!\n"); 388 return (-1); 389 } 390 391 buffer = (char*)block->buffer; 392 bufEnd = buffer + file->fcbBlockSize; 393 394 while (bufs[i] != NULL && (buffer < bufEnd)) { 395 fragSize = bufs[i]->Length; 396 buffer += fragSize; 397 (void) CacheRelease (cache, bufs[i], true); 398 ++i; 399 } 400 401 DisposeMemory(block->buffer); 402 DisposeMemory(block->blockHeader); 403 404 block->buffer = NULL; 405 block->blockHeader = NULL; 406 block->fragmented = false; 407 408 return (noErr); 409} 410 411