432 lines
7.6 KiB
C++
432 lines
7.6 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
|
|||
|
|||
|
|||
KDiskDevice::KDiskDevice(partition_id id)
|
|||
:
|
|||
|
|
KPartition(id),
|
||
|
|
fDeviceData(),
|
||
|
|
fLocker(RW_LOCK_INITIALIZER("disk device")),
|
||
|
|
fFD(-1),
|
||
|
|
fMediaStatus(B_ERROR)
|
||
{
|
|||
Unset();
|
|||
fDevice = this;
|
|||
fPublishedName = (char*)"raw";
|
|||
}
|
|||
|
|
|
||
|
|||
KDiskDevice::~KDiskDevice()
|
|||
|
|
{
|
||
|
|
Unset();
|
||
|
|
}
|
||
|
|
|
||
|
|||
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;
|
|||
|
|
}
|
||
|
|
|
||
|
|||
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();
|
|||
}
|
|||
|
|
|
||
|
|||
status_t
|
|||
|
|
KDiskDevice::InitCheck() const
|
||
|
|
{
|
||
return B_OK;
|
|||
}
|
|||
|
|
|
||
|
|||
bool
|
|||
|
|
KDiskDevice::ReadLock()
|
||
|
|
{
|
||
return rw_lock_read_lock(&fLocker) == B_OK;
|
|||
}
|
|||
|
|
|
||
|
|||
void
|
|||
|
|
KDiskDevice::ReadUnlock()
|
||
|
|
{
|
||
rw_lock_read_unlock(&fLocker);
|
|||
}
|
|||
|
|
|
||
|
|||
bool
|
|||
|
|
KDiskDevice::WriteLock()
|
||
|
|
{
|
||
return rw_lock_write_lock(&fLocker) == B_OK;
|
|||
}
|
|||
|
|
|
||
|
|||
void
|
|||
|
|
KDiskDevice::WriteUnlock()
|
||
|
|
{
|
||
rw_lock_write_unlock(&fLocker);
|
|||
}
|
|||
|
|
|
||
|
|||
void
|
|||
|
|
KDiskDevice::SetID(partition_id id)
|
||
|
|
{
|
||
KPartition::SetID(id);
|
|||
fDeviceData.id = id;
|
|||
|
|
}
|
||
|
|
|
||
|
|||
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);
|
||
|
|
}
|
||
|
|
|