* 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:
@@ -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 */
|
|
||||||
@@ -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
|
|
||||||
#;
|
|
||||||
|
|
||||||
@@ -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
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
|
|
||||||
static const char *kModuleDebugName = "session";
|
DBG(static const char *kModuleDebugName = "session");
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helper function declarations
|
// Helper function declarations
|
||||||
@@ -814,8 +814,9 @@ dump_scsi_command(raw_device_command *cmd) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
|
||||||
void
|
#ifdef DEBUG
|
||||||
|
static void
|
||||||
dump_full_table_of_contents(uchar *data, uint16 data_length)
|
dump_full_table_of_contents(uchar *data, uint16 data_length)
|
||||||
{
|
{
|
||||||
cdrom_table_of_contents_header *header;
|
cdrom_table_of_contents_header *header;
|
||||||
@@ -865,12 +866,12 @@ dump_full_table_of_contents(uchar *data, uint16 data_length)
|
|||||||
}
|
}
|
||||||
TRACE(("--------------------------------------------------\n"));
|
TRACE(("--------------------------------------------------\n"));
|
||||||
}
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
// read_table_of_contents
|
|
||||||
static
|
static status_t
|
||||||
status_t
|
|
||||||
read_table_of_contents(int deviceFD, uint32 first_session, uchar *buffer,
|
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;
|
scsi_table_of_contents_command scsi_command;
|
||||||
raw_device_command raw_command;
|
raw_device_command raw_command;
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <ByteOrder.h>
|
#include <ByteOrder.h>
|
||||||
#include <disk_scanner.h>
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <scsi.h>
|
#include <scsi.h>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user