2003-01-31 22:06:20 +00:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
// This software is part of the OpenBeOS distribution and is covered
|
|
|
|
|
// by the OpenBeOS license.
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
2003-07-06 23:11:10 +00:00
|
|
|
#include <DiskDevice.h>
|
|
|
|
|
|
2003-02-16 18:07:23 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <fcntl.h>
|
2003-02-08 00:42:14 +00:00
|
|
|
#include <new.h>
|
2003-02-16 18:07:23 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
2003-02-08 00:42:14 +00:00
|
|
|
|
2004-10-29 01:41:30 +00:00
|
|
|
#include <syscalls.h>
|
|
|
|
|
|
2003-01-31 22:06:20 +00:00
|
|
|
#include <DiskDevice.h>
|
2003-07-06 23:11:10 +00:00
|
|
|
#include <DiskDeviceVisitor.h>
|
2003-02-16 18:07:23 +00:00
|
|
|
#include <Drivers.h>
|
2003-02-08 00:42:14 +00:00
|
|
|
#include <Message.h>
|
2003-07-06 23:11:10 +00:00
|
|
|
#include <Path.h>
|
|
|
|
|
|
2003-01-31 22:06:20 +00:00
|
|
|
|
2003-02-01 18:13:13 +00:00
|
|
|
/*! \class BDiskDevice
|
|
|
|
|
\brief A BDiskDevice object represents a storage device.
|
|
|
|
|
*/
|
|
|
|
|
|
2003-01-31 22:06:20 +00:00
|
|
|
// constructor
|
2003-02-01 18:13:13 +00:00
|
|
|
/*! \brief Creates an uninitialized BDiskDevice object.
|
|
|
|
|
*/
|
2003-01-31 22:06:20 +00:00
|
|
|
BDiskDevice::BDiskDevice()
|
2003-07-06 23:11:10 +00:00
|
|
|
: fDeviceData(NULL)
|
2003-01-31 22:06:20 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// destructor
|
2003-02-01 18:13:13 +00:00
|
|
|
/*! \brief Frees all resources associated with this object.
|
|
|
|
|
*/
|
2003-01-31 22:06:20 +00:00
|
|
|
BDiskDevice::~BDiskDevice()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-08 23:28:32 +00:00
|
|
|
// HasMedia
|
|
|
|
|
/*! \brief Returns whether the device contains a media.
|
|
|
|
|
\return \c true, if the device contains a media, \c false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
BDiskDevice::HasMedia() const
|
|
|
|
|
{
|
|
|
|
|
return (fDeviceData
|
|
|
|
|
&& fDeviceData->device_flags & B_DISK_DEVICE_HAS_MEDIA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsRemovableMedia
|
2003-07-06 23:11:10 +00:00
|
|
|
/*! \brief Returns whether the device media are removable.
|
|
|
|
|
\return \c true, if the device media are removable, \c false otherwise.
|
2003-02-01 18:13:13 +00:00
|
|
|
*/
|
2003-07-06 23:11:10 +00:00
|
|
|
bool
|
2003-07-08 23:28:32 +00:00
|
|
|
BDiskDevice::IsRemovableMedia() const
|
2003-02-01 18:13:13 +00:00
|
|
|
{
|
2003-07-06 23:11:10 +00:00
|
|
|
return (fDeviceData
|
|
|
|
|
&& fDeviceData->device_flags & B_DISK_DEVICE_REMOVABLE);
|
2003-02-01 18:13:13 +00:00
|
|
|
}
|
|
|
|
|
|
2003-07-08 23:28:32 +00:00
|
|
|
// IsReadOnlyMedia
|
2003-07-06 23:11:10 +00:00
|
|
|
bool
|
2003-07-08 23:28:32 +00:00
|
|
|
BDiskDevice::IsReadOnlyMedia() const
|
2003-02-01 18:13:13 +00:00
|
|
|
{
|
2003-07-06 23:11:10 +00:00
|
|
|
return (fDeviceData
|
2003-07-08 23:28:32 +00:00
|
|
|
&& fDeviceData->device_flags & B_DISK_DEVICE_READ_ONLY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsWriteOnceMedia
|
|
|
|
|
bool
|
|
|
|
|
BDiskDevice::IsWriteOnceMedia() const
|
|
|
|
|
{
|
|
|
|
|
return (fDeviceData
|
|
|
|
|
&& fDeviceData->device_flags & B_DISK_DEVICE_WRITE_ONCE);
|
2003-02-01 18:13:13 +00:00
|
|
|
}
|
|
|
|
|
|
2003-07-06 23:11:10 +00:00
|
|
|
// Eject
|
|
|
|
|
/*! \brief Eject the device's media.
|
|
|
|
|
|
|
|
|
|
The device media must, of course, be removable, and the device must
|
|
|
|
|
support ejecting the media.
|
|
|
|
|
|
|
|
|
|
\param update If \c true, Update() is invoked after successful ejection.
|
|
|
|
|
\return
|
|
|
|
|
- \c B_OK: Everything went fine.
|
|
|
|
|
- \c B_NO_INIT: The device is not properly initialized.
|
|
|
|
|
- \c B_BAD_VALUE: The device media is not removable.
|
|
|
|
|
- other error codes
|
2003-02-01 18:13:13 +00:00
|
|
|
*/
|
2003-07-06 23:11:10 +00:00
|
|
|
status_t
|
|
|
|
|
BDiskDevice::Eject(bool update)
|
2003-01-31 22:06:20 +00:00
|
|
|
{
|
2003-07-06 23:11:10 +00:00
|
|
|
/* // get path
|
|
|
|
|
const char *path = Path();
|
|
|
|
|
status_t error = (path ? B_OK : B_NO_INIT);
|
|
|
|
|
// check whether the device media is removable
|
|
|
|
|
if (error == B_OK && !IsRemovable())
|
|
|
|
|
error = B_BAD_VALUE;
|
|
|
|
|
// open, eject and close the device
|
|
|
|
|
if (error == B_OK) {
|
|
|
|
|
int fd = open(path, O_RDONLY);
|
|
|
|
|
if (fd < 0 || ioctl(fd, B_EJECT_DEVICE) != 0)
|
|
|
|
|
error = errno;
|
|
|
|
|
if (fd >= 0)
|
|
|
|
|
close(fd);
|
|
|
|
|
}
|
|
|
|
|
if (error == B_OK && update)
|
|
|
|
|
error = Update();
|
|
|
|
|
return error;
|
|
|
|
|
*/
|
|
|
|
|
// not implemented
|
|
|
|
|
return B_ERROR;
|
2003-01-31 22:06:20 +00:00
|
|
|
}
|
|
|
|
|
|
2003-07-15 01:15:17 +00:00
|
|
|
// SetTo
|
|
|
|
|
status_t
|
|
|
|
|
BDiskDevice::SetTo(partition_id id)
|
|
|
|
|
{
|
|
|
|
|
return _SetTo(id, true, false, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-06 23:11:10 +00:00
|
|
|
// Update
|
|
|
|
|
/*! \brief Updates the object to reflect the latest changes to the device.
|
|
|
|
|
|
|
|
|
|
Note, that subobjects (BSessions, BPartitions) may be deleted during this
|
|
|
|
|
operation. It is also possible, that the device doesn't exist anymore --
|
|
|
|
|
e.g. if it is hot-pluggable. Then an error is returned and the object is
|
|
|
|
|
uninitialized.
|
|
|
|
|
|
|
|
|
|
\param updated Pointer to a bool variable which shall be set to \c true,
|
|
|
|
|
if the object needed to be updated and to \c false otherwise.
|
|
|
|
|
May be \c NULL. Is not touched, if the method fails.
|
|
|
|
|
\return \c B_OK, if the update went fine, another error code otherwise.
|
2003-02-01 18:13:13 +00:00
|
|
|
*/
|
2003-07-06 23:11:10 +00:00
|
|
|
status_t
|
|
|
|
|
BDiskDevice::Update(bool *updated)
|
2003-01-31 22:06:20 +00:00
|
|
|
{
|
2003-07-22 00:19:23 +00:00
|
|
|
return _Update(_IsShadow(), updated);
|
2003-01-31 22:06:20 +00:00
|
|
|
}
|
|
|
|
|
|
2003-07-06 23:11:10 +00:00
|
|
|
// Unset
|
|
|
|
|
void
|
|
|
|
|
BDiskDevice::Unset()
|
|
|
|
|
{
|
2003-07-15 01:15:17 +00:00
|
|
|
BPartition::_Unset();
|
2003-07-06 23:11:10 +00:00
|
|
|
free(fDeviceData);
|
|
|
|
|
fDeviceData = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-15 01:15:17 +00:00
|
|
|
// InitCheck
|
|
|
|
|
status_t
|
|
|
|
|
BDiskDevice::InitCheck() const
|
|
|
|
|
{
|
|
|
|
|
return (fDeviceData ? B_OK : B_NO_INIT);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-06 23:11:10 +00:00
|
|
|
// GetPath
|
|
|
|
|
status_t
|
|
|
|
|
BDiskDevice::GetPath(BPath *path) const
|
2003-01-31 22:06:20 +00:00
|
|
|
{
|
2003-07-06 23:11:10 +00:00
|
|
|
if (!path || !fDeviceData)
|
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
return path->SetTo(fDeviceData->path);
|
2003-01-31 22:06:20 +00:00
|
|
|
}
|
|
|
|
|
|
2003-07-06 23:11:10 +00:00
|
|
|
// IsModified
|
|
|
|
|
bool
|
|
|
|
|
BDiskDevice::IsModified() const
|
|
|
|
|
{
|
2003-07-15 01:15:17 +00:00
|
|
|
return (InitCheck() == B_OK && _IsShadow()
|
|
|
|
|
&& _kern_is_disk_device_modified(ID()));
|
2003-07-06 23:11:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PrepareModifications
|
|
|
|
|
status_t
|
|
|
|
|
BDiskDevice::PrepareModifications()
|
|
|
|
|
{
|
2003-07-15 01:15:17 +00:00
|
|
|
// check initialization
|
|
|
|
|
status_t error = InitCheck();
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
if (_IsShadow())
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
// ask kernel to prepare for modifications
|
|
|
|
|
error = _kern_prepare_disk_device_modifications(ID());
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
// update
|
2003-07-22 00:19:23 +00:00
|
|
|
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;
|
2003-07-06 23:11:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CommitModifications
|
|
|
|
|
status_t
|
|
|
|
|
BDiskDevice::CommitModifications(bool synchronously,
|
|
|
|
|
BMessenger progressMessenger,
|
|
|
|
|
bool receiveCompleteProgressUpdates)
|
|
|
|
|
{
|
2003-09-22 21:48:33 +00:00
|
|
|
status_t error = InitCheck();
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
if (!_IsShadow())
|
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
// TODO: Get port and token from the progressMessenger
|
|
|
|
|
port_id port = -1;
|
|
|
|
|
int32 token = -1;
|
|
|
|
|
error = _kern_commit_disk_device_modifications(ID(), port, token,
|
|
|
|
|
receiveCompleteProgressUpdates);
|
|
|
|
|
if (error == B_OK)
|
|
|
|
|
error = _SetTo(ID(), true, false, 0);
|
|
|
|
|
return error;
|
2003-07-06 23:11:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CancelModifications
|
|
|
|
|
status_t
|
|
|
|
|
BDiskDevice::CancelModifications()
|
|
|
|
|
{
|
2003-07-15 01:15:17 +00:00
|
|
|
status_t error = InitCheck();
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
if (!_IsShadow())
|
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
error = _kern_cancel_disk_device_modifications(ID());
|
|
|
|
|
if (error == B_OK)
|
|
|
|
|
error = _SetTo(ID(), true, false, 0);
|
|
|
|
|
return error;
|
2003-07-06 23:11:10 +00:00
|
|
|
}
|
|
|
|
|
|
2003-07-22 00:19:23 +00:00
|
|
|
// 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
|
2003-07-06 23:11:10 +00:00
|
|
|
status_t
|
2003-07-22 00:19:23 +00:00
|
|
|
BDiskDevice::_GetData(partition_id id, bool deviceOnly, bool shadow,
|
|
|
|
|
size_t neededSize, user_disk_device_data **data)
|
2003-07-06 23:11:10 +00:00
|
|
|
{
|
|
|
|
|
// get the device data
|
|
|
|
|
void *buffer = NULL;
|
|
|
|
|
size_t bufferSize = 0;
|
|
|
|
|
if (neededSize > 0) {
|
|
|
|
|
// allocate initial buffer
|
|
|
|
|
buffer = malloc(neededSize);
|
|
|
|
|
if (!buffer)
|
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
bufferSize = neededSize;
|
|
|
|
|
}
|
|
|
|
|
status_t error = B_OK;
|
|
|
|
|
do {
|
2003-07-15 01:15:17 +00:00
|
|
|
error = _kern_get_disk_device_data(id, deviceOnly, shadow,
|
2003-07-06 23:11:10 +00:00
|
|
|
(user_disk_device_data*)buffer,
|
|
|
|
|
bufferSize, &neededSize);
|
|
|
|
|
if (error == B_BUFFER_OVERFLOW) {
|
|
|
|
|
// buffer to small re-allocate it
|
|
|
|
|
if (buffer)
|
|
|
|
|
free(buffer);
|
|
|
|
|
buffer = malloc(neededSize);
|
|
|
|
|
if (buffer)
|
|
|
|
|
bufferSize = neededSize;
|
|
|
|
|
else
|
|
|
|
|
error = B_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
} while (error == B_BUFFER_OVERFLOW);
|
2003-07-22 00:19:23 +00:00
|
|
|
// 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);
|
2003-07-06 23:11:10 +00:00
|
|
|
// set the data
|
|
|
|
|
if (error == B_OK)
|
2003-07-22 00:19:23 +00:00
|
|
|
error = _SetTo(data);
|
2003-07-06 23:11:10 +00:00
|
|
|
// cleanup on error
|
2003-07-22 00:19:23 +00:00
|
|
|
if (error != B_OK && data)
|
|
|
|
|
free(data);
|
2003-07-06 23:11:10 +00:00
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-08 18:26:15 +00:00
|
|
|
// _SetTo
|
2003-07-06 23:11:10 +00:00
|
|
|
status_t
|
2003-07-08 18:26:15 +00:00
|
|
|
BDiskDevice::_SetTo(user_disk_device_data *data)
|
2003-07-06 23:11:10 +00:00
|
|
|
{
|
|
|
|
|
Unset();
|
|
|
|
|
if (!data)
|
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
fDeviceData = data;
|
2003-07-08 18:26:15 +00:00
|
|
|
status_t error = BPartition::_SetTo(this, NULL,
|
|
|
|
|
&fDeviceData->device_partition_data);
|
2003-07-06 23:11:10 +00:00
|
|
|
if (error != B_OK) {
|
2003-07-15 01:15:17 +00:00
|
|
|
// If _SetTo() fails, the caller retains ownership of the supplied
|
|
|
|
|
// data. So, unset fDeviceData before calling Unset().
|
2003-07-06 23:11:10 +00:00
|
|
|
fDeviceData = NULL;
|
2003-07-15 01:15:17 +00:00
|
|
|
Unset();
|
2003-07-06 23:11:10 +00:00
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-22 00:19:23 +00:00
|
|
|
// _Update
|
2003-02-08 00:42:14 +00:00
|
|
|
status_t
|
2003-07-22 00:19:23 +00:00
|
|
|
BDiskDevice::_Update(bool shadow, bool *updated)
|
2003-02-08 00:42:14 +00:00
|
|
|
{
|
2003-07-22 00:19:23 +00:00
|
|
|
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
|
2003-02-08 23:34:47 +00:00
|
|
|
if (error == B_OK)
|
2003-07-22 00:19:23 +00:00
|
|
|
error = _Update(data, updated);
|
2003-02-08 00:42:14 +00:00
|
|
|
// cleanup on error
|
2003-07-22 00:19:23 +00:00
|
|
|
if (error != B_OK && data)
|
|
|
|
|
free(data);
|
2003-02-08 00:42:14 +00:00
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-16 18:07:23 +00:00
|
|
|
// _Update
|
|
|
|
|
status_t
|
2003-07-22 00:19:23 +00:00
|
|
|
BDiskDevice::_Update(user_disk_device_data *data, bool *updated)
|
2003-02-16 18:07:23 +00:00
|
|
|
{
|
2003-07-22 00:19:23 +00:00
|
|
|
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);
|
2003-02-16 18:07:23 +00:00
|
|
|
if (error == B_OK) {
|
2003-07-22 00:19:23 +00:00
|
|
|
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;
|
2003-02-16 18:07:23 +00:00
|
|
|
}
|
2003-07-22 00:19:23 +00:00
|
|
|
free(oldData);
|
2003-02-16 18:07:23 +00:00
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-22 00:19:23 +00:00
|
|
|
// _AcceptVisitor
|
2003-02-08 00:42:14 +00:00
|
|
|
bool
|
2003-07-22 00:19:23 +00:00
|
|
|
BDiskDevice::_AcceptVisitor(BDiskDeviceVisitor *visitor, int32 level)
|
2003-02-08 00:42:14 +00:00
|
|
|
{
|
2003-07-22 00:19:23 +00:00
|
|
|
return visitor->Visit(this);
|
2003-02-08 00:42:14 +00:00
|
|
|
}
|
|
|
|
|
|