* Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold, bonefish@cs.tu-berlin.de
* Tomas Kucera, kucerat@centrum.cz
*/
\file intel.cpp
\brief partitioning system module for "intel" style partitions.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <new>
#include <KernelExport.h>
#include <AutoDeleter.h>
#include <disk_device_manager/ddm_modules.h>
#include "intel.h"
#include "PartitionLocker.h"
#include "PartitionMap.h"
#include "PartitionMapParser.h"
#ifdef _BOOT_MODE
# include <boot/partitions.h>
# include <util/kernel_cpp.h>
# undef TRACE_INTEL
#else
# include <DiskDeviceTypes.h>
# include "write_support.h"
#endif
#if TRACE_INTEL
# define TRACE(x...) dprintf("intel: " x)
#else
# define TRACE(x...) ;
#endif
#define INTEL_PARTITION_MODULE_NAME "partitioning_systems/intel/map/v1"
#define INTEL_EXTENDED_PARTITION_MODULE_NAME \
"partitioning_systems/intel/extended/v1"
using std::nothrow;
#ifndef _BOOT_MODE
static status_t
get_type_for_content_type(const char* contentType, char* type)
{
TRACE("get_type_for_content_type(%s)\n", contentType);
if (!contentType || !type)
return B_BAD_VALUE;
PartitionType ptype;
ptype.SetContentType(contentType);
if (!ptype.IsValid())
return B_NAME_NOT_FOUND;
ptype.GetTypeString(type);
return B_OK;
}
#endif
static status_t
pm_std_ops(int32 op, ...)
{
TRACE("pm_std_ops(0x%" B_PRIx32 ")\n", op);
switch(op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
static float
pm_identify_partition(int fd, partition_data* partition, void** cookie)
{
if (fd < 0 || !partition || !cookie)
return -1;
TRACE("pm_identify_partition(%d, %" B_PRId32 ": %" B_PRId64 ", "
"%" B_PRId64 ", %" B_PRId32 ")\n", fd, partition->id, partition->offset,
partition->size, partition->block_size);
if (partition->type != NULL
&& !strcmp(partition->type, kPartitionTypeIntelExtended)) {
return -1;
}
PartitionMapCookie* map = new(nothrow) PartitionMapCookie;
if (!map)
return -1;
PartitionMapParser parser(fd, 0, partition->size, partition->block_size);
status_t error = parser.Parse(NULL, map);
if (error != B_OK) {
delete map;
return -1;
}
*cookie = map;
bool hasChildren = (map->CountNonEmptyPartitions() > 0);
bool hasParent = (get_parent_partition(partition->id) != NULL);
if (!hasParent) {
if (hasChildren) {
return 0.81;
}
return 0.5;
}
#if 0
if (hasChildren)
return 0.4;
return 0.1;
#endif
return -1;
}
static status_t
pm_scan_partition(int fd, partition_data* partition, void* cookie)
{
if (fd < 0 || !partition || !cookie)
return B_ERROR;
TRACE("pm_scan_partition(%d, %" B_PRId32 ": %" B_PRId64 ", "
"%" B_PRId64 ", %" B_PRId32 ")\n", fd, partition->id, partition->offset,
partition->size, partition->block_size);
PartitionMapCookie* map = (PartitionMapCookie*)cookie;
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
partition->content_size = partition->size;
partition->content_cookie = map;
status_t error = B_OK;
int32 index = 0;
for (int32 i = 0; i < 4; i++) {
PrimaryPartition* primary = map->PrimaryPartitionAt(i);
if (!primary->IsEmpty()) {
partition_data* child = create_child_partition(partition->id,
index, partition->offset + primary->Offset(), primary->Size(),
-1);
index++;
if (!child) {
error = B_ERROR;
break;
}
child->block_size = partition->block_size;
char type[B_FILE_NAME_LENGTH];
primary->GetTypeString(type);
child->type = strdup(type);
char buffer[128];
sprintf(buffer, "type = %u ; active = %d", primary->Type(),
primary->Active());
child->parameters = strdup(buffer);
child->cookie = primary;
if (!child->type || !child->parameters) {
error = B_NO_MEMORY;
break;
}
}
}
if (error == B_OK) {
atomic_add(&map->ref_count, 1);
} else {
partition->content_cookie = NULL;
for (int32 i = 0; i < partition->child_count; i++) {
if (partition_data* child = get_child_partition(partition->id, i))
child->cookie = NULL;
}
}
return error;
}
static void
pm_free_identify_partition_cookie(partition_data*, void* cookie)
{
if (cookie) {
PartitionMapCookie* map = (PartitionMapCookie*)cookie;
if (atomic_add(&map->ref_count, -1) == 1)
delete map;
}
}
static void
pm_free_partition_cookie(partition_data* partition)
{
if (partition)
partition->cookie = NULL;
}
static void
pm_free_partition_content_cookie(partition_data* partition)
{
if (partition && partition->content_cookie) {
pm_free_identify_partition_cookie(partition, partition->content_cookie);
partition->content_cookie = NULL;
}
}
static status_t
ep_std_ops(int32 op, ...)
{
TRACE("ep_std_ops(0x%" B_PRIx32 ")\n", op);
switch(op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
static float
ep_identify_partition(int fd, partition_data* partition, void** cookie)
{
if (fd < 0 || !partition || !cookie || !partition->cookie)
return -1;
TRACE("ep_identify_partition(%d, %" B_PRId64 ", %" B_PRId64 ", "
"%" B_PRId32 ")\n", fd, partition->offset, partition->size,
partition->block_size);
if (!partition->type
|| strcmp(partition->type, kPartitionTypeIntelExtended)) {
return -1;
}
partition_data* parent = get_parent_partition(partition->id);
if (!parent || !parent->content_type
|| strcmp(parent->content_type, kPartitionTypeIntel)) {
return -1;
}
return 0.95;
}
static status_t
ep_scan_partition(int fd, partition_data* partition, void* cookie)
{
if (fd < 0 || !partition || !partition->cookie)
return B_ERROR;
TRACE("ep_scan_partition(%d, %" B_PRId64 ", %" B_PRId64 ", "
"%" B_PRId32 ")\n", fd, partition->offset, partition->size,
partition->block_size);
partition_data* parent = get_parent_partition(partition->id);
if (!parent)
return B_ERROR;
PrimaryPartition* primary = (PrimaryPartition*)partition->cookie;
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM;
partition->content_size = partition->size;
partition->content_cookie = primary;
status_t error = B_OK;
int32 index = 0;
for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) {
LogicalPartition* logical = primary->LogicalPartitionAt(i);
partition_data* child = create_child_partition(partition->id, index,
parent->offset + logical->Offset(), logical->Size(), -1);
index++;
if (!child) {
TRACE("ep_scan_partition(): failed to create child partition\n");
error = B_ERROR;
break;
}
child->block_size = partition->block_size;
char type[B_FILE_NAME_LENGTH];
logical->GetTypeString(type);
child->type = strdup(type);
char buffer[128];
sprintf(buffer, "active %s ;\npartition_table_offset %" B_PRId64 " ;\n",
logical->Active() ? "true" : "false",
logical->PartitionTableOffset());
child->parameters = strdup(buffer);
child->cookie = logical;
if (!child->type || !child->parameters) {
TRACE("ep_scan_partition(): failed to allocation type "
"or parameters\n");
error = B_NO_MEMORY;
break;
}
}
if (error != B_OK) {
partition->content_cookie = NULL;
for (int32 i = 0; i < partition->child_count; i++) {
if (partition_data* child = get_child_partition(partition->id, i))
child->cookie = NULL;
}
}
return error;
}
static void
ep_free_identify_partition_cookie(partition_data* partition, void* cookie)
{
}
static void
ep_free_partition_cookie(partition_data* partition)
{
if (partition)
partition->cookie = NULL;
}
static void
ep_free_partition_content_cookie(partition_data* partition)
{
if (partition)
partition->content_cookie = NULL;
}
#ifdef _BOOT_MODE
partition_module_info gIntelPartitionMapModule =
#else
static partition_module_info intel_partition_map_module =
#endif
{
{
INTEL_PARTITION_MODULE_NAME,
0,
pm_std_ops
},
"intel",
INTEL_PARTITION_NAME,
0
| B_DISK_SYSTEM_SUPPORTS_RESIZING
| B_DISK_SYSTEM_SUPPORTS_MOVING
| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
| B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
| B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
| B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
| B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD
| B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD
,
pm_identify_partition,
pm_scan_partition,
pm_free_identify_partition_cookie,
pm_free_partition_cookie,
pm_free_partition_content_cookie,
#ifndef _BOOT_MODE
pm_get_supported_operations,
pm_get_supported_child_operations,
NULL,
pm_is_sub_system_for,
pm_validate_resize,
pm_validate_resize_child,
pm_validate_move,
pm_validate_move_child,
NULL,
NULL,
pm_validate_set_type,
NULL,
NULL,
pm_validate_initialize,
pm_validate_create_child,
pm_get_partitionable_spaces,
pm_get_next_supported_type,
get_type_for_content_type,
pm_shadow_changed,
NULL,
pm_resize,
pm_resize_child,
pm_move,
pm_move_child,
NULL,
NULL,
pm_set_type,
pm_set_parameters,
pm_set_parameters,
pm_initialize,
pm_uninitialize,
pm_create_child,
pm_delete_child,
#else
NULL
#endif
};
#ifdef _BOOT_MODE
partition_module_info gIntelExtendedPartitionModule =
#else
static partition_module_info intel_extended_partition_module =
#endif
{
{
INTEL_EXTENDED_PARTITION_MODULE_NAME,
0,
ep_std_ops
},
"intel_extended",
INTEL_EXTENDED_PARTITION_NAME,
0
| B_DISK_SYSTEM_SUPPORTS_RESIZING
| B_DISK_SYSTEM_SUPPORTS_MOVING
| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
| B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
| B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
| B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
| B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD
| B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD
,
ep_identify_partition,
ep_scan_partition,
ep_free_identify_partition_cookie,
ep_free_partition_cookie,
ep_free_partition_content_cookie,
#ifndef _BOOT_MODE
ep_get_supported_operations,
ep_get_supported_child_operations,
NULL,
ep_is_sub_system_for,
ep_validate_resize,
ep_validate_resize_child,
ep_validate_move,
ep_validate_move_child,
NULL,
NULL,
ep_validate_set_type,
NULL,
NULL,
ep_validate_initialize,
ep_validate_create_child,
ep_get_partitionable_spaces,
ep_get_next_supported_type,
get_type_for_content_type,
ep_shadow_changed,
NULL,
ep_resize,
ep_resize_child,
ep_move,
ep_move_child,
NULL,
NULL,
ep_set_type,
NULL,
NULL,
ep_initialize,
NULL,
ep_create_child,
ep_delete_child,
#else
NULL
#endif
};
#ifndef _BOOT_MODE
extern "C" partition_module_info* modules[];
_EXPORT partition_module_info* modules[] =
{
&intel_partition_map_module,
&intel_extended_partition_module,
NULL
};
#endif