Added parameter to the get_nth_*_info() hooks and implemented simple caching used for the FS modules.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2500 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2003-01-19 01:19:52 +00:00
parent 81f71acbee
commit dafa158b38

View File

@ -26,11 +26,34 @@ static const char *kFSModulePrefix = "disk_scanner/fs";
#define TRACE(x) ;
//#define TRACE(x) dprintf x
// fs_block
typedef struct fs_block {
off_t offset;
void *data;
struct fs_block *previous;
struct fs_block *next;
} fs_block;
// fs_buffer_cache
typedef struct fs_buffer_cache {
int fd;
off_t offset;
off_t size;
size_t block_size;
struct fs_block *first_block;
struct fs_block *last_block;
} fs_buffer_cache;
// prototypes
static status_t read_block(int fd, off_t offset, size_t size, uchar **block);
static status_t get_partition_module_block(int deviceFD,
const session_info *sessionOffset, const uchar *block,
partition_module_info **partitionModule);
static status_t init_fs_buffer_cache(struct fs_buffer_cache *cache, int fd,
off_t offset, off_t size, size_t blockSize);
static status_t cleanup_fs_buffer_cache(struct fs_buffer_cache *cache);
static status_t get_buffer(struct fs_buffer_cache *cache, off_t offset,
size_t size, void **_buffer, size_t *actualSize);
// std_ops
@ -91,7 +114,7 @@ read_block(int fd, off_t offset, size_t size, uchar **block)
if (error == B_OK) {
*block = malloc(size);
if (*block) {
if (read_pos(fd, 0, *block, size) != (ssize_t)size) {
if (read_pos(fd, offset, *block, size) != (ssize_t)size) {
error = errno;
if (error == B_OK)
error = B_ERROR;
@ -170,10 +193,12 @@ disk_scanner_get_partition_module(int deviceFD,
static
status_t
disk_scanner_get_nth_session_info(int deviceFD, int32 index,
session_info *sessionInfo)
session_info *sessionInfo,
session_module_info **_sessionModule)
{
status_t error = B_OK;
session_module_info *sessionModule = NULL;
session_module_info *sessionModule
= (_sessionModule ? *_sessionModule : NULL);
bool isCD = false;
int32 blockSize = 0;
off_t deviceSize = 0;
@ -192,18 +217,24 @@ disk_scanner_get_nth_session_info(int deviceFD, int32 index,
} else
error = errno;
}
TRACE(("disk_scanner: check: %s\n", strerror(error)));
// get a session module, if the device is a CD, otherwise return a
// virtual session
if (error == B_OK) {
if (isCD) {
// get the session module
error = disk_scanner_get_session_module(deviceFD, deviceSize,
blockSize, &sessionModule);
if (!sessionModule) {
error = disk_scanner_get_session_module(deviceFD, deviceSize,
blockSize,
&sessionModule);
TRACE(("disk_scanner: check: %s\n", strerror(error)));
}
// get the info
if (error == B_OK) {
error = sessionModule->get_nth_info(deviceFD, index,
deviceSize, blockSize,
sessionInfo);
TRACE(("disk_scanner: check: %s\n", strerror(error)));
}
} else if (index == 0) {
// no CD -- virtual session
@ -215,9 +246,14 @@ disk_scanner_get_nth_session_info(int deviceFD, int32 index,
} else // no CD, fail after the first session
error = B_ENTRY_NOT_FOUND;
}
// cleanup
if (sessionModule)
TRACE(("disk_scanner: check: %s\n", strerror(error)));
// cleanup / set results
if (_sessionModule)
*_sessionModule = sessionModule;
else if (sessionModule)
put_module(sessionModule->module.name);
TRACE(("disk_scanner: get_nth_session_info() done: %s\n",
strerror(error)));
return error;
}
@ -227,12 +263,14 @@ status_t
disk_scanner_get_nth_partition_info(int deviceFD,
const session_info *sessionInfo,
int32 partitionIndex,
extended_partition_info *partitionInfo)
extended_partition_info *partitionInfo,
partition_module_info **_partitionModule)
{
partition_module_info *partitionModule = NULL;
partition_module_info *partitionModule
= (_partitionModule ? *_partitionModule : NULL);
status_t error = (partitionInfo ? B_OK : B_BAD_VALUE);
TRACE(("disk_scanner: get_nth_partition_info(%d, %lld, %lld, %ld, %ld, %ld)\n",
deviceFD, sessionOffset, sessionSize,
deviceFD, sessionInfo->offset, sessionInfo->size,
partitionInfo->info.logical_block_size, partitionInfo->info.session,
partitionInfo->info.partition));
if (error == B_OK) {
@ -245,21 +283,23 @@ disk_scanner_get_nth_partition_info(int deviceFD,
partitionInfo->info.session = sessionInfo->index;
partitionInfo->info.partition = partitionIndex;
// read the first block of the session and get the partition module
error = read_block(deviceFD, sessionOffset, blockSize, &block);
if (error == B_OK) {
error = get_partition_module_block(deviceFD, sessionInfo, block,
&partitionModule);
if (error == B_ENTRY_NOT_FOUND
&& partitionInfo->info.partition == 0) {
// no matching partition module found: return a virtual
// partition info
partitionInfo->info.offset = sessionOffset;
partitionInfo->info.size = sessionSize;
partitionInfo->flags = B_VIRTUAL_PARTITION;
partitionInfo->partition_name[0] = '\0';
partitionInfo->partition_type[0] = '\0';
partitionInfo->partition_code = 0xeb; // doesn't matter
error = B_OK;
if (!partitionModule) {
error = read_block(deviceFD, sessionOffset, blockSize, &block);
if (error == B_OK) {
error = get_partition_module_block(deviceFD, sessionInfo,
block, &partitionModule);
if (error == B_ENTRY_NOT_FOUND
&& partitionInfo->info.partition == 0) {
// no matching partition module found: return a virtual
// partition info
partitionInfo->info.offset = sessionOffset;
partitionInfo->info.size = sessionSize;
partitionInfo->flags = B_VIRTUAL_PARTITION;
partitionInfo->partition_name[0] = '\0';
partitionInfo->partition_type[0] = '\0';
partitionInfo->partition_code = 0xeb; // doesn't matter
error = B_OK;
}
}
}
// get the info
@ -267,8 +307,10 @@ disk_scanner_get_nth_partition_info(int deviceFD,
error = partitionModule->get_nth_info(deviceFD, sessionInfo,
block, partitionIndex, partitionInfo);
}
// cleanup
if (partitionModule)
// cleanup / set results
if (_partitionModule)
*_partitionModule = partitionModule;
else if (partitionModule)
put_module(partitionModule->module.name);
if (block)
free(block);
@ -280,15 +322,24 @@ disk_scanner_get_nth_partition_info(int deviceFD,
static
status_t
disk_scanner_get_partition_fs_info(int deviceFD,
extended_partition_info *partitionInfo)
extended_partition_info *partitionInfo)
{
// Iterate through the list of FS modules and return the result of the
// first one that thinks, it is the right one.
status_t error = (partitionInfo ? B_OK : B_BAD_VALUE);
void *list = NULL;
fs_buffer_cache cache;
bool cacheInitialized = false;
TRACE(("disk_scanner: get_partition_fs_info(%d, %lld, %lld, %ld)\n", deviceFD,
partitionInfo->info.offset, partitionInfo->info.size,
partitionInfo->info.logical_block_size));
// init the cache
if (error == B_OK) {
error = init_fs_buffer_cache(&cache, deviceFD,
partitionInfo->info.offset, partitionInfo->info.size,
partitionInfo->info.logical_block_size);
cacheInitialized = (error == B_OK);
}
// Iterate through the list of FS modules and return the result of the
// first one that thinks, it is the right one.
if (error == B_OK && ((list = open_module_list(kFSModulePrefix)))) {
extended_partition_info bestInfo;
float bestPriority = -2;
@ -304,7 +355,8 @@ disk_scanner_get_partition_fs_info(int deviceFD,
// get the info
extended_partition_info info = *partitionInfo;
float priority = 0;
if (module->identify(deviceFD, &info, &priority)) {
if (module->identify(deviceFD, &info, &priority, get_buffer,
&cache)) {
// copy the info, if it is the first or the has a higher
// priority than the one found before
if (error == B_ENTRY_NOT_FOUND
@ -322,9 +374,168 @@ disk_scanner_get_partition_fs_info(int deviceFD,
}
close_module_list(list);
}
// cleanup the cache
if (cacheInitialized)
cleanup_fs_buffer_cache(&cache);
return error;
}
// new_fs_block
static
status_t
new_fs_block(int fd, off_t offset, size_t size, fs_block **_block)
{
status_t error = (_block ? B_OK : B_BAD_VALUE);
fs_block *block = NULL;
// alloc the block
if (error == B_OK) {
block = (fs_block*)malloc(sizeof(fs_block));
if (!block)
error = B_NO_MEMORY;
}
// read the block
if (error == B_OK)
error = read_block(fd, offset, size, (uchar**)&block->data);
// set the fields / cleanup on error
if (error == B_OK) {
block->offset = offset;
block->previous = NULL;
block->next = NULL;
*_block = block;
} else {
if (block)
free(block);
}
return error;
}
// delete_fs_block
static
void
delete_fs_block(fs_block *block)
{
if (block) {
if (block->data)
free(block->data);
free(block);
}
}
// init_fs_buffer_cache
static
status_t
init_fs_buffer_cache(struct fs_buffer_cache *cache, int fd, off_t offset,
off_t size, size_t blockSize)
{
cache->fd = fd;
cache->offset = offset;
cache->size = size;
cache->block_size = blockSize;
cache->first_block = NULL;
cache->last_block = NULL;
return B_OK;
}
// cleanup_fs_buffer_cache
static
status_t
cleanup_fs_buffer_cache(struct fs_buffer_cache *cache)
{
if (cache) {
while (cache->first_block) {
fs_block *block = cache->first_block;
cache->first_block = block->next;
delete_fs_block(block);
}
}
return B_OK;
}
// get_buffer
static
status_t
get_buffer(struct fs_buffer_cache *cache, off_t offset, size_t size,
void **_buffer, size_t *actualSize)
{
status_t error = (cache && _buffer && actualSize
&& offset >= cache->offset && size > 0
? B_OK : B_BAD_VALUE);
uint8 *buffer = NULL;
// check the bounds
if (error == B_OK) {
if (offset >= cache->offset + cache->size)
size = 0;
else if (offset + size > cache->offset + cache->size)
size = cache->offset + cache->size - offset;
}
// allocate the buffer
if (error == B_OK && size > 0) {
buffer = (uint8*)malloc(size);
if (buffer) {
// iterate through the list of cached blocks
off_t blockOffset = offset - offset % cache->block_size;
size_t remainingBytes = size;
fs_block *block = NULL;
for (block = cache->first_block;
error == B_OK && remainingBytes > 0;
block = block->next) {
if (!block || block->offset >= blockOffset) {
if (!block || block->offset > blockOffset) {
// the block is not in cache, read it
fs_block *newBlock = NULL;
error = new_fs_block(cache->fd, blockOffset,
cache->block_size, &newBlock);
if (error == B_OK) {
// insert the new block
if (block)
newBlock->previous = block->previous;
else
newBlock->previous = cache->last_block;
newBlock->next = block;
if (newBlock->previous)
newBlock->previous->next = newBlock;
else
cache->first_block = newBlock;
if (newBlock->next)
newBlock->next->previous = newBlock;
else
cache->last_block = newBlock;
block = newBlock;
}
}
if (error == B_OK) {
// block is (now) in cache, copy the data
off_t inBlockOffset = 0;
size_t toCopy = cache->block_size;
if (blockOffset < offset) {
inBlockOffset = offset - blockOffset;
toCopy -= inBlockOffset;
}
if (toCopy > remainingBytes)
toCopy = remainingBytes;
memcpy(buffer + blockOffset + inBlockOffset - offset,
(uint8*)block->data + inBlockOffset, toCopy);
blockOffset += cache->block_size;
remainingBytes -= toCopy;
}
}
}
} else
error = B_NO_MEMORY;
}
// set results / cleanup on error
if (error == B_OK) {
*_buffer = buffer;
*actualSize = size;
} else {
if (buffer)
free(buffer);
}
return error;
}
static disk_scanner_module_info disk_scanner_module =
{
// module_info