#include <DiskDeviceRoster.h>
#include <new>
#include <Directory.h>
#include <DiskDevice.h>
#include <DiskDevicePrivate.h>
#include <DiskSystem.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <Message.h>
#include <Partition.h>
#include <Path.h>
#include <Volume.h>
#include <MessengerPrivate.h>
#include <syscalls.h>
#include <ddm_userland_interface_defs.h>
static const directory_which kAddOnDirs[] = {
B_USER_NONPACKAGED_ADDONS_DIRECTORY,
B_USER_ADDONS_DIRECTORY,
B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY,
};
static const int32 kAddOnDirCount
= sizeof(kAddOnDirs) / sizeof(directory_which);
BDiskDeviceRoster::BDiskDeviceRoster()
: fDeviceCookie(0),
fDiskSystemCookie(0),
fJobCookie(0)
{
}
BDiskDeviceRoster::~BDiskDeviceRoster()
{
}
status_t
BDiskDeviceRoster::GetNextDevice(BDiskDevice* device)
{
if (!device)
return B_BAD_VALUE;
size_t neededSize = 0;
partition_id id = _kern_get_next_disk_device_id(&fDeviceCookie,
&neededSize);
if (id < 0)
return id;
return device->_SetTo(id, true, neededSize);
}
status_t
BDiskDeviceRoster::RewindDevices()
{
fDeviceCookie = 0;
return B_OK;
}
status_t
BDiskDeviceRoster::GetNextDiskSystem(BDiskSystem* system)
{
if (!system)
return B_BAD_VALUE;
user_disk_system_info info;
status_t error = _kern_get_next_disk_system_info(&fDiskSystemCookie,
&info);
if (error == B_OK)
error = system->_SetTo(&info);
return error;
}
status_t
BDiskDeviceRoster::RewindDiskSystems()
{
fDiskSystemCookie = 0;
return B_OK;
}
status_t
BDiskDeviceRoster::GetDiskSystem(BDiskSystem* system, const char* name)
{
if (!system)
return B_BAD_VALUE;
int32 cookie = 0;
user_disk_system_info info;
while (_kern_get_next_disk_system_info(&cookie, &info) == B_OK) {
if (!strcmp(name, info.name)
|| !strcmp(name, info.short_name)
|| !strcmp(name, info.pretty_name))
return system->_SetTo(&info);
}
return B_ENTRY_NOT_FOUND;
}
partition_id
BDiskDeviceRoster::RegisterFileDevice(const char* filename)
{
if (!filename)
return B_BAD_VALUE;
return _kern_register_file_device(filename);
}
status_t
BDiskDeviceRoster::UnregisterFileDevice(const char* filename)
{
if (!filename)
return B_BAD_VALUE;
return _kern_unregister_file_device(-1, filename);
}
status_t
BDiskDeviceRoster::UnregisterFileDevice(partition_id device)
{
if (device < 0)
return B_BAD_VALUE;
return _kern_unregister_file_device(device, NULL);
}
bool
BDiskDeviceRoster::VisitEachDevice(BDiskDeviceVisitor* visitor,
BDiskDevice* device)
{
bool terminatedEarly = false;
if (visitor) {
int32 oldCookie = fDeviceCookie;
fDeviceCookie = 0;
BDiskDevice deviceOnStack;
BDiskDevice* useDevice = device ? device : &deviceOnStack;
while (!terminatedEarly && GetNextDevice(useDevice) == B_OK)
terminatedEarly = visitor->Visit(useDevice);
fDeviceCookie = oldCookie;
if (!terminatedEarly)
useDevice->Unset();
}
return terminatedEarly;
}
bool
BDiskDeviceRoster::VisitEachPartition(BDiskDeviceVisitor* visitor,
BDiskDevice* device, BPartition** partition)
{
bool terminatedEarly = false;
if (visitor) {
int32 oldCookie = fDeviceCookie;
fDeviceCookie = 0;
BDiskDevice deviceOnStack;
BDiskDevice* useDevice = device ? device : &deviceOnStack;
BPartition* foundPartition = NULL;
while (GetNextDevice(useDevice) == B_OK) {
foundPartition = useDevice->VisitEachDescendant(visitor);
if (foundPartition) {
terminatedEarly = true;
break;
}
}
fDeviceCookie = oldCookie;
if (!terminatedEarly)
useDevice->Unset();
else if (device && partition)
*partition = foundPartition;
}
return terminatedEarly;
}
bool
BDiskDeviceRoster::VisitEachMountedPartition(BDiskDeviceVisitor* visitor,
BDiskDevice* device, BPartition** partition)
{
bool terminatedEarly = false;
if (visitor) {
struct MountedPartitionFilter : public PartitionFilter {
virtual bool Filter(BPartition *partition, int32)
{ return partition->IsMounted(); }
} filter;
PartitionFilterVisitor filterVisitor(visitor, &filter);
terminatedEarly
= VisitEachPartition(&filterVisitor, device, partition);
}
return terminatedEarly;
}
bool
BDiskDeviceRoster::VisitEachMountablePartition(BDiskDeviceVisitor* visitor,
BDiskDevice* device, BPartition** partition)
{
bool terminatedEarly = false;
if (visitor) {
struct MountablePartitionFilter : public PartitionFilter {
virtual bool Filter(BPartition *partition, int32)
{ return partition->ContainsFileSystem(); }
} filter;
PartitionFilterVisitor filterVisitor(visitor, &filter);
terminatedEarly
= VisitEachPartition(&filterVisitor, device, partition);
}
return terminatedEarly;
}
status_t
BDiskDeviceRoster::FindPartitionByVolume(const BVolume& volume,
BDiskDevice* device, BPartition** _partition)
{
class FindPartitionVisitor : public BDiskDeviceVisitor {
public:
FindPartitionVisitor(dev_t volume)
:
fVolume(volume)
{
}
virtual bool Visit(BDiskDevice* device)
{
return Visit(device, 0);
}
virtual bool Visit(BPartition* partition, int32 level)
{
BVolume volume;
return partition->GetVolume(&volume) == B_OK
&& volume.Device() == fVolume;
}
private:
dev_t fVolume;
} visitor(volume.Device());
if (VisitEachMountedPartition(&visitor, device, _partition))
return B_OK;
return B_ENTRY_NOT_FOUND;
}
status_t
BDiskDeviceRoster::FindPartitionByMountPoint(const char* mountPoint,
BDiskDevice* device, BPartition** _partition)
{
BVolume volume(dev_for_path(mountPoint));
if (volume.InitCheck() == B_OK
&& FindPartitionByVolume(volume, device, _partition) == B_OK)
return B_OK;
return B_ENTRY_NOT_FOUND;
}
status_t
BDiskDeviceRoster::GetDeviceWithID(int32 id, BDiskDevice* device) const
{
if (!device)
return B_BAD_VALUE;
return device->_SetTo(id, true, 0);
}
status_t
BDiskDeviceRoster::GetPartitionWithID(int32 id, BDiskDevice* device,
BPartition** partition) const
{
if (!device || !partition)
return B_BAD_VALUE;
status_t error = device->_SetTo(id, false, 0);
if (error != B_OK)
return error;
*partition = device->FindDescendant(id);
if (!*partition)
return B_ENTRY_NOT_FOUND;
return B_OK;
}
status_t
BDiskDeviceRoster::GetDeviceForPath(const char* filename, BDiskDevice* device)
{
if (!filename || !device)
return B_BAD_VALUE;
size_t neededSize = 0;
partition_id id = _kern_find_disk_device(filename, &neededSize);
if (id < 0)
return id;
return device->_SetTo(id, true, neededSize);
}
status_t
BDiskDeviceRoster::GetPartitionForPath(const char* filename,
BDiskDevice* device, BPartition** partition)
{
if (!filename || !device || !partition)
return B_BAD_VALUE;
size_t neededSize = 0;
partition_id id = _kern_find_partition(filename, &neededSize);
if (id < 0)
return id;
status_t error = device->_SetTo(id, false, neededSize);
if (error != B_OK)
return error;
*partition = device->FindDescendant(id);
if (!*partition)
return B_ENTRY_NOT_FOUND;
return B_OK;
}
status_t
BDiskDeviceRoster::GetFileDeviceForPath(const char* filename,
BDiskDevice* device)
{
if (!filename || !device)
return B_BAD_VALUE;
size_t neededSize = 0;
partition_id id = _kern_find_file_disk_device(filename, &neededSize);
if (id < 0)
return id;
return device->_SetTo(id, true, neededSize);
}
status_t
BDiskDeviceRoster::StartWatching(BMessenger target, uint32 eventMask)
{
if (eventMask == 0)
return B_BAD_VALUE;
BMessenger::Private messengerPrivate(target);
port_id port = messengerPrivate.Port();
int32 token = messengerPrivate.Token();
return _kern_start_watching_disks(eventMask, port, token);
}
status_t
BDiskDeviceRoster::StopWatching(BMessenger target)
{
BMessenger::Private messengerPrivate(target);
port_id port = messengerPrivate.Port();
int32 token = messengerPrivate.Token();
return _kern_stop_watching_disks(port, token);
}
#if 0
status_t
BDiskDeviceRoster::GetNextPartitioningSystem(char *shortName, char *longName)
{
status_t error = (shortName ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
bool found = false;
do {
AddOnImage image;
error = _GetNextAddOn(fPartitionAddOnDir, &image);
if (error == B_OK) {
BDiskScannerPartitionAddOn *(*create_add_on)();
if (get_image_symbol(image.ID(), "create_ds_partition_add_on",
B_SYMBOL_TYPE_TEXT,
(void**)&create_add_on) == B_OK) {
if (BDiskScannerPartitionAddOn *addOn
= (*create_add_on)()) {
const char *addOnShortName = addOn->ShortName();
const char *addOnLongName = addOn->LongName();
if (addOnShortName && addOnLongName) {
strcpy(shortName, addOnShortName);
if (longName)
strcpy(longName, addOnLongName);
found = true;
}
delete addOn;
}
}
} else if (error == B_ENTRY_NOT_FOUND) {
error = _GetNextAddOnDir(&fPartitionAddOnDir,
&fPartitionAddOnDirIndex,
"partition");
}
} while (error == B_OK && !found);
}
return error;
}
status_t
BDiskDeviceRoster::GetNextFileSystem(char *shortName, char *longName)
{
status_t error = (shortName ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
bool found = false;
do {
AddOnImage image;
error = _GetNextAddOn(fFSAddOnDir, &image);
if (error == B_OK) {
BDiskScannerFSAddOn *(*create_add_on)();
if (get_image_symbol(image.ID(), "create_ds_fs_add_on",
B_SYMBOL_TYPE_TEXT,
(void**)&create_add_on) == B_OK) {
if (BDiskScannerFSAddOn *addOn = (*create_add_on)()) {
const char *addOnShortName = addOn->ShortName();
const char *addOnLongName = addOn->LongName();
if (addOnShortName && addOnLongName) {
strcpy(shortName, addOnShortName);
if (longName)
strcpy(longName, addOnLongName);
found = true;
}
delete addOn;
}
}
} else if (error == B_ENTRY_NOT_FOUND) {
error = _GetNextAddOnDir(&fFSAddOnDir, &fFSAddOnDirIndex,
"fs");
}
} while (error == B_OK && !found);
}
return error;
}
status_t
BDiskDeviceRoster::RewindPartitiningSystems()
{
if (fPartitionAddOnDir) {
delete fPartitionAddOnDir;
fPartitionAddOnDir = NULL;
}
fPartitionAddOnDirIndex = 0;
return B_OK;
}
status_t
BDiskDeviceRoster::RewindFileSystems()
{
if (fFSAddOnDir) {
delete fFSAddOnDir;
fFSAddOnDir = NULL;
}
fFSAddOnDirIndex = 0;
return B_OK;
}
status_t
BDiskDeviceRoster::_GetObjectWithID(const char *fieldName, int32 id,
BDiskDevice *device) const
{
status_t error = (device ? B_OK : B_BAD_VALUE);
BMessage request(B_REG_GET_DISK_DEVICE);
if (error == B_OK)
error = request.AddInt32(fieldName, id);
BMessage reply;
if (error == B_OK)
error = fManager.SendMessage(&request, &reply);
if (error == B_OK) {
status_t result = B_OK;
error = reply.FindInt32("result", &result);
if (error == B_OK)
error = result;
BMessage archive;
if (error == B_OK)
error = reply.FindMessage("device", &archive);
if (error == B_OK)
error = device->_Unarchive(&archive);
}
return error;
}
status_t
BDiskDeviceRoster::_GetNextAddOn(BDirectory **directory, int32 *index,
const char *subdir, AddOnImage *image)
{
status_t error = (directory && index && subdir && image
? B_OK : B_BAD_VALUE);
if (error == B_OK) {
bool found = false;
do {
error = _GetNextAddOn(*directory, image);
if (error == B_OK) {
found = true;
} else if (error == B_ENTRY_NOT_FOUND) {
error = _GetNextAddOnDir(directory, index, subdir);
}
} while (error == B_OK && !found);
}
return error;
}
status_t
BDiskDeviceRoster::_GetNextAddOn(BDirectory *directory, AddOnImage *image)
{
status_t error = (directory ? B_OK : B_ENTRY_NOT_FOUND);
if (error == B_OK) {
bool found = false;
while (error == B_OK && !found) {
BEntry entry;
error = directory->GetNextEntry(&entry);
BPath path;
if (error == B_OK && entry.GetPath(&path) == B_OK)
found = (image->Load(path.Path()) == B_OK);
}
}
return error;
}
status_t
BDiskDeviceRoster::_GetNextAddOnDir(BPath *path, int32 *index,
const char *subdir)
{
status_t error = (*index < kAddOnDirCount ? B_OK : B_ENTRY_NOT_FOUND);
if (error == B_OK) {
error = find_directory(kAddOnDirs[*index], path);
(*index)++;
}
if (error == B_OK) {
error = path->Append("disk_scanner");
if (error == B_OK)
error = path->Append(subdir);
}
if (error == B_OK)
printf(" next add-on dir: `%s'\n", path->Path());
return error;
}
status_t
BDiskDeviceRoster::_GetNextAddOnDir(BDirectory **directory, int32 *index,
const char *subdir)
{
BPath path;
status_t error = _GetNextAddOnDir(&path, index, subdir);
if (error == B_OK && !*directory) {
*directory = new BDirectory;
if (!*directory)
error = B_NO_MEMORY;
}
if (error == B_OK)
error = (*directory)->SetTo(path.Path());
if (error != B_OK && *directory) {
delete *directory;
*directory = NULL;
}
return error;
}
status_t
BDiskDeviceRoster::_LoadPartitionAddOn(const char *partitioningSystem,
AddOnImage *image, BDiskScannerPartitionAddOn **_addOn)
{
status_t error = partitioningSystem && image && _addOn
? B_OK : B_BAD_VALUE;
bool found = false;
BPath path;
BDirectory *directory = NULL;
int32 index = 0;
while (error == B_OK && !found) {
error = _GetNextAddOn(&directory, &index, "partition", image);
if (error == B_OK) {
BDiskScannerPartitionAddOn *(*create_add_on)();
if (get_image_symbol(image->ID(), "create_ds_partition_add_on",
B_SYMBOL_TYPE_TEXT,
(void**)&create_add_on) == B_OK) {
if (BDiskScannerPartitionAddOn *addOn = (*create_add_on)()) {
if (!strcmp(addOn->ShortName(), partitioningSystem)) {
*_addOn = addOn;
found = true;
} else
delete addOn;
}
}
}
}
if (directory)
delete directory;
if (error != B_OK && image)
image->Unload();
return error;
}
#endif