2 * Copyright (c) 2000-2003, 2005, 2007-2008 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@
25 #include "Scavenger.h"
30 extern Cache_t fscache
;
33 static OSStatus
ReadFragmentedBlock (SFCB
*file
, UInt32 blockNum
, BlockDescriptor
*block
);
34 static OSStatus
WriteFragmentedBlock( SFCB
*file
,
35 BlockDescriptor
*block
,
37 uint32_t writeOptions
);
38 static OSStatus
ReleaseFragmentedBlock (SFCB
*file
, BlockDescriptor
*block
, int age
);
42 InitBlockCache(SVCB
*volume
)
44 volume
->vcbBlockCache
= (void *) &fscache
;
55 GetVolumeBlock (SVCB
*volume
, UInt64 blockNum
, GetBlockOptions options
, BlockDescriptor
*block
)
65 cache
= (Cache_t
*) volume
->vcbBlockCache
;
68 offset
= (SInt64
) ((UInt64
) blockNum
) << kSectorShift
;
70 result
= CacheRead (cache
, offset
, blockSize
, &buffer
);
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;
80 block
->blockHeader
= NULL
;
84 if (!(options
& kSkipEndianSwap
) && (result
== 0)) {
85 HFSMasterDirectoryBlock
*mdb
;
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
);
106 ReleaseVolumeBlock (SVCB
*volume
, BlockDescriptor
*block
, ReleaseBlockOptions options
)
114 cache
= (Cache_t
*) volume
->vcbBlockCache
;
115 buffer
= (Buf_t
*) block
->blockHeader
;
116 age
= ((options
& kTrashBlock
) != 0);
119 * Always leave the blocks in the cache in big endian
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
);
129 if (options
& (kMarkBlockDirty
| kForceWriteBlock
)) {
130 result
= CacheWrite(cache
, buffer
, age
, 0);
131 } else { /* not dirty */
132 result
= CacheRelease (cache
, buffer
, age
);
144 GetFileBlock (SFCB
*file
, UInt32 blockNum
, GetBlockOptions options
, BlockDescriptor
*block
)
147 UInt32 contiguousBytes
;
155 block
->buffer
= NULL
;
156 block
->blockHeader
= NULL
;
157 cache
= (Cache_t
*)file
->fcbVolume
->vcbBlockCache
;
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
);
165 if (contiguousBytes
< file
->fcbBlockSize
)
166 return ( ReadFragmentedBlock(file
, blockNum
, block
) );
168 offset
= (SInt64
) ((UInt64
) diskBlock
) << kSectorShift
;
170 result
= CacheRead (cache
, offset
, file
->fcbBlockSize
, &buffer
);
171 if (result
) return (result
);
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;
191 ReleaseFileBlock (SFCB
*file
, BlockDescriptor
*block
, ReleaseBlockOptions options
)
197 uint32_t writeOptions
= 0;
199 cache
= (Cache_t
*)file
->fcbVolume
->vcbBlockCache
;
200 buffer
= (Buf_t
*) block
->blockHeader
;
201 age
= ((options
& kTrashBlock
) != 0);
203 if ( (options
& kForceWriteBlock
) == 0 )
204 /* only write if we're forced to */
205 writeOptions
|= kLazyWrite
;
207 if (options
& (kMarkBlockDirty
| kForceWriteBlock
)) {
208 if (block
->fragmented
)
209 result
= WriteFragmentedBlock(file
, block
, age
, writeOptions
);
211 result
= CacheWrite(cache
, buffer
, age
, writeOptions
);
212 } else { /* not dirty */
214 if (block
->fragmented
)
215 result
= ReleaseFragmentedBlock(file
, block
, age
);
217 result
= CacheRelease (cache
, buffer
, age
);
227 SetFileBlockSize (SFCB
*file
, ByteCount blockSize
)
229 file
->fcbBlockSize
= blockSize
;
236 * Read a block that is fragmented across 2 or more allocation blocks
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
243 ReadFragmentedBlock (SFCB
*file
, UInt32 blockNum
, BlockDescriptor
*block
)
246 UInt32 fragSize
, blockSize
;
252 Buf_t
** bufs
; /* list of Buf_t pointers */
256 volume
= file
->fcbVolume
;
257 cache
= (Cache_t
*)volume
->vcbBlockCache
;
259 blockSize
= file
->fcbBlockSize
;
260 maxFrags
= blockSize
/ volume
->vcbBlockSize
;
261 fileOffset
= (UInt64
)blockNum
* (UInt64
)blockSize
;
263 buffer
= (char *) AllocateMemory(blockSize
);
264 bufs
= (Buf_t
**) AllocateClearMemory(maxFrags
* sizeof(Buf_t
*));
265 if (buffer
== NULL
|| bufs
== NULL
) {
270 block
->buffer
= buffer
;
271 block
->blockHeader
= bufs
;
272 block
->blockNum
= blockNum
;
273 block
->blockSize
= blockSize
;
274 block
->blockReadFromDisk
= false;
275 block
->fragmented
= true;
277 for (i
= 0; (i
< maxFrags
) && (blockSize
> 0); ++i
) {
278 result
= MapFileBlockC (volume
, file
, blockSize
,
279 fileOffset
>> kSectorShift
,
281 if (result
) goto ErrorExit
;
283 diskOffset
= (SInt64
) (sector
) << kSectorShift
;
284 result
= CacheRead (cache
, diskOffset
, fragSize
, &bufs
[i
]);
285 if (result
) goto ErrorExit
;
287 if (bufs
[i
]->Length
!= fragSize
) {
288 plog("ReadFragmentedBlock: cache failure (Length != fragSize)\n");
293 CopyMemory(bufs
[i
]->Buffer
, buffer
, fragSize
);
295 fileOffset
+= fragSize
;
296 blockSize
-= fragSize
;
303 while (bufs
[i
] != NULL
) {
304 (void) CacheRelease (cache
, bufs
[i
], true);
308 DisposeMemory(block
->buffer
);
309 DisposeMemory(block
->blockHeader
);
311 block
->blockHeader
= NULL
;
312 block
->buffer
= NULL
;
319 * Write a block that is fragmented across 2 or more allocation blocks
323 WriteFragmentedBlock( SFCB
*file
, BlockDescriptor
*block
, int age
, uint32_t writeOptions
)
326 Buf_t
** bufs
; /* list of Buf_t pointers */
334 cache
= (Cache_t
*) file
->fcbVolume
->vcbBlockCache
;
335 bufs
= (Buf_t
**) block
->blockHeader
;
336 buffer
= (char *) block
->buffer
;
337 bufEnd
= buffer
+ file
->fcbBlockSize
;
340 plog("WriteFragmentedBlock: NULL bufs list!\n");
344 while ((bufs
[i
] != NULL
) && (buffer
< bufEnd
)) {
345 fragSize
= bufs
[i
]->Length
;
347 /* copy data for this fragment */
348 CopyMemory(buffer
, bufs
[i
]->Buffer
, fragSize
);
350 /* write it back to cache */
351 result
= CacheWrite(cache
, bufs
[i
], age
, writeOptions
);
358 DisposeMemory(block
->buffer
);
359 DisposeMemory(block
->blockHeader
);
361 block
->buffer
= NULL
;
362 block
->blockHeader
= NULL
;
363 block
->fragmented
= false;
370 * Release a block that is fragmented across 2 or more allocation blocks
374 ReleaseFragmentedBlock (SFCB
*file
, BlockDescriptor
*block
, int age
)
377 Buf_t
** bufs
; /* list of Buf_t pointers */
383 cache
= (Cache_t
*)file
->fcbVolume
->vcbBlockCache
;
384 bufs
= (Buf_t
**) block
->blockHeader
;
387 plog("ReleaseFragmentedBlock: NULL buf list!\n");
391 buffer
= (char*)block
->buffer
;
392 bufEnd
= buffer
+ file
->fcbBlockSize
;
394 while (bufs
[i
] != NULL
&& (buffer
< bufEnd
)) {
395 fragSize
= bufs
[i
]->Length
;
397 (void) CacheRelease (cache
, bufs
[i
], true);
401 DisposeMemory(block
->buffer
);
402 DisposeMemory(block
->blockHeader
);
404 block
->buffer
= NULL
;
405 block
->blockHeader
= NULL
;
406 block
->fragmented
= false;