]> git.saurik.com Git - apple/hfs.git/blob - fsck_hfs/dfalib/BlockCache.c
hfs-556.60.1.tar.gz
[apple/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 if (debug) {
289 plog("ReadFragmentedBlock: cache failure (Length != fragSize)\n");
290 }
291 result = -1;
292 goto ErrorExit;
293 }
294
295 CopyMemory(bufs[i]->Buffer, buffer, fragSize);
296 buffer += fragSize;
297 fileOffset += fragSize;
298 blockSize -= fragSize;
299 }
300
301 return (noErr);
302
303 ErrorExit:
304 i = 0;
305 while (bufs[i] != NULL) {
306 (void) CacheRelease (cache, bufs[i], true);
307 ++i;
308 }
309
310 DisposeMemory(block->buffer);
311 DisposeMemory(block->blockHeader);
312
313 block->blockHeader = NULL;
314 block->buffer = NULL;
315
316 return (result);
317 }
318
319
320 /*
321 * Write a block that is fragmented across 2 or more allocation blocks
322 *
323 */
324 static OSStatus
325 WriteFragmentedBlock( SFCB *file, BlockDescriptor *block, int age, uint32_t writeOptions )
326 {
327 Cache_t * cache;
328 Buf_t ** bufs; /* list of Buf_t pointers */
329 char * buffer;
330 char * bufEnd;
331 UInt32 fragSize;
332 OSStatus result;
333 int i = 0;
334
335 result = 0;
336 cache = (Cache_t *) file->fcbVolume->vcbBlockCache;
337 bufs = (Buf_t **) block->blockHeader;
338 buffer = (char *) block->buffer;
339 bufEnd = buffer + file->fcbBlockSize;
340
341 if (bufs == NULL) {
342 if (debug) {
343 plog("WriteFragmentedBlock: NULL bufs list!\n");
344 }
345 return (-1);
346 }
347
348 while ((bufs[i] != NULL) && (buffer < bufEnd)) {
349 fragSize = bufs[i]->Length;
350
351 /* copy data for this fragment */
352 CopyMemory(buffer, bufs[i]->Buffer, fragSize);
353
354 /* write it back to cache */
355 result = CacheWrite(cache, bufs[i], age, writeOptions);
356 if (result) break;
357
358 buffer += fragSize;
359 ++i;
360 }
361
362 DisposeMemory(block->buffer);
363 DisposeMemory(block->blockHeader);
364
365 block->buffer = NULL;
366 block->blockHeader = NULL;
367 block->fragmented = false;
368
369 return (result);
370 }
371
372
373 /*
374 * Release a block that is fragmented across 2 or more allocation blocks
375 *
376 */
377 static OSStatus
378 ReleaseFragmentedBlock (SFCB *file, BlockDescriptor *block, int age)
379 {
380 Cache_t * cache;
381 Buf_t ** bufs; /* list of Buf_t pointers */
382 char *buffer;
383 char *bufEnd;
384 UInt32 fragSize;
385 int i = 0;
386
387 cache = (Cache_t *)file->fcbVolume->vcbBlockCache;
388 bufs = (Buf_t **) block->blockHeader;
389
390 if (bufs == NULL) {
391 if (debug) {
392 plog("ReleaseFragmentedBlock: NULL buf list!\n");
393 }
394 return (-1);
395 }
396
397 buffer = (char*)block->buffer;
398 bufEnd = buffer + file->fcbBlockSize;
399
400 while (bufs[i] != NULL && (buffer < bufEnd)) {
401 fragSize = bufs[i]->Length;
402 buffer += fragSize;
403 (void) CacheRelease (cache, bufs[i], true);
404 ++i;
405 }
406
407 DisposeMemory(block->buffer);
408 DisposeMemory(block->blockHeader);
409
410 block->buffer = NULL;
411 block->blockHeader = NULL;
412 block->fragmented = false;
413
414 return (noErr);
415 }
416