Implemented disk device updating. Some changes due to syscall changes.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4050 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2003-07-22 00:19:23 +00:00
parent e627d686c3
commit 426b44c60b
4 changed files with 292 additions and 605 deletions

View File

@ -40,9 +40,17 @@ private:
friend class BDiskDeviceList;
friend class BDiskDeviceRoster;
BDiskDevice::BDiskDevice(const BDiskDevice &);
BDiskDevice &BDiskDevice::operator=(const BDiskDevice &);
static status_t _GetData(partition_id id, bool deviceOnly, bool shadow,
size_t neededSize, user_disk_device_data **data);
status_t _SetTo(partition_id id, bool deviceOnly, bool shadow,
size_t neededSize);
status_t _SetTo(user_disk_device_data *data);
status_t _Update(bool shadow, bool *updated);
status_t _Update(user_disk_device_data *data, bool *updated);
virtual bool _AcceptVisitor(BDiskDeviceVisitor *visitor, int32 level);

View File

@ -139,10 +139,15 @@ private:
status_t _SetTo(BDiskDevice *device, BPartition *parent,
user_partition_data *data);
void _Unset();
status_t _RemoveObsoleteDescendants(user_partition_data *data,
bool *updated);
status_t _Update(user_partition_data *data, bool *updated);
void _RemoveChild(int32 index);
bool _IsShadow() const;
partition_id _ShadowID() const;
disk_system_id _DiskSystem() const;
int32 _ChangeCounter() const;
int32 _CountDescendants() const;
int32 _Level() const;

View File

