* Copyright 2008-2010, Axel DΓΆrfler, axeld@pinc-software.de.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "file_systems/DeviceOpener.h"
#ifndef FS_SHELL
# include <errno.h>
# include <Drivers.h>
# include <fs_cache.h>
#endif
DeviceOpener::DeviceOpener(const char* device, int mode)
:
fBlockCache(NULL)
{
Open(device, mode);
}
DeviceOpener::DeviceOpener(int fd, int mode)
:
fBlockCache(NULL)
{
Open(fd, mode);
}
DeviceOpener::~DeviceOpener()
{
if (fDevice >= 0){
RemoveCache(false);
close(fDevice);
}
}
int
DeviceOpener::Open(const char* device, int mode)
{
fDevice = open(device, mode | O_NOCACHE);
if (fDevice < 0)
fDevice = errno;
if (fDevice < 0 && _IsReadWrite(mode)) {
return Open(device, O_RDONLY | O_NOCACHE);
}
if (fDevice >= 0) {
fMode = mode;
if (_IsReadWrite(mode)) {
device_geometry geometry;
if (!ioctl(fDevice, B_GET_GEOMETRY, &geometry,
sizeof(device_geometry)))
{
if (geometry.read_only) {
close(fDevice);
return Open(device, O_RDONLY | O_NOCACHE);
}
}
}
}
return fDevice;
}
int
DeviceOpener::Open(int fd, int mode)
{
fDevice = dup(fd);
if (fDevice < 0)
return errno;
fMode = mode;
return fDevice;
}
void*
DeviceOpener::InitCache(off_t numBlocks, uint32 blockSize)
{
return fBlockCache = block_cache_create(fDevice, numBlocks, blockSize,
IsReadOnly());
}
void
DeviceOpener::RemoveCache(bool allowWrites)
{
if (fBlockCache == NULL)
return;
block_cache_delete(fBlockCache, allowWrites);
fBlockCache = NULL;
}
void
DeviceOpener::Keep()
{
fDevice = -1;
}
status_t
DeviceOpener::GetSize(off_t* _size, uint32* _blockSize)
{
device_geometry geometry;
if (ioctl(fDevice, B_GET_GEOMETRY, &geometry,
sizeof(device_geometry)) < 0) {
struct stat stat;
if (fstat(fDevice, &stat) < 0)
return B_ERROR;
if (_size)
*_size = stat.st_size;
if (_blockSize)
*_blockSize = 512;
return B_OK;
}
if (_size) {
*_size = 1ULL * geometry.head_count * geometry.cylinder_count
* geometry.sectors_per_track * geometry.bytes_per_sector;
}
if (_blockSize)
*_blockSize = geometry.bytes_per_sector;
return B_OK;
}