diff --git a/src/tests/add-ons/kernel/Jamfile b/src/tests/add-ons/kernel/Jamfile index 334b039272..393fddebf7 100644 --- a/src/tests/add-ons/kernel/Jamfile +++ b/src/tests/add-ons/kernel/Jamfile @@ -7,3 +7,4 @@ SubInclude HAIKU_TOP src tests add-ons kernel drivers ; SubInclude HAIKU_TOP src tests add-ons kernel file_systems ; SubInclude HAIKU_TOP src tests add-ons kernel kernelland_emu ; SubInclude HAIKU_TOP src tests add-ons kernel network ; +SubInclude HAIKU_TOP src tests add-ons kernel partitioning_systems ; diff --git a/src/tests/add-ons/kernel/partitioning_systems/Jamfile b/src/tests/add-ons/kernel/partitioning_systems/Jamfile new file mode 100644 index 0000000000..7096a65205 --- /dev/null +++ b/src/tests/add-ons/kernel/partitioning_systems/Jamfile @@ -0,0 +1,72 @@ +SubDir HAIKU_TOP src tests add-ons kernel partitioning_systems ; + +UsePrivateHeaders interface kernel shared storage ; +UsePrivateSystemHeaders ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits storage disk_device ] ; + # DiskDeviceTypes.cpp + +SimpleTest PartitioningSystemsTest : + PartitioningSystemsTest.cpp + + # disk device types + DiskDeviceTypes.cpp + + : libkernelland_emu.so be +; + +{ + local defines = [ FDefines USERLAND ] ; + SubDirCcFlags $(defines) ; + SubDirC++Flags $(defines) ; +} + +SEARCH_SOURCE + += [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems amiga ] ; + +Addon amiga_rdb : + amiga_rdb.cpp + : PartitioningSystemsTest libkernelland_emu.so +; + +SEARCH_SOURCE + += [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems intel ] ; + +Addon intel : + intel.cpp + PartitionLocker.cpp + PartitionMap.cpp + PartitionMapParser.cpp + PartitionMapWriter.cpp + write_support.cpp + : PartitioningSystemsTest libkernelland_emu.so +; + +SEARCH_SOURCE + += [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems efi ] ; + +Addon efi_gpt : + efi_gpt.cpp + PartitionLocker.cpp + : PartitioningSystemsTest libkernelland_emu.so +; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems + session ] ; + +Addon session : + session.cpp + Debug.cpp + Disc.cpp + : PartitioningSystemsTest libkernelland_emu.so +; + +# for convenience: this target builds all userland modules + +NotFile userland_partitioning_modules ; +Depends userland_partitioning_modules : + amiga_rdb + intel + session + efi_gpt +; diff --git a/src/tests/add-ons/kernel/partitioning_systems/PartitioningSystemsTest.cpp b/src/tests/add-ons/kernel/partitioning_systems/PartitioningSystemsTest.cpp new file mode 100644 index 0000000000..c3168931eb --- /dev/null +++ b/src/tests/add-ons/kernel/partitioning_systems/PartitioningSystemsTest.cpp @@ -0,0 +1,403 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +struct partition_entry; +typedef std::vector PartitionVector; + +struct partition_entry : partition_data { + partition_entry* parent; + PartitionVector children; + char path[PATH_MAX]; +}; + +typedef std::map PartitionMap; +typedef std::map DiskDeviceMap; + + +static PartitionMap sPartitions; +static DiskDeviceMap sDiskDevices; +static partition_id sNextID = 1; + + +static status_t +create_disk_device(int fd, const char* path, partition_id* _id) +{ + partition_entry* partition = new partition_entry; + memset(partition, 0, sizeof(partition_entry)); + partition->id = sNextID++; + strlcpy(partition->path, path, sizeof(partition->path)); + + disk_device_data* device = new disk_device_data; + device->id = partition->id; + device->path = partition->path; + device->flags = 0; + + if (ioctl(fd, B_GET_GEOMETRY, &device->geometry) < 0) { + // maybe it's just a file + struct stat stat; + if (fstat(fd, &stat) < 0) { + delete partition; + delete device; + return errno; + } + + uint32 blockSize = 512; + off_t blocks = stat.st_size / blockSize; + uint32 heads = (blocks + ULONG_MAX - 1) / ULONG_MAX; + if (heads == 0) + heads = 1; + device->geometry.bytes_per_sector = blockSize; + device->geometry.sectors_per_track = 1; + device->geometry.cylinder_count = blocks / heads; + device->geometry.head_count = heads; + device->geometry.device_type = B_DISK; + device->geometry.removable = false; + device->geometry.read_only = true; + device->geometry.write_once = false; + } + + partition->offset = 0; + partition->size = 1LL * device->geometry.head_count + * device->geometry.cylinder_count * device->geometry.sectors_per_track + * device->geometry.bytes_per_sector; + partition->block_size = device->geometry.bytes_per_sector; + + sDiskDevices.insert(std::make_pair(partition->id, device)); + sPartitions.insert(std::make_pair(partition->id, partition)); + + if (_id != NULL) + *_id = partition->id; + + return B_OK; +} + + +static void +print_disk_device(partition_id id) +{ + disk_device_data* data = get_disk_device(id); + + printf("device ID %ld\n", id); + printf(" path %s\n", data->path); + printf(" geometry\n"); + printf(" bytes per sector %lu\n", data->geometry.bytes_per_sector); + printf(" sectors per track %lu\n", data->geometry.sectors_per_track); + printf(" cylinder count %lu\n", data->geometry.cylinder_count); + printf(" head count %lu (size %lld bytes)\n", + data->geometry.head_count, 1LL * data->geometry.head_count + * data->geometry.cylinder_count * data->geometry.sectors_per_track + * data->geometry.bytes_per_sector); + printf(" device type %d\n", data->geometry.device_type); + printf(" removable %d\n", data->geometry.removable); + printf(" read only %d\n", data->geometry.read_only); + printf(" write once %d\n\n", data->geometry.write_once); +} + + +static void +print_partition(partition_id id) +{ + partition_data* data = get_partition(id); + + printf("partition ID %ld\n", id); + printf(" offset %lld\n", data->offset); + printf(" size %lld\n", data->size); + printf(" content_size %lld\n", data->content_size); + printf(" block_size %lu\n", data->block_size); + printf(" child_count %ld\n", data->child_count); + printf(" index %ld\n", data->index); + printf(" status %#lx\n", data->status); + printf(" flags %#lx\n", data->flags); + printf(" name %s\n", data->name); + printf(" type %s\n", data->type); + printf(" content_name %s\n", data->content_name); + printf(" content_type %s\n", data->content_type); + printf(" parameters %s\n", data->parameters); + printf(" content_parameters %s\n", data->content_parameters); +} + + +status_t +scan_partition(int fd, partition_id partitionID) +{ + partition_data* data = get_partition(partitionID); + + void* list = open_module_list("partitioning_systems"); + char name[PATH_MAX]; + size_t nameSize = sizeof(name); + while (read_next_module_name(list, name, &nameSize) == B_OK) { + partition_module_info* moduleInfo; + if (get_module(name, (module_info**)&moduleInfo) == B_OK + && moduleInfo->identify_partition != NULL) { + void* cookie; + float priority = moduleInfo->identify_partition(fd, data, &cookie); + + printf("%s: %g\n", name, priority); + + if (priority >= 0) { + // scan partitions + moduleInfo->scan_partition(fd, data, cookie); + moduleInfo->free_identify_partition_cookie(data, cookie); + + free((char*)data->content_type); + data->content_type = strdup(moduleInfo->pretty_name); + } + + put_module(name); + } + nameSize = sizeof(name); + } + + return B_OK; +} + + +// #pragma mark - disk device manager API + + +disk_device_data* +write_lock_disk_device(partition_id partitionID) +{ + // TODO: we could check if the device is properly unlocked again + return get_disk_device(partitionID); +} + + +void +write_unlock_disk_device(partition_id partitionID) +{ +} + + +disk_device_data* +read_lock_disk_device(partition_id partitionID) +{ + // TODO: we could check if the device is properly unlocked again + return get_disk_device(partitionID); +} + + +void +read_unlock_disk_device(partition_id partitionID) +{ +} + + +disk_device_data* +get_disk_device(partition_id partitionID) +{ + DiskDeviceMap::iterator found = sDiskDevices.find(partitionID); + if (found == sDiskDevices.end()) + return NULL; + + return found->second; +} + + +partition_data* +get_partition(partition_id partitionID) +{ + PartitionMap::iterator found = sPartitions.find(partitionID); + if (found == sPartitions.end()) + return NULL; + + return found->second; +} + + +partition_data* +get_parent_partition(partition_id partitionID) +{ + PartitionMap::iterator found = sPartitions.find(partitionID); + if (found == sPartitions.end()) + return NULL; + + return found->second->parent; +} + + +partition_data* +get_child_partition(partition_id partitionID, int32 index) +{ + PartitionMap::iterator found = sPartitions.find(partitionID); + if (found == sPartitions.end()) + return NULL; + + partition_entry* partition = found->second; + + if (index < 0 || index >= (int32)partition->children.size()) + return NULL; + + return partition->children[index]; +} + + +int +open_partition(partition_id partitionID, int openMode) +{ + return -1; +} + + +partition_data* +create_child_partition(partition_id partitionID, int32 index, off_t offset, + off_t size, partition_id childID) +{ + PartitionMap::iterator found = sPartitions.find(partitionID); + if (found == sPartitions.end()) + return NULL; + + partition_entry* parent = found->second; + + partition_entry* child = new partition_entry(); + memset(child, 0, sizeof(partition_entry)); + + child->id = sNextID++; + child->offset = offset; + child->size = size; + child->index = parent->children.size(); + + parent->children.push_back(child); + parent->child_count++; + sPartitions.insert(std::make_pair(child->id, child)); + + printf(" new partition ID %ld (child of %ld)\n", child->id, parent->id); + return child; +} + + +bool +delete_partition(partition_id partitionID) +{ + // TODO + return false; +} + + +void +partition_modified(partition_id partitionID) +{ + // TODO: implemented +} + + +status_t +scan_partition(partition_id partitionID) +{ + PartitionMap::iterator found = sPartitions.find(partitionID); + if (found == sPartitions.end()) + return B_ENTRY_NOT_FOUND; + + if (sDiskDevices.find(partitionID) == sDiskDevices.end()) { + // TODO: we would need to fake child partitons + return B_NOT_SUPPORTED; + } + + partition_entry* partition = found->second; + int fd = open(partition->path, O_RDONLY); + if (fd < 0) + return errno; + + scan_partition(fd, partitionID); + void* list = open_module_list("partitioning_systems"); + char name[PATH_MAX]; + size_t nameSize = sizeof(name); + while (read_next_module_name(list, name, &nameSize) == B_OK) { + puts(name); + nameSize = sizeof(name); + } + return B_ERROR; +} + + +bool +update_disk_device_job_progress(disk_job_id jobID, float progress) +{ + return false; +} + + +bool +set_disk_device_job_error_message(disk_job_id jobID, const char* message) +{ +#if 0 + KDiskDeviceManager* manager = KDiskDeviceManager::Default(); + if (ManagerLocker locker = manager) { + if (KDiskDeviceJob* job = manager->FindJob(jobID)) { + job->SetErrorMessage(message); + return true; + } + } +#endif + return false; +} + + +// #pragma mark - + + +static void +usage() +{ + extern const char* __progname; + + fprintf(stderr, "usage: %s \n" + "Must be started from the top-level Haiku directory to find its " + "add-ons.\n", __progname); + exit(1); +} + + +int +main(int argc, char** argv) +{ + if (argc != 2) + usage(); + + const char* deviceName = argv[1]; + + int device = open(deviceName, O_RDONLY); + if (device < 0) { + fprintf(stderr, "Could not open device \"%s\": %s\n", deviceName, + strerror(errno)); + return 1; + } + + partition_id id; + status_t status = create_disk_device(device, deviceName, &id); + if (status != B_OK) { + fprintf(stderr, "Could not get device size \"%s\": %s\n", deviceName, + strerror(status)); + return 1; + } + + print_disk_device(id); + scan_partition(device, id); + + PartitionMap::iterator iterator = sPartitions.begin(); + for (; iterator != sPartitions.end(); iterator++) { + print_partition(iterator->first); + } + + close(device); + return 0; +} +