2003-06-22 22:54:16 +00:00
|
|
|
// KFileDiskDevice.cpp
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
2004-06-11 21:03:31 +00:00
|
|
|
#include <KernelExport.h>
|
2003-06-22 22:54:16 +00:00
|
|
|
#include <Drivers.h>
|
2004-10-29 01:43:15 +00:00
|
|
|
#include <devfs.h>
|
2003-06-22 22:54:16 +00:00
|
|
|
|
|
|
|
|
#include <KDiskDeviceUtils.h>
|
|
|
|
|
#include <KFileDiskDevice.h>
|
2004-10-27 21:56:05 +00:00
|
|
|
#include <KPath.h>
|
2003-06-22 22:54:16 +00:00
|
|
|
|
2003-06-24 23:56:16 +00:00
|
|
|
#include "virtualdrive.h"
|
|
|
|
|
|
|
|
|
|
// debugging
|
|
|
|
|
//#define DBG(x)
|
|
|
|
|
#define DBG(x) x
|
2004-06-11 21:03:31 +00:00
|
|
|
#define OUT dprintf
|
2003-06-24 23:56:16 +00:00
|
|
|
|
2003-06-22 22:54:16 +00:00
|
|
|
static const char *kFileDevicesDir = "/dev/disk/virtual/files";
|
|
|
|
|
|
2004-10-28 22:22:04 +00:00
|
|
|
|
2003-06-22 22:54:16 +00:00
|
|
|
// 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
|
2004-10-28 22:22:04 +00:00
|
|
|
// (should actually not be necessary, since this method is only invoked
|
|
|
|
|
// by the DDM, which has already normalized the path)
|
2004-10-27 21:56:05 +00:00
|
|
|
KPath tmpFilePath;
|
2004-10-28 22:22:04 +00:00
|
|
|
status_t error = tmpFilePath.SetTo(filePath, true);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
2003-06-22 22:54:16 +00:00
|
|
|
// 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
|
2004-10-27 21:56:05 +00:00
|
|
|
KPath tmpDevicePath;
|
2003-06-22 22:54:16 +00:00
|
|
|
if (!devicePath) {
|
2004-10-28 22:22:04 +00:00
|
|
|
// no device path: we shall create a new device entry
|
2004-10-27 21:56:05 +00:00
|
|
|
if (tmpDevicePath.InitCheck() != B_OK)
|
|
|
|
|
return tmpDevicePath.InitCheck();
|
2004-10-28 22:22:04 +00:00
|
|
|
// TODO: Cleanup. The directory creation is done automatically by the devfs.
|
|
|
|
|
// // make the file devices dir
|
|
|
|
|
// if (mkdir(kFileDevicesDir, 0777) != 0) {
|
|
|
|
|
// if (errno != B_FILE_EXISTS)
|
|
|
|
|
// return errno;
|
|
|
|
|
// }
|
2003-06-22 22:54:16 +00:00
|
|
|
// make the directory
|
2004-10-28 16:05:22 +00:00
|
|
|
status_t error = _GetDirectoryPath(ID(), &tmpDevicePath);
|
2004-10-27 21:56:05 +00:00
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
2004-10-28 22:22:04 +00:00
|
|
|
// if (mkdir(tmpDevicePath.Path(), 0777) != 0)
|
|
|
|
|
// return errno;
|
2003-06-22 22:54:16 +00:00
|
|
|
// get the device path name
|
2004-10-28 22:22:04 +00:00
|
|
|
error = tmpDevicePath.Append("raw");
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
2004-10-27 21:56:05 +00:00
|
|
|
devicePath = tmpDevicePath.Path();
|
2004-10-28 22:22:04 +00:00
|
|
|
// register the file as virtual disk device
|
2004-10-28 16:05:22 +00:00
|
|
|
error = _RegisterDevice(filePath, devicePath);
|
2003-06-24 23:56:16 +00:00
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
2003-06-22 22:54:16 +00:00
|
|
|
}
|
2004-10-28 22:22:04 +00:00
|
|
|
error = set_string(fFilePath, filePath);
|
2003-06-22 22:54:16 +00:00
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
return KDiskDevice::SetTo(devicePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unset
|
|
|
|
|
void
|
|
|
|
|
KFileDiskDevice::Unset()
|
|
|
|
|
{
|
2003-06-24 23:56:16 +00:00
|
|
|
// remove the device and the directory it resides in
|
|
|
|
|
if (Path() && ID() >= 0) {
|
|
|
|
|
_UnregisterDevice(Path());
|
2004-10-28 22:22:04 +00:00
|
|
|
// TODO: Cleanup. The devfs will automatically remove the directory.
|
|
|
|
|
// KPath dirPath;
|
|
|
|
|
// if (_GetDirectoryPath(ID(), &dirPath) == B_OK)
|
|
|
|
|
// rmdir(dirPath.Path());
|
2003-06-24 23:56:16 +00:00
|
|
|
}
|
|
|
|
|
// free file path
|
2003-06-22 22:54:16 +00:00
|
|
|
free(fFilePath);
|
|
|
|
|
fFilePath = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// InitCheck
|
|
|
|
|
status_t
|
|
|
|
|
KFileDiskDevice::InitCheck() const
|
|
|
|
|
{
|
|
|
|
|
return KDiskDevice::InitCheck();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FilePath
|
|
|
|
|
const char *
|
|
|
|
|
KFileDiskDevice::FilePath() const
|
|
|
|
|
{
|
|
|
|
|
return fFilePath;
|
|
|
|
|
}
|
|
|
|
|
|
2004-10-28 22:22:04 +00:00
|
|
|
// GetMediaStatus
|
|
|
|
|
status_t
|
|
|
|
|
KFileDiskDevice::GetMediaStatus(status_t *mediaStatus)
|
|
|
|
|
{
|
|
|
|
|
// check the file
|
|
|
|
|
struct stat st;
|
|
|
|
|
if (stat(fFilePath, &st) == 0 && S_ISREG(st.st_mode))
|
|
|
|
|
*mediaStatus = B_OK;
|
|
|
|
|
else
|
|
|
|
|
*mediaStatus = B_DEV_NO_MEDIA;
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetGeometry
|
|
|
|
|
status_t
|
|
|
|
|
KFileDiskDevice::GetGeometry(device_geometry *geometry)
|
|
|
|
|
{
|
|
|
|
|
// check the file
|
|
|
|
|
struct stat st;
|
|
|
|
|
if (stat(fFilePath, &st) != 0 || !S_ISREG(st.st_mode))
|
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
|
|
// fill in the geometry
|
|
|
|
|
// default to 512 bytes block 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 = st.st_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;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-24 23:56:16 +00:00
|
|
|
// _RegisterDevice
|
2003-06-22 22:54:16 +00:00
|
|
|
status_t
|
2003-06-24 23:56:16 +00:00
|
|
|
KFileDiskDevice::_RegisterDevice(const char *file, const char *device)
|
2003-06-22 22:54:16 +00:00
|
|
|
{
|
2004-10-28 22:22:04 +00:00
|
|
|
return devfs_publish_file_device(device, file);
|
|
|
|
|
|
2003-06-24 23:56:16 +00:00
|
|
|
// TODO: For now we use the virtualdrive driver to register a file
|
|
|
|
|
// as a device and then simply symlink the assigned device to the
|
|
|
|
|
// desired device location. Replace that with the
|
|
|
|
|
// respective kernel magic for the OBOS kernel!
|
2004-10-27 21:56:05 +00:00
|
|
|
// -> Well, we could simply symlink the file there. Doesn't work for R5,
|
|
|
|
|
// but we should be able to deal with it properly.
|
2004-10-28 22:22:04 +00:00
|
|
|
//
|
|
|
|
|
// // open the virtualdrive control device
|
|
|
|
|
// int fd = open(VIRTUAL_DRIVE_CONTROL_DEVICE, O_RDONLY);
|
|
|
|
|
// if (fd < 0) {
|
|
|
|
|
// DBG(OUT("Failed to open virtualdrive control device: %s\n",
|
|
|
|
|
// strerror(errno)));
|
|
|
|
|
// return errno;
|
|
|
|
|
// }
|
|
|
|
|
// // set up the info
|
|
|
|
|
// virtual_drive_info info;
|
|
|
|
|
// strcpy(info.file_name, file);
|
|
|
|
|
// info.use_geometry = false;
|
|
|
|
|
// status_t error = B_OK;
|
|
|
|
|
// if (ioctl(fd, VIRTUAL_DRIVE_REGISTER_FILE, &info) != 0) {
|
|
|
|
|
// error = errno;
|
|
|
|
|
// DBG(OUT("Failed to install file device: %s\n", strerror(error)));
|
|
|
|
|
// }
|
|
|
|
|
// // close the control device
|
|
|
|
|
// close(fd);
|
|
|
|
|
// // create a symlink
|
|
|
|
|
// if (error == B_OK) {
|
|
|
|
|
// if (symlink(info.device_name, device) != 0) {
|
|
|
|
|
// DBG(OUT("Failed to create file device symlink: %s\n",
|
|
|
|
|
// strerror(error)));
|
|
|
|
|
// error = errno;
|
|
|
|
|
// // unregister the file device
|
|
|
|
|
// // open the device
|
|
|
|
|
// int deviceFD = open(info.device_name, O_RDONLY);
|
|
|
|
|
// if (deviceFD >= 0) {
|
|
|
|
|
// ioctl(deviceFD, VIRTUAL_DRIVE_UNREGISTER_FILE);
|
|
|
|
|
// close(deviceFD);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// return error;
|
2003-06-22 22:54:16 +00:00
|
|
|
}
|
|
|
|
|
|
2003-06-24 23:56:16 +00:00
|
|
|
// _UnregisterDevice
|
2003-06-22 22:54:16 +00:00
|
|
|
status_t
|
2003-06-24 23:56:16 +00:00
|
|
|
KFileDiskDevice::_UnregisterDevice(const char *_device)
|
2003-06-22 22:54:16 +00:00
|
|
|
{
|
2004-10-28 22:22:04 +00:00
|
|
|
return devfs_unpublish_file_device(_device);
|
|
|
|
|
|
|
|
|
|
// // read the symlink to get the path of the virtualdrive device
|
|
|
|
|
// char device[B_PATH_NAME_LENGTH];
|
|
|
|
|
// ssize_t bytesRead = readlink(_device, device, sizeof(device) - 1);
|
|
|
|
|
// if (bytesRead < 0)
|
|
|
|
|
// return errno;
|
|
|
|
|
// device[bytesRead] = '\0';
|
|
|
|
|
// // open the device
|
|
|
|
|
// int fd = open(device, O_RDONLY);
|
|
|
|
|
// if (fd < 0)
|
|
|
|
|
// return errno;
|
|
|
|
|
// // issue the ioctl
|
|
|
|
|
// status_t error = B_OK;
|
|
|
|
|
// if (ioctl(fd, VIRTUAL_DRIVE_UNREGISTER_FILE) != 0)
|
|
|
|
|
// error = errno;
|
|
|
|
|
// // close the control device
|
|
|
|
|
// close(fd);
|
|
|
|
|
// // remove the symlink
|
|
|
|
|
// if (error == B_OK) {
|
|
|
|
|
// if (remove(_device) < 0)
|
|
|
|
|
// error = errno;
|
|
|
|
|
// }
|
|
|
|
|
// return error;
|
2003-06-22 22:54:16 +00:00
|
|
|
}
|
|
|
|
|
|
2004-10-27 21:56:05 +00:00
|
|
|
// _GetDirectoryPath
|
|
|
|
|
status_t
|
|
|
|
|
KFileDiskDevice::_GetDirectoryPath(partition_id id, KPath *path)
|
|
|
|
|
{
|
|
|
|
|
if (!path || path->InitCheck() != B_OK)
|
|
|
|
|
return path->InitCheck();
|
2004-10-28 16:05:22 +00:00
|
|
|
status_t error = path->SetPath(kFileDevicesDir);
|
2004-10-27 21:56:05 +00:00
|
|
|
if (error == B_OK) {
|
2004-10-28 16:05:22 +00:00
|
|
|
char idBuffer[12];
|
2004-10-27 21:56:05 +00:00
|
|
|
sprintf(idBuffer, "%ld", id);
|
|
|
|
|
error = path->Append(idBuffer);
|
|
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|