/* * 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 # include # include #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) { // maybe it's just a file struct stat stat; if (fstat(fDevice, &stat) < 0) return B_ERROR; if (_size) *_size = stat.st_size; if (_blockSize) // that shouldn't cause us any problems *_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; }