* Added support for updating.

* Implemented BDiskDevice::Eject() and GetName().
* Added a private support function for getting a messenger targeting the
  DiskDeviceManager in the registrar.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2723 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2003-02-16 18:07:23 +00:00
parent e2077e8d4c
commit 686968fb35
4 changed files with 398 additions and 41 deletions

View File

@ -3,12 +3,21 @@
// by the OpenBeOS license.
//---------------------------------------------------------------------
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <new.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <DiskDevice.h>
#include <DiskDevicePrivate.h>
#include <Drivers.h>
#include <Message.h>
#include <Partition.h>
#include <RegistrarDefs.h>
#include <Session.h>
/*! \class BDiskDevice
@ -44,6 +53,7 @@ BDiskDevice::~BDiskDevice()
void
BDiskDevice::Unset()
{
printf("BDiskDevice::Unset()\n");
fSessions.MakeEmpty();
fUniqueID = -1;
fChangeCounter = 0;
@ -122,6 +132,20 @@ 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.
@ -131,15 +155,79 @@ BDiskDevice::Path() const
\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.
to be returned (of interest for SCSI devices).
\param includeLUN \c true, if the LUN shall be included in the name
to be returned.
\return A human readable name for the device.
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.
*/
void
status_t
BDiskDevice::GetName(BString *name, bool includeBusID, bool includeLUN) const
{
// not implemented
// 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
@ -151,15 +239,24 @@ BDiskDevice::GetName(BString *name, bool includeBusID, bool includeLUN) const
\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.
to be returned (of interest for SCSI devices).
\param includeLUN \c true, if the LUN shall be included in the name
to be returned.
\return A human readable name for the device.
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.
*/
void
status_t
BDiskDevice::GetName(char *name, bool includeBusID, bool includeLUN) const
{
// not implemented
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
@ -247,13 +344,33 @@ BDiskDevice::UniqueID() const
The device media must, of course, be removable, and the device must
support ejecting the media.
\return \c B_OK, if the media are ejected successfully, another error code
otherwise.
\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
*/
status_t
BDiskDevice::Eject()
BDiskDevice::Eject(bool update)
{
return B_ERROR; // not implemented
// 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;
}
// LowLevelFormat
@ -274,12 +391,55 @@ BDiskDevice::LowLevelFormat()
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.
*/
status_t
BDiskDevice::Update()
BDiskDevice::Update(bool *updated)
{
return B_ERROR; // not implemented
// 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;
}
// VisitEachSession
@ -427,32 +587,22 @@ BDiskDevice::_Unarchive(BMessage *archive)
error = archive->FindInt32("id", &fUniqueID);
if (error == B_OK)
error = archive->FindInt32("change_counter", &fChangeCounter);
//printf(" check: %s\n", strerror(error));
// geometry
if (error == B_OK)
error = archive->FindInt64("size", &fSize);
//printf(" check: %s\n", strerror(error));
if (error == B_OK)
error = archive->FindInt32("block_size", &fBlockSize);
//printf(" check: %s\n", strerror(error));
if (error == B_OK)
error = archive->FindInt8("type", (int8*)&fType);
//printf(" check: %s\n", strerror(error));
if (error == B_OK)
error = archive->FindBool("removable", &fRemovable);
//printf(" check: %s\n", strerror(error));
if (error == B_OK)
error = archive->FindBool("read_only", &fReadOnly);
// if (error == B_OK)
// error = archive->FindBool("write_once", fGeometry.write_once);
// other data
//printf(" check: %s\n", strerror(error));
if (error == B_OK)
error = find_string(archive, "path", fPath);
//printf(" check: %s\n", strerror(error));
if (error == B_OK)
error = archive->FindInt32("media_status", &fMediaStatus);
//printf(" check: %s\n", strerror(error));
// sessions
type_code fieldType;
int32 count = 0;
@ -460,13 +610,10 @@ BDiskDevice::_Unarchive(BMessage *archive)
if (archive->GetInfo("sessions", &fieldType, &count) != B_OK)
count = 0;
}
//printf(" check: %s\n", strerror(error));
for (int32 i = 0; error == B_OK && i < count; i++) {
//printf(" check1: %s\n", strerror(error));
// get the archived session
BMessage sessionArchive;
error = archive->FindMessage("sessions", i, &sessionArchive);
//printf(" check1.1: %s\n", strerror(error));
// allocate a session object
BSession *session = NULL;
if (error == B_OK) {
@ -474,15 +621,12 @@ BDiskDevice::_Unarchive(BMessage *archive)
if (!session)
error = B_NO_MEMORY;
}
//printf(" check1.1: %s\n", strerror(error));
// unarchive the session
if (error == B_OK)
error = session->_Unarchive(&sessionArchive);
//printf(" check1.1: %s\n", strerror(error));
// add the session
if (error == B_OK && !_AddSession(session))
error = B_NO_MEMORY;
//printf(" check1.1: %s\n", strerror(error));
// cleanup on error
if (error != B_OK && session)
delete session;
@ -495,6 +639,104 @@ BDiskDevice::_Unarchive(BMessage *archive)
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)

View File

@ -5,6 +5,9 @@
#include <DiskDevicePrivate.h>
#include <DiskDevice.h>
#include <RegistrarDefs.h>
#include <RosterPrivate.h>
#include <Messenger.h>
#include <Partition.h>
#include <Session.h>
@ -73,3 +76,21 @@ IDFinderVisitor::Visit(BPartition *partition)
return (partition->UniqueID() == fID);
}
// get_disk_device_messenger
status_t
BPrivate::get_disk_device_messenger(BMessenger *messenger)
{
status_t error = (messenger ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
BMessage request(B_REG_GET_DISK_DEVICE_MESSENGER);
BMessage reply;
error = BRoster::Private().SendTo(&request, &reply, false);
if (error == B_OK && reply.what == B_REG_SUCCESS)
error = reply.FindMessenger("messenger", messenger);
else
error = B_ERROR;
}
return error;
}

