#include <errno.h>
#include <new>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <Directory.h>
#include <DiskDevice.h>
#include <DiskDevicePrivate.h>
#include <DiskDeviceVisitor.h>
#include <DiskSystem.h>
#include <fs_volume.h>
#include <Message.h>
#include <ObjectList.h>
#include <Partition.h>
#include <PartitioningInfo.h>
#include <Path.h>
#include <String.h>
#include <Volume.h>
#include <AutoDeleter.h>
#include <ddm_userland_interface_defs.h>
#include <syscalls.h>
#include "PartitionDelegate.h"
#undef TRACE
#ifdef TRACE_PARTITION
# define TRACE(x...) printf(x)
#else
# define TRACE(x...) do {} while (false)
#endif
using std::nothrow;
static const char *skAutoCreatePrefix = "_HaikuAutoCreated";
static inline int
compare_string(const char* str1, const char* str2)
{
if (str1 == NULL) {
if (str2 == NULL)
return 0;
return 1;
}
if (str2 == NULL)
return -1;
return strcmp(str1, str2);
}
BPartition::BPartition()
:
fDevice(NULL),
fParent(NULL),
fPartitionData(NULL),
fDelegate(NULL)
{
}
BPartition::~BPartition()
{
_Unset();
}
off_t
BPartition::Offset() const
{
return _PartitionData()->offset;
}
off_t
BPartition::Size() const
{
return _PartitionData()->size;
}
off_t
BPartition::ContentSize() const
{
return _PartitionData()->content_size;
}
uint32
BPartition::BlockSize() const
{
return _PartitionData()->block_size;
}
uint32
BPartition::PhysicalBlockSize() const
{
return _PartitionData()->physical_block_size;
}
int32
BPartition::Index() const
{
return _PartitionData()->index;
}
uint32
BPartition::Status() const
{
return _PartitionData()->status;
}
bool
BPartition::ContainsFileSystem() const
{
return _PartitionData()->flags & B_PARTITION_FILE_SYSTEM;
}
bool
BPartition::ContainsPartitioningSystem() const
{
return _PartitionData()->flags & B_PARTITION_PARTITIONING_SYSTEM;
}
bool
BPartition::IsDevice() const
{
return _PartitionData()->flags & B_PARTITION_IS_DEVICE;
}
bool
BPartition::IsReadOnly() const
{
return _PartitionData()->flags & B_PARTITION_READ_ONLY;
}
bool
BPartition::IsMounted() const
{
return _PartitionData()->flags & B_PARTITION_MOUNTED;
}
bool
BPartition::IsBusy() const
{
return _PartitionData()->flags & B_PARTITION_BUSY;
}
bool
BPartition::SupportsChildName() const
{
return _SupportsChildOperation(NULL, B_DISK_SYSTEM_SUPPORTS_NAME);
}
uint32
BPartition::Flags() const
{
return _PartitionData()->flags;
}
const char*
BPartition::Name() const
{
return _PartitionData()->name;
}
BString
BPartition::ContentName() const
{
if ((_PartitionData()->content_name == NULL || strlen(_PartitionData()->content_name) == 0)
&& ContainsFileSystem()) {
off_t divisor = 1ULL << 40;
off_t diskSize = _PartitionData()->content_size;
char unit = 'T';
if (diskSize < divisor) {
divisor = 1UL << 30;
unit = 'G';
if (diskSize < divisor) {
divisor = 1UL << 20;
unit = 'M';
}
}
double size = double((10 * diskSize + divisor - 1) / divisor);
BString name;
name.SetToFormat("%g %ciB %s volume", size / 10, unit, _PartitionData()->content_type);
return name;
}
return _PartitionData()->content_name;
}
const char*
BPartition::RawContentName() const
{
return _PartitionData()->content_name;
}
const char*
BPartition::Type() const
{
return _PartitionData()->type;
}
const char*
BPartition::ContentType() const
{
return _PartitionData()->content_type;
}
int32
BPartition::ID() const
{
return _PartitionData()->id;
}
const char*
BPartition::Parameters() const
{
return _PartitionData()->parameters;
}
const char*
BPartition::ContentParameters() const
{
return _PartitionData()->content_parameters;
}
status_t
BPartition::GetDiskSystem(BDiskSystem* diskSystem) const
{
const user_partition_data* data = _PartitionData();
if (data == NULL || diskSystem == NULL)
return B_BAD_VALUE;
if (data->disk_system < 0)
return B_ENTRY_NOT_FOUND;
return diskSystem->_SetTo(data->disk_system);
}
status_t
BPartition::GetPath(BPath* path) const
{
if (path == NULL || Parent() == NULL || Index() < 0)
return B_BAD_VALUE;
status_t error = Parent()->GetPath(path);
if (error != B_OK)
return error;
char indexBuffer[24];
if (Parent()->IsDevice()) {
const char* leaf = path->Leaf();
if (!leaf || strcmp(leaf, "raw") != B_OK)
return B_ERROR;
snprintf(indexBuffer, sizeof(indexBuffer), "%" B_PRId32, Index());
} else {
snprintf(indexBuffer, sizeof(indexBuffer), "%s_%" B_PRId32,
path->Leaf(), Index());
}
error = path->GetParent(path);
if (error == B_OK)
error = path->Append(indexBuffer);
return error;
}
status_t
BPartition::GetVolume(BVolume* volume) const
{
if (volume == NULL)
return B_BAD_VALUE;
return volume->SetTo(_PartitionData()->volume);
}
status_t
BPartition::GetIcon(BBitmap* icon, icon_size which) const
{
if (icon == NULL)
return B_BAD_VALUE;
status_t error;
if (IsMounted()) {
BVolume volume;
error = GetVolume(&volume);
if (error == B_OK)
error = volume.GetIcon(icon, which);
} else {
if (BDiskDevice* device = Device()) {
BPath path;
error = device->GetPath(&path);
if (error == B_OK)
error = get_device_icon(path.Path(), icon, which);
} else
error = B_ERROR;
}
return error;
}
status_t
BPartition::GetIcon(uint8** _data, size_t* _size, type_code* _type) const
{
if (_data == NULL || _size == NULL || _type == NULL)
return B_BAD_VALUE;
status_t error;
if (IsMounted()) {
BVolume volume;
error = GetVolume(&volume);
if (error == B_OK)
error = volume.GetIcon(_data, _size, _type);
} else {
if (BDiskDevice* device = Device()) {
BPath path;
error = device->GetPath(&path);
if (error == B_OK)
error = get_device_icon(path.Path(), _data, _size, _type);
} else
error = B_ERROR;
}
return error;
}
status_t
BPartition::GetMountPoint(BPath* mountPoint) const
{
if (mountPoint == NULL || !ContainsFileSystem())
return B_BAD_VALUE;
BVolume volume;
if (GetVolume(&volume) == B_OK) {
BDirectory dir;
status_t error = volume.GetRootDirectory(&dir);
if (error == B_OK)
error = mountPoint->SetTo(&dir, NULL);
return error;
}
const char* volumeName = ContentName();
if (volumeName == NULL || strlen(volumeName) == 0)
volumeName = Name();
if (volumeName == NULL || strlen(volumeName) == 0)
volumeName = "unnamed volume";
BString mountPointPath(volumeName);
mountPointPath.ReplaceAll('/', '-');
mountPointPath.Insert("/", 0);
BString basePath(mountPointPath);
int counter = 1;
while (true) {
BEntry entry;
status_t error = entry.SetTo(mountPointPath.String());
if (error != B_OK)
return error;
if (!entry.Exists())
break;
mountPointPath = basePath;
mountPointPath << counter;
counter++;
}
return mountPoint->SetTo(mountPointPath.String());
}
status_t
BPartition::Mount(const char* mountPoint, uint32 mountFlags, const char* parameters)
{
if (IsMounted())
return B_BUSY;
if (!ContainsFileSystem())
return B_BAD_VALUE;
BPath partitionPath;
status_t error = GetPath(&partitionPath);
if (error != B_OK)
return error;
bool deleteMountPoint = false;
BPath mountPointPath, markerPath;
if (!mountPoint) {
error = GetMountPoint(&mountPointPath);
if (error != B_OK)
return error;
mountPoint = mountPointPath.Path();
markerPath = mountPointPath;
markerPath.Append(skAutoCreatePrefix);
if (mkdir(mountPoint, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
return errno;
if (mkdir(markerPath.Path(), S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
rmdir(mountPoint);
return errno;
}
deleteMountPoint = true;
}
dev_t device = fs_mount_volume(mountPoint, partitionPath.Path(), NULL,
mountFlags, parameters);
if (device < B_OK && deleteMountPoint) {
rmdir(markerPath.Path());
rmdir(mountPoint);
}
if (device >= 0)
return Device()->Update();
return device;
}
status_t
BPartition::Unmount(uint32 unmountFlags)
{
if (!IsMounted())
return B_BAD_VALUE;
BPath path;
status_t status = GetMountPoint(&path);
if (status != B_OK)
return status;
status = fs_unmount_volume(path.Path(), unmountFlags);
if (status == B_OK) {
status = Device()->Update();
BPath markerPath = path;
markerPath.Append(skAutoCreatePrefix);
BEntry pathEntry (markerPath.Path());
if (pathEntry.InitCheck() == B_OK && pathEntry.Exists()) {
rmdir(markerPath.Path());
rmdir(path.Path());
}
}
return status;
}
BDiskDevice*
BPartition::Device() const
{
return fDevice;
}
BPartition*
BPartition::Parent() const
{
return fParent;
}
BPartition*
BPartition::ChildAt(int32 index) const
{
if (fDelegate != NULL) {
Delegate* child = fDelegate->ChildAt(index);
return child ? child->Partition() : NULL;
}
return _ChildAt(index);
}
int32
BPartition::CountChildren() const
{
if (fDelegate != NULL)
return fDelegate->CountChildren();
return _CountChildren();
}
int32
BPartition::CountDescendants() const
{
int32 count = 1;
for (int32 i = 0; BPartition* child = ChildAt(i); i++)
count += child->CountDescendants();
return count;
}
BPartition*
BPartition::FindDescendant(partition_id id) const
{
IDFinderVisitor visitor(id);
return VisitEachDescendant(&visitor);
}
status_t
BPartition::GetPartitioningInfo(BPartitioningInfo* info) const
{
if (!info)
return B_BAD_VALUE;
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->GetPartitioningInfo(info);
}
BPartition*
BPartition::VisitEachChild(BDiskDeviceVisitor* visitor) const
{
if (visitor != NULL) {
int32 level = _Level();
for (int32 i = 0; BPartition* child = ChildAt(i); i++) {
if (child->_AcceptVisitor(visitor, level))
return child;
}
}
return NULL;
}
BPartition*
BPartition::VisitEachDescendant(BDiskDeviceVisitor* visitor) const
{
if (visitor != NULL)
return const_cast<BPartition*>(this)->_VisitEachDescendant(visitor);
return NULL;
}
bool
BPartition::CanDefragment(bool* whileMounted) const
{
return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING,
B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED, whileMounted);
}
status_t
BPartition::Defragment() const
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->Defragment();
}
bool
BPartition::CanRepair(bool checkOnly, bool* whileMounted) const
{
uint32 flag;
uint32 whileMountedFlag;
if (checkOnly) {
flag = B_DISK_SYSTEM_SUPPORTS_CHECKING;
whileMountedFlag = B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED;
} else {
flag = B_DISK_SYSTEM_SUPPORTS_REPAIRING;
whileMountedFlag = B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED;
}
return _SupportsOperation(flag, whileMountedFlag, whileMounted);
}
status_t
BPartition::Repair(bool checkOnly) const
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->Repair(checkOnly);
}
bool
BPartition::CanResize(bool* canResizeContents, bool* whileMounted) const
{
BPartition* parent = Parent();
if (parent == NULL)
return false;
if (!parent->_SupportsChildOperation(this,
B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD)) {
return false;
}
if (!_HasContent())
return true;
return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_RESIZING,
B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED, whileMounted);
}
status_t
BPartition::ValidateResize(off_t* size) const
{
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL)
return B_NO_INIT;
status_t error = parent->fDelegate->ValidateResizeChild(fDelegate, size);
if (error != B_OK)
return error;
if (_HasContent()) {
off_t contentSize = *size;
error = fDelegate->ValidateResize(&contentSize);
if (error != B_OK)
return error;
if (contentSize > *size)
return B_BAD_VALUE;
}
return B_OK;
}
status_t
BPartition::Resize(off_t size)
{
BPartition* parent = Parent();
if (!parent || !fDelegate)
return B_NO_INIT;
status_t error;
off_t contentSize = size;
if (_HasContent()) {
error = fDelegate->ValidateResize(&contentSize);
if (error != B_OK)
return error;
if (contentSize > size)
return B_BAD_VALUE;
}
bool shrink = Size() > size;
if (shrink && ContentType() != NULL) {
error = fDelegate->Resize(contentSize);
if (error != B_OK)
return error;
}
error = parent->fDelegate->ResizeChild(fDelegate, size);
if (error != B_OK)
return error;
if (!shrink && ContentType() != NULL) {
error = fDelegate->Resize(contentSize);
if (error != B_OK)
return error;
}
return B_OK;
}
bool
BPartition::CanMove(BObjectList<BPartition>* unmovableDescendants,
BObjectList<BPartition>* movableOnlyIfUnmounted) const
{
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL)
return false;
if (!parent->_SupportsChildOperation(this,
B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD)) {
return false;
}
bool whileMounted;
bool movable = _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_MOVING,
B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED, &whileMounted);
if (!movable)
return false;
if (!whileMounted)
movableOnlyIfUnmounted->AddItem(const_cast<BPartition*>(this));
return true;
}
status_t
BPartition::ValidateMove(off_t* offset) const
{
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL)
return B_NO_INIT;
status_t error = parent->fDelegate->ValidateMoveChild(fDelegate, offset);
if (error != B_OK)
return error;
if (_HasContent()) {
off_t contentOffset = *offset;
error = fDelegate->ValidateMove(&contentOffset);
if (error != B_OK)
return error;
if (contentOffset != *offset)
return B_BAD_VALUE;
}
return B_OK;
}
status_t
BPartition::Move(off_t offset)
{
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL)
return B_NO_INIT;
status_t error = parent->fDelegate->MoveChild(fDelegate, offset);
if (error != B_OK)
return error;
if (_HasContent()) {
error = fDelegate->Move(offset);
if (error != B_OK)
return error;
}
return B_OK;
}
bool
BPartition::CanSetName() const
{
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL)
return false;
return parent->_SupportsChildOperation(this,
B_DISK_SYSTEM_SUPPORTS_SETTING_NAME);
}
status_t
BPartition::ValidateSetName(BString* name) const
{
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL)
return B_NO_INIT;
return parent->fDelegate->ValidateSetName(fDelegate, name);
}
status_t
BPartition::SetName(const char* name)
{
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL)
return B_NO_INIT;
return parent->fDelegate->SetName(fDelegate, name);
}
bool
BPartition::CanSetContentName(bool* whileMounted) const
{
return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME,
B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED,
whileMounted);
}
status_t
BPartition::ValidateSetContentName(BString* name) const
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->ValidateSetContentName(name);
}
status_t
BPartition::SetContentName(const char* name)
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->SetContentName(name);
}
bool
BPartition::CanSetType() const
{
BPartition* parent = Parent();
if (parent == NULL)
return false;
return parent->_SupportsChildOperation(this,
B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE);
}
status_t
BPartition::ValidateSetType(const char* type) const
{
BPartition* parent = Parent();
if (parent == NULL || parent->fDelegate == NULL || fDelegate == NULL)
return B_NO_INIT;
return parent->fDelegate->ValidateSetType(fDelegate, type);
}
status_t
BPartition::SetType(const char* type)
{
BPartition* parent = Parent();
if (parent == NULL || parent->fDelegate == NULL || fDelegate == NULL)
return B_NO_INIT;
return parent->fDelegate->SetType(fDelegate, type);
}
bool
BPartition::CanEditParameters() const
{
BPartition* parent = Parent();
if (parent == NULL)
return false;
return parent->_SupportsChildOperation(this,
B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS);
}
status_t
BPartition::GetParameterEditor(B_PARAMETER_EDITOR_TYPE type,
BPartitionParameterEditor** editor)
{
if (type == B_CREATE_PARAMETER_EDITOR) {
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->GetParameterEditor(type, editor);
} else {
BPartition* parent = Parent();
if (parent == NULL || parent->fDelegate == NULL)
return B_NO_INIT;
return parent->fDelegate->GetParameterEditor(type, editor);
}
}
status_t
BPartition::SetParameters(const char* parameters)
{
BPartition* parent = Parent();
if (parent == NULL || parent->fDelegate == NULL || fDelegate == NULL)
return B_NO_INIT;
return parent->fDelegate->SetParameters(fDelegate, parameters);
}
bool
BPartition::CanEditContentParameters(bool* whileMounted) const
{
return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS,
B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED,
whileMounted);
}
status_t
BPartition::SetContentParameters(const char* parameters)
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->SetContentParameters(parameters);
}
status_t
BPartition::GetNextSupportedType(int32* cookie, BString* type) const
{
TRACE("%p->BPartition::GetNextSupportedType(%ld)\n", this, *cookie);
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL) {
TRACE(" not prepared (parent: %p, fDelegate: %p)!\n", parent,
fDelegate);
return B_NO_INIT;
}
return parent->fDelegate->GetNextSupportedChildType(fDelegate, cookie,
type);
}
status_t
BPartition::GetNextSupportedChildType(int32* cookie, BString* type) const
{
TRACE("%p->BPartition::GetNextSupportedChildType(%ld)\n", this, *cookie);
if (fDelegate == NULL) {
TRACE(" not prepared!\n");
return B_NO_INIT;
}
return fDelegate->GetNextSupportedChildType(NULL, cookie, type);
}
bool
BPartition::BPartition::IsSubSystem(const char* diskSystem) const
{
BPartition* parent = Parent();
if (parent == NULL || fDelegate == NULL)
return false;
return parent->fDelegate->IsSubSystem(fDelegate, diskSystem);
}
bool
BPartition::CanInitialize(const char* diskSystem) const
{
if (Size() == 0 || BlockSize() == 0 || fDelegate == NULL)
return false;
return fDelegate->CanInitialize(diskSystem);
}
status_t
BPartition::ValidateInitialize(const char* diskSystem, BString* name,
const char* parameters)
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->ValidateInitialize(diskSystem, name, parameters);
}
status_t
BPartition::Initialize(const char* diskSystem, const char* name,
const char* parameters)
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->Initialize(diskSystem, name, parameters);
}
status_t
BPartition::Uninitialize()
{
return fDelegate->Uninitialize();
}
bool
BPartition::CanCreateChild() const
{
return _SupportsChildOperation(NULL, B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD);
}
status_t
BPartition::ValidateCreateChild(off_t* offset, off_t* size, const char* type,
BString* name, const char* parameters) const
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->ValidateCreateChild(offset, size, type, name, parameters);
}
status_t
BPartition::CreateChild(off_t offset, off_t size, const char* type,
const char* name, const char* parameters, BPartition** child)
{
if (fDelegate == NULL)
return B_NO_INIT;
return fDelegate->CreateChild(offset, size, type, name, parameters, child);
}
bool
BPartition::CanDeleteChild(int32 index) const
{
BPartition* child = ChildAt(index);
if (fDelegate == NULL || child == NULL)
return false;
return _SupportsChildOperation(child,
B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD);
}
status_t
BPartition::DeleteChild(int32 index)
{
if (fDelegate == NULL)
return B_NO_INIT;
BPartition* child = ChildAt(index);
if (child == NULL || child->Parent() != this)
return B_BAD_VALUE;
return fDelegate->DeleteChild(child->fDelegate);
}
BPartition::BPartition(const BPartition &)
{
}
BPartition &
BPartition::operator=(const BPartition &)
{
return *this;
}
status_t
BPartition::_SetTo(BDiskDevice* device, BPartition* parent,
user_partition_data* data)
{
_Unset();
if (device == NULL || data == NULL)
return B_BAD_VALUE;
fPartitionData = data;
fDevice = device;
fParent = parent;
fPartitionData->user_data = this;
status_t error = B_OK;
for (int32 i = 0; error == B_OK && i < fPartitionData->child_count; i++) {
BPartition* child = new(nothrow) BPartition;
if (child) {
error = child->_SetTo(fDevice, this, fPartitionData->children[i]);
if (error != B_OK)
delete child;
} else
error = B_NO_MEMORY;
}
if (error != B_OK)
_Unset();
return error;
}
void
BPartition::_Unset()
{
if (fPartitionData != NULL) {
for (int32 i = 0; i < fPartitionData->child_count; i++) {
if (BPartition* child = ChildAt(i))
delete child;
}
fPartitionData->user_data = NULL;
}
fDevice = NULL;
fParent = NULL;
fPartitionData = NULL;
fDelegate = NULL;
}
status_t
BPartition::_RemoveObsoleteDescendants(user_partition_data* data, bool* updated)
{
int32 count = CountChildren();
for (int32 i = count - 1; i >= 0; i--) {
BPartition* child = ChildAt(i);
bool found = false;
for (int32 k = data->child_count - 1; k >= 0; k--) {
if (data->children[k]->id == child->ID()) {
found = true;
status_t error = child->_RemoveObsoleteDescendants(
data->children[k], updated);
if (error != B_OK)
return error;
data->children[k]->user_data = child;
break;
}
}
if (!found) {
*updated = true;
_RemoveChild(i);
}
}
return B_OK;
}
status_t
BPartition::_Update(user_partition_data* data, bool* updated)
{
user_partition_data* oldData = fPartitionData;
fPartitionData = data;
if (data->offset != oldData->offset
|| data->size != oldData->size
|| data->block_size != oldData->block_size
|| data->physical_block_size != oldData->physical_block_size
|| data->status != oldData->status
|| data->flags != oldData->flags
|| data->volume != oldData->volume
|| data->disk_system != oldData->disk_system
|| compare_string(data->name, oldData->name)
|| compare_string(data->content_name, oldData->content_name)
|| compare_string(data->type, oldData->type)
|| compare_string(data->content_type, oldData->content_type)
|| compare_string(data->parameters, oldData->parameters)
|| compare_string(data->content_parameters,
oldData->content_parameters)) {
*updated = true;
}
status_t error = B_OK;
for (int32 i = 0; i < data->child_count; i++) {
user_partition_data* childData = data->children[i];
BPartition* child = (BPartition*)childData->user_data;
if (child) {
error = child->_Update(childData, updated);
if (error != B_OK)
return error;
} else {
*updated = true;
child = new(nothrow) BPartition;
if (!child)
return B_NO_MEMORY;
error = child->_SetTo(fDevice, this, childData);
if (error != B_OK) {
delete child;
return error;
}
childData->user_data = child;
}
}
return error;
}
void
BPartition::_RemoveChild(int32 index)
{
int32 count = CountChildren();
if (!fPartitionData || index < 0 || index >= count)
return;
delete ChildAt(index);
for (int32 i = index + 1; i < count; i++)
fPartitionData->children[i - 1] = fPartitionData->children[i];
fPartitionData->child_count--;
}
BPartition*
BPartition::_ChildAt(int32 index) const
{
if (index < 0 || index >= fPartitionData->child_count)
return NULL;
return (BPartition*)fPartitionData->children[index]->user_data;
}
int32
BPartition::_CountChildren() const
{
return fPartitionData->child_count;
}
int32
BPartition::_CountDescendants() const
{
int32 count = 1;
for (int32 i = 0; BPartition* child = _ChildAt(i); i++)
count += child->_CountDescendants();
return count;
}
int32
BPartition::_Level() const
{
int32 level = 0;
const BPartition* ancestor = this;
while ((ancestor = ancestor->Parent()))
level++;
return level;
}
bool
BPartition::_AcceptVisitor(BDiskDeviceVisitor* visitor, int32 level)
{
return visitor->Visit(this, level);
}
BPartition*
BPartition::_VisitEachDescendant(BDiskDeviceVisitor* visitor, int32 level)
{
if (level < 0)
level = _Level();
if (_AcceptVisitor(visitor, level))
return this;
for (int32 i = 0; BPartition* child = ChildAt(i); i++) {
if (BPartition* result = child->_VisitEachDescendant(visitor,
level + 1)) {
return result;
}
}
return NULL;
}
const user_partition_data*
BPartition::_PartitionData() const
{
return fDelegate ? fDelegate->PartitionData() : fPartitionData;
}
bool
BPartition::_HasContent() const
{
return ContentType() != NULL;
}
bool
BPartition::_SupportsOperation(uint32 flag, uint32 whileMountedFlag,
bool* whileMounted) const
{
if (fDelegate == NULL)
return false;
uint32 supported = fDelegate->SupportedOperations(flag | whileMountedFlag);
if (whileMounted)
*whileMounted = supported & whileMountedFlag;
return (supported & flag) != 0;
}
bool
BPartition::_SupportsChildOperation(const BPartition* child, uint32 flag) const
{
if (fDelegate == NULL || (child != NULL && child->fDelegate == NULL))
return false;
uint32 supported = fDelegate->SupportedChildOperations(
child != NULL ? child->fDelegate : NULL, flag);
return (supported & flag) != 0;
}
status_t
BPartition::_CreateDelegates()
{
if (fDelegate != NULL || fPartitionData == NULL)
return B_NO_INIT;
fDelegate = new(nothrow) Delegate(this);
if (fDelegate == NULL)
return B_NO_MEMORY;
status_t error = fDelegate->InitHierarchy(fPartitionData,
fParent != NULL ? fParent->fDelegate : NULL);
if (error != B_OK)
return error;
int32 count = _CountChildren();
for (int32 i = 0; i < count; i++) {
BPartition* child = _ChildAt(i);
error = child->_CreateDelegates();
if (error != B_OK)
return error;
}
return B_OK;
}
status_t
BPartition::_InitDelegates()
{
status_t error = fDelegate->InitAfterHierarchy();
if (error != B_OK)
return error;
int32 count = CountChildren();
for (int32 i = 0; i < count; i++) {
error = ChildAt(i)->_InitDelegates();
if (error != B_OK)
return error;
}
return B_OK;
}
void
BPartition::_DeleteDelegates()
{
int32 count = CountChildren();
for (int32 i = count - 1; i >= 0; i--)
ChildAt(i)->_DeleteDelegates();
delete fDelegate;
fDelegate = NULL;
if (fPartitionData == NULL)
delete this;
}
bool
BPartition::_IsModified() const
{
if (fDelegate == NULL)
return false;
return fDelegate->IsModified();
}