Files
haiku-beta6/src/kits/storage/DiskDevice.cpp
T

386 lines
8.5 KiB
C++
Raw Normal View History

//----------------------------------------------------------------------
// 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>
#include <new.h>
2003-02-16 18:07:23 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
2004-10-29 01:41:30 +00:00
#include <syscalls.h>
#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>
#include <Message.h>
2003-07-06 23:11:10 +00:00
#include <Path.h>
/*! \class BDiskDevice
\brief A BDiskDevice object represents a storage device.
*/
// constructor
/*! \brief Creates an uninitialized BDiskDevice object.
*/
BDiskDevice::BDiskDevice()
2003-07-06 23:11:10 +00:00
: fDeviceData(NULL)
{
}
// destructor
/*! \brief Frees all resources associated with this object.
*/
BDiskDevice::~BDiskDevice()
{
}
// 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-07-06 23:11:10 +00:00
bool
BDiskDevice::IsRemovableMedia() const
{
2003-07-06 23:11:10 +00:00
return (fDeviceData
&& fDeviceData->device_flags & B_DISK_DEVICE_REMOVABLE);
}
// IsReadOnlyMedia
2003-07-06 23:11:10 +00:00
bool
BDiskDevice::IsReadOnlyMedia() const
{
2003-07-06 23:11:10 +00:00
return (fDeviceData
&& fDeviceData->device_flags & B_DISK_DEVICE_READ_ONLY);
}
// IsWriteOnceMedia
bool
BDiskDevice::IsWriteOnceMedia() const
{
return (fDeviceData
&& fDeviceData->device_flags & B_DISK_DEVICE_WRITE_ONCE);
}
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-07-06 23:11:10 +00:00
status_t
BDiskDevice::Eject(bool update)
{
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-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-07-06 23:11:10 +00:00
status_t
BDiskDevice::Update(bool *updated)
{
return _Update(_IsShadow(), updated);
}
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-07-06 23:11:10 +00:00
if (!path || !fDeviceData)
return B_BAD_VALUE;
return path->SetTo(fDeviceData->path);
}
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
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)
{
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
}
// 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
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);
// 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)
error = _SetTo(data);
2003-07-06 23:11:10 +00:00
// cleanup on error
if (error != B_OK && data)
free(data);
2003-07-06 23:11:10 +00:00
return error;
}
// _SetTo
2003-07-06 23:11:10 +00:00
status_t
BDiskDevice::_SetTo(user_disk_device_data *data)
2003-07-06 23:11:10 +00:00
{
Unset();
if (!data)
return B_BAD_VALUE;
fDeviceData = data;
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;
}
// _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;
}
2003-02-16 18:07:23 +00:00
// _Update
status_t
BDiskDevice::_Update(user_disk_device_data *data, bool *updated)
2003-02-16 18:07: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) {
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
}
free(oldData);
2003-02-16 18:07:23 +00:00
}
return error;
}
// _AcceptVisitor
bool
BDiskDevice::_AcceptVisitor(BDiskDeviceVisitor *visitor, int32 level)
{
return visitor->Visit(this);
}