* Accidently committed the wrong bash history line... these are the files that

were supposed to be deleted/changed with the previous commit.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31888 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-07-29 01:31:19 +00:00
parent c6e2291fc2
commit c881516f65
16 changed files with 111 additions and 4676 deletions
-81
View File
@@ -1,81 +0,0 @@
/* Disk device iteration and information
**
** Distributed under the terms of the OpenBeOS License.
*/
#ifndef _FS_DEVICE_H
#define _FS_DEVICE_H
#include <Drivers.h>
#include <OS.h>
#include <SupportDefs.h>
// session flags
enum {
B_DATA_SESSION = 0x01, /* data session */
B_VIRTUAL_SESSION = 0x02, /* e.g. hard disk */
};
typedef struct session_info {
off_t offset; /* offset from start of device (in bytes) */
off_t size; /* size (in bytes) */
int32 logical_block_size; /* logical block size (in bytes) */
int32 index; /* session index */
uint32 flags; /* session flags */
} session_info;
// partition flags
enum {
B_HIDDEN_PARTITION = 0x01, /* non-file system partition */
B_VIRTUAL_PARTITION = 0x02, /* e.g. floppy */
B_EMPTY_PARTITION = 0x04, /* empty partition, implies
B_HIDDEN_PARTITION */
};
typedef struct extended_partition_info {
partition_info info;
uint32 flags; /* partition flags */
char partition_name[B_FILE_NAME_LENGTH];
char partition_type[B_FILE_NAME_LENGTH];
char file_system_short_name[B_FILE_NAME_LENGTH]; /* "", if hidden */
char file_system_long_name[B_FILE_NAME_LENGTH]; /* or unknown FS */
char volume_name[B_FILE_NAME_LENGTH]; /* "", if hidden */
uint32 file_system_flags; /* same as fs_info::flags */
} extended_partition_info;
#ifdef __cplusplus
extern "C" {
#endif
// getting infos
status_t get_nth_session_info(int deviceFD, int32 index,
session_info *sessionInfo);
status_t get_nth_partition_info(int deviceFD, int32 sessionIndex,
int32 partitionIndex,
extended_partition_info *partitionInfo,
char *partitionMapName);
// partitioning
status_t get_partitioning_parameters(int deviceFD, int32 sessionIndex,
const char *identifier, char *buffer,
size_t bufferSize, size_t *actualSize);
status_t partition_session(int deviceFD, int32 sessionIndex,
const char *identifier, const char *parameters);
// initialization
status_t get_fs_initialization_parameters(int deviceFD, int32 sessionIndex,
int32 partitionIndex,
const char *fileSystem, char *buffer,
size_t bufferSize,
size_t *actualSize);
// TODO: Move to <unistd.h>. It fits better there.
status_t initialize_volume(const char *where, const char *fileSystem,
const char *volumeName, const char *parameters);
#ifdef __cplusplus
}
#endif
#endif /* _FS_DEVICE_H */
-11
View File
@@ -1,11 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel disk_scanner ;
UsePrivateHeaders $(DOT) ;
KernelAddon disk_scanner :
disk_scanner.c
;
#SubInclude HAIKU_TOP src add-ons kernel disk_scanner fs ;
SubInclude HAIKU_TOP src add-ons kernel disk_scanner partition ;
SubInclude HAIKU_TOP src add-ons kernel disk_scanner session ;
@@ -1,665 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file disk_scanner.c
disk_scanner kernel module
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <disk_scanner.h>
#include <KernelExport.h>
#include <disk_scanner/fs.h>
#include <disk_scanner/partition.h>
#include <disk_scanner/disk_scanner.h>
#include <disk_scanner/session.h>
static const char *kSessionModulePrefix = "disk_scanner/session";
static const char *kPartitionModulePrefix = "disk_scanner/partition";
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
static
status_t
std_ops(int32 op, ...)
{
TRACE(("disk_scanner: std_ops(0x%lx)\n", op));
switch(op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
// get_session_module
static
status_t
disk_scanner_get_session_module(int deviceFD, off_t deviceSize, int32 blockSize,
session_module_info **sessionModule)
{
// Iterate through the list of session modules and return the first one
// that thinks, it is the right one.
status_t error = (sessionModule ? B_OK : B_BAD_VALUE);
void *list = NULL;
TRACE(("disk_scanner: get_session_module(%d, %lld, %ld)\n", deviceFD,
deviceSize, blockSize));
if (error == B_OK)
*sessionModule = NULL;
if (error == B_OK && ((list = open_module_list(kSessionModulePrefix)))) {
char moduleName[B_PATH_NAME_LENGTH];
size_t bufferSize = sizeof(moduleName);
for (; read_next_module_name(list, moduleName, &bufferSize) == B_OK;
bufferSize = sizeof(moduleName)) {
session_module_info *module = NULL;
if (get_module(moduleName, (module_info**)&module) == B_OK) {
if (module->identify(deviceFD, deviceSize, blockSize)) {
// found module
*sessionModule = module;
break;
}
put_module(moduleName);
}
}
close_module_list(list);
}
// set result
if (error == B_OK && !*sessionModule)
error = B_ENTRY_NOT_FOUND;
return error;
}
// read_block
static
status_t
read_block(int fd, off_t offset, size_t size, uchar **block)
{
status_t error = (block && size > 0 ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
*block = malloc(size);
if (*block) {
if (read_pos(fd, offset, *block, size) != (ssize_t)size) {
error = errno;
if (error == B_OK)
error = B_IO_ERROR;
free(*block);
*block = NULL;
}
} else
error = B_NO_MEMORY;
}
return error;
}
// get_partition_module_block
static
status_t
get_partition_module_block(int deviceFD, const session_info *sessionInfo,
const uchar *block,
partition_module_info **partitionModule)
{
// Iterate through the list of partition modules and return the first one
// that thinks, it is the right one.
status_t error = (partitionModule && block ? B_OK : B_BAD_VALUE);
void *list = NULL;
if (error == B_OK)
*partitionModule = NULL;
if (error == B_OK && ((list = open_module_list(kPartitionModulePrefix)))) {
char moduleName[B_PATH_NAME_LENGTH];
size_t bufferSize = sizeof(moduleName);
for (; read_next_module_name(list, moduleName, &bufferSize) == B_OK;
bufferSize = sizeof(moduleName)) {
partition_module_info *module = NULL;
TRACE(("disk_scanner: trying partition module: `%s'\n", moduleName));
if (get_module(moduleName, (module_info**)&module) == B_OK) {
if (module->identify(deviceFD, sessionInfo, block)) {
// found module
*partitionModule = module;
break;
}
put_module(moduleName);
}
}
close_module_list(list);
}
// set result
if (error == B_OK && !*partitionModule)
error = B_ENTRY_NOT_FOUND;
return error;
}
// get_partition_module_for_identifier
static
status_t
get_partition_module_for_identifier(const char *identifier,
partition_module_info **partitionModule)
{
// find the partition module that knows the supplied identifier
status_t error = (identifier ? B_OK : B_BAD_VALUE);
void *list = NULL;
if (error == B_OK)
*partitionModule = NULL;
if (error == B_OK && ((list = open_module_list(kPartitionModulePrefix)))) {
char moduleName[B_PATH_NAME_LENGTH];
size_t bufferSize = sizeof(moduleName);
for (; read_next_module_name(list, moduleName, &bufferSize) == B_OK;
bufferSize = sizeof(moduleName)) {
partition_module_info *module = NULL;
if (get_module(moduleName, (module_info**)&module) == B_OK) {
if (!strcmp(module->short_name, identifier)) {
// found module
*partitionModule = module;
break;
}
put_module(moduleName);
}
}
close_module_list(list);
}
if (error == B_OK && !*partitionModule)
error = B_ENTRY_NOT_FOUND;
return error;
}
// get_partition_module
static
status_t
disk_scanner_get_partition_module(int deviceFD,
const session_info *sessionInfo,
partition_module_info **partitionModule)
{
status_t error = (partitionModule && sessionInfo ? B_OK : B_BAD_VALUE);
TRACE(("disk_scanner: get_partition_module(%d, %lld, %lld, %ld)\n",
deviceFD, sessionInfo->offset, sessionInfo->size,
sessionInfo->logical_block_size));
if (error == B_OK) {
off_t sessionOffset = sessionInfo->offset;
int32 blockSize = sessionInfo->logical_block_size;
// read the first block of the session and let the helper function
// do the job
uchar *block = NULL;
error = read_block(deviceFD, sessionOffset, blockSize, &block);
if (error == B_OK) {
error = get_partition_module_block(deviceFD, sessionInfo,
block, partitionModule);
free(block);
}
}
return error;
}
// get_nth_session_info
static
status_t
disk_scanner_get_nth_session_info(int deviceFD, int32 index,
session_info *sessionInfo,
session_module_info **_sessionModule)
{
status_t error = B_OK;
session_module_info *sessionModule
= (_sessionModule ? *_sessionModule : NULL);
int32 blockSize = 0;
off_t deviceSize = 0;
device_geometry geometry;
// get the media status
if (ioctl(deviceFD, B_GET_MEDIA_STATUS, &error) != 0)
error = errno;
// get the device geometry
TRACE(("disk_scanner: get_nth_session_info(%d, %ld)\n", deviceFD, index));
if (error == B_OK) {
if (ioctl(deviceFD, B_GET_GEOMETRY, &geometry) == 0) {
blockSize = geometry.bytes_per_sector;
deviceSize = (off_t)blockSize * geometry.sectors_per_track
* geometry.cylinder_count * geometry.head_count;
} else
error = errno;
}
// get a session module, if the device is a CD, otherwise return a
// virtual session
if (error == B_OK) {
// get the session module
if (!sessionModule) {
error = disk_scanner_get_session_module(deviceFD, deviceSize,
blockSize,
&sessionModule);
if (error == B_OK) {
error = sessionModule->get_nth_info(deviceFD, index,
deviceSize, blockSize,
sessionInfo);
} else if (error == B_ENTRY_NOT_FOUND) {
// no session add-on found -- return a virtual session for
// index 0
error = B_OK;
if (index == 0) {
sessionInfo->offset = 0;
sessionInfo->size = deviceSize;
sessionInfo->logical_block_size = blockSize;
sessionInfo->index = 0;
sessionInfo->flags = B_VIRTUAL_SESSION | B_DATA_SESSION;
} else
error = B_ENTRY_NOT_FOUND;
}
}
}
// 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;
}
// get_nth_partition_info
static
status_t
disk_scanner_get_nth_partition_info(int deviceFD,
const session_info *sessionInfo,
int32 partitionIndex,
extended_partition_info *partitionInfo,
char *partitionMapName,
partition_module_info **_partitionModule)
{
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, sessionInfo->offset, sessionInfo->size,
partitionInfo->info.logical_block_size, partitionInfo->info.session,
partitionInfo->info.partition));
if (error == B_OK) {
off_t sessionOffset = sessionInfo->offset;
off_t sessionSize = sessionInfo->size;
int32 blockSize = sessionInfo->logical_block_size;
uchar *block = NULL;
// fill in the fields we do already know
partitionInfo->info.logical_block_size = blockSize;
partitionInfo->info.session = sessionInfo->index;
partitionInfo->info.partition = partitionIndex;
// Read the first block of the session and get the partition module.
if (!(sessionInfo->flags & B_DATA_SESSION)) {
// Don't that, if the session is an audio session.
// Fall through and return a virtual partition, if partition 0
// is requested.
if (partitionInfo->info.partition != 0)
error = B_ENTRY_NOT_FOUND;
} else if (!partitionModule) {
error = read_block(deviceFD, sessionOffset, blockSize, &block);
TRACE((" check: %s\n", strerror(error)));
if (error == B_OK) {
error = get_partition_module_block(deviceFD, sessionInfo,
block, &partitionModule);
TRACE((" check: %s\n", strerror(error)));
if (error == B_ENTRY_NOT_FOUND
&& partitionInfo->info.partition == 0) {
// No matching partition module found, and first partition
// requested: Just set the error to B_OK: below a virtual
// partition info will be returned.
error = B_OK;
}
}
}
// get the info
if (error == B_OK) {
if (partitionModule) {
error = partitionModule->get_nth_info(deviceFD, sessionInfo,
block, partitionIndex, partitionInfo);
} else {
// no partition module: 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';
}
}
TRACE((" check: %s\n", strerror(error)));
// set results / cleanup
if (error == B_OK && partitionMapName) {
// return partition module identifier
if (partitionModule)
strcpy(partitionMapName, partitionModule->short_name);
else
partitionMapName[0] = '\0';
}
if (_partitionModule)
*_partitionModule = partitionModule;
else if (partitionModule)
put_module(partitionModule->module.name);
if (block)
free(block);
}
return error;
}
// get_partition_fs_info
static
status_t
disk_scanner_get_partition_fs_info(int deviceFD,
extended_partition_info *partitionInfo)
{
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
// one with the highest priority that thinks, it is the right one.
if (error == B_OK && ((list = open_module_list(kFSModulePrefix)))) {
extended_partition_info bestInfo;
float bestPriority = -2;
char moduleName[B_PATH_NAME_LENGTH];
size_t bufferSize = sizeof(moduleName);
error = B_ENTRY_NOT_FOUND;
for (; read_next_module_name(list, moduleName, &bufferSize) == B_OK;
bufferSize = sizeof(moduleName)) {
fs_module_info *module = NULL;
TRACE(("disk_scanner: trying fs module: `%s'\n", moduleName));
// get the module
if (get_module(moduleName, (module_info**)&module) == B_OK) {
// get the info
extended_partition_info info = *partitionInfo;
float priority = 0;
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
|| priority > bestPriority) {
bestInfo = info;
bestPriority = priority;
}
error = B_OK;
}
put_module(moduleName);
}
// set the return value
if (error == B_OK)
*partitionInfo = bestInfo;
}
close_module_list(list);
}
// cleanup the cache
if (cacheInitialized)
cleanup_fs_buffer_cache(&cache);
return error;
}
// get_partitioning_params
static
status_t
disk_scanner_get_partitioning_params(int deviceFD,
const struct session_info *sessionInfo,
const char *identifier, char *buffer,
size_t bufferSize, size_t *actualSize)
{
// find the partition module that knows the supplied identifier
status_t error = (sessionInfo && identifier && buffer && actualSize
? B_OK : B_BAD_VALUE);
partition_module_info *partitionModule = NULL;
if (error == B_OK)
get_partition_module_for_identifier(identifier, &partitionModule);
// get the parameters from the module
if (error == B_OK) {
error = partitionModule->get_partitioning_params(deviceFD, sessionInfo,
buffer, bufferSize, actualSize);
}
// cleanup
if (partitionModule)
put_module(partitionModule->module.name);
return error;
}
// partition
static
status_t
disk_scanner_partition(int deviceFD, const struct session_info *sessionInfo,
const char *identifier, const char *parameters)
{
// find the partition module that knows the supplied identifier
status_t error = (sessionInfo && identifier ? B_OK : B_BAD_VALUE);
partition_module_info *partitionModule = NULL;
if (error == B_OK)
get_partition_module_for_identifier(identifier, &partitionModule);
// let the module do the actual partitioning
if (error == B_OK)
error = partitionModule->partition(deviceFD, sessionInfo, parameters);
// cleanup
if (partitionModule)
put_module(partitionModule->module.name);
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 >= 0 && size > 0
? B_OK : B_BAD_VALUE);
uint8 *buffer = NULL;
// check the bounds
if (error == B_OK) {
offset += cache->offset; // make relative to beginning of device
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;
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;
}
}
// bail out on failure
if (error != B_OK)
break;
}
} 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
{
DISK_SCANNER_MODULE_NAME,
0, // better B_KEEP_LOADED?
std_ops
},
disk_scanner_get_session_module,
disk_scanner_get_partition_module,
disk_scanner_get_nth_session_info,
disk_scanner_get_nth_partition_info,
disk_scanner_get_partition_fs_info,
disk_scanner_get_partitioning_params,
disk_scanner_partition
};
_EXPORT disk_scanner_module_info *modules[] =
{
&disk_scanner_module,
NULL
};
@@ -1,25 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel disk_scanner fs ;
UsePrivateHeaders $(DOT) ;
UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
UsePrivateHeaders [ FDirName storage ] ;
# For now build a userland version only.
Addon <file_system>bfs :
bfs.c
;
LinkAgainst <file_system>bfs :
libkernelland_emu.so
libdisk_device_manager.so
;
#KernelAddon bfs : kernel disk_scanner fs :
# bfs.c
#;
#KernelAddon iso9660 : kernel disk_scanner fs :
# iso9660.cpp
#;
-435
View File
@@ -1,435 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file bfs.c
disk_scanner filesystem module for BFS filesystems
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ddm_modules.h>
#include <DiskDeviceTypes.h>
#include <KernelExport.h>
// B_PLAIN_C_ERROR:
//static const char *kBFSModuleName = "file_systems/bfs/v1";
#define kBFSModuleName "file_systems/bfs/v1"
const char *kModuleDebugName = "fs/bfs";
#define TRACE(x) ;
//#define TRACE(x) dprintf x
// prototypes
//static bool bfs_fs_identify(int deviceFD,
// struct extended_partition_info *partitionInfo, float *priority,
// fs_get_buffer get_buffer, struct fs_buffer_cache *cache);
//----------------------------------------------------------------------
// Stolen from src/add-ons/kernel/file_systems/bfs/bfs.h
//----------------------------------------------------------------------
typedef struct block_run
{
int32 allocation_group;
uint16 start;
uint16 length;
} block_run;
typedef block_run inode_addr;
#define BFS_DISK_NAME_LENGTH 32
typedef struct disk_super_block
{
char name[BFS_DISK_NAME_LENGTH];
int32 magic1;
int32 fs_byte_order;
uint32 block_size;
uint32 block_shift;
off_t num_blocks;
off_t used_blocks;
int32 inode_size;
int32 magic2;
int32 blocks_per_ag;
int32 ag_shift;
int32 num_ags;
int32 flags;
block_run log_blocks;
off_t log_start;
off_t log_end;
int32 magic3;
inode_addr root_dir;
inode_addr indices;
int32 pad[8];
} disk_super_block;
#define SUPER_BLOCK_FS_LENDIAN 'BIGE' /* BIGE */
#define SUPER_BLOCK_MAGIC1 'BFS1' /* BFS1 */
#define SUPER_BLOCK_MAGIC2 0xdd121031
#define SUPER_BLOCK_MAGIC3 0x15b6830e
#define SUPER_BLOCK_DISK_CLEAN 'CLEN' /* CLEN */
#define SUPER_BLOCK_DISK_DIRTY 'DIRT' /* DIRT */
static
char *
get_tupel(uint32 id)
{
static unsigned char tupel[5];
int16 i;
tupel[0] = 0xff & (id >> 24);
tupel[1] = 0xff & (id >> 16);
tupel[2] = 0xff & (id >> 8);
tupel[3] = 0xff & (id);
tupel[4] = 0;
for (i = 0;i < 4;i++)
if (tupel[i] < ' ' || tupel[i] > 128)
tupel[i] = '.';
return (char *)tupel;
}
static
void
dump_super_block(disk_super_block *superBlock)
{
dprintf("disk_super_block:\n");
dprintf(" name = %s\n",superBlock->name);
dprintf(" magic1 = %#08lx (%s) %s\n",superBlock->magic1, get_tupel(superBlock->magic1), (superBlock->magic1 == SUPER_BLOCK_MAGIC1 ? "valid" : "INVALID"));
dprintf(" fs_byte_order = %#08lx (%s)\n",superBlock->fs_byte_order, get_tupel(superBlock->fs_byte_order));
dprintf(" block_size = %lu\n",superBlock->block_size);
dprintf(" block_shift = %lu\n",superBlock->block_shift);
dprintf(" num_blocks = %Lu\n",superBlock->num_blocks);
dprintf(" used_blocks = %Lu\n",superBlock->used_blocks);
dprintf(" inode_size = %lu\n",superBlock->inode_size);
dprintf(" magic2 = %#08lx (%s) %s\n",superBlock->magic2, get_tupel(superBlock->magic2), (superBlock->magic2 == (int)SUPER_BLOCK_MAGIC2 ? "valid" : "INVALID"));
dprintf(" blocks_per_ag = %lu\n",superBlock->blocks_per_ag);
dprintf(" ag_shift = %lu (%lld bytes)\n",superBlock->ag_shift, 1LL << superBlock->ag_shift);
dprintf(" num_ags = %lu\n",superBlock->num_ags);
dprintf(" flags = %#08lx (%s)\n",superBlock->flags, get_tupel(superBlock->flags));
// dump_block_run(" log_blocks = ",superBlock->log_blocks);
dprintf(" log_start = %Lu\n",superBlock->log_start);
dprintf(" log_end = %Lu\n",superBlock->log_end);
dprintf(" magic3 = %#08lx (%s) %s\n",superBlock->magic3, get_tupel(superBlock->magic3), (superBlock->magic3 == SUPER_BLOCK_MAGIC3 ? "valid" : "INVALID"));
// dump_block_run(" root_dir = ",superBlock->root_dir);
// dump_block_run(" indices = ",superBlock->indices);
}
static
inline int64
divide_roundup(int64 num,int32 divisor)
{
return (num + divisor - 1) / divisor;
}
//----------------------------------------------------------------------
// End stolen BFS code
//----------------------------------------------------------------------
#if 0
// std_ops
static
status_t
std_ops(int32 op, ...)
{
TRACE(("%s: std_ops(0x%lx)\n", kModuleDebugName, op));
switch(op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
// read_block
static
status_t
read_block(fs_get_buffer get_buffer, struct fs_buffer_cache *cache,
off_t offset, size_t size, uchar **block)
{
size_t actualSize = 0;
status_t error = get_buffer(cache, offset, size, (void**)block,
&actualSize);
if (error == B_OK && actualSize != size) {
error = B_ERROR;
free(*block);
}
return error;
}
// bfs_fs_identify
/*! \brief Returns true if the given partition is a valid BFS partition.
See fs_identify_hook() for more information.
\todo Fill in partitionInfo->mounted_at with something useful.
*/
static
bool
bfs_fs_identify(int deviceFD, struct extended_partition_info *partitionInfo,
float *priority, fs_get_buffer get_buffer,
struct fs_buffer_cache *cache)
{
bool result = false;
TRACE(("%s: identify(%d, %p, offset: %lld)\n", kModuleDebugName, deviceFD,
partitionInfo, partitionInfo ? partitionInfo->info.offset : -1));
if (partitionInfo) {
uchar *buffer = NULL;
disk_super_block *superBlock = NULL;
status_t error = read_block(get_buffer, cache, 0, 1024, &buffer);
if (!error && buffer) {
superBlock = (disk_super_block*)(buffer+512);
// dump_super_block(superBlock);
if (superBlock->magic1 != (int32)SUPER_BLOCK_MAGIC1
|| superBlock->magic2 != (int32)SUPER_BLOCK_MAGIC2
|| superBlock->magic3 != (int32)SUPER_BLOCK_MAGIC3
|| (int32)superBlock->block_size != superBlock->inode_size
|| superBlock->fs_byte_order != SUPER_BLOCK_FS_LENDIAN
|| (1UL << superBlock->block_shift) != superBlock->block_size
|| superBlock->num_ags < 1
|| superBlock->ag_shift < 1
|| superBlock->blocks_per_ag < 1
|| superBlock->num_blocks < 10
|| superBlock->num_ags != divide_roundup(superBlock->num_blocks,1L << superBlock->ag_shift))
{
result = false;
} else {
if (partitionInfo->file_system_short_name)
strcpy(partitionInfo->file_system_short_name, "bfs");
if (partitionInfo->file_system_long_name)
strcpy(partitionInfo->file_system_long_name, "Be File System");
if (partitionInfo->volume_name)
strcpy(partitionInfo->volume_name, superBlock->name);
if (priority)
*priority = 0;
partitionInfo->file_system_flags = B_FS_IS_PERSISTENT
| B_FS_HAS_ATTR | B_FS_HAS_MIME | B_FS_HAS_QUERY;
result = true;
}
free(buffer);
}
}
return result;
}
static fs_module_info bfs_fs_module =
{
// module_info
{
BFS_FS_MODULE_NAME,
0, // better B_KEEP_LOADED?
std_ops
},
bfs_fs_identify
};
_EXPORT fs_module_info *modules[] =
{
&bfs_fs_module,
NULL
};
#endif // 0
// module
static status_t bfs_std_ops(int32 op, ...);
// scanning
static float bfs_identify_partition(int fd, partition_data *partition,
void **cookie);
static status_t bfs_scan_partition(int fd, partition_data *partition,
void *cookie);
static void bfs_free_identify_partition_cookie(partition_data *partition,
void *cookie);
static void bfs_free_partition_content_cookie(partition_data *partition);
static fs_module_info bfs_module = {
{
kBFSModuleName,
0,
bfs_std_ops
},
// B_PLAIN_C_ERROR:
// kPartitionTypeBFS, // pretty_name
"BFS Filesystem", // pretty_name
B_DISK_SYSTEM_IS_FILE_SYSTEM, // flags
// scanning
bfs_identify_partition, // identify_partition
bfs_scan_partition, // scan_partition
bfs_free_identify_partition_cookie, // free_identify_partition_cookie
bfs_free_partition_content_cookie, // free_partition_content_cookie
// querying
NULL, // supports_defragmenting
NULL, // supports_repairing
NULL, // supports_resizing
NULL, // supports_moving
NULL, // supports_setting_content_name
NULL, // supports_setting_content_parameters
NULL, // supports_initializing
NULL, // validate_resize
NULL, // validate_move
NULL, // validate_set_content_name
NULL, // validate_set_content_parameters
NULL, // validate_initialize
// shadow partition modification
NULL, // shadow_changed
// writing
NULL, // defragment
NULL, // repair
NULL, // resize
NULL, // move
NULL, // set_content_name
NULL, // set_content_parameters
NULL, // initialize
};
#ifdef __cplusplus
extern "C"
#endif
fs_module_info *modules[];
_EXPORT fs_module_info *modules[] =
{
&bfs_module,
NULL
};
// read_super_block
static
status_t
read_super_block(int fd, disk_super_block **_superBlock)
{
status_t error = B_OK;
ssize_t bytesRead;
// allocate space for the super block
disk_super_block *superBlock
= (disk_super_block*)malloc(sizeof(disk_super_block));
if (!superBlock)
return B_NO_MEMORY;
// read and check the super block
bytesRead = read_pos(fd, 512, superBlock, sizeof(disk_super_block));
if (bytesRead < 0) {
error = bytesRead;
} else if (bytesRead != sizeof(disk_super_block)
|| superBlock->magic1 != (int32)SUPER_BLOCK_MAGIC1
|| superBlock->magic2 != (int32)SUPER_BLOCK_MAGIC2
|| superBlock->magic3 != (int32)SUPER_BLOCK_MAGIC3
|| (int32)superBlock->block_size != superBlock->inode_size
|| superBlock->fs_byte_order != SUPER_BLOCK_FS_LENDIAN
|| (1UL << superBlock->block_shift) != superBlock->block_size
|| superBlock->num_ags < 1
|| superBlock->ag_shift < 1
|| superBlock->blocks_per_ag < 1
|| superBlock->num_blocks < 10
|| superBlock->num_ags != divide_roundup(superBlock->num_blocks,
1L << superBlock->ag_shift)) {
error = B_ERROR;
}
// set result / cleanup on failure
if (error == B_OK)
*_superBlock = superBlock;
else if (superBlock)
free(superBlock);
return error;
}
// bfs_std_ops
static
status_t
bfs_std_ops(int32 op, ...)
{
TRACE(("bfs: bfs_std_ops(0x%lx)\n", op));
switch(op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
// bfs_identify_partition
static
float
bfs_identify_partition(int fd, partition_data *partition, void **cookie)
{
disk_super_block *superBlock = NULL;
// check parameters
if (fd < 0 || !partition || !cookie)
return -1;
TRACE(("bfs: bfs_identify_partition(%d, %ld: %lld, %lld, %ld)\n", fd,
partition->id, partition->offset, partition->size,
partition->block_size));
// read super block
if (read_super_block(fd, &superBlock) != B_OK)
return -1;
*cookie = superBlock;
return 0.5;
}
// bfs_scan_partition
static
status_t
bfs_scan_partition(int fd, partition_data *partition, void *cookie)
{
disk_super_block *superBlock = NULL;
// check parameters
if (fd < 0 || !partition || !cookie)
return B_ERROR;
TRACE(("bfs: bfs_scan_partition(%d, %ld: %lld, %lld, %ld)\n", fd,
partition->id, partition->offset, partition->size,
partition->block_size));
superBlock = (disk_super_block*)cookie;
// fill in the partition_data structure
partition->content_size
= (off_t)superBlock->num_blocks * superBlock->block_size;
if (partition->content_size <= partition->size)
partition->status = B_PARTITION_VALID;
else
partition->status = B_PARTITION_CORRUPT;
partition->flags |= B_PARTITION_FILE_SYSTEM;
partition->block_size = superBlock->block_size;
partition->content_name = strdup(superBlock->name);
// (content_type is set by the system)
// (no content_parameters, content_cookie ?)
// free the super block
free(superBlock);
if (!partition->content_name)
return B_NO_MEMORY;
return B_OK;
}
// bfs_free_identify_partition_cookie
static
void
bfs_free_identify_partition_cookie(partition_data *partition, void *cookie)
{
if (cookie)
free(cookie);
}
// bfs_free_partition_content_cookie
static
void
bfs_free_partition_content_cookie(partition_data *partition)
{
if (partition)
partition->content_cookie = NULL;
}
@@ -1,635 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file iso9660.cpp
\brief disk_scanner filesystem module for iso9660 CD-ROM filesystems
<h5>iso9660</h5>
The standard to which this module is written is ECMA-119 second
edition, a freely available iso9660 equivalent.
<h5>Joliet</h5>
Joliet support comes courtesy of the following document:
http://www-plateau.cs.berkeley.edu/people/chaffee/jolspec.htm
As specified there, the existence of any of the following escape
sequences in a supplementary volume descriptor's "escape sequences"
field denotes a Joliet volume descriptor using unicode ucs-2
character encoding (2-byte characters, big-endian):
- UCS-2 Level 1: 0x252F40 == "%/@"
- UCS-2 Level 2: 0x252F43 == "%/C"
- UCS-2 Level 3: 0x252F45 == "%/E"
The following UCS-2 characters are considered illegal (we allow them,
printing out a warning if encountered):
- All values between 0x0000 and 0x001f inclusive == control chars
- 0x002A == '*'
- 0x002F == '/'
- 0x003A == ':'
- 0x003B == ';'
- 0x003F == '?'
- 0x005C == '\'
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <ByteOrder.h>
#include <disk_scanner.h>
#include <fs_info.h>
#include <KernelExport.h>
#include <disk_scanner/fs.h>
#define TRACE(x) ;
//#define TRACE(x) dprintf x
// misc constants
#define ISO9660_FS_MODULE_NAME "disk_scanner/fs/iso9660/v1"
static const char *kModuleDebugName = "fs/iso9660";
static const char *kISO9660Signature = "CD001";
static const uint32 kVolumeDescriptorLength = 2048;
#define ISO9660_VOLUME_IDENTIFIER_LENGTH 32
#define ISO9660_ESCAPE_SEQUENCE_LENGTH 32
//! Volume descriptor types
typedef enum {
ISO9660VD_BOOT,
ISO9660VD_PRIMARY,
ISO9660VD_SUPPLEMENTARY,
ISO9660VD_PARTITION,
ISO9660VD_TERMINATOR = 255
} iso9660_volume_descriptor_type;
/*! \brief The portion of the volume descriptor common to all
descriptor types.
*/
typedef struct iso9660_common_volume_descriptor {
uchar volume_descriptor_type;
char standard_identifier[5]; // should be 'CD001'
uchar volume_descriptor_version;
// Remaining bytes are unused
} __attribute__((packed)) iso9660_common_volume_descriptor;
/*! \brief Primary volume descriptor
*/
typedef struct iso9660_primary_volume_descriptor {
iso9660_common_volume_descriptor info;
uchar volume_flags;
char system_identifier[32];
char volume_identifier[ISO9660_VOLUME_IDENTIFIER_LENGTH];
uchar unused01[8];
uint32 volume_space_size_little_endian;
uint32 volume_space_size_big_endian;
uchar unused02[ISO9660_ESCAPE_SEQUENCE_LENGTH];
uint16 volume_set_size_little_endian;
uint16 volume_set_size_big_endian;
uint16 volume_sequence_number_little_endian;
uint16 volume_sequence_number_big_endian;
uint16 logical_block_size_little_endian;
uint16 logical_block_size_big_endian;
uint32 path_table_size_little_endian;
uint32 path_table_size_big_endian;
uint32 ignored02[4];
uchar root_directory_record[34];
char volume_set_identifier[28];
// Remaining bytes are disinteresting to us
} __attribute__((packed)) iso9660_primary_volume_descriptor;
typedef struct iso9660_supplementary_volume_descriptor {
iso9660_common_volume_descriptor info;
uchar volume_flags;
char system_identifier[32];
char volume_identifier[ISO9660_VOLUME_IDENTIFIER_LENGTH];
uchar unused01[8];
uint32 volume_space_size_little_endian;
uint32 volume_space_size_big_endian;
char escape_sequences[ISO9660_ESCAPE_SEQUENCE_LENGTH];
uint16 volume_set_size_little_endian;
uint16 volume_set_size_big_endian;
uint16 volume_sequence_number_little_endian;
uint16 volume_sequence_number_big_endian;
uint16 logical_block_size_little_endian;
uint16 logical_block_size_big_endian;
uint32 path_table_size_little_endian;
uint32 path_table_size_big_endian;
uint32 ignored02[4];
uchar root_directory_record[34];
char volume_set_identifier[28];
// Remaining bytes are disinteresting to us
} __attribute__((packed)) iso9660_supplementary_volume_descriptor;
typedef struct iso9660_directory_record {
uint8 length;
uint8 extended_attribute_record_length;
uint32 location_le;
uint32 location_be;
uint32 data_length;
uchar ignored[14];
uint16 volume_space_le;
} __attribute__((packed)) iso9660_directory_record;
/*! \brief Contains all the info of interest pertaining to an
iso9660 volume.
Currently supported character set encoding styles (in decreasing
order of precedence):
- Joliet (UCS-12 (16-bit unicode), which is converted to UTF-8)
- iso9660 (some absurdly tiny character set, but we actually allow UTF-8)
*/
struct iso9660_info {
iso9660_info();
~iso9660_info();
bool is_valid();
void set_iso9660_volume_name(const char *name, uint32 length);
void set_joliet_volume_name(const char *name, uint32 length);
const char* get_preferred_volume_name();
char *iso9660_volume_name;
char *joliet_volume_name;
void set_string(char **string, const char *new_string, uint32 new_length);
};
//----------------------------------------------------------------------------
// iso9660_info
//----------------------------------------------------------------------------
/*! \brief Creates a new iso9660_info struct with empty volume names.
\note Use the applicable set_XYZ_volume_name() functions rather than
messing with the volume name data members directly.
*/
iso9660_info::iso9660_info()
: iso9660_volume_name(NULL)
, joliet_volume_name(NULL)
{
}
/*! \brief Destroys the struct, freeing the volume name strings.
*/
iso9660_info::~iso9660_info()
{
if (iso9660_volume_name) {
free(iso9660_volume_name);
iso9660_volume_name = NULL;
}
if (joliet_volume_name) {
free(joliet_volume_name);
joliet_volume_name = NULL;
}
}
/*! \brief Returns true if a valid volume name exists.
*/
bool
iso9660_info::is_valid()
{
return iso9660_volume_name || joliet_volume_name;
}
/*! \brief Sets the iso9660 volume name.
\param name UTF-8 string containing the name.
\param length The length (in bytes) of the string.
*/
void
iso9660_info::set_iso9660_volume_name(const char *name, uint32 length)
{
set_string(&iso9660_volume_name, name, length);
}
/*! \brief Sets the Joliet volume name.
\param name UTF-8 string containing the name.
\param length The length (in bytes) of the string.
*/
void
iso9660_info::set_joliet_volume_name(const char *name, uint32 length)
{
set_string(&joliet_volume_name, name, length);
}
/*! \brief Returns the volume name of highest precedence.
Currently, the ordering is (decreasingly):
- Joliet
- iso9660
*/
const char*
iso9660_info::get_preferred_volume_name()
{
if (joliet_volume_name)
return joliet_volume_name;
else
return iso9660_volume_name;
}
/*! \brief Copies the given string into the old string, managing memory
deallocation and allocation as necessary.
*/
void
iso9660_info::set_string(char **string, const char *new_string, uint32 new_length)
{
TRACE(("%s: iso9660_info::set_string(%p (`%s'), `%s', %ld)\n", kModuleDebugName,
string, *string, new_string, new_length));
if (string) {
char *&old_string = *string;
if (old_string)
free(old_string);
if (new_string) {
old_string = (char*)malloc(new_length+1);
if (old_string) {
strncpy(old_string, new_string, new_length);
old_string[new_length] = 0;
}
} else {
old_string = NULL;
}
}
}
//----------------------------------------------------------------------------
// C functions
//----------------------------------------------------------------------------
/*! \brief Converts the given unicode character to utf8.
Courtesy Mr. Axel Dörfler.
\todo Once OpenTracker's locale kit is done, perhaps that functionality
should be used rather than outright stealing the code.
*/
static
void
unicode_to_utf8(uint32 c, char **out)
{
char *s = *out;
if (c < 0x80)
*(s++) = c;
else if (c < 0x800) {
*(s++) = 0xc0 | (c>>6);
*(s++) = 0x80 | (c & 0x3f);
} else if (c < 0x10000) {
*(s++) = 0xe0 | (c>>12);
*(s++) = 0x80 | ((c>>6) & 0x3f);
*(s++) = 0x80 | (c & 0x3f);
} else if (c <= 0x10ffff) {
*(s++) = 0xf0 | (c>>18);
*(s++) = 0x80 | ((c>>12) & 0x3f);
*(s++) = 0x80 | ((c>>6) & 0x3f);
*(s++) = 0x80 | (c & 0x3f);
}
*out = s;
}
static
const char*
volume_descriptor_type_to_string(iso9660_volume_descriptor_type type)
{
switch (type) {
case ISO9660VD_BOOT: return "boot";
case ISO9660VD_PRIMARY: return "primary";
case ISO9660VD_SUPPLEMENTARY: return "supplementary";
case ISO9660VD_PARTITION: return "partiton";
case ISO9660VD_TERMINATOR: return "terminator";
default: return "invalid";
}
}
static
void
dump_common_volume_descriptor(iso9660_common_volume_descriptor *common, const char *indent,
bool print_header)
{
if (print_header)
TRACE(("%siso9660_common_volume_descriptor:\n", indent));
TRACE(("%s volume descriptor type == %d (%s)\n", indent,
common->volume_descriptor_type,
volume_descriptor_type_to_string((iso9660_volume_descriptor_type)common->volume_descriptor_type)));
TRACE(("%s standard identifier == %.5s (%s)\n", indent, common->standard_identifier,
strncmp(common->standard_identifier, kISO9660Signature, 5) == 0 ? "valid" : "INVALID"));
TRACE(("%s volume descriptor version == %d\n", indent, common->volume_descriptor_version));
}
static
void
dump_directory_record(iso9660_directory_record *record, const char *indent);
static
void
dump_primary_volume_descriptor(iso9660_primary_volume_descriptor *primary, const char *indent,
bool print_header)
{
if (print_header)
TRACE(("%siso9660_primary_volume_descriptor:\n", indent));
dump_common_volume_descriptor(&(primary->info), indent, false);
TRACE(("%s volume identifier == `%.32s'\n", indent,
primary->volume_identifier));
TRACE(("%s volume space size == %ld\n", indent,
primary->volume_space_size_little_endian));
TRACE(("%s volume set size == %d\n", indent,
primary->volume_set_size_little_endian));
TRACE(("%s volume sequence number == %d\n", indent,
primary->volume_sequence_number_little_endian));
TRACE(("%s logical block size == %d\n", indent,
primary->logical_block_size_little_endian));
TRACE(("%s path table size == %ld\n", indent,
primary->path_table_size_little_endian));
TRACE(("%s volume set identifier == %.28s\n", indent,
primary->volume_set_identifier));
dump_directory_record((iso9660_directory_record*)primary->root_directory_record, indent);
}
static
void
dump_supplementary_volume_descriptor(iso9660_supplementary_volume_descriptor *supplementary, const char *indent,
bool print_header)
{
if (print_header)
TRACE(("%siso9660_supplementary_volume_descriptor:\n", indent));
dump_primary_volume_descriptor((iso9660_primary_volume_descriptor*)supplementary, indent, false);
TRACE(("%s escape sequences ==", indent));
for (int i = 0; i < ISO9660_ESCAPE_SEQUENCE_LENGTH; i++) {
TRACE((" %2x", supplementary->escape_sequences[i]));
if (i == ISO9660_ESCAPE_SEQUENCE_LENGTH/2-1)
TRACE(("\n "));
}
TRACE(("\n"));
}
static
void
dump_directory_record(iso9660_directory_record *record, const char *indent)
{
TRACE(("%s root directory record:\n", indent));
TRACE(("%s length == %d\n", indent, record->length));
TRACE(("%s location == %ld\n", indent, record->location_le));
TRACE(("%s data length == %ld\n", indent, record->data_length));
TRACE(("%s volume sequence number == %d\n", indent, record->volume_space_le));
}
static
status_t
check_common_volume_descriptor(iso9660_common_volume_descriptor *common)
{
status_t error = common ? B_OK : B_BAD_VALUE;
if (!error) {
error = strncmp(common->standard_identifier, kISO9660Signature,
5) == 0 ? B_OK : B_BAD_DATA;
}
return error;
}
// std_ops
static
status_t
std_ops(int32 op, ...)
{
TRACE(("%s: std_ops(0x%lx)\n", kModuleDebugName, op));
switch(op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
// read_block
static
status_t
read_block(fs_get_buffer get_buffer, struct fs_buffer_cache *cache,
off_t offset, size_t size, uchar **block)
{
size_t actualSize = 0;
status_t error = get_buffer(cache, offset, size, (void**)block,
&actualSize);
if (error == B_OK && actualSize != size) {
error = B_ERROR;
free(*block);
}
return error;
}
// iso9660_fs_identify
/*! \brief Returns true if the given partition is a valid iso9660 partition.
See fs_identify_hook() for more information.
\todo Fill in partitionInfo->mounted_at with something useful.
*/
static
bool
iso9660_fs_identify(int deviceFD, struct extended_partition_info *partitionInfo,
float *priority, fs_get_buffer get_buffer,
struct fs_buffer_cache *cache)
{
bool result = false;
uchar *buffer = NULL;
uint32 blockSize = partitionInfo->info.logical_block_size;
bool exit = false;
// The first 16 blocks are for "system use" only, and thus are
// irrelevant to us and generally just zeros
off_t offset = 16 * blockSize;
status_t error = B_OK;
TRACE(("%s: identify(%d, %p)\n", kModuleDebugName, deviceFD,
partitionInfo));
iso9660_info info;
// Read through the volume descriptors looking for a primary descriptor.
// If for some reason there are more than one primary descriptor, the
// volume name from the last encountered descriptor will be used.
while (!error && !exit) {// && count++ < 10) {
iso9660_common_volume_descriptor *common = NULL;
// Read the block containing the current descriptor
error = read_block(get_buffer, cache, offset, blockSize, &buffer);
offset += blockSize;
if (!error) {
common = (iso9660_common_volume_descriptor*)buffer;
error = check_common_volume_descriptor(common);
// dump_common_volume_descriptor(common, "", true);
}
// Handle each type of descriptor appropriately
if (!error) {
TRACE(("%s: found %s descriptor\n", kModuleDebugName,
volume_descriptor_type_to_string((iso9660_volume_descriptor_type)common->volume_descriptor_type)));
switch (common->volume_descriptor_type) {
case ISO9660VD_BOOT:
break;
case ISO9660VD_PRIMARY:
{
int i;
iso9660_primary_volume_descriptor *primary = (iso9660_primary_volume_descriptor*)buffer;
dump_primary_volume_descriptor(primary, " ", true);
// Cut off any trailing spaces from the volume id. Note
// that this allows for spaces INSIDE the volume id, even
// though that's not technically allowed by the standard;
// this was necessary to support certain RedHat 6.2 CD-ROMs
// from a certain Linux company who shall remain unnamed. ;-)
for (i = ISO9660_VOLUME_IDENTIFIER_LENGTH-1; i >= 0; i--) {
if (primary->volume_identifier[i] != 0x20)
break;
}
// Give a holler if the iso9660 name is already set
if (info.iso9660_volume_name) {
char str[ISO9660_VOLUME_IDENTIFIER_LENGTH+1];
strncpy(str, primary->volume_identifier, i+1);
str[i+1] = 0;
TRACE(("%s: duplicate iso9660 volume name found, using latter (`%s') "
"instead of former (`%s')\n", kModuleDebugName, str,
info.iso9660_volume_name));
}
info.set_iso9660_volume_name(primary->volume_identifier, i+1);
break;
}
case ISO9660VD_SUPPLEMENTARY:
{
iso9660_supplementary_volume_descriptor *supplementary = (iso9660_supplementary_volume_descriptor*)buffer;
dump_supplementary_volume_descriptor((iso9660_supplementary_volume_descriptor*)supplementary, " ", true);
// Copy and null terminate the escape sequences
char escapes[ISO9660_ESCAPE_SEQUENCE_LENGTH+1];
strncpy(escapes, supplementary->escape_sequences, ISO9660_ESCAPE_SEQUENCE_LENGTH);
escapes[ISO9660_ESCAPE_SEQUENCE_LENGTH] = 0;
// Check for a Joliet VD
if (strstr(escapes, "%/@") || strstr(escapes, "%/C") || strstr(escapes, "%/E")) {
char str[(ISO9660_VOLUME_IDENTIFIER_LENGTH*3/2)+1];
// Since we're dealing with 16-bit Unicode, each UTF-8 sequence
// will be at most 3 bytes long. So we need 3/2 as many chars as
// we start out with.
char *str_iterator = str;
uint16 ch;
// Walk thru the unicode volume name, converting to utf8 as we go.
for (int i = 0;
(ch = B_BENDIAN_TO_HOST_INT16(((uint16*)supplementary->volume_identifier)[i]))
&& i < ISO9660_VOLUME_IDENTIFIER_LENGTH;
i++) {
// Give a warning if the character is technically illegal
if ( ch <= 0x001F
|| ch == 0x002A
|| ch == 0x002F
|| ch == 0x003A
|| ch == 0x003B
|| ch == 0x003F
|| ch == 0x005C)
{
TRACE(("%s: warning: illegal Joliet character found: 0%4x\n",
kModuleDebugName, ch));
}
// Convert to utf-8
unicode_to_utf8(ch, &str_iterator);
}
*str_iterator = 0;
// Give a holler if the joliet name is already set
if (info.joliet_volume_name) {
TRACE(("%s: duplicate joliet volume name found, using latter (`%s') "
"instead of former (`%s')\n", kModuleDebugName, str,
info.joliet_volume_name));
}
info.set_joliet_volume_name(str, strlen(str));
} // end "if Joliet VD"
break;
}
case ISO9660VD_PARTITION:
break;
case ISO9660VD_TERMINATOR:
exit = true;
break;
default:
break;
}
}
if (buffer) {
free(buffer);
buffer = NULL;
}
}
switch (error) {
case B_OK:
if (info.is_valid()) {
result = true;
if (partitionInfo->file_system_short_name)
strcpy(partitionInfo->file_system_short_name, "iso9660");
if (partitionInfo->file_system_long_name)
strcpy(partitionInfo->file_system_long_name, "iso9660 CD-ROM File System");
partitionInfo->file_system_flags = B_FS_IS_PERSISTENT;
if (priority)
*priority = 0;
// Copy the volume name of highest precedence
if (partitionInfo->volume_name) {
TRACE(("%s: iso9660 name: `%s'\n", kModuleDebugName, info.iso9660_volume_name));
TRACE(("%s: joliet name: `%s'\n", kModuleDebugName, info.joliet_volume_name));
const char *name = info.get_preferred_volume_name();
int length = strlen(name);
if (length > B_FILE_NAME_LENGTH-1)
length = B_FILE_NAME_LENGTH-1;
strncpy(partitionInfo->volume_name, name, length);
partitionInfo->volume_name[length] = 0;
}
}
break;
case B_BAD_DATA:
TRACE(("%s: identify: bad signature\n", kModuleDebugName));
break;
default:
TRACE(("%s: identify error: 0x%lx\n", kModuleDebugName,
error));
break;
}
return result;
}
static fs_module_info iso9660_fs_module =
{
// module_info
{
ISO9660_FS_MODULE_NAME,
0, // better B_KEEP_LOADED?
std_ops
},
iso9660_fs_identify,
};
_EXPORT fs_module_info *modules[] =
{
&iso9660_fs_module,
NULL
};
@@ -1,8 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel disk_scanner partition ;
UsePrivateHeaders $(DOT) ;
#KernelAddon intel : kernel disk_scanner partition :
# intel.cpp
#;
@@ -1,425 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel.cpp
\brief disk_scanner partition module for "intel" style partitions.
*/
// TODO: The implementation is very strict right now. It rejects a partition
// completely, if it finds an error in its partition tables. We should see,
// what error can be handled gracefully, e.g. by ignoring the partition
// descriptor or the whole partition table sector.
#include <errno.h>
#include <new.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <disk_scanner.h>
#include <KernelExport.h>
#include <disk_scanner/partition.h>
#include "intel_parameters.h"
#include "intel_partition_map.h"
#define TRACE(x) ;
//#define TRACE(x) dprintf x
#define INTEL_PARTITION_MODULE_NAME "disk_scanner/partition/intel/v1"
// partition module identifier
static const char *const kShortModuleName = "intel";
// Maximal number of logical partitions per extended partition we allow.
static const int32 kMaxLogicalPartitionCount = 128;
// PartitionMapParser
class PartitionMapParser {
public:
PartitionMapParser(int deviceFD, off_t sessionOffset, off_t sessionSize,
int32 blockSize);
~PartitionMapParser();
status_t Parse(const uint8 *block, PartitionMap *map);
int32 CountPartitions() const;
const Partition *PartitionAt(int32 index) const;
private:
status_t _ParsePrimary(const partition_table_sector *pts);
status_t _ParseExtended(PrimaryPartition *primary, off_t offset);
status_t _ReadPTS(off_t offset, partition_table_sector *pts = NULL);
private:
int fDeviceFD;
off_t fSessionOffset;
off_t fSessionSize;
int32 fBlockSize;
partition_table_sector *fPTS; // while parsing
PartitionMap *fMap; //
};
// constructor
PartitionMapParser::PartitionMapParser(int deviceFD, off_t sessionOffset,
off_t sessionSize, int32 blockSize)
: fDeviceFD(deviceFD),
fSessionOffset(sessionOffset),
fSessionSize(sessionSize),
fBlockSize(blockSize),
fPTS(NULL),
fMap(NULL)
{
}
// destructor
PartitionMapParser::~PartitionMapParser()
{
}
// Parse
status_t
PartitionMapParser::Parse(const uint8 *block, PartitionMap *map)
{
status_t error = (map ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
fMap = map;
fMap->Unset();
if (block) {
const partition_table_sector *pts
= (const partition_table_sector*)block;
error = _ParsePrimary(pts);
} else {
partition_table_sector pts;
error = _ReadPTS(0, &pts);
if (error == B_OK)
error = _ParsePrimary(&pts);
}
if (error == B_OK && !fMap->Check(fSessionSize, fBlockSize))
error = B_BAD_DATA;
fMap = NULL;
}
return error;
}
// _ParsePrimary
status_t
PartitionMapParser::_ParsePrimary(const partition_table_sector *pts)
{
status_t error = (pts ? B_OK : B_BAD_VALUE);
// check the signature
if (error == B_OK && pts->signature != kPartitionTableSectorSignature) {
TRACE(("intel: _ParsePrimary(): invalid PTS signature\n"));
error = B_BAD_DATA;
}
// examine the table
if (error == B_OK) {
for (int32 i = 0; i < 4; i++) {
const partition_descriptor *descriptor = &pts->table[i];
PrimaryPartition *partition = fMap->PrimaryPartitionAt(i);
partition->SetTo(descriptor, 0, fBlockSize);
// fail, if location is bad
if (!partition->CheckLocation(fSessionSize, fBlockSize)) {
error = B_BAD_DATA;
break;
}
}
}
// allocate a PTS buffer
if (error == B_OK) {
fPTS = new(nothrow) partition_table_sector;
if (!fPTS)
error = B_NO_MEMORY;
}
// parse extended partitions
if (error == B_OK) {
for (int32 i = 0; error == B_OK && i < 4; i++) {
PrimaryPartition *primary = fMap->PrimaryPartitionAt(i);
if (primary->IsExtended())
error = _ParseExtended(primary, primary->Offset());
}
}
// cleanup
if (fPTS) {
delete fPTS;
fPTS = NULL;
}
return error;
}
// _ParseExtended
status_t
PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset)
{
status_t error = B_OK;
int32 partitionCount = 0;
while (error == B_OK) {
// check for cycles
if (++partitionCount > kMaxLogicalPartitionCount) {
TRACE(("intel: _ParseExtended(): Maximal number of logical "
"partitions for extended partition reached. Cycle?\n"));
error = B_BAD_DATA;
}
// read the PTS
if (error == B_OK)
error = _ReadPTS(offset);
// check the signature
if (error == B_OK
&& fPTS->signature != kPartitionTableSectorSignature) {
TRACE(("intel: _ParseExtended(): invalid PTS signature\n"));
error = B_BAD_DATA;
}
// ignore the PTS, if any error occured till now
if (error != B_OK) {
TRACE(("intel: _ParseExtended(): ignoring this PTS\n"));
error = B_OK;
break;
}
// examine the table
LogicalPartition extended;
LogicalPartition nonExtended;
if (error == B_OK) {
for (int32 i = 0; error == B_OK && i < 4; i++) {
const partition_descriptor *descriptor = &fPTS->table[i];
LogicalPartition *partition = NULL;
if (!descriptor->is_empty()) {
if (descriptor->is_extended()) {
if (extended.IsEmpty()) {
extended.SetTo(descriptor, offset, fBlockSize,
primary);
partition = &extended;
} else {
// only one extended partition allowed
error = B_BAD_DATA;
TRACE(("intel: _ParseExtended(): "
"only one extended partition allowed\n"));
}
} else {
if (nonExtended.IsEmpty()) {
nonExtended.SetTo(descriptor, offset, fBlockSize,
primary);
partition = &nonExtended;
} else {
// only one non-extended partition allowed
error = B_BAD_DATA;
TRACE(("intel: _ParseExtended(): only one "
"non-extended partition allowed\n"));
}
}
// check the partition's location
if (partition && !partition->CheckLocation(fSessionSize,
fBlockSize)) {
error = B_BAD_DATA;
}
}
}
}
// add non-extended partition to list
if (error == B_OK && !nonExtended.IsEmpty()) {
LogicalPartition *partition
= new(nothrow) LogicalPartition(nonExtended);
if (partition)
primary->AddLogicalPartition(partition);
else
error = B_NO_MEMORY;
}
// prepare to parse next extended partition
if (error == B_OK && !extended.IsEmpty())
offset = extended.Offset();
else
break;
}
return error;
}
// _ReadPTS
status_t
PartitionMapParser::_ReadPTS(off_t offset, partition_table_sector *pts)
{
status_t error = B_OK;
if (!pts)
pts = fPTS;
int32 toRead = sizeof(partition_table_sector);
// check the offset
if (offset < 0 || offset + toRead > fSessionSize) {
error = B_BAD_VALUE;
TRACE(("intel: _ReadPTS(): bad offset: %Ld\n", offset));
// read
} else if (read_pos(fDeviceFD, fSessionOffset + offset, pts, toRead)
!= toRead) {
error = errno;
if (error == B_OK)
error = B_IO_ERROR;
TRACE(("intel: _ReadPTS(): reading the PTS failed: %s\n",
strerror(error)));
}
return error;
}
// std_ops
static
status_t
std_ops(int32 op, ...)
{
TRACE(("intel: std_ops(0x%lx)\n", op));
switch(op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
// read_partition_map
static
bool
read_partition_map(int deviceFD, const session_info *sessionInfo,
const uchar *block, PartitionMap *map)
{
bool result = true;
off_t sessionOffset = sessionInfo->offset;
off_t sessionSize = sessionInfo->size;
int32 blockSize = sessionInfo->logical_block_size;
TRACE(("intel: read_partition_map(%d, %lld, %lld, %p, %ld)\n", deviceFD,
sessionOffset, sessionSize, block, blockSize));
// check block size
if (result) {
result = ((uint32)blockSize >= sizeof(partition_table_sector));
if (!result) {
TRACE(("intel: read_partition_map: bad block size: %ld, should be "
">= %ld\n", blockSize, sizeof(partition_table_sector)));
}
}
// read the partition structure
if (result) {
PartitionMapParser parser(deviceFD, sessionOffset, sessionSize,
blockSize);
result = (parser.Parse(block, map) == B_OK);
}
return result;
}
// intel_identify
static
bool
intel_identify(int deviceFD, const session_info *sessionInfo,
const uchar *block)
{
TRACE(("intel: identify(%d, %lld, %lld, %p, %ld)\n", deviceFD,
sessionInfo->offset, sessionInfo->size, block,
sessionInfo->logical_block_size));
PartitionMap map;
return read_partition_map(deviceFD, sessionInfo, block, &map);
}
// intel_get_nth_info
static
status_t
intel_get_nth_info(int deviceFD, const session_info *sessionInfo,
const uchar *block, int32 index,
extended_partition_info *partitionInfo)
{
status_t error = B_OK;
off_t sessionOffset = sessionInfo->offset;
TRACE(("intel: get_nth_info(%d, %lld, %lld, %p, %ld, %ld)\n", deviceFD,
sessionOffset, sessionInfo->size, block,
sessionInfo->logical_block_size, index));
PartitionMap map;
if (read_partition_map(deviceFD, sessionInfo, block, &map)) {
if (Partition *partition = map.PartitionAt(index)) {
if (partition->IsEmpty()) {
// empty partition
partitionInfo->info.offset = sessionOffset;
partitionInfo->info.size = 0;
partitionInfo->flags
= B_HIDDEN_PARTITION | B_EMPTY_PARTITION;
} else {
// non-empty partition
partitionInfo->info.offset
= partition->Offset() + sessionOffset;
partitionInfo->info.size = partition->Size();
if (partition->IsExtended())
partitionInfo->flags = B_HIDDEN_PARTITION;
else
partitionInfo->flags = 0;
}
partitionInfo->partition_name[0] = '\0';
partition->GetTypeString(partitionInfo->partition_type);
} else
error = B_ENTRY_NOT_FOUND;
} else // couldn't read partition map -- we shouldn't be in get_nth_info()
error = B_BAD_DATA;
return error;
}
// intel_get_partitioning_params
static
status_t
intel_get_partitioning_params(int deviceFD,
const struct session_info *sessionInfo,
char *buffer, size_t bufferSize,
size_t *actualSize)
{
status_t error = B_OK;
PartitionMap map;
if (!read_partition_map(deviceFD, sessionInfo, NULL, &map)) {
// couldn't read partition map, set up a default one:
// four empty primary partitions
map.Unset();
}
// get the parameter length
size_t length = 0;
if (error == B_OK) {
ParameterUnparser unparser;
error = unparser.GetParameterLength(&map, &length);
}
// write the parameters
if (error == B_OK && length <= bufferSize) {
ParameterUnparser unparser;
error = unparser.Unparse(&map, buffer, bufferSize);
}
// set the results
if (error == B_OK)
*actualSize = length;
return error;
}
// intel_partition
static
status_t
intel_partition(int deviceFD, const struct session_info *sessionInfo,
const char *parameters)
{
// not yet supported
return B_UNSUPPORTED;
}
static partition_module_info intel_partition_module =
{
// module_info
{
INTEL_PARTITION_MODULE_NAME,
0, // better B_KEEP_LOADED?
std_ops
},
kShortModuleName,
intel_identify,
intel_get_nth_info,
intel_get_partitioning_params,
intel_partition,
};
extern "C" partition_module_info *modules[];
_EXPORT partition_module_info *modules[] =
{
&intel_partition_module,
NULL
};
@@ -1,390 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel_parameters.cpp
\brief Class implementations for "intel" style partitioning
parameter support.
*/
#include <ctype.h>
#include <new.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intel_parameters.h"
#include "intel_partition_map.h"
// Grammar for parameters:
//
// partition ::= "{" ptsoffset "," offset "," size "," type ","
// active "}"
// primary ::= "{" partition+ "}"
// partition_map ::= primary primary primary primary
// longest token (including terminating null)
const int32 kMaxTokenLen = 256;
// Tokenizer
// constructor
Tokenizer::Tokenizer()
: fInput(NULL),
fPosition(0),
fLastPosition(0)
{
}
// constructor
Tokenizer::Tokenizer(const char *input)
: fInput(input),
fPosition(0),
fLastPosition(0)
{
}
// SetTo
void
Tokenizer::SetTo(const char *input)
{
fInput = input;
fPosition = 0;
fLastPosition = 0;
}
// GetNextToken
int32
Tokenizer::GetNextToken(char *buffer)
{
int32 kind = TOKEN_ERROR;
fLastPosition = fPosition;
// skip WS
_SkipWhiteSpace();
switch (fInput[fPosition]) {
case '{':
case '}':
case ',':
kind = fInput[fPosition];
fPosition++;
break;
case '\0':
kind = TOKEN_EOF;
break;
default:
{
if (isdigit(fInput[fPosition])) {
int32 startPos = fPosition;
while (isdigit(fInput[fPosition]))
fPosition++;
int32 len = fPosition - startPos;
if (len < kMaxTokenLen) {
if (buffer) {
memcpy(buffer, fInput + startPos, len);
buffer[len] = '\0';
}
kind = TOKEN_NUMBER;
} else {
printf("token too long at: %ld\n", startPos);
kind = TOKEN_ERROR;
}
}
break;
}
}
return kind;
}
// ExpectToken
bool
Tokenizer::ExpectToken(int32 kind, char *buffer)
{
bool result = (GetNextToken(buffer) == kind);
if (!result)
PutLastToken();
return result;
}
// ReadNumber
bool
Tokenizer::ReadNumber(int64 &number)
{
char buffer[kMaxTokenLen];
bool result = ExpectToken(TOKEN_NUMBER, buffer);
if (result)
number = atoll(buffer);
return result;
}
// _SkipWhiteSpace
void
Tokenizer::_SkipWhiteSpace()
{
while (fInput[fPosition] != '\0' && isspace(fInput[fPosition]))
fPosition++;
}
// ParameterParser
// constructor
ParameterParser::ParameterParser()
: fTokenizer(),
fParseError(B_OK),
fMap(NULL)
{
}
// Parse
status_t
ParameterParser::Parse(const char *parameters, PartitionMap *map)
{
status_t error = (parameters && map ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
// init parser
fParseError = B_OK;
fTokenizer.SetTo(parameters);
fMap = map;
// partition_map ::= primary primary primary primary
if (_ParsePrimaryPartition(fMap->PrimaryPartitionAt(0))
&& _ParsePrimaryPartition(fMap->PrimaryPartitionAt(1))
&& _ParsePrimaryPartition(fMap->PrimaryPartitionAt(2))
&& _ParsePrimaryPartition(fMap->PrimaryPartitionAt(3))
&& fTokenizer.ReadEOF()) {
// successfully parsed
} else
_ErrorOccurred();
// cleanup / set results
fMap = NULL;
error = fParseError;
}
return error;
}
// _ParsePrimaryPartition
bool
ParameterParser::_ParsePrimaryPartition(PrimaryPartition *primary)
{
// primary ::= "{" partition+ "}"
if (fTokenizer.ReadOpen()
&& _ParsePartition(primary)) {
while (_NoError() && !fTokenizer.ReadClose()) {
LogicalPartition *partition = new(nothrow) LogicalPartition;
if (partition) {
if (_ParsePartition(partition))
primary->AddLogicalPartition(partition);
else
delete partition;
} else
_ErrorOccurred(B_NO_MEMORY);
}
} else
_ErrorOccurred();
return _NoError();
}
// _ParsePartition
bool
ParameterParser::_ParsePartition(Partition *partition)
{
// partition ::= "{" ptsoffset "," offset "," size "," type ","
// active "}"
int64 ptsOffset, offset, size, type, active;
if (fTokenizer.ReadOpen()
&& fTokenizer.ReadNumber(ptsOffset)
&& fTokenizer.ReadComma()
&& fTokenizer.ReadNumber(offset)
&& fTokenizer.ReadComma()
&& fTokenizer.ReadNumber(size)
&& fTokenizer.ReadComma()
&& fTokenizer.ReadNumber(type)
&& fTokenizer.ReadComma()
&& fTokenizer.ReadNumber(active)
&& fTokenizer.ReadClose()) {
if (ptsOffset >= 0 && offset >= 0 && size >= 0
&& type >= 0 && type < 256) {
partition->SetPTSOffset(ptsOffset);
partition->SetOffset(offset);
partition->SetSize(size);
partition->SetType((uint8)type);
partition->SetActive(active);
} else
_ErrorOccurred(B_BAD_VALUE);
} else
_ErrorOccurred();
return _NoError();
}
// _ErrorOccurred
void
ParameterParser::_ErrorOccurred(status_t error)
{
if (fParseError == B_OK)
fParseError = error;
}
// ParameterUnparser
// constructor
ParameterUnparser::ParameterUnparser()
: fMap(NULL),
fParameters(NULL),
fPosition(0),
fSize(0),
fDryRun(false),
fUnparseError(B_OK)
{
}
// GetParameterLength
status_t
ParameterUnparser::GetParameterLength(const PartitionMap *map, size_t *length)
{
status_t error = (map && length ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
// init unparser for a dry run
fUnparseError = B_OK;
fMap = map;
char buffer[kMaxTokenLen];
fParameters = buffer;
fPosition = 0;
fSize = 0;
fDryRun = true;
// dry run -- get the parameter size
if (_UnparsePartitionMap())
*length = fPosition + 1;
// cleanup / set results
fMap = NULL;
error = fUnparseError;
}
return error;
}
// Unparse
status_t
ParameterUnparser::Unparse(const PartitionMap *map, char *parameters,
size_t size)
{
status_t error = (map && parameters ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
// init unparser
fUnparseError = B_OK;
fMap = map;
fParameters = parameters;
fPosition = 0;
fSize = size;
fDryRun = false;
// unparse the partition map
_UnparsePartitionMap();
// cleanup / set results
fMap = NULL;
error = fUnparseError;
}
return error;
}
// _UnparsePartitionMap
bool
ParameterUnparser::_UnparsePartitionMap()
{
if (_UnparsePrimaryPartition(fMap->PrimaryPartitionAt(0))
&& _UnparsePrimaryPartition(fMap->PrimaryPartitionAt(1))
&& _UnparsePrimaryPartition(fMap->PrimaryPartitionAt(2))
&& _UnparsePrimaryPartition(fMap->PrimaryPartitionAt(3))) {
// successfully unparsed
}
return _NoError();
}
// _UnparsePrimaryPartition
bool
ParameterUnparser::_UnparsePrimaryPartition(const PrimaryPartition *primary)
{
// primary ::= "{" partition+ "}"
if (_WriteOpen() && _UnparsePartition(primary)) {
for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) {
const LogicalPartition *partition = primary->LogicalPartitionAt(i);
if (!_UnparsePartition(partition))
break;
}
if (_NoError())
_WriteClose();
}
return _NoError();
}
// _UnparsePartition
bool
ParameterUnparser::_UnparsePartition(const Partition *partition)
{
// partition ::= "{" ptsoffset "," offset "," size "," type ","
// active "}"
if (_WriteOpen()
&& _WriteNumber(partition->PTSOffset())
&& _WriteComma()
&& _WriteNumber(partition->Offset())
&& _WriteComma()
&& _WriteNumber(partition->Size())
&& _WriteComma()
&& _WriteNumber(partition->Type())
&& _WriteComma()
&& _WriteNumber(partition->Active() ? 1 : 0)
&& _WriteClose()) {
// success
}
return _NoError();
}
// _Write
bool
ParameterUnparser::_Write(const char *str)
{
size_t len = strlen(str);
if (!fDryRun) {
if (fSize > fPosition + len)
strcpy(fParameters + fPosition, str);
else
_ErrorOccurred(B_BAD_VALUE);
}
fPosition += len;
return _NoError();
}
// _WriteNumber
bool
ParameterUnparser::_WriteNumber(int64 number)
{
char buffer[kMaxTokenLen];
sprintf(buffer, "%lld", number);
return _Write(buffer);
}
// _ErrorOccurred
void
ParameterUnparser::_ErrorOccurred(status_t error)
{
if (fUnparseError == B_OK)
fUnparseError = error;
}
/*
// main
int
main()
{
const char *parameters = "{{ 0, 10, 1, 0}{ 0, 3, 1, 0}}"
"{{10, 13, 1, 1}}"
"{{23, 7, 1, 0}}"
"{{30, 9, 1, 0}}";
ParameterParser parser;
status_t error = parser.Parse(parameters);
if (error != B_OK)
printf("error while parsing: %s\n", strerror(error));
return 0;
}
*/
@@ -1,110 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel_parameters.h
\brief Class interface definitions for "intel" style partitioning
parameter support.
*/
#ifndef _INTEL_PARAMETERS_H
#define _INTEL_PARAMETERS_H
#include <SupportDefs.h>
class Partition;
class PartitionMap;
class PrimaryPartition;
// tokens
enum {
TOKEN_ERROR = -1,
TOKEN_EOF = '\0',
TOKEN_OPEN = '{',
TOKEN_CLOSE = '}',
TOKEN_COMMA = ',',
TOKEN_NUMBER = '0',
};
// Tokenizer
class Tokenizer {
public:
Tokenizer();
Tokenizer(const char *input);
void SetTo(const char *input);
int32 GetNextToken(char *buffer = NULL);
void PutLastToken() { fPosition = fLastPosition; }
bool ExpectToken(int32 kind, char *buffer = NULL);
bool ReadOpen() { return (ExpectToken(TOKEN_OPEN)); }
bool ReadClose() { return (ExpectToken(TOKEN_CLOSE)); }
bool ReadComma() { return (ExpectToken(TOKEN_COMMA)); }
bool ReadEOF() { return (ExpectToken(TOKEN_EOF)); }
bool ReadNumber(int64 &number);
private:
void _SkipWhiteSpace();
private:
const char *fInput;
int32 fPosition;
int32 fLastPosition;
};
// ParameterParser
class ParameterParser {
public:
ParameterParser();
~ParameterParser() {}
status_t Parse(const char *parameters, PartitionMap *map);
private:
bool _ParsePrimaryPartition(PrimaryPartition *primary);
bool _ParsePartition(Partition *partition);
void _ErrorOccurred(status_t error = B_ERROR);
bool _NoError() const { return (fParseError == B_OK); }
private:
Tokenizer fTokenizer;
status_t fParseError;
PartitionMap *fMap;
};
// ParameterUnparser
class ParameterUnparser {
public:
ParameterUnparser();
~ParameterUnparser() {}
status_t GetParameterLength(const PartitionMap *map, size_t *length);
status_t Unparse(const PartitionMap *map, char *parameters, size_t length);
private:
bool _UnparsePartitionMap();
bool _UnparsePrimaryPartition(const PrimaryPartition *primary);
bool _UnparsePartition(const Partition *partition);
bool _Write(const char *str);
bool _WriteOpen() { return _Write("{"); }
bool _WriteClose() { return _Write("}"); }
bool _WriteComma() { return _Write(","); }
bool _WriteNumber(int64 number);
void _ErrorOccurred(status_t error = B_ERROR);
bool _NoError() const { return (fUnparseError == B_OK); }
private:
const PartitionMap *fMap;
char *fParameters;
size_t fPosition;
size_t fSize;
bool fDryRun;
status_t fUnparseError;
};
#endif // _INTEL_PARAMETERS_H
@@ -1,476 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel_partition_map.cpp
\brief Definitions for "intel" style partitions and implementation
of related classes.
*/
#include <new.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
#include "intel_partition_map.h"
#define TRACE(x) ;
//#define TRACE(x) dprintf x
// partition_type
struct partition_type {
uint8 type;
char *name;
};
static const struct partition_type kPartitionTypes[] = {
// these entries must be sorted by type (currently not)
{ 0x00, "empty" },
{ 0x01, "FAT 12-bit" },
{ 0x02, "Xenix root" },
{ 0x03, "Xenix user" },
{ 0x04, "FAT 16-bit (dos 3.0)" },
{ 0x05, "Extended Partition" },
{ 0x06, "FAT 16-bit (dos 3.31)" },
{ 0x07, "OS/2 IFS, Windows NT, Advanced Unix" },
{ 0x0b, "FAT 32-bit" },
{ 0x0c, "FAT 32-bit, LBA-mapped" },
{ 0x0d, "FAT 16-bit, LBA-mapped" },
{ 0x0f, "Extended Partition, LBA-mapped" },
{ 0x42, "Windows 2000 marker (switches to a proprietary partition table)" },
{ 0x4d, "QNX 4" },
{ 0x4e, "QNX 4 2nd part" },
{ 0x4f, "QNX 4 3rd part" },
{ 0x78, "XOSL boot loader" },
{ 0x82, "Linux swapfile" },
{ 0x83, "Linux native" },
{ 0x85, "Linux extendend partition" },
{ 0xa5, "FreeBSD" },
{ 0xa6, "OpenBSD" },
{ 0xa7, "NextSTEP" },
{ 0xa8, "MacOS X" },
{ 0xa9, "NetBSD" },
{ 0xab, "MacOS X boot" },
{ 0xbe, "Solaris 8 boot" },
{ 0xeb, "BeOS" },
{ 0, NULL }
};
// partition_type_string
static
const char *
partition_type_string(uint8 type)
{
int32 i;
for (i = 0; kPartitionTypes[i].name ; i++)
{
if (type == kPartitionTypes[i].type)
return kPartitionTypes[i].name;
}
return NULL;
}
// get_partition_type_string
void
get_partition_type_string(uint8 type, char *buffer)
{
if (buffer) {
if (const char *str = partition_type_string(type))
strcpy(buffer, str);
else
sprintf(buffer, "Unrecognized Type 0x%x", type);
}
}
// Partition
// constructor
Partition::Partition()
: fPTSOffset(0),
fOffset(0),
fSize(0),
fType(0),
fActive(false)
{
}
// constructor
Partition::Partition(const partition_descriptor *descriptor,off_t ptsOffset,
off_t baseOffset, int32 blockSize)
: fPTSOffset(0),
fOffset(0),
fSize(0),
fType(0),
fActive(false)
{
SetTo(descriptor, ptsOffset, baseOffset, blockSize);
}
// SetTo
void
Partition::SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize)
{
TRACE(("Partition::SetTo(): active: %x\n", descriptor->active));
fPTSOffset = ptsOffset;
fOffset = baseOffset + (off_t)descriptor->start * blockSize;
fSize = (off_t)descriptor->size * blockSize;
fType = descriptor->type;
fActive = descriptor->active;
if (fSize == 0)
Unset();
}
// Unset
void
Partition::Unset()
{
fPTSOffset = 0;
fOffset = 0;
fSize = 0;
fType = 0;
fActive = false;
}
// CheckLocation
bool
Partition::CheckLocation(off_t sessionSize, int32 blockSize) const
{
// offsets and size must be block aligned, PTS and partition must lie
// within the session
return (fPTSOffset % blockSize == 0
&& fOffset % blockSize == 0
&& fSize % blockSize == 0
&& fPTSOffset >= 0 && fPTSOffset < sessionSize
&& fOffset >= 0 && fOffset + fSize <= sessionSize);
}
// PrimaryPartition
// constructor
PrimaryPartition::PrimaryPartition()
: Partition(),
fHead(NULL),
fTail(NULL),
fLogicalPartitionCount(0)
{
}
// constructor
PrimaryPartition::PrimaryPartition(const partition_descriptor *descriptor,
off_t ptsOffset, int32 blockSize)
: Partition(),
fHead(NULL),
fTail(NULL),
fLogicalPartitionCount(0)
{
SetTo(descriptor, ptsOffset, blockSize);
}
// SetTo
void
PrimaryPartition::SetTo(const partition_descriptor *descriptor,
off_t ptsOffset, int32 blockSize)
{
Unset();
Partition::SetTo(descriptor, ptsOffset, 0, blockSize);
}
// Unset
void
PrimaryPartition::Unset()
{
while (LogicalPartition *partition = fHead) {
fHead = partition->Next();
delete partition;
}
fHead = NULL;
fTail = NULL;
fLogicalPartitionCount = 0;
Partition::Unset();
}
// LogicalPartitionAt
LogicalPartition *
PrimaryPartition::LogicalPartitionAt(int32 index) const
{
LogicalPartition *partition = NULL;
if (index >= 0 && index < fLogicalPartitionCount) {
for (partition = fHead; index > 0; index--)
partition = partition->Next();
}
return partition;
}
// AddLogicalPartition
void
PrimaryPartition::AddLogicalPartition(LogicalPartition *partition)
{
if (partition) {
partition->SetPrimaryPartition(this);
if (fTail) {
fTail->SetNext(partition);
fTail = partition;
} else
fHead = fTail = partition;
partition->SetNext(NULL);
fLogicalPartitionCount++;
}
}
// LogicalPartition
// constructor
LogicalPartition::LogicalPartition()
: Partition(),
fPrimary(NULL),
fNext(NULL)
{
}
// constructor
LogicalPartition::LogicalPartition(const partition_descriptor *descriptor,
off_t ptsOffset, int32 blockSize,
PrimaryPartition *primary)
: Partition(),
fPrimary(NULL),
fNext(NULL)
{
SetTo(descriptor, ptsOffset, blockSize, primary);
}
// SetTo
void
LogicalPartition::SetTo(const partition_descriptor *descriptor,
off_t ptsOffset, int32 blockSize,
PrimaryPartition *primary)
{
Unset();
if (descriptor && primary) {
off_t baseOffset = (descriptor->is_extended() ? primary->Offset()
: ptsOffset);
Partition::SetTo(descriptor, ptsOffset, baseOffset, blockSize);
fPrimary = primary;
}
}
// Unset
void
LogicalPartition::Unset()
{
fPrimary = NULL;
fNext = NULL;
Partition::Unset();
}
// PartitionMap
// constructor
PartitionMap::PartitionMap()
{
}
// destructor
PartitionMap::~PartitionMap()
{
}
// Unset
void
PartitionMap::Unset()
{
for (int32 i = 0; i < 4; i++)
fPrimaries[i].Unset();
}
// PrimaryPartitionAt
PrimaryPartition *
PartitionMap::PrimaryPartitionAt(int32 index)
{
PrimaryPartition *partition = NULL;
if (index >= 0 && index < 4)
partition = fPrimaries + index;
return partition;
}
// PrimaryPartitionAt
const PrimaryPartition *
PartitionMap::PrimaryPartitionAt(int32 index) const
{
const PrimaryPartition *partition = NULL;
if (index >= 0 && index < 4)
partition = fPrimaries + index;
return partition;
}
// CountPartitions
int32
PartitionMap::CountPartitions() const
{
int32 count = 4;
for (int32 i = 0; i < 4; i++)
count += fPrimaries[i].CountLogicalPartitions();
return count;
}
// PartitionAt
Partition *
PartitionMap::PartitionAt(int32 index)
{
Partition *partition = NULL;
int32 count = CountPartitions();
if (index >= 0 && index < count) {
if (index < 4)
partition = fPrimaries + index;
else {
index -= 4;
int32 primary = 0;
while (index >= fPrimaries[primary].CountLogicalPartitions()) {
index -= fPrimaries[primary].CountLogicalPartitions();
primary++;
}
partition = fPrimaries[primary].LogicalPartitionAt(index);
}
}
return partition;
}
// PartitionAt
const Partition *
PartitionMap::PartitionAt(int32 index) const
{
return const_cast<PartitionMap*>(this)->PartitionAt(index);
}
// cmp_partition_offset
static
int
cmp_partition_offset(const void *p1, const void *p2)
{
const Partition *partition1 = *(const Partition**)p1;
const Partition *partition2 = *(const Partition**)p2;
if (partition1->Offset() < partition2->Offset())
return -1;
else if (partition1->Offset() > partition2->Offset())
return 1;
return 0;
}
// cmp_offset
static
int
cmp_offset(const void *o1, const void *o2)
{
off_t offset1 = *static_cast<const off_t*>(o1);
off_t offset2 = *static_cast<const off_t*>(o2);
if (offset1 < offset2)
return -1;
else if (offset1 > offset2)
return 1;
return 0;
}
// is_inside_partitions
static
bool
is_inside_partitions(off_t location, const Partition **partitions, int32 count)
{
bool result = false;
if (count > 0) {
// binary search
int32 lower = 0;
int32 upper = count - 1;
while (lower < upper) {
int32 mid = (lower + upper) / 2;
const Partition *midPartition = partitions[mid];
if (location >= midPartition->Offset() + midPartition->Size())
lower = mid + 1;
else
upper = mid;
}
const Partition *partition = partitions[lower];
result = (location >= partition->Offset() &&
location < partition->Offset() + partition->Size());
}
return result;
}
// Check
bool
PartitionMap::Check(off_t sessionSize, int32 blockSize) const
{
int32 partitionCount = CountPartitions();
// 1. check partition locations
for (int32 i = 0; i < partitionCount; i++) {
if (!PartitionAt(i)->CheckLocation(sessionSize, blockSize))
return false;
}
// 2. check overlapping of partitions and location of PTSs
bool result = true;
const Partition **byOffset = new(nothrow) const Partition*[partitionCount];
off_t *ptsOffsets = new(nothrow) off_t[partitionCount - 3];
if (byOffset && ptsOffsets) {
// fill the arrays
int32 byOffsetCount = 0;
int32 ptsOffsetCount = 1; // primary PTS
ptsOffsets[0] = 0; //
for (int32 i = 0; i < partitionCount; i++) {
const Partition *partition = PartitionAt(i);
if (!partition->IsExtended())
byOffset[byOffsetCount++] = partition;
// add only logical partition PTS locations
if (i >= 4)
ptsOffsets[ptsOffsetCount++] = partition->PTSOffset();
}
// sort the arrays
qsort(byOffset, byOffsetCount, sizeof(const Partition*),
cmp_partition_offset);
qsort(ptsOffsets, ptsOffsetCount, sizeof(off_t), cmp_offset);
// check for overlappings
off_t nextOffset = 0;
for (int32 i = 0; i < byOffsetCount; i++) {
const Partition *partition = byOffset[i];
if (partition->Offset() < nextOffset) {
TRACE(("intel: PartitionMap::Check(): overlapping partitions!"
"\n"));
result = false;
break;
}
nextOffset = partition->Offset() + partition->Size();
}
// check uniqueness of PTS offsets and whether they lie outside of the
// non-extended partitions
if (result) {
for (int32 i = 0; i < ptsOffsetCount; i++) {
if (i > 0 && ptsOffsets[i] == ptsOffsets[i - 1]) {
TRACE(("intel: PartitionMap::Check(): same PTS for "
"different extended partitions!\n"));
result = false;
break;
} else if (is_inside_partitions(ptsOffsets[i], byOffset,
byOffsetCount)) {
TRACE(("intel: PartitionMap::Check(): a PTS lies "
"inside a non-extended partition!\n"));
result = false;
break;
}
}
}
} else
result = false; // no memory: assume failure
// cleanup
if (byOffset)
delete[] byOffset;
if (ptsOffsets)
delete[] ptsOffsets;
return result;
}
@@ -1,169 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel_partition_map.h
\brief Definitions for "intel" style partitions and interface definitions
for related classes.
*/
#ifndef _INTEL_PARTITION_MAP_H
#define _INTEL_PARTITION_MAP_H
#include <SupportDefs.h>
// is_empty_type
static inline
bool
is_empty_type(uint8 type)
{
return (type == 0x00);
}
// is_extended_type
static inline
bool
is_extended_type(uint8 type)
{
return (type == 0x05 || type == 0x0f || type == 0x85);
}
void get_partition_type_string(uint8 type, char *buffer);
// chs
struct chs {
uint8 cylinder;
uint16 head_sector; // head[15:10], sector[9:0]
} _PACKED;
// partition_descriptor
struct partition_descriptor {
uint8 active;
chs begin;
uint8 type;
chs end;
uint32 start;
uint32 size;
bool is_empty() const { return is_empty_type(type); }
bool is_extended() const { return is_extended_type(type); }
} _PACKED;
// partition_table_sector
struct partition_table_sector {
char pad1[446];
partition_descriptor table[4];
uint16 signature;
} _PACKED;
static const uint16 kPartitionTableSectorSignature = 0xaa55;
class Partition;
class PrimaryPartition;
class LogicalPartition;
// Partition
class Partition {
public:
Partition();
Partition(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize);
void Unset();
bool IsEmpty() const { return is_empty_type(fType); }
bool IsExtended() const { return is_extended_type(fType); }
off_t PTSOffset() const { return fPTSOffset; }
off_t Offset() const { return fOffset; }
off_t Size() const { return fSize; }
uint8 Type() const { return fType; }
bool Active() const { return fActive; }
void GetTypeString(char *buffer) const
{ get_partition_type_string(fType, buffer); }
void SetPTSOffset(off_t offset) { fPTSOffset = offset; }
void SetOffset(off_t offset) { fOffset = offset; }
void SetSize(off_t size) { fSize = size; }
void SetType(uint8 type) { fType = type; }
void SetActive(bool active) { fActive = active; }
bool CheckLocation(off_t sessionSize, int32 blockSize) const;
private:
off_t fPTSOffset;
off_t fOffset; // relative to the start of the session
off_t fSize;
uint8 fType;
bool fActive;
};
// PrimaryPartition
class PrimaryPartition : public Partition {
public:
PrimaryPartition();
PrimaryPartition(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize);
void Unset();
// only if extended
int32 CountLogicalPartitions() const { return fLogicalPartitionCount; }
LogicalPartition *LogicalPartitionAt(int32 index) const;
void AddLogicalPartition(LogicalPartition *partition);
private:
LogicalPartition *fHead;
LogicalPartition *fTail;
int32 fLogicalPartitionCount;
};
// LogicalPartition
class LogicalPartition : public Partition {
public:
LogicalPartition();
LogicalPartition(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize, PrimaryPartition *primary);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize, PrimaryPartition *primary);
void Unset();
void SetPrimaryPartition(PrimaryPartition *primary) { fPrimary = primary; }
PrimaryPartition *GetPrimaryPartition() const { return fPrimary; }
void SetNext(LogicalPartition *next) { fNext = next; }
LogicalPartition *Next() const { return fNext; }
private:
PrimaryPartition *fPrimary;
LogicalPartition *fNext;
};
// PartitionMap
class PartitionMap {
public:
PartitionMap();
~PartitionMap();
void Unset();
PrimaryPartition *PrimaryPartitionAt(int32 index);
const PrimaryPartition *PrimaryPartitionAt(int32 index) const;
int32 CountPartitions() const;
Partition *PartitionAt(int32 index);
const Partition *PartitionAt(int32 index) const;
bool Check(off_t sessionSize, int32 blockSize) const;
private:
PrimaryPartition fPrimaries[4];
};
#endif // _INTEL_PARTITION_MAP_H
@@ -1,8 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel disk_scanner session ;
UsePrivateHeaders $(DOT) ;
#KernelAddon intel : kernel disk_scanner session :
# cdrom.cpp
#;
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
@@ -7,14 +7,14 @@
/*!
\file Disc.cpp
Disc class implementation, used to enumerate the CD/DVD sessions.
Disc class implementation, used to enumerate the CD/DVD sessions.
The protocols followed in this module are based on information
taken from the "SCSI-3 Multimedia Commands" draft, revision 10A.
The SCSI command of interest is "READ TOC/PMA/ATIP", command
number \c 0x43.
The format of interest for said command is "Full TOC", format
number \c 0x2.
*/
@@ -26,7 +26,7 @@
#include "Debug.h"
static const char *kModuleDebugName = "session";
DBG(static const char *kModuleDebugName = "session");
//------------------------------------------------------------------------------
// Helper function declarations
@@ -62,15 +62,15 @@ class List {
public:
List();
~List();
list_item* Find(int32 index) const;
void Add(list_item *item);
void Clear();
void SortAndRemoveDuplicates();
list_item* First() const;
list_item* Last() const;
private:
list_item *fFirst;
list_item *fLast;
@@ -89,7 +89,7 @@ public:
, adr(adr)
{
}
off_t start_lba;
uint8 control; //!< only used to give what are probably useless warnings
uint8 adr; //!< only used to give what are probably useless warnings
@@ -102,11 +102,11 @@ public:
struct session : public list_item {
public:
session(uint32 index, session *next = NULL);
bool first_track_hint_is_set();
bool last_track_hint_is_set();
bool end_lba_is_set(); // also implies control and adr are set
bool is_audio();
int8 first_track_hint;
@@ -114,7 +114,7 @@ public:
int8 control;
int8 adr;
off_t end_lba;
List track_list;
};
@@ -142,7 +142,7 @@ List::Find(int32 index) const
{
// TRACE(("%s: List::Find(%ld)\n", kModuleDebugName, index));
list_item *item = fFirst;
while (item && item->index != index) {
while (item && item->index != index) {
item = item->next;
}
return item;
@@ -185,7 +185,7 @@ List::Clear()
/*! \brief Bubble sorts the list by index, removing any duplicates
(the first instance is kept).
\todo I believe duplicate removal is actually unnecessary, but I need to verify that.
*/
void
@@ -203,23 +203,23 @@ List::SortAndRemoveDuplicates()
// dprintf("List::Sort: %ld -> %ld\n", item->index, next->index);
if (item->index > next->index) {
sorted = false;
// Keep fLast up to date
if (next == fLast)
fLast = item;
// Swap
// Swap
if (prev) {
// item is not fFirst
prev->next = next;
item->next = next->next;
next->next = item;
next->next = item;
} else {
// item must be fFirst
fFirst = next;
item->next = next->next;
next->next = item;
}
}
} else if (item->index == next->index) {
// Duplicate indicies
TRACE(("%s: List::SortAndRemoveDuplicates: duplicate indicies found (#%ld); "
@@ -227,7 +227,7 @@ List::SortAndRemoveDuplicates()
item->next = next->next;
delete next;
next = item->next;
continue;
continue;
}
prev = item;
item = next;
@@ -285,7 +285,7 @@ session::last_track_hint_is_set()
/*! \brief Returns true if the \a end_lba member has not been
set to a legal value yet.
The result of this function also signals that the \a control
and \a adr members have or have not been set, since they are
set at the same time as \a end_lba.
@@ -314,7 +314,7 @@ session::is_audio()
/*! \brief Creates a new Disc object by parsing the given table of contents
entries and checking the resultant data structure for errors and
warnings.
If successful, subsequent calls to InitCheck() will return \c B_OK,
elsewise they will return an error code.
*/
@@ -326,25 +326,25 @@ Disc::Disc(int fd)
uchar data[kBlockSize];
/*
if (!error)
if (!error)
error = sessionInfo && index >= 0 ? B_OK : B_BAD_VALUE;
int32 session = index+1;
// Check for a valid session index
if (session < 1 || session > 99)
error = B_ENTRY_NOT_FOUND;
*/
*/
status_t error = fSessionList ? B_OK : B_NO_MEMORY;
// Attempt to read the table of contents, first in lba mode, then in msf mode
if (!error) {
error = read_table_of_contents(fd, 1, data, kBlockSize, false);
}
}
if (error) {
TRACE(("%s: lba read_toc failed, trying msf instead\n", kModuleDebugName));
error = read_table_of_contents(fd, 1, data, kBlockSize, true);
}
// Interpret the data returned, if successful
if (!error) {
cdrom_table_of_contents_header *header;
@@ -354,17 +354,17 @@ Disc::Disc(int fd)
header = (cdrom_table_of_contents_header*)data;
entries = (cdrom_full_table_of_contents_entry*)(data+4);
header->length = B_BENDIAN_TO_HOST_INT16(header->length);
count = (header->length-2) / sizeof(cdrom_full_table_of_contents_entry);
error = _ParseTableOfContents(entries, count);
// Dump();
if (!error) {
_SortAndRemoveDuplicates();
error = _CheckForErrorsAndWarnings();
}
}
}
PRINT(("Setting init status to 0x%lx, `%s'\n", error, strerror(error)));
fInitStatus = error;
}
@@ -386,7 +386,7 @@ Disc::InitCheck()
/*! \brief Stores the info for the given session (using 0 based indicies) in the
struct pointed to by \a sessionInfo.
Returns \c B_ENTRY_NOT_FOUND if no such session exists.
*/
Session*
@@ -399,7 +399,7 @@ Disc::GetSession(int32 index)
session = (struct session*)session->next)
{
if (session->is_audio()) {
counter++; // only one session per audio session
counter++; // only one session per audio session
if (counter == index) {
// Found an audio session. Take the start of the first
// track with the end of session.
@@ -409,22 +409,22 @@ Disc::GetSession(int32 index)
off_t start_lba = track->start_lba;
off_t end_lba = session->end_lba;
off_t offset = start_lba * kBlockSize;
off_t size = (end_lba - start_lba) * kBlockSize;
Session *result = new Session(offset, size, kBlockSize,
index, B_PARTITION_READ_ONLY,
kPartitionTypeAudioSession);
if (!result)
if (!result)
PRINT(("Error allocating new Session object; out of memory!\n"));
return result;
} else {
PRINT(("Error: session #%ld is an audio "
"session with no tracks!\n", index));
return NULL;
}
}
}
}
} else {
for (track *track = (struct track*)session->track_list.First();
track;
@@ -438,21 +438,21 @@ Disc::GetSession(int32 index)
off_t end_lba = track->next
? ((struct track*)track->next)->start_lba
: session->end_lba;
off_t offset = start_lba * kBlockSize;
off_t size = (end_lba - start_lba) * kBlockSize;
Session *result = new Session(offset, size, kBlockSize,
index, B_PARTITION_READ_ONLY,
kPartitionTypeDataSession);
if (!result)
if (!result)
PRINT(("Error allocating new Session object; out of memory!\n"));
return result;
}
}
}
}
}
}
}
PRINT(("no session #%ld found!\n", index));
return NULL;
}
@@ -502,11 +502,11 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32
fSessionList->Add(session);
}
}
uint8 point = entries[i].point;
switch (point) {
// first track hint
case 0xA0:
if (!session->first_track_hint_is_set()) {
@@ -521,10 +521,10 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32
} else {
WARN(("%s: warning: duplicated first track hint values found for"
"session %d; using first value encountered: %d", kModuleDebugName,
session_index, session->first_track_hint));
}
session_index, session->first_track_hint));
}
break;
// last track hint
case 0xA1:
if (!session->last_track_hint_is_set()) {
@@ -539,10 +539,10 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32
} else {
WARN(("%s: warning: duplicate last track hint values found for"
"session %d; using first value encountered: %d", kModuleDebugName,
session_index, session->last_track_hint));
}
session_index, session->last_track_hint));
}
break;
// end of session address
case 0xA2:
if (!session->end_lba_is_set()) {
@@ -564,10 +564,10 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32
} else {
WARN(("%s: warning: duplicate end lba values found for"
"session %d; using first value encountered: %lld",
kModuleDebugName, session_index, session->end_lba));
}
kModuleDebugName, session_index, session->end_lba));
}
break;
// Valid, but uninteresting, points
case 0xB0:
case 0xB1:
@@ -577,7 +577,7 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32
case 0xC0:
case 0xC1:
break;
default:
// Anything else had better be a valid track number,
// or it's an invalid point
@@ -590,7 +590,7 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32
entries[i].pframes));
// The control and adr values grabbed here are only used later on
// to signal a warning if they don't match the corresponding values
// of the parent session.
// of the parent session.
track *track = new(nothrow) struct track(track_index, start_lba,
entries[i].control, entries[i].adr);
if (!track) {
@@ -602,7 +602,7 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32
WARN(("%s: warning: illegal point 0x%2x found in table of contents\n",
kModuleDebugName, entries[i].point));
}
break;
break;
}
}
return B_OK;
@@ -631,7 +631,7 @@ Disc::_SortAndRemoveDuplicates()
Anomalies that result in errors:
- Sessions with no end_lba set
- Sessions with no tracks
Anomalies that result in warnings:
- Inaccurate first_track_hint and/or last_track_hint values
- Sequences of sessions or tracks that do not start at 1,
@@ -640,33 +640,33 @@ Disc::_SortAndRemoveDuplicates()
numbering does not restart with each session).
- Tracks with different control and/or adr values than their
parent session
Anomalies that are currently *not* checked:
- First Track Hint or Last Track Hint control and adr values
that do not match the values for their session; Ingo's copy
of the BeOS R5 CD is like this, but I don't believe it's
a matter we need to worry about. This could certainly be
changed in the future if needed.
*/
*/
status_t
Disc::_CheckForErrorsAndWarnings() {
int32 lastSessionIndex = 0;
int32 lastTrackIndex = 0;
for (session *session = (struct session*)fSessionList->First();
session;
session = (struct session*)session->next)
{
// Check for errors
//-----------------
// missing end lba
if (!session->end_lba_is_set()) {
TRACE(("%s: Disc::_CheckForErrorsAndWarnings: error: no end of session "
"address for session #%ld\n", kModuleDebugName, session->index));
return B_ERROR;
}
// empty track list
track *track = (struct track*)session->track_list.First();
if (!track) {
@@ -674,10 +674,10 @@ Disc::_CheckForErrorsAndWarnings() {
"tracks\n", kModuleDebugName, session->index));
return B_ERROR;
}
// Check for warnings
//-------------------
// incorrect first track hint
if (session->first_track_hint_is_set()
&& session->first_track_hint != track->index)
@@ -696,7 +696,7 @@ Disc::_CheckForErrorsAndWarnings() {
"track hint (%d) doesn't match actual last track (%ld)\n", kModuleDebugName,
session->index, session->last_track_hint, last->index));
}
// invalid session sequence
if (lastSessionIndex+1 != session->index) {
TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: index for session #%ld "
@@ -704,7 +704,7 @@ Disc::_CheckForErrorsAndWarnings() {
session->index, lastSessionIndex));
}
lastSessionIndex = session->index;
for ( ; track; track = (struct track*)track->next) {
// invalid track sequence
if (lastTrackIndex+1 != track->index) {
@@ -732,7 +732,7 @@ Disc::_CheckForErrorsAndWarnings() {
"(adr = %d) does not match adr for parent session #%ld (adr = %d)\n", kModuleDebugName,
track->index, track->adr, session->index, session->adr));
}
}
}
}
return B_OK;
@@ -750,7 +750,7 @@ Session::Session(off_t offset, off_t size, uint32 blockSize, int32 index,
, fIndex(index)
, fFlags(flags)
, fType(strdup(type))
{
{
}
Session::~Session() {
@@ -814,15 +814,16 @@ dump_scsi_command(raw_device_command *cmd) {
}
*/
static
void
#ifdef DEBUG
static void
dump_full_table_of_contents(uchar *data, uint16 data_length)
{
cdrom_table_of_contents_header *header;
cdrom_full_table_of_contents_entry *entries;
int i, count;
int header_length;
header = (cdrom_table_of_contents_header*)data;
entries = (cdrom_full_table_of_contents_entry*)(data+4);
header_length = B_BENDIAN_TO_HOST_INT16(header->length);
@@ -831,18 +832,18 @@ dump_full_table_of_contents(uchar *data, uint16 data_length)
data_length, header_length));
header_length = data_length;
}
TRACE(("%s: table of contents dump:\n", kModuleDebugName));
TRACE(("--------------------------------------------------\n"));
TRACE(("header:\n"));
TRACE((" length = %d\n", header_length));
TRACE((" first = %d\n", header->first));
TRACE((" last = %d\n", header->last));
count = (header_length-2) / sizeof(cdrom_full_table_of_contents_entry);
TRACE(("\n"));
TRACE(("entry count = %d\n", count));
for (i = 0; i < count; i++) {
TRACE(("\n"));
TRACE(("entry #%d:\n", i));
@@ -865,25 +866,25 @@ dump_full_table_of_contents(uchar *data, uint16 data_length)
}
TRACE(("--------------------------------------------------\n"));
}
#endif // DEBUG
// read_table_of_contents
static
status_t
static status_t
read_table_of_contents(int deviceFD, uint32 first_session, uchar *buffer,
uint16 buffer_length, bool msf)
uint16 buffer_length, bool msf)
{
scsi_table_of_contents_command scsi_command;
raw_device_command raw_command;
const uint32 sense_data_length = 1024;
uchar sense_data[sense_data_length];
status_t error = buffer ? B_OK : B_BAD_VALUE;
DEBUG_INIT_ETC(NULL, ("fd: %d, buffer: %p, buffer_length: %d",
DEBUG_INIT_ETC(NULL, ("fd: %d, buffer: %p, buffer_length: %d",
deviceFD, buffer, buffer_length));
if (error)
return error;
// Init the scsi command and copy it into the BeOS "raw scsi command" ioctl struct
memset(raw_command.command, 0, 16);
scsi_command.command = 0x43;
@@ -891,7 +892,7 @@ read_table_of_contents(int deviceFD, uint32 first_session, uchar *buffer,
scsi_command.format = kFullTableOfContentsFormat;
scsi_command.number = first_session;
scsi_command.length = B_HOST_TO_BENDIAN_INT16(buffer_length);
scsi_command.control = 0;
scsi_command.control = 0;
scsi_command.reserved0 = scsi_command.reserved1 = scsi_command.reserved2
= scsi_command.reserved3 = scsi_command.reserved4
= scsi_command.reserved5 = scsi_command.reserved6 = 0;
@@ -900,7 +901,7 @@ read_table_of_contents(int deviceFD, uint32 first_session, uchar *buffer,
// Init the rest of the raw command
raw_command.command_length = 10;
raw_command.flags = kScsiFlags;
raw_command.scsi_status = 0;
raw_command.scsi_status = 0;
raw_command.cam_status = 0;
raw_command.data = buffer;
raw_command.data_length = buffer_length;
@@ -908,8 +909,8 @@ read_table_of_contents(int deviceFD, uint32 first_session, uchar *buffer,
raw_command.sense_data = sense_data;
raw_command.sense_data_length = sense_data_length;
memset(raw_command.sense_data, 0, raw_command.sense_data_length);
raw_command.timeout = kScsiTimeout;
raw_command.timeout = kScsiTimeout;
if (ioctl(deviceFD, B_RAW_DEVICE_COMMAND, &raw_command) == 0) {
if (raw_command.scsi_status == 0 && raw_command.cam_status == 1) {
// SUCCESS!!!
@@ -926,7 +927,7 @@ read_table_of_contents(int deviceFD, uint32 first_session, uchar *buffer,
}
return error;
}
// cdrom_session_get_nth_info
@@ -941,19 +942,19 @@ cdrom_session_get_nth_info(int deviceFD, int32 index, off_t deviceSize,
status_t error = sessionInfo && index >= 0 ? B_OK : B_BAD_VALUE;
uchar data[2048];
int32 session = index+1;
TRACE(("%s: get_nth_info(%d, %ld, %lld, %ld, %p)\n", kModuleDebugName,
deviceFD, index, deviceSize, blockSize, sessionInfo));
// Attempt to read the table of contents, first in lba mode, then in msf mode
if (!error) {
error = read_table_of_contents(deviceFD, 1, data, 2048, false);
}
}
if (error) {
TRACE(("%s: lba read_toc failed, trying msf instead\n", kModuleDebugName));
error = read_table_of_contents(deviceFD, 1, data, 2048, true);
}
// Interpret the data returned, if successful
if (!error) {
cdrom_table_of_contents_header *header;
@@ -963,25 +964,25 @@ cdrom_session_get_nth_info(int deviceFD, int32 index, off_t deviceSize,
header = (cdrom_table_of_contents_header*)data;
entries = (cdrom_full_table_of_contents_entry*)(data+4);
header->length = B_BENDIAN_TO_HOST_INT16(header->length);
count = (header->length-2) / sizeof(cdrom_full_table_of_contents_entry);
// Check for a valid session index
if (session < 1 || session > 99)
error = B_ENTRY_NOT_FOUND;
// Extract the data of interest
if (!error) {
Disc disc(entries, count);
error = disc.InitCheck();
if (!error)
if (!error)
error = disc.GetSessionInfo(index, blockSize, sessionInfo);
}
}
if (error)
if (error)
TRACE(("%s: get_nth error 0x%lx\n", kModuleDebugName, error));
return error;
}
*/
@@ -1,5 +1,5 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
@@ -9,7 +9,7 @@
Disc class, used to enumerate the CD/DVD sessions.
*/
#ifndef _DISC_H
#define _DISC_H
@@ -20,7 +20,6 @@
#include <unistd.h>
#include <ByteOrder.h>
#include <disk_scanner.h>
#include <KernelExport.h>
#include <scsi.h>
@@ -37,16 +36,16 @@ class Disc {
public:
Disc(int fd);
~Disc();
status_t InitCheck();
Session* GetSession(int32 index);
void Dump();
// CDs and DVDs are required to have a block size of 2K by
// the SCSI-3 standard
static const int kBlockSize = 2048;
private:
status_t _ParseTableOfContents(cdrom_full_table_of_contents_entry entries[],
uint32 count);
@@ -63,11 +62,11 @@ private:
class Session {
public:
~Session();
off_t Offset() { return fOffset; }
off_t Size() { return fSize; }
uint32 BlockSize() { return fBlockSize; }
int32 Index() { return fIndex; }
int32 Index() { return fIndex; }
uint32 Flags() { return fFlags; }
const char* Type() { return fType; }
private:
@@ -76,13 +75,13 @@ private:
uint32 flags, const char *type);
Session(const Session &ref); // not implemented
Session& operator=(const Session &ref); // not implemented
off_t fOffset;
off_t fSize;
uint32 fBlockSize;
int32 fIndex;
int32 fIndex;
uint32 fFlags;
char *fType;
char *fType;
};
#endif // _DISC_H