Files
haiku-beta6/src/system/kernel/disk_device_manager/KDiskDevice.cpp
T
Ingo Weinhold a365e1cfbb Patch by Bryce Groff, some changes by myself:
* devfs:
  - devfs_[un]publish_partition(): They no longer get the partition path as
    parameter, but rather the device path and the partition name.
  - Added devfs_rename_partition(), which renames an already published
    partition node.
* KPartition/KDiskDevice:
  - Replaced the fPublished flag by fPublishedName, the name under which the
    partition is published. This simplifies UnpublishDevice() and makes it
    practically infallible.
  - Added GetFileName(), which only returns the partition's file name.
    Simplified GetPath() by using it.
  - When a partition is added/removed the subsequent sibling partitions get a
    new index. Now we also rename their published device nodes (and those of
    their descendents). When something goes wrong we unpublish the concerned
    partition's device to be on the safe side. Would be a shame to accidentally
    format the wrong partition, eh? :-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31520 a95241bf-73f2-0310-859d-f6bbb57e9c96
2009-07-11 14:35:04 +00:00

446 lines
7.9 KiB
C++

/*
* Copyright 2003-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <KernelExport.h>
#include <Drivers.h>
#include "ddm_userland_interface.h"
#include "KDiskDevice.h"
#include "KDiskDeviceUtils.h"
#include "KPath.h"
#include "UserDataWriter.h"
// debugging
//#define DBG(x)
#define DBG(x) x
#define OUT dprintf
// constructor
KDiskDevice::KDiskDevice(partition_id id)
: KPartition(id),
fDeviceData(),
fLocker("diskdevice"),
fFD(-1),
fMediaStatus(B_ERROR)
{
Unset();
fDevice = this;
fPublishedName = (char*)"raw";
}
// destructor
KDiskDevice::~KDiskDevice()
{
Unset();
}
// SetTo
status_t
KDiskDevice::SetTo(const char *path)
{
// check initialization and parameter
status_t error = InitCheck();
if (error != B_OK)
return error;
if (!path)
return B_BAD_VALUE;
Unset();
// set the path
error = set_string(fDeviceData.path, path);
if (error != B_OK)
return error;
// open the device
fFD = open(path, O_RDONLY);
if (fFD < 0)
return errno;
// get media status
error = GetMediaStatus(&fMediaStatus);
if (error != B_OK)
return error;
if (fMediaStatus == B_DEV_MEDIA_CHANGED)
fMediaStatus = B_OK;
// get device geometry
if (fMediaStatus == B_OK) {
error = GetGeometry(&fDeviceData.geometry);
if (error != B_OK)
return error;
} else {
// no media present: reset the geometry
_ResetGeometry();
}
// set device flags
_UpdateDeviceFlags();
// update partition data
_InitPartitionData();
return B_OK;
}
// Unset
void
KDiskDevice::Unset()
{
if (fFD >= 0) {
close(fFD);
fFD = -1;
}
fMediaStatus = B_ERROR;
fDeviceData.id = -1;
fDeviceData.flags = 0;
if (fDeviceData.path) {
free(fDeviceData.path);
fDeviceData.path = NULL;
}
_ResetGeometry();
}
// InitCheck
status_t
KDiskDevice::InitCheck() const
{
return fLocker.InitCheck();
}
// ReadLock
bool
KDiskDevice::ReadLock()
{
return fLocker.ReadLock();
}
// ReadUnlock
void
KDiskDevice::ReadUnlock()
{
fLocker.ReadUnlock();
}
// IsReadLocked
bool
KDiskDevice::IsReadLocked(bool orWriteLocked)
{
return fLocker.IsReadLocked(orWriteLocked);
}
// WriteLock
bool
KDiskDevice::WriteLock()
{
return fLocker.WriteLock();
}
// WriteUnlock
void
KDiskDevice::WriteUnlock()
{
fLocker.WriteUnlock();
}
// IsWriteLocked
bool
KDiskDevice::IsWriteLocked()
{
return fLocker.IsWriteLocked();
}
// SetID
void
KDiskDevice::SetID(partition_id id)
{
KPartition::SetID(id);
fDeviceData.id = id;
}
// PublishDevice
status_t
KDiskDevice::PublishDevice()
{
// PublishDevice(), UnpublishDevice() and Republish are no-ops
// for KDiskDevices, since they are always published.
return B_OK;
}
// UnpublishDevice
status_t
KDiskDevice::UnpublishDevice()
{
// PublishDevice(), UnpublishDevice() and Republish are no-ops
// for KDiskDevices, since they are always published.
return B_OK;
}
// RepublishDevice
status_t
KDiskDevice::RepublishDevice()
{
// PublishDevice(), UnpublishDevice() and Republish are no-ops
// for KDiskDevices, since they are always published.
return B_OK;
}
// SetDeviceFlags
void
KDiskDevice::SetDeviceFlags(uint32 flags)
{
fDeviceData.flags = flags;
}
// DeviceFlags
uint32
KDiskDevice::DeviceFlags() const
{
return fDeviceData.flags;
}
// IsReadOnlyMedia
bool
KDiskDevice::IsReadOnlyMedia() const
{
return fDeviceData.geometry.read_only;
}
// IsWriteOnce
bool
KDiskDevice::IsWriteOnce() const
{
return fDeviceData.geometry.write_once;
}
// IsRemovable
bool
KDiskDevice::IsRemovable() const
{
return fDeviceData.geometry.removable;
}
// HasMedia
bool
KDiskDevice::HasMedia() const
{
return fMediaStatus == B_OK || fMediaStatus == B_DEV_MEDIA_CHANGED;
}
bool
KDiskDevice::MediaChanged() const
{
return fMediaStatus == B_DEV_MEDIA_CHANGED;
}
void
KDiskDevice::UpdateMediaStatusIfNeeded()
{
// TODO: allow a device to notify us about its media status!
// This will then also need to clear any B_DEV_MEDIA_CHANGED
GetMediaStatus(&fMediaStatus);
}
void
KDiskDevice::UninitializeMedia()
{
UninitializeContents();
_ResetGeometry();
_UpdateDeviceFlags();
_InitPartitionData();
}
void
KDiskDevice::UpdateGeometry()
{
if (GetGeometry(&fDeviceData.geometry) != B_OK)
return;
_UpdateDeviceFlags();
_InitPartitionData();
}
// SetPath
status_t
KDiskDevice::SetPath(const char *path)
{
return set_string(fDeviceData.path, path);
}
// Path
const char *
KDiskDevice::Path() const
{
return fDeviceData.path;
}
status_t
KDiskDevice::GetFileName(char *buffer, size_t size) const
{
if (strlcpy(buffer, "raw", size) >= size)
return B_NAME_TOO_LONG;
return B_OK;
}
// GetPath
status_t
KDiskDevice::GetPath(KPath *path) const
{
if (!path || path->InitCheck() != B_OK)
return B_BAD_VALUE;
if (!fDeviceData.path)
return B_NO_INIT;
return path->SetPath(fDeviceData.path);
}
// SetFD
void
KDiskDevice::SetFD(int fd)
{
fFD = fd;
}
// FD
int
KDiskDevice::FD() const
{
return fFD;
}
// DeviceData
disk_device_data *
KDiskDevice::DeviceData()
{
return &fDeviceData;
}
// DeviceData
const disk_device_data *
KDiskDevice::DeviceData() const
{
return &fDeviceData;
}
// WriteUserData
void
KDiskDevice::WriteUserData(UserDataWriter &writer, user_partition_data *data)
{
return KPartition::WriteUserData(writer, data);
}
// WriteUserData
void
KDiskDevice::WriteUserData(UserDataWriter &writer)
{
KPartition *partition = this;
user_disk_device_data *data
= writer.AllocateDeviceData(partition->CountChildren());
char *path = writer.PlaceString(Path());
if (data) {
data->device_flags = DeviceFlags();
data->path = path;
writer.AddRelocationEntry(&data->path);
partition->WriteUserData(writer, &data->device_partition_data);
} else
partition->WriteUserData(writer, NULL);
}
// Dump
void
KDiskDevice::Dump(bool deep, int32 level)
{
OUT("device %ld: %s\n", ID(), Path());
OUT(" media status: %s\n", strerror(fMediaStatus));
OUT(" device flags: %lx\n", DeviceFlags());
if (fMediaStatus == B_OK)
KPartition::Dump(deep, 0);
}
// GetMediaStatus
status_t
KDiskDevice::GetMediaStatus(status_t *mediaStatus)
{
status_t error = B_OK;
if (ioctl(fFD, B_GET_MEDIA_STATUS, mediaStatus) != 0)
error = errno;
// maybe the device driver doesn't implement this ioctl -- see, if getting
// the device geometry succeeds
if (error != B_OK) {
device_geometry geometry;
if (GetGeometry(&geometry) == B_OK) {
// if the device is not removable, we can ignore the failed ioctl
// and return a media status of B_OK
if (!geometry.removable) {
error = B_OK;
*mediaStatus = B_OK;
}
}
}
return error;
}
// GetGeometry
status_t
KDiskDevice::GetGeometry(device_geometry *geometry)
{
if (ioctl(fFD, B_GET_GEOMETRY, geometry) != 0)
return errno;
return B_OK;
}
// _InitPartitionData
void
KDiskDevice::_InitPartitionData()
{
fDeviceData.id = fPartitionData.id;
fPartitionData.block_size = fDeviceData.geometry.bytes_per_sector;
fPartitionData.offset = 0;
fPartitionData.size = (off_t)fPartitionData.block_size
* fDeviceData.geometry.sectors_per_track
* fDeviceData.geometry.cylinder_count
* fDeviceData.geometry.head_count;
fPartitionData.flags |= B_PARTITION_IS_DEVICE;
}
void
KDiskDevice::_ResetGeometry()
{
fDeviceData.geometry.bytes_per_sector = 0;
fDeviceData.geometry.sectors_per_track = 0;
fDeviceData.geometry.cylinder_count = 0;
fDeviceData.geometry.head_count = 0;
fDeviceData.geometry.device_type = B_DISK;
fDeviceData.geometry.removable = true;
fDeviceData.geometry.read_only = true;
fDeviceData.geometry.write_once = false;
}
void
KDiskDevice::_UpdateDeviceFlags()
{
if (fDeviceData.geometry.removable)
SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_REMOVABLE);
if (HasMedia())
SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_HAS_MEDIA);
else
SetDeviceFlags(DeviceFlags() & ~B_DISK_DEVICE_HAS_MEDIA);
if (fDeviceData.geometry.read_only)
SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_READ_ONLY);
if (fDeviceData.geometry.write_once)
SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_WRITE_ONCE);
}