#include "SRuntime.h"
#include "Scavenger.h"
#include "../cache.h"
extern OSErr MapFileBlockC (
SVCB * vcb,
SFCB * fcb,
UInt32 numberOfBytes,
UInt32 sectorOffset,
UInt64 * startSector,
UInt32 * availableBytes
);
extern Cache_t fscache;
static OSStatus ReadFragmentedBlock (SFCB *file, UInt32 blockNum, BlockDescriptor *block);
static OSStatus WriteFragmentedBlock( SFCB *file,
BlockDescriptor *block,
int age,
uint32_t writeOptions );
static OSStatus ReleaseFragmentedBlock (SFCB *file, BlockDescriptor *block, int age);
void
InitBlockCache(SVCB *volume)
{
volume->vcbBlockCache = (void *) &fscache;
}
OSStatus
GetVolumeBlock (SVCB *volume, UInt64 blockNum, GetBlockOptions options, BlockDescriptor *block)
{
UInt32 blockSize;
SInt64 offset;
OSStatus result;
Buf_t * buffer;
Cache_t * cache;
buffer = NULL;
cache = (Cache_t *) volume->vcbBlockCache;
blockSize = 512;
offset = (SInt64) ((UInt64) blockNum) << kSectorShift;
result = CacheRead (cache, offset, blockSize, &buffer);
if (result == 0) {
block->blockHeader = buffer;
block->buffer = buffer->Buffer;
block->blockSize = blockSize;
block->blockReadFromDisk = 0;
block->fragmented = 0;
} else {
block->blockHeader = NULL;
block->buffer = NULL;
}
return (result);
}
OSStatus
ReleaseVolumeBlock (SVCB *volume, BlockDescriptor *block, ReleaseBlockOptions options)
{
OSStatus result = 0;
Cache_t * cache;
Buf_t * buffer;
int age;
cache = (Cache_t *) volume->vcbBlockCache;
buffer = (Buf_t *) block->blockHeader;
age = ((options & kTrashBlock) != 0);
if (options & (kMarkBlockDirty | kForceWriteBlock))
result = CacheWrite(cache, buffer, age, 0);
else
result = CacheRelease (cache, buffer, age);
return (result);
}
OSStatus
GetFileBlock (SFCB *file, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block)
{
UInt64 diskBlock;
UInt32 contiguousBytes;
SInt64 offset;
OSStatus result;
Buf_t * buffer;
Cache_t * cache;
buffer = NULL;
block->buffer = NULL;
block->blockHeader = NULL;
cache = (Cache_t *)file->fcbVolume->vcbBlockCache;
result = MapFileBlockC(file->fcbVolume, file, file->fcbBlockSize,
(((UInt64)blockNum * (UInt64)file->fcbBlockSize) >> kSectorShift),
&diskBlock, &contiguousBytes);
if (result) return (result);
if (contiguousBytes < file->fcbBlockSize)
return ( ReadFragmentedBlock(file, blockNum, block) );
offset = (SInt64) ((UInt64) diskBlock) << kSectorShift;
result = CacheRead (cache, offset, file->fcbBlockSize, &buffer);
if (result) return (result);
block->blockHeader = buffer;
block->buffer = buffer->Buffer;
block->blockSize = file->fcbBlockSize;
block->blockReadFromDisk = 0;
block->fragmented = 0;
return (noErr);
}
OSStatus
ReleaseFileBlock (SFCB *file, BlockDescriptor *block, ReleaseBlockOptions options)
{
OSStatus result = 0;
Cache_t * cache;
Buf_t * buffer;
int age;
uint32_t writeOptions = 0;
cache = (Cache_t *)file->fcbVolume->vcbBlockCache;
buffer = (Buf_t *) block->blockHeader;
age = ((options & kTrashBlock) != 0);
if ( (options & kForceWriteBlock) == 0 )
writeOptions |= kLazyWrite;
if (options & (kMarkBlockDirty | kForceWriteBlock)) {
if (block->fragmented)
result = WriteFragmentedBlock(file, block, age, writeOptions);
else
result = CacheWrite(cache, buffer, age, writeOptions);
} else {
if (block->fragmented)
result = ReleaseFragmentedBlock(file, block, age);
else
result = CacheRelease (cache, buffer, age);
}
return (result);
}
OSStatus
SetFileBlockSize (SFCB *file, ByteCount blockSize)
{
file->fcbBlockSize = blockSize;
return (0);
}
static OSStatus
ReadFragmentedBlock (SFCB *file, UInt32 blockNum, BlockDescriptor *block)
{
UInt64 sector;
UInt32 fragSize, blockSize;
UInt64 fileOffset;
SInt64 diskOffset;
SVCB * volume;
int i, maxFrags;
OSStatus result;
Buf_t ** bufs;
Cache_t * cache;
char * buffer;
volume = file->fcbVolume;
cache = (Cache_t *)volume->vcbBlockCache;
blockSize = file->fcbBlockSize;
maxFrags = blockSize / volume->vcbBlockSize;
fileOffset = (UInt64)blockNum * (UInt64)blockSize;
buffer = (char *) AllocateMemory(blockSize);
bufs = (Buf_t **) AllocateClearMemory(maxFrags * sizeof(Buf_t *));
if (buffer == NULL || bufs == NULL) {
result = memFullErr;
return (result);
}
block->buffer = buffer;
block->blockHeader = bufs;
block->blockSize = blockSize;
block->blockReadFromDisk = false;
block->fragmented = true;
for (i = 0; (i < maxFrags) && (blockSize > 0); ++i) {
result = MapFileBlockC (volume, file, blockSize,
fileOffset >> kSectorShift,
§or, &fragSize);
if (result) goto ErrorExit;
diskOffset = (SInt64) (sector) << kSectorShift;
result = CacheRead (cache, diskOffset, fragSize, &bufs[i]);
if (result) goto ErrorExit;
if (bufs[i]->Length != fragSize) {
printf("ReadFragmentedBlock: cache failure (Length != fragSize)\n");
result = -1;
goto ErrorExit;
}
CopyMemory(bufs[i]->Buffer, buffer, fragSize);
buffer += fragSize;
fileOffset += fragSize;
blockSize -= fragSize;
}
return (noErr);
ErrorExit:
i = 0;
while (bufs[i] != NULL) {
(void) CacheRelease (cache, bufs[i], true);
++i;
}
DisposeMemory(block->buffer);
DisposeMemory(block->blockHeader);
block->blockHeader = NULL;
block->buffer = NULL;
return (result);
}
static OSStatus
WriteFragmentedBlock( SFCB *file, BlockDescriptor *block, int age, uint32_t writeOptions )
{
Cache_t * cache;
Buf_t ** bufs;
char * buffer;
char * bufEnd;
UInt32 fragSize;
OSStatus result;
int i = 0;
result = 0;
cache = (Cache_t *) file->fcbVolume->vcbBlockCache;
bufs = (Buf_t **) block->blockHeader;
buffer = (char *) block->buffer;
bufEnd = buffer + file->fcbBlockSize;
if (bufs == NULL) {
printf("WriteFragmentedBlock: NULL bufs list!\n");
return (-1);
}
while ((bufs[i] != NULL) && (buffer < bufEnd)) {
fragSize = bufs[i]->Length;
CopyMemory(buffer, bufs[i]->Buffer, fragSize);
result = CacheWrite(cache, bufs[i], age, writeOptions);
if (result) break;
buffer += fragSize;
++i;
}
DisposeMemory(block->buffer);
DisposeMemory(block->blockHeader);
block->buffer = NULL;
block->blockHeader = NULL;
block->fragmented = false;
return (result);
}
static OSStatus
ReleaseFragmentedBlock (SFCB *file, BlockDescriptor *block, int age)
{
Cache_t * cache;
Buf_t ** bufs;
int i = 0;
cache = (Cache_t *)file->fcbVolume->vcbBlockCache;
bufs = (Buf_t **) block->blockHeader;
if (bufs == NULL) {
printf("ReleaseFragmentedBlock: NULL buf list!\n");
return (-1);
}
while (bufs[i] != NULL && bufs[i]->Length) {
(void) CacheRelease (cache, bufs[i], true);
++i;
}
DisposeMemory(block->buffer);
DisposeMemory(block->blockHeader);
block->buffer = NULL;
block->blockHeader = NULL;
block->fragmented = false;
return (noErr);
}