From 17750c77749bf04c961ce37626a5406b23cfdc5d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 22 Jun 2003 22:54:16 +0000 Subject: [PATCH] Added a special disk device class, that is responsible for representing files as disk devices. This will not only be great for testing the file and partitioning system modules' writing capabilities, it will also just be a nice feature to have. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3598 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../disk_device_manager/KFileDiskDevice.h | 42 +++++ .../disk_device_manager/KFileDiskDevice.cpp | 152 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 headers/private/kernel/disk_device_manager/KFileDiskDevice.h create mode 100644 src/kernel/core/disk_device_manager/KFileDiskDevice.cpp diff --git a/headers/private/kernel/disk_device_manager/KFileDiskDevice.h b/headers/private/kernel/disk_device_manager/KFileDiskDevice.h new file mode 100644 index 0000000000..b53ebe3d6e --- /dev/null +++ b/headers/private/kernel/disk_device_manager/KFileDiskDevice.h @@ -0,0 +1,42 @@ +// KFileDiskDevice.h + +#ifndef _K_FILE_DISK_DEVICE_H +#define _K_FILE_DISK_DEVICE_H + +#include + +#include "KDiskDevice.h" + +namespace BPrivate { +namespace DiskDevice { + +class KFileDiskDevice : public KDiskDevice { +public: + KFileDiskDevice(partition_id id = -1); + virtual ~KFileDiskDevice(); + + status_t SetTo(const char *filePath, const char *devicePath = NULL); + void Unset(); + virtual status_t InitCheck() const; + // TODO: probably superfluous + + const char *FilePath() const; + + virtual KPartition *CreateShadowPartition(); + +// virtual void Dump(bool deep = true, int32 level = 0); + +protected: + virtual status_t GetMediaStatus(status_t *mediaStatus); + virtual status_t GetGeometry(device_geometry *geometry); + +private: + char *fFilePath; +}; + +} // namespace DiskDevice +} // namespace BPrivate + +using BPrivate::DiskDevice::KFileDiskDevice; + +#endif // _K_FILE_DISK_DEVICE_H diff --git a/src/kernel/core/disk_device_manager/KFileDiskDevice.cpp b/src/kernel/core/disk_device_manager/KFileDiskDevice.cpp new file mode 100644 index 0000000000..5bff0267bf --- /dev/null +++ b/src/kernel/core/disk_device_manager/KFileDiskDevice.cpp @@ -0,0 +1,152 @@ +// KFileDiskDevice.cpp + +#include +#include +#include +#include + +#include + +#include +#include + +static const char *kFileDevicesDir = "/dev/disk/virtual/files"; + +// constructor +KFileDiskDevice::KFileDiskDevice(partition_id id) + : KDiskDevice(id), + fFilePath(NULL) +{ +} + +// destructor +KFileDiskDevice::~KFileDiskDevice() +{ + Unset(); +} + +// SetTo +status_t +KFileDiskDevice::SetTo(const char *filePath, const char *devicePath) +{ + // check params + if (!filePath || strlen(filePath) > B_PATH_NAME_LENGTH + || (devicePath && strlen(devicePath) > B_PATH_NAME_LENGTH)) { + return B_BAD_VALUE; + } + // normalize the file path + // TODO: For the time being, we get an absolute file name only. + char tmpFilePath[B_PATH_NAME_LENGTH]; + if (filePath[0] != '/') { + int32 len = (int32)B_PATH_NAME_LENGTH - (int32)strlen(filePath) - 2; + if (len < 0) + return B_ERROR; + // prepend the current directory path + if (!getcwd(tmpFilePath, len)) + return B_ERROR; + strcat(tmpFilePath, "/"); + strcat(tmpFilePath, filePath); + filePath = tmpFilePath; + } + // check the file + struct stat st; + if (stat(filePath, &st) != 0) + return errno; + if (!S_ISREG(st.st_mode)) + return B_BAD_VALUE; + // create the device, if requested + char tmpDevicePath[B_PATH_NAME_LENGTH]; + if (!devicePath) { + // no device path: we shall create a new device entry + // create the device entry + // TODO: Now we simply create a link. Replace that with the + // respective kernel magic! + // make the file devices dir + if (mkdir(kFileDevicesDir, 0777) != 0) { + if (errno != B_FILE_EXISTS) + return errno; + } + // make the directory + sprintf(tmpDevicePath, "%s/%ld", kFileDevicesDir, ID()); + if (mkdir(tmpDevicePath, 0777) != 0) + return errno; + // get the device path name + sprintf(tmpDevicePath, "%s/%ld/raw", kFileDevicesDir, ID()); + devicePath = tmpDevicePath; + if (symlink(filePath, devicePath) != 0) + return errno; + } + status_t error = set_string(fFilePath, filePath); + if (error != B_OK) + return error; + return KDiskDevice::SetTo(devicePath); +} + +// Unset +void +KFileDiskDevice::Unset() +{ + free(fFilePath); + fFilePath = NULL; +} + +// InitCheck +status_t +KFileDiskDevice::InitCheck() const +{ + return KDiskDevice::InitCheck(); +} + +// FilePath +const char * +KFileDiskDevice::FilePath() const +{ + return fFilePath; +} + +// CreateShadowPartition +KPartition * +KFileDiskDevice::CreateShadowPartition() +{ + // not implemented + return NULL; +} + +// GetMediaStatus +status_t +KFileDiskDevice::GetMediaStatus(status_t *mediaStatus) +{ + *mediaStatus = B_OK; + return B_OK; +} + +// GetGeometry +status_t +KFileDiskDevice::GetGeometry(device_geometry *geometry) +{ + // get the file size + struct stat st; + if (stat(fFilePath, &st) != 0) + return errno; + // default to 512 bytes block size + off_t size = st.st_size; + uint32 blockSize = 512; + // Optimally we have only 1 block per sector and only one head. + // Since we have only a uint32 for the cylinder count, this won't work + // for files > 2TB. So, we set the head count to the minimally possible + // value. + off_t blocks = size / blockSize; + uint32 heads = (blocks + ULONG_MAX - 1) / ULONG_MAX; + if (heads == 0) + heads = 1; + geometry->bytes_per_sector = blockSize; + geometry->sectors_per_track = 1; + geometry->cylinder_count = blocks / heads; + geometry->head_count = heads; + geometry->device_type = B_DISK; // TODO: Add a new constant. + geometry->removable = false; + geometry->read_only = false; + geometry->write_once = false; + return B_OK; +} +