]> git.saurik.com Git - hfs.git/blob - fsck_hfs/dfalib/BlockCache.c
hfs-226.1.1.tar.gz
[hfs.git] / fsck_hfs / dfalib / BlockCache.c
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
30 extern Cache_t fscache;
31
32
33 static OSStatus ReadFragmentedBlock (SFCB *file, UInt32 blockNum, BlockDescriptor *block);
34 static OSStatus WriteFragmentedBlock( SFCB *file,
35 BlockDescriptor *block,
36 int age,
37 uint32_t writeOptions );
38 static OSStatus ReleaseFragmentedBlock (SFCB *file, BlockDescriptor *block, int age);
39
40
41 void
42 InitBlockCache(SVCB *volume)
43 {
44 volume->vcbBlockCache = (void *) &fscache;
45 }
46
47
48 /*
49 * kGetBlock
50 * kForceReadBlock
51 * kGetEmptyBlock
52 * kSkipEndianSwap
53 */
54 OSStatus
55 GetVolumeBlock (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 */
105 OSStatus
106 ReleaseVolumeBlock (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 */
143 OSStatus
144 GetFileBlock (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 */
190 OSStatus
191 ReleaseFileBlock (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 */
226 OSStatus
227 SetFileBlockSize (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 */
242 static OSStatus
243 ReadFragmentedBlock (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 &sector, &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
301 ErrorExit:
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 */
322 static OSStatus
323 WriteFragmentedBlock( 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 */
373 static OSStatus
374 ReleaseFragmentedBlock (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