@ -140,51 +140,7 @@ BDiskDevice::SetTo(partition_id id)
status_t
BDiskDevice::Update(bool *updated)
{
/*
// get a messenger for the disk device manager
// TODO: Cache the messenger? Maybe add a global variable?
BMessenger manager;
status_t error = get_disk_device_messenger(&manager);
// compose request message
BMessage request(B_REG_UPDATE_DISK_DEVICE);
if (error == B_OK)
error = request.AddInt32("device_id", fUniqueID);
if (error == B_OK)
error = request.AddInt32("change_counter", fChangeCounter);
if (error == B_OK)
error = request.AddInt32("update_policy", B_REG_DEVICE_UPDATE_CHANGED);
// send request
BMessage reply;
if (error == B_OK)
error = manager.SendMessage(&request, &reply);
// analyze reply
bool upToDate = true;
if (error == B_OK) {
// result
status_t result = B_OK;
error = reply.FindInt32("result", &result);
if (error == B_OK)
error = result;
if (error == B_OK)
error = reply.FindBool("up_to_date", &upToDate);
}
// get the archived device, if not up to date
if (error == B_OK && !upToDate) {
BMessage archive;
error = reply.FindMessage("device", &archive);
if (error == B_OK)
error = _Update(&archive);
}
// set result / cleanup on error
if (error == B_OK) {
if (updated)
*updated = !upToDate;
} else
Unset();
return error;
*/
// not implemented
return B_ERROR;
return _Update(_IsShadow(), updated);
}
// Unset
@ -235,8 +191,12 @@ BDiskDevice::PrepareModifications()
if (error != B_OK)
return error;
// update
// TODO: Add an _Update(bool shadow)?
return _SetTo(ID(), true, true, 0);
error = _Update(true, NULL);
if (error != B_OK) {
// bad -- cancelling the modifications is all we can do
_kern_cancel_disk_device_modifications(ID());
}
return error;
}
// CommitModifications
@ -264,12 +224,27 @@ BDiskDevice::CancelModifications()
return error;
}
// _SetTo
status_t
BDiskDevice::_SetTo(partition_id id, bool deviceOnly, bool shadow,
size_t neededSize)
// copy constructor
/*! \brief Privatized copy constructor to avoid usage.
*/
BDiskDevice::BDiskDevice(const BDiskDevice &)
{
}
// =
/*! \brief Privatized assignment operator to avoid usage.
*/
BDiskDevice &
BDiskDevice::operator=(const BDiskDevice &)
{
return *this;
}
// _GetData
status_t
BDiskDevice::_GetData(partition_id id, bool deviceOnly, bool shadow,
size_t neededSize, user_disk_device_data **data)
{
Unset();
// get the device data
void *buffer = NULL;
size_t bufferSize = 0;
@ -296,12 +271,29 @@ BDiskDevice::_SetTo(partition_id id, bool deviceOnly, bool shadow,
error = B_NO_MEMORY;
}
} while (error == B_BUFFER_OVERFLOW);
// set result / cleanup on error
if (error == B_OK)
*data = (user_disk_device_data*)buffer;
else if (buffer)
free(buffer);
return error;
}
// _SetTo
status_t
BDiskDevice::_SetTo(partition_id id, bool deviceOnly, bool shadow,
size_t neededSize)
{
Unset();
// get the device data
user_disk_device_data *data = NULL;
status_t error = _GetData(id, deviceOnly, shadow, neededSize, &data);
// set the data
if (error == B_OK)
error = _SetTo((user_disk_device_data*)buffer);
error = _SetTo(data);
// cleanup on error
if (error != B_OK)
free(buffer);
if (error != B_OK && data)
free(data);
return error;
}
@ -324,6 +316,54 @@ BDiskDevice::_SetTo(user_disk_device_data *data)
return error;
}
// _Update
status_t
BDiskDevice::_Update(bool shadow, bool *updated)
{
if (InitCheck() != B_OK)
return InitCheck();
// get the device data
user_disk_device_data *data = NULL;
status_t error = _GetData(ID(), true, shadow, 0, &data);
// set the data
if (error == B_OK)
error = _Update(data, updated);
// cleanup on error
if (error != B_OK && data)
free(data);
return error;
}
// _Update
status_t
BDiskDevice::_Update(user_disk_device_data *data, bool *updated)
{
if (!data || !fDeviceData || ID() != data->device_partition_data.id)
return B_BAD_VALUE;
bool _updated;
if (!updated)
updated = &_updated;
*updated = false;
// remove obsolete partitions
status_t error = _RemoveObsoleteDescendants(&data->device_partition_data,
updated);
if (error != B_OK)
return error;
// update existing partitions and add new ones
error = BPartition::_Update(&data->device_partition_data, updated);
if (error == B_OK) {
user_disk_device_data *oldData = fDeviceData;
fDeviceData = data;
// check for changes
if (data->device_flags != oldData->device_flags
|| strcmp(data->path, oldData->path)) {
*updated = true;
}
free(oldData);
}
return error;
}
// _AcceptVisitor
bool
BDiskDevice::_AcceptVisitor(BDiskDeviceVisitor *visitor, int32 level)
@ -331,518 +371,3 @@ BDiskDevice::_AcceptVisitor(BDiskDeviceVisitor *visitor, int32 level)
return visitor->Visit(this);
}
#if 0
// Path
/*! \brief Returns the path to the device.
\return The path to the device.
*/
const char *
BDiskDevice::Path() const
{
return (fPath[0] != '\0' ? fPath : NULL);
}
// skip_string_component
static
const char *
skip_string_component(const char *str, const char *component)
{
const char *remainder = NULL;
if (str && component) {
size_t len = strlen(component);
if (!strncmp(str, component, len))
remainder = str + len;
}
return remainder;
}
// GetName
/*! \brief Returns a human readable name for the device.
The method tries to interpret the device path, which it can do only for
floppy, IDE and SCSI devices, for others the device path is returned.
\param name Pointer to a pre-allocated BString to be set to the device
name.
\param includeBusID \c true, if the bus ID shall be included in the name
to be returned (of interest for SCSI devices).
\param includeLUN \c true, if the LUN shall be included in the name
to be returned (of interest for SCSI devices).
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a name.
- \c B_NO_INIT: The device is not properly initialized.
*/
status_t
BDiskDevice::GetName(BString *name, bool includeBusID, bool includeLUN) const
{
// check params and initialization
status_t error = (name ? B_OK : B_BAD_VALUE);
const char *path = Path();
if (error == B_OK && !path)
error = B_BAD_VALUE;
// analyze the device path
if (error == B_OK) {
bool recognized = false;
const char *prefix = "/dev/disk/";
size_t prefixLen = strlen(prefix);
if (!strncmp(path, prefix, prefixLen)) {
path = path + prefixLen;
// check first component
const char *tail = NULL;
// floppy
if (skip_string_component(path, "floppy/")) {
name->SetTo("floppy");
recognized = true;
// ide
} else if ((tail = skip_string_component(path, "ide/"))) {
int controller = 0;
bool master = false;
const char *_tail = tail;
if ((((tail = skip_string_component(_tail, "atapi/")))
|| ((tail = skip_string_component(_tail, "ata/"))))
&& isdigit(*tail)) {
controller = atoi(tail);
master = false;
if ((tail = strchr(tail, '/'))) {
tail++;
if (skip_string_component(tail, "master/")) {
master = true;
recognized = true;
} else if (skip_string_component(tail, "slave/"))
recognized = true;
}
}
if (recognized) {
name->SetTo("IDE ");
*name << (master ? "master" : "slave") << " bus:"
<< controller;
}
// scsi
} else if ((tail = skip_string_component(path, "scsi/"))) {
int bus = 0;
int id = 0;
int lun = 0;
if (sscanf(tail, "%d/%d/%d/raw", &bus, &id, &lun) == 3) {
recognized = true;
name->SetTo("SCSI");
if (includeBusID)
*name << " bus:" << bus;
*name << " id:" << id;
if (includeLUN)
*name << " lun:" << lun;
}
}
}
if (!recognized)
name->SetTo(path);
}
return error;
}
// GetName
/*! \brief Returns a human readable name for the device.
The method tries to interpret the device path, which it can do only for
floppy, IDE and SCSI devices, for others the device path is returned.
\param name Pointer to a pre-allocated char buffer into which the device
name shall be copied.
\param includeBusID \c true, if the bus ID shall be included in the name
to be returned (of interest for SCSI devices).
\param includeLUN \c true, if the LUN shall be included in the name
to be returned (of interest for SCSI devices).
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a name.
- \c B_NO_INIT: The device is not properly initialized.
*/
status_t
BDiskDevice::GetName(char *name, bool includeBusID, bool includeLUN) const
{
status_t error = (name ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
BString _name;
error = GetName(&_name, includeBusID, includeLUN);
if (error == B_OK)
strcpy(name, _name.String());
}
return error;
}
// IsReadOnly
/*! \brief Returns whether the device is read-only.
\return \c true, if the device is read-only, \c false otherwise.
*/
bool
BDiskDevice::IsReadOnly() const
{
return fReadOnly;
}
// IsFloppy
/*! \brief Returns whether the device is a floppy device.
\return \c true, if the device is a floppy device, \c false otherwise.
*/
bool
BDiskDevice::IsFloppy() const
{
return !strcmp(fPath, "/dev/disk/floppy/raw");
}
// Type
/*! \brief Returns the type of the device.
The type may be one of the following (note, that not all types make sense
for storage device, but they are listed anyway):
- \c B_DISK: Hard disks, floppy disks, etc.
- \c B_TAPE: Tape drives.
- \c B_PRINTER: Printers.
- \c B_CPU: CPU devices.
- \c B_WORM: Write-once, read-many devives.
- \c B_CD: CD ROMs.
- \c B_SCANNER: Scanners.
- \c B_OPTICAL: Optical devices.
- \c B_JUKEBOX: Jukeboxes.
- \c B_NETWORK: Network devices.
\return The type of the device.
*/
uint8
BDiskDevice::Type() const
{
return fType;
}
// UniqueID
/*! \brief Returns a unique identifier for this device.
The ID is not persistent, i.e. in general won't be the same after
rebooting.
\see BDiskDeviceRoster::GetDeviceWithID().
\return A unique identifier for this device.
*/
int32
BDiskDevice::UniqueID() const
{
return fUniqueID;
}
// LowLevelFormat
/*! \brief Low level formats the device.
\return \c B_OK, if everything went fine, another error code otherwise.
*/
status_t
BDiskDevice::LowLevelFormat()
{
return B_ERROR; // not implemented
}
// VisitEachSession
/*! \brief Iterates through the device's sessions.
The supplied visitor's Visit(BSession*) is invoked for each session.
If Visit() returns \c true, the iteration is terminated and the BSession
object just visited is returned.
\param visitor The visitor.
\return The BSession object at which the iteration was terminated, or
\c NULL, if the iteration has not been terminated.
*/
BSession *
BDiskDevice::VisitEachSession(BDiskDeviceVisitor *visitor)
{
if (visitor) {
for (int32 i = 0; BSession *session = SessionAt(i); i++) {
if (visitor->Visit(session))
return session;
}
}
return NULL;
}
// VisitEachPartition
/*! \brief Iterates through the device's partitions.
The supplied visitor's Visit(BPartition*) is invoked for each partition.
If Visit() returns \c true, the iteration is terminated and the BPartition
object just visited is returned.
\param visitor The visitor.
\return The BPartition object at which the iteration was terminated, or
\c NULL, if the iteration has not been terminated.
*/
BPartition *
BDiskDevice::VisitEachPartition(BDiskDeviceVisitor *visitor)
{
if (visitor) {
for (int32 i = 0; BSession *session = SessionAt(i); i++) {
if (BPartition *partition = session->VisitEachPartition(visitor))
return partition;
}
}
return NULL;
}
// Traverse
/*! \brief Pre-order traverses the tree of the spanned by the BDiskDevice and
its subobjects.
The supplied visitor's Visit() is invoked for the device object itself,
for each session and for each partition.
If Visit() returns \c true, the iteration is terminated and this method
returns \c true as well.
\param visitor The visitor.
\return \c true, if the iteration was terminated, \c false otherwise.
*/
bool
BDiskDevice::Traverse(BDiskDeviceVisitor *visitor)
{
if (visitor) {
// visit the device itself
if (visitor->Visit(this))
return true;
for (int32 i = 0; BSession *session = SessionAt(i); i++) {
// visit the session
if (visitor->Visit(session))
return true;
// visit all partitions on the session
if (session->VisitEachPartition(visitor))
return true;
}
}
return false;
}
// SessionWithID
/*! \brief Returns the session on the device, that has a certain ID.
\param id The ID of the session to be returned.
\return The session with ID \a id, or \c NULL, if a session with that
ID does not exist on this device.
*/
BSession *
BDiskDevice::SessionWithID(int32 id)
{
IDFinderVisitor visitor(id);
return VisitEachSession(&visitor);
}
// PartitionWithID
/*! \brief Returns the partition on the device, that has a certain ID.
\param id The ID of the partition to be returned.
\return The partition with ID \a id, or \c NULL, if a partition with that
ID does not exist on this device.
*/
BPartition *
BDiskDevice::PartitionWithID(int32 id)
{
IDFinderVisitor visitor(id);
return VisitEachPartition(&visitor);
}
// copy constructor
/*! \brief Privatized copy constructor to avoid usage.
*/
BDiskDevice::BDiskDevice(const BDiskDevice &)
{
}
// =
/*! \brief Privatized assignment operator to avoid usage.
*/
BDiskDevice &
BDiskDevice::operator=(const BDiskDevice &)
{
return *this;
}
// find_string
static
status_t
find_string(BMessage *message, const char *name, char *buffer)
{
const char *str;
status_t error = message->FindString(name, &str);
if (error == B_OK)
strcpy(buffer, str);
return error;
}
// _Unarchive
status_t
BDiskDevice::_Unarchive(BMessage *archive)
{
//printf("BDiskDevice::_Unarchive()\n");
//archive->PrintToStream();
Unset();
status_t error = (archive ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
// ID and change counter
if (error == B_OK)
error = archive->FindInt32("id", &fUniqueID);
if (error == B_OK)
error = archive->FindInt32("change_counter", &fChangeCounter);
// geometry
if (error == B_OK)
error = archive->FindInt64("size", &fSize);
if (error == B_OK)
error = archive->FindInt32("block_size", &fBlockSize);
if (error == B_OK)
error = archive->FindInt8("type", (int8*)&fType);
if (error == B_OK)
error = archive->FindBool("removable", &fRemovable);
if (error == B_OK)
error = archive->FindBool("read_only", &fReadOnly);
// other data
if (error == B_OK)
error = find_string(archive, "path", fPath);
if (error == B_OK)
error = archive->FindInt32("media_status", &fMediaStatus);
// sessions
type_code fieldType;
int32 count = 0;
if (error == B_OK) {
if (archive->GetInfo("sessions", &fieldType, &count) != B_OK)
count = 0;
}
for (int32 i = 0; error == B_OK && i < count; i++) {
// get the archived session
BMessage sessionArchive;
error = archive->FindMessage("sessions", i, &sessionArchive);
// allocate a session object
BSession *session = NULL;
if (error == B_OK) {
session = new(nothrow) BSession;
if (!session)
error = B_NO_MEMORY;
}
// unarchive the session
if (error == B_OK)
error = session->_Unarchive(&sessionArchive);
// add the session
if (error == B_OK && !_AddSession(session))
error = B_NO_MEMORY;
// cleanup on error
if (error != B_OK && session)
delete session;
}
}
// cleanup on error
if (error != B_OK)
Unset();
//printf("BDiskDevice::_Unarchive() done: %s\n", strerror(error));
return error;
}
// _Update
status_t
BDiskDevice::_Update(BMessage *archive)
{
status_t error = (archive ? B_OK : B_BAD_VALUE);
bool upToDate = false;
if (error == B_OK) {
// ID and change counter
int32 id;
if (error == B_OK)
error = archive->FindInt32("id", &id);
if (error == B_OK && id != fUniqueID)
error = B_ERROR;
int32 changeCounter;
if (error == B_OK)
error = archive->FindInt32("change_counter", &changeCounter);
upToDate = (fChangeCounter == changeCounter);
fChangeCounter = changeCounter;
}
if (error == B_OK && !upToDate) {
// geometry
if (error == B_OK)
error = archive->FindInt64("size", &fSize);
if (error == B_OK)
error = archive->FindInt32("block_size", &fBlockSize);
if (error == B_OK)
error = archive->FindInt8("type", (int8*)&fType);
if (error == B_OK)
error = archive->FindBool("removable", &fRemovable);
if (error == B_OK)
error = archive->FindBool("read_only", &fReadOnly);
// other data
if (error == B_OK)
error = find_string(archive, "path", fPath);
if (error == B_OK)
error = archive->FindInt32("media_status", &fMediaStatus);
// sessions
// copy old session list and empty it
BObjectList<BSession> sessions;
for (int32 i = 0; BSession *session = fSessions.ItemAt(i); i++)
sessions.AddItem(session);
for (int32 i = fSessions.CountItems() - 1; i >= 0; i--)
fSessions.RemoveItemAt(i);
// get the session count
type_code fieldType;
int32 count = 0;
if (error == B_OK) {
if (archive->GetInfo("sessions", &fieldType, &count) != B_OK)
count = 0;
}
for (int32 i = 0; error == B_OK && i < count; i++) {
// get the archived session
BMessage sessionArchive;
error = archive->FindMessage("sessions", i, &sessionArchive);
// check, whether we do already know that session
int32 sessionID;
if (error == B_OK)
error = sessionArchive.FindInt32("id", &sessionID);
BSession *session = NULL;
for (int32 k = 0; k < sessions.CountItems(); k++) {
BSession *oldSession = sessions.ItemAt(i);
if (oldSession->UniqueID() == sessionID) {
session = oldSession;
break;
}
}
if (error == B_OK) {
if (session) {
// the session is known: just update it
error = session->_Update(&sessionArchive);
} else {
// the session is unknown
// allocate a session object
session = new(nothrow) BSession;
if (!session)
error = B_NO_MEMORY;
// unarchive the session
if (error == B_OK)
error = session->_Unarchive(&sessionArchive);
}
}
// add the session
if (error == B_OK && !_AddSession(session))
error = B_NO_MEMORY;
// cleanup on error
if (error != B_OK && session)
delete session;
}
// delete all obsolete sessions
for (int32 i = sessions.CountItems() - 1; i >= 0; i--)
delete sessions.RemoveItemAt(i);
}
// cleanup on error
if (error != B_OK)
Unset();
return error;
}
// _AddSession
bool
BDiskDevice::_AddSession(BSession *session)
{
bool result = fSessions.AddItem(session);
if (result)
session->_SetDevice(this);
return result;
}
#endif //0

View File

@ -405,7 +405,7 @@ BPartition::GetPartitioningInfo(BPartitioningInfo *info) const
{
if (!info || !fPartitionData || !_IsShadow())
return B_BAD_VALUE;
return info->_SetTo(_ShadowID());
return info->_SetTo(_ShadowID(), _ChangeCounter());
}
// VisitEachChild
@ -437,6 +437,7 @@ BPartition::CanDefragment(bool *whileMounted) const
{
return (fPartitionData && _IsShadow()
&& _kern_supports_defragmenting_partition(_ShadowID(),
_ChangeCounter(),
whileMounted));
}
@ -446,7 +447,7 @@ BPartition::Defragment() const
{
if (!fPartitionData || !_IsShadow())
return B_BAD_VALUE;
status_t error = _kern_defragment_partition(_ShadowID());
status_t error = _kern_defragment_partition(_ShadowID(), _ChangeCounter());
if (error == B_OK)
error = Device()->Update();
return error;
@ -457,8 +458,8 @@ bool
BPartition::CanRepair(bool checkOnly, bool *whileMounted) const
{
return (fPartitionData && _IsShadow()
&& _kern_supports_repairing_partition(_ShadowID(), checkOnly,
whileMounted));
&& _kern_supports_repairing_partition(_ShadowID(), _ChangeCounter(),
checkOnly, whileMounted));
}
// Repair
@ -467,7 +468,8 @@ BPartition::Repair(bool checkOnly) const
{
if (!fPartitionData || !_IsShadow())
return B_BAD_VALUE;
status_t error = _kern_repair_partition(_ShadowID(), checkOnly);
status_t error = _kern_repair_partition(_ShadowID(), _ChangeCounter(),
checkOnly);
if (error == B_OK)
error = Device()->Update();
return error;
@ -478,7 +480,7 @@ bool
BPartition::CanResize(bool *canResizeContents, bool *whileMounted) const
{
return (fPartitionData && !IsDevice() && Parent() && _IsShadow()
&& _kern_supports_resizing_partition(_ShadowID(),
&& _kern_supports_resizing_partition(_ShadowID(), _ChangeCounter(),
canResizeContents, whileMounted));
}
@ -488,7 +490,8 @@ BPartition::ValidateResize(off_t *size, bool resizeContents) const
{
if (!fPartitionData || IsDevice() || !Parent() || !_IsShadow() || !size)
return B_BAD_VALUE;
return _kern_validate_resize_partition(_ShadowID(), size, resizeContents);
return _kern_validate_resize_partition(_ShadowID(), _ChangeCounter(), size,
resizeContents);
}
// Resize
@ -497,7 +500,8 @@ BPartition::Resize(off_t size, bool resizeContents)
{
if (!fPartitionData || IsDevice() || !Parent() || !_IsShadow())
return B_BAD_VALUE;
status_t error = _kern_resize_partition(_ShadowID(), size, resizeContents);
status_t error = _kern_resize_partition(_ShadowID(), _ChangeCounter(),
size, resizeContents);
if (error == B_OK)
error = Device()->Update();
return error;
@ -534,8 +538,9 @@ BPartition::CanMove(BObjectList<BPartition> *unmovableDescendants,
}
}
// get the info
bool result = _kern_supports_moving_partition(_ShadowID(), unmovableIDs,
needUnmountingIDs, descendantCount);
bool result = _kern_supports_moving_partition(_ShadowID(),
_ChangeCounter(), unmovableIDs, needUnmountingIDs,
descendantCount);
if (result) {
// find unmovable BPartition objects for returned IDs
for (int32 i = 0; i < descendantCount && unmovableIDs[i] != -1; i++) {
@ -562,7 +567,8 @@ BPartition::ValidateMove(off_t *newOffset, bool force) const
|| !newOffset) {
return B_BAD_VALUE;
}
return _kern_validate_move_partition(_ShadowID(), newOffset, force);
return _kern_validate_move_partition(_ShadowID(), _ChangeCounter(),
newOffset, force);
}
// Move
@ -571,7 +577,8 @@ BPartition::Move(off_t newOffset, bool force)
{
if (!fPartitionData || IsDevice() || !Parent() || !_IsShadow())
return B_BAD_VALUE;
status_t error = _kern_resize_partition(_ShadowID(), newOffset, force);
status_t error = _kern_resize_partition(_ShadowID(), _ChangeCounter(),
newOffset, force);
if (error == B_OK)
error = Device()->Update();
return error;
@ -582,7 +589,8 @@ bool
BPartition::CanSetName() const
{
return (fPartitionData && Parent() && _IsShadow()
&& _kern_supports_setting_partition_name(_ShadowID()));
&& _kern_supports_setting_partition_name(_ShadowID(),
_ChangeCounter()));
}
// ValidateSetName
@ -591,7 +599,8 @@ BPartition::ValidateSetName(char *name) const
{
if (!fPartitionData || IsDevice() || !Parent() || !_IsShadow() || !name)
return B_BAD_VALUE;
return _kern_validate_set_partition_name(_ShadowID(), name);
return _kern_validate_set_partition_name(_ShadowID(), _ChangeCounter(),
name);
}
// SetName
@ -600,7 +609,8 @@ BPartition::SetName(const char *name)
{
if (!fPartitionData || IsDevice() || !Parent() || !_IsShadow() || !name)
return B_BAD_VALUE;
status_t error = _kern_set_partition_name(_ShadowID(), name);
status_t error = _kern_set_partition_name(_ShadowID(), _ChangeCounter(),
name);
if (error == B_OK)
error = Device()->Update();
return error;
@ -612,6 +622,7 @@ BPartition::CanSetContentName(bool *whileMounted) const
{
return (fPartitionData && _IsShadow()
&& _kern_supports_setting_partition_content_name(_ShadowID(),
_ChangeCounter(),
whileMounted));
}
@ -621,7 +632,8 @@ BPartition::ValidateSetContentName(char *name) const
{
if (!fPartitionData || !_IsShadow() || !name)
return B_BAD_VALUE;
return _kern_validate_set_partition_content_name(_ShadowID(), name);
return _kern_validate_set_partition_content_name(_ShadowID(),
_ChangeCounter(), name);
}
// SetContentName
@ -630,7 +642,8 @@ BPartition::SetContentName(const char *name)
{
if (!fPartitionData || !_IsShadow() || !name)
return B_BAD_VALUE;
status_t error = _kern_set_partition_content_name(_ShadowID(), name);
status_t error = _kern_set_partition_content_name(_ShadowID(),
_ChangeCounter(), name);
if (error == B_OK)
error = Device()->Update();
return error;
@ -641,7 +654,8 @@ bool
BPartition::CanSetType() const
{
return (fPartitionData && Parent() && _IsShadow()
&& _kern_supports_setting_partition_type(_ShadowID()));
&& _kern_supports_setting_partition_type(_ShadowID(),
_ChangeCounter()));
}
// ValidateSetType
@ -650,7 +664,8 @@ BPartition::ValidateSetType(const char *type) const
{
if (!fPartitionData || IsDevice() || !Parent() || !_IsShadow() || !type)
return B_BAD_VALUE;
return _kern_validate_set_partition_type(_ShadowID(), type);
return _kern_validate_set_partition_type(_ShadowID(), _ChangeCounter(),
type);
}
// SetType
@ -659,7 +674,8 @@ BPartition::SetType(const char *type)
{
if (!fPartitionData || IsDevice() || !Parent() || !_IsShadow() || !type)
return B_BAD_VALUE;
status_t error = _kern_set_partition_type(_ShadowID(), type);
status_t error = _kern_set_partition_type(_ShadowID(), _ChangeCounter(),
type);
if (error == B_OK)
error = Device()->Update();
return error;
@ -670,7 +686,8 @@ bool
BPartition::CanEditParameters() const
{
return (fPartitionData && Parent() && _IsShadow()
&& _kern_supports_setting_partition_parameters(_ShadowID()));
&& _kern_supports_setting_partition_parameters(_ShadowID(),
_ChangeCounter()));
}
// GetParameterEditor
@ -687,7 +704,9 @@ BPartition::SetParameters(const char *parameters)
{
if (!fPartitionData || IsDevice() || !Parent() || !_IsShadow())
return B_BAD_VALUE;
status_t error = _kern_set_partition_parameters(_ShadowID(), parameters);
status_t error = _kern_set_partition_parameters(_ShadowID(),
_ChangeCounter(),
parameters);
if (error == B_OK)
error = Device()->Update();
return error;
@ -699,7 +718,7 @@ BPartition::CanEditContentParameters(bool *whileMounted) const
{
return (fPartitionData && _IsShadow()
&& _kern_supports_setting_partition_content_parameters(
_ShadowID(), whileMounted));
_ShadowID(), _ChangeCounter(), whileMounted));
}
// GetContentParameterEditor
@ -717,6 +736,7 @@ BPartition::SetContentParameters(const char *parameters)
if (!fPartitionData || !_IsShadow())
return B_BAD_VALUE;
status_t error = _kern_set_partition_content_parameters(_ShadowID(),
_ChangeCounter(),
parameters);
if (error == B_OK)
error = Device()->Update();
@ -728,7 +748,9 @@ bool
BPartition::CanInitialize(const char *diskSystem) const
{
return (fPartitionData && diskSystem && _IsShadow()
&& _kern_supports_initializing_partition(_ShadowID(), diskSystem));
&& _kern_supports_initializing_partition(_ShadowID(),
_ChangeCounter(),
diskSystem));
}
// GetInitializationParameterEditor
@ -747,8 +769,8 @@ BPartition::ValidateInitialize(const char *diskSystem, char *name,
{
if (!fPartitionData || !_IsShadow() || !diskSystem || !name)
return B_BAD_VALUE;
return _kern_validate_initialize_partition(_ShadowID(), diskSystem, name,
parameters);
return _kern_validate_initialize_partition(_ShadowID(), _ChangeCounter(),
diskSystem, name, parameters);
}
// Initialize
@ -758,8 +780,8 @@ BPartition::Initialize(const char *diskSystem, const char *name,
{
if (!fPartitionData || !_IsShadow() || !diskSystem || !name)
return B_BAD_VALUE;
status_t error = _kern_initialize_partition(_ShadowID(), diskSystem, name,
parameters);
status_t error = _kern_initialize_partition(_ShadowID(), _ChangeCounter(),
diskSystem, name, parameters);
if (error == B_OK)
error = Device()->Update();
return error;
@ -770,7 +792,8 @@ bool
BPartition::CanCreateChild() const
{
return (fPartitionData && _IsShadow()
&& _kern_supports_creating_child_partition(_ShadowID()));
&& _kern_supports_creating_child_partition(_ShadowID(),
_ChangeCounter()));
}
// GetChildCreationParameterEditor
@ -789,8 +812,9 @@ BPartition::ValidateCreateChild(off_t *offset, off_t *size, const char *type,
{
if (!fPartitionData || !_IsShadow() || !offset || !size || !type)
return B_BAD_VALUE;
return _kern_validate_create_child_partition(_ShadowID(), offset, size,
type, parameters);
return _kern_validate_create_child_partition(_ShadowID(), _ChangeCounter(),
offset, size, type,
parameters);
}
// CreateChild
@ -802,8 +826,9 @@ BPartition::CreateChild(off_t offset, off_t size, const char *type,
return B_BAD_VALUE;
// send the request
partition_id childID = -1;
status_t error = _kern_create_child_partition(_ShadowID(), offset, size,
type, parameters, &childID);
status_t error = _kern_create_child_partition(_ShadowID(),
_ChangeCounter(), offset, size, type, parameters,
&childID);
// update the device
if (error == B_OK)
error = Device()->Update();
@ -822,7 +847,8 @@ BPartition::CanDeleteChild(int32 index) const
{
BPartition *child = ChildAt(index);
return (child && child->_IsShadow()
&& _kern_supports_deleting_child_partition(child->_ShadowID()));
&& _kern_supports_deleting_child_partition(child->_ShadowID(),
child->_ChangeCounter()));
}
// DeleteChild
@ -833,7 +859,8 @@ BPartition::DeleteChild(int32 index)
if (!fPartitionData || !_IsShadow() || !child)
return B_BAD_VALUE;
// send the request
status_t error = _kern_delete_partition(child->_ShadowID());
status_t error = _kern_delete_partition(child->_ShadowID(),
child->_ChangeCounter());
// update the device
if (error == B_OK)
error = Device()->Update();
@ -902,6 +929,121 @@ BPartition::_Unset()
fPartitionData = NULL;
}
// _RemoveObsoleteDescendants
status_t
BPartition::_RemoveObsoleteDescendants(user_partition_data *data,
bool *updated)
{
// remove all children not longer persistent
// Not exactly efficient: O(n^2), considering BList::RemoveItem()
// O(1). We could do better (O(n*log(n))), when sorting the arrays before,
// but then the list access is more random and we had to find the
// BPartition to remove, which makes the list operation definitely O(n).
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 partition: ask it to remove its obsolete descendants
found = true;
status_t error = child->_RemoveObsoleteDescendants(
data->children[k], updated);
if (error != B_OK)
return error;
// set the user data to the BPartition object to find it
// quicker later
data->children[k]->user_data = child;
break;
}
}
// if partition is obsolete, remove it
if (!found) {
*updated = true;
_RemoveChild(i);
}
}
return B_OK;
}
// compare_string
static
int
compare_string(const char *str1, const char *str2)
{
if (str1 == NULL) {
if (str2 == NULL)
return 0;
return 1;
} else if (str2 == NULL)
return -1;
return strcmp(str1, str2);
}
// _Update
status_t
BPartition::_Update(user_partition_data *data, bool *updated)
{
user_partition_data *oldData = fPartitionData;
fPartitionData = data;
// check for changes
if (data->offset != oldData->offset
|| data->size != oldData->size
|| data->block_size != oldData->block_size
|| data->status != oldData->status
|| data->flags != oldData->flags
|| data->volume != oldData->volume
|| data->disk_system != oldData->disk_system // not needed
|| 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;
}
// add new children and update existing ones
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) {
// old partition
error = child->_Update(childData, updated);
if (error != B_OK)
return error;
} else {
// new partition
*updated = true;
child = new(nothrow) BPartition;
if (child) {
error = child->_SetTo(fDevice, this, data->children[i]);
if (error != B_OK)
delete child;
} else
return B_NO_MEMORY;
childData->user_data = child;
}
}
return error;
}
// _RemoveChild
void
BPartition::_RemoveChild(int32 index)
{
int32 count = CountChildren();
if (!fPartitionData || index < 0 || index >= count)
return;
// delete the BPartition and its children
delete ChildAt(index);
// compact the children array
for (int32 i = index + 1; i < count; i++)
fPartitionData->children[i - 1] = fPartitionData->children[i];
fPartitionData->child_count--;
}
// _IsShadow
bool
BPartition::_IsShadow() const
@ -923,6 +1065,13 @@ BPartition::_DiskSystem() const
return (fPartitionData ? fPartitionData->disk_system : -1);
}
// _ChangeCounter
int32
BPartition::_ChangeCounter() const
{
return (fPartitionData ? fPartitionData->change_counter : -1);
}
// _CountDescendants
int32
BPartition::_CountDescendants() const