View File

@ -29,12 +29,7 @@ BDiskDeviceRoster::BDiskDeviceRoster()
: fManager(),
fCookie(0)
{
BMessage request(B_REG_GET_DISK_DEVICE_MESSENGER);
BMessage reply;
if (BRoster::Private().SendTo(&request, &reply, false) == B_OK
&& reply.what == B_REG_SUCCESS) {
reply.FindMessenger("messenger", &fManager);
}
get_disk_device_messenger(&fManager);
}
// destructor
@ -499,6 +494,8 @@ BDiskDeviceRoster::StopWatching(BMessenger target)
return error;
}
void print_time(const char *format, bigtime_t &time);
// _GetObjectWithID
/*! \brief Returns a BDiskDevice for a given device, session or partition ID.
@ -520,15 +517,18 @@ status_t
BDiskDeviceRoster::_GetObjectWithID(const char *fieldName, int32 id,
BDiskDevice *device) const
{
bigtime_t time = system_time();
status_t error = (device ? B_OK : B_BAD_VALUE);
// compose request message
BMessage request(B_REG_GET_DISK_DEVICE);
if (error == B_OK)
error = request.AddInt32(fieldName, id);
print_time("composing request message", time);
// send request
BMessage reply;
if (error == B_OK)
error = fManager.SendMessage(&request, &reply);
print_time("sending request", time);
// analyze reply
if (error == B_OK) {
// result
@ -540,8 +540,10 @@ BDiskDeviceRoster::_GetObjectWithID(const char *fieldName, int32 id,
BMessage archive;
if (error == B_OK)
error = reply.FindMessage("device", &archive);
print_time("extracting archived device", time);
if (error == B_OK)
error = device->_Unarchive(&archive);
print_time("unarchiving device", time);
}
return error;
}

View File

@ -387,7 +387,6 @@ BSession::_Unarchive(BMessage *archive)
error = archive->FindInt32("change_counter", &fChangeCounter);
if (error == B_OK)
error = archive->FindInt32("index", &fIndex);
//printf(" check: %s\n", strerror(error));
// fInfo.*
if (error == B_OK)
error = archive->FindInt64("offset", &fInfo.offset);
@ -395,11 +394,9 @@ BSession::_Unarchive(BMessage *archive)
error = archive->FindInt64("size", &fInfo.size);
if (error == B_OK)
error = archive->FindInt32("flags", (int32*)&fInfo.flags);
//printf(" check: %s\n", strerror(error));
// other data
if (error == B_OK)
error = archive->FindString("partitioning", &fPartitioningSystem);
//printf(" check: %s\n", strerror(error));
// partitions
type_code fieldType;
int32 count = 0;
@ -436,6 +433,101 @@ BSession::_Unarchive(BMessage *archive)
return error;
}
// _Update
status_t
BSession::_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) {
if (error == B_OK)
error = archive->FindInt32("index", &fIndex);
// fInfo.*
if (error == B_OK)
error = archive->FindInt64("offset", &fInfo.offset);
if (error == B_OK)
error = archive->FindInt64("size", &fInfo.size);
if (error == B_OK)
error = archive->FindInt32("flags", (int32*)&fInfo.flags);
// other data
if (error == B_OK)
error = archive->FindString("partitioning", &fPartitioningSystem);
// partitions
// copy old partition list and empty it
BObjectList<BPartition> partitions;
for (int32 i = 0; BPartition *partition = fPartitions.ItemAt(i); i++)
partitions.AddItem(partition);
for (int32 i = fPartitions.CountItems() - 1; i >= 0; i--)
fPartitions.RemoveItemAt(i);
// get the partition count
type_code fieldType;
int32 count = 0;
if (error == B_OK) {
if (archive->GetInfo("partitions", &fieldType, &count) != B_OK)
count = 0;
}
for (int32 i = 0; error == B_OK && i < count; i++) {
// get the archived partitions
BMessage partitionArchive;
error = archive->FindMessage("partitions", i, &partitionArchive);
// check, whether we do already know that partition
int32 partitionID;
if (error == B_OK)
error = partitionArchive.FindInt32("id", &partitionID);
BPartition *partition = NULL;
for (int32 k = 0; k < partitions.CountItems(); k++) {
BPartition *oldPartition = partitions.ItemAt(i);
if (oldPartition->UniqueID() == partitionID) {
partition = oldPartition;
break;
}
}
if (error == B_OK) {
if (partition) {
// the partition is known: just update it
error = partition->_Unarchive(&partitionArchive);
} else {
// the partition is unknown
// allocate a partition object
partition = new(nothrow) BPartition;
if (!partition)
error = B_NO_MEMORY;
// unarchive the partition
if (error == B_OK)
error = partition->_Unarchive(&partitionArchive);
}
}
// add the partition
if (error == B_OK && !_AddPartition(partition))
error = B_NO_MEMORY;
// cleanup on error
if (error != B_OK && partition)
delete partition;
}
// delete all obsolete partitions
for (int32 i = partitions.CountItems() - 1; i >= 0; i--)
delete partitions.RemoveItemAt(i);
}
// cleanup on error
if (error != B_OK)
_Unset();
return error;
}
// _SetDevice
void
BSession::_SetDevice(BDiskDevice *device)