diff --git a/headers/private/storage/DiskDevice.h b/headers/private/storage/DiskDevice.h index b1394418bc..92c0cf3f8d 100644 --- a/headers/private/storage/DiskDevice.h +++ b/headers/private/storage/DiskDevice.h @@ -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); diff --git a/headers/private/storage/Partition.h b/headers/private/storage/Partition.h index a36da525fb..5c55d06fb9 100644 --- a/headers/private/storage/Partition.h +++ b/headers/private/storage/Partition.h @@ -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; diff --git a/src/kits/storage/DiskDevice.cpp b/src/kits/storage/DiskDevice.cpp index 8cd31d7e2e..c8c93689bf 100644 --- a/src/kits/storage/DiskDevice.cpp +++ b/src/kits/storage/DiskDevice.cpp @@ -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 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 diff --git a/src/kits/storage/Partition.cpp b/src/kits/storage/Partition.cpp index 687411c440..6a97a8ae2a 100644 --- a/src/kits/storage/Partition.cpp +++ b/src/kits/storage/Partition.cpp @@ -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 *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