diff --git a/Device/BlockDevice.cpp b/Device/BlockDevice.cpp index 8cb61af..4a326b1 100644 --- a/Device/BlockDevice.cpp +++ b/Device/BlockDevice.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -13,14 +14,183 @@ #include +#include +#include +#include +#include +#include using namespace Device; using ProFUSE::Exception; using ProFUSE::POSIXException; -#pragma mark - -#pragma mark BlockDevice + + +unsigned BlockDevice::ImageType(const char *type, unsigned defv) +{ + const char *tmp; + + + if (type == 0 || *type == 0) return defv; + + // type could be a filename, in which case we check the extension. + tmp = std::strrchr(type, '.'); + if (tmp) type = tmp + 1; + if (*type == 0) return defv; + + + if (::strcasecmp(type, "2mg") == 0) + return '2IMG'; + if (::strcasecmp(type, "2img") == 0) + return '2IMG'; + + if (::strcasecmp(type, "dc42") == 0) + return 'DC42'; + + if (::strcasecmp(type, "po") == 0) + return 'PO__'; + if (::strcasecmp(type, "dmg") == 0) + return 'PO__'; + + if (::strcasecmp(type, "dsk") == 0) + return 'DO__'; + if (::strcasecmp(type, "do") == 0) + return 'DO__'; + + if (::strcasecmp(type, "dvx") == 0) + return 'DVX_'; + if (::strcasecmp(type, "davex") == 0) + return 'DVX_'; + + + // not supported yet. + if (::strcasecmp(tmp, "sdk") == 0) + return 'SDK_'; + + return defv; +} + +BlockDevice *BlockDevice::Open(const char *name, bool readOnly, unsigned imageType) +{ +#undef __METHOD__ +#define __METHOD__ "BlockDevice::Open" + + struct stat st; + + std::memset(&st, 0, sizeof(st)); + + if (::stat(name, &st) != 0) + { + throw POSIXException(__METHOD__ ": stat error", errno); + } + + if (!imageType) + { + // /dev/xxxx + if (S_ISBLK(st.st_mode)) + return RawDevice::Open(name, readOnly); + + + imageType = ImageType(name, 'PO__'); + } + + + // TODO -- if no image type, guess based on file size? + + MappedFile file(name, readOnly); + + + switch (imageType) + { + case '2IMG': + return UniversalDiskImage::Open(&file); + + case 'DC42': + return DiskCopy42Image::Open(&file); + + case 'DO__': + return DOSOrderDiskImage::Open(&file); + + case 'PO__': + return ProDOSOrderDiskImage::Open(&file); + + case 'DVX_': + return DavexDiskImage::Open(&file); + + } + + // throw an error? + return NULL; + +} + + +// return the basename, without an extension. +static std::string filename(const std::string& src) +{ + unsigned start; + unsigned end; + + + if (src.empty()) return std::string(""); + + start = end = 0; + + for(unsigned i = 0, l = src.length(); i < l; ++i) + { + char c = src[i]; + if (c == '/') start = end = i + 1; + if (c == '.') end = i; + } + + if (start == src.length()) return std::string(""); + + if (start == end) return src.substr(start); + return src.substr(start, end - start); +} + + +BlockDevice *BlockDevice::Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType) +{ + std::string xname; + + if (!imageType) imageType = ImageType(fname, 'PO__'); + + if (vname == NULL) + { + xname = filename(std::string(fname)); + vname = xname.c_str(); + } + + + + + switch(imageType) + { + case '2IMG': + return UniversalDiskImage::Create(fname, blocks); + + case 'DC42': + return DiskCopy42Image::Create(fname, blocks, vname); + + case 'DO__': + return DOSOrderDiskImage::Create(fname, blocks); + + case 'PO__': + return ProDOSOrderDiskImage::Create(fname, blocks); + + case 'DVX_': + return DavexDiskImage::Create(fname, blocks, vname); + } + + return NULL; + +} + + + + BlockDevice::BlockDevice() { diff --git a/Device/BlockDevice.h b/Device/BlockDevice.h index 453958f..33680e3 100644 --- a/Device/BlockDevice.h +++ b/Device/BlockDevice.h @@ -15,6 +15,17 @@ namespace Device { class BlockDevice { public: + + // static methods. + static unsigned ImageType(const char *type, unsigned defv = 0); + + static BlockDevice *Open(const char *name, bool readOnly, unsigned imageType = 0); + static BlockDevice *Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType = 0); + + + + + virtual ~BlockDevice(); virtual BlockCache *createBlockCache(); diff --git a/Device/DiskImage.cpp b/Device/DiskImage.cpp index 156cb36..3820534 100644 --- a/Device/DiskImage.cpp +++ b/Device/DiskImage.cpp @@ -5,13 +5,9 @@ #include #include -#include - #include -#include -#include -#include + #include @@ -28,91 +24,6 @@ using ProFUSE::POSIXException; - - - - - -unsigned DiskImage::ImageType(const char *type, unsigned defv) -{ - const char *tmp; - - if (type == 0 || *type == 0) return defv; - - // type could be a filename, in which case we check the extension. - tmp = std::strrchr(type, '.'); - if (tmp) type = tmp + 1; - if (*type == 0) return defv; - - - if (::strcasecmp(type, "2mg") == 0) - return '2IMG'; - if (::strcasecmp(type, "2img") == 0) - return '2IMG'; - - if (::strcasecmp(type, "dc42") == 0) - return 'DC42'; - - if (::strcasecmp(type, "po") == 0) - return 'PO__'; - if (::strcasecmp(type, "dmg") == 0) - return 'PO__'; - - if (::strcasecmp(type, "dsk") == 0) - return 'DO__'; - if (::strcasecmp(type, "do") == 0) - return 'DO__'; - - if (::strcasecmp(type, "dvx") == 0) - return 'DVX_'; - if (::strcasecmp(type, "davex") == 0) - return 'DVX_'; - - /* - // not supported yet. - if (::strcasecmp(tmp, "sdk") == 0) - return 'SDK_'; - */ - return defv; -} - -BlockDevice *DiskImage::Open(const char *name, bool readOnly, unsigned imageType) -{ - if (!imageType) imageType = ImageType(name, 'PO__'); - - // TODO -- if no image type, guess based on file size? - // TODO -- check for /dev/* ? - - MappedFile file(name, readOnly); - - - switch (imageType) - { - case '2IMG': - return UniversalDiskImage::Open(&file); - - case 'DC42': - return DiskCopy42Image::Open(&file); - - case 'DO__': - return DOSOrderDiskImage::Open(&file); - - case 'PO__': - return ProDOSOrderDiskImage::Open(&file); - - case 'DVX_': - return DavexDiskImage::Open(&file); - - } - - // throw an error? - return NULL; - -} - - - - DiskImage::DiskImage(const char *name, bool readOnly) { File fd(name, readOnly ? O_RDONLY : O_RDWR); diff --git a/Device/DiskImage.h b/Device/DiskImage.h index e5b9b55..2132c37 100644 --- a/Device/DiskImage.h +++ b/Device/DiskImage.h @@ -18,11 +18,7 @@ namespace Device { class DiskImage : public BlockDevice { public: - static unsigned ImageType(const char *type, unsigned defv = 0); - - static BlockDevice *Open(const char *name, bool readOnly, unsigned imageType = 0); - virtual ~DiskImage(); virtual void read(unsigned block, void *bp); diff --git a/Device/RawDevice.cpp b/Device/RawDevice.cpp index 1e9c6ca..2d29df7 100644 --- a/Device/RawDevice.cpp +++ b/Device/RawDevice.cpp @@ -22,7 +22,6 @@ #include -#include #include using namespace Device; @@ -95,43 +94,57 @@ void RawDevice::devSize(int fd) // TODO -- FreeBSD/NetBSD/OpenBSD -RawDevice::RawDevice(const char *name, bool readOnly) +RawDevice::RawDevice(const char *name, bool readOnly) : + _file(name, readOnly) { #undef __METHOD__ #define __METHOD__ "RawDevice::RawDevice" - // open read-only, verify if device is readable, and then try to upgrade to read/write? - - ProFUSE::auto_fd fd; - - if (!readOnly) fd.reset(::open(name, O_RDWR)); - if (fd < 0) + if (!_file.isValid()) { - readOnly = false; - fd.reset(::open(name, O_RDONLY)); + throw new Exception(__METHOD__ ": Invalid file handle."); } - - if (fd < 0) - throw POSIXException(__METHOD__ ": Unable to open device.", errno); - - _fd = -1; - + _readOnly = readOnly; _size = 0; _blocks = 0; _blockSize = 0; - devSize(fd); + devSize(_file.fd()); +} + +RawDevice::RawDevice(File& file, bool readOnly) : + _file(file) +{ +#undef __METHOD__ +#define __METHOD__ "RawDevice::RawDevice" - _fd = fd.release(); + + if (!_file.isValid()) + { + throw new Exception(__METHOD__ ": Invalid file handle."); + } + + _readOnly = readOnly; + _size = 0; + _blocks = 0; + _blockSize = 0; + + + devSize(_file.fd()); } RawDevice::~RawDevice() { - if (_fd >= 0) ::close(_fd); +} + + +RawDevice *RawDevice::Open(const char *name, bool readOnly) +{ + return new RawDevice(name, readOnly); } @@ -147,7 +160,7 @@ void RawDevice::read(unsigned block, void *bp) // apple - read full native block(s) ? off_t offset = block * 512; - size_t ok = ::pread(_fd, bp, 512, offset); + size_t ok = ::pread(_file.fd(), bp, 512, offset); // TODO -- EINTR? if (ok != 512) @@ -170,7 +183,7 @@ void RawDevice::read(TrackSector ts, void *bp) // apple - read full native block(s) ? off_t offset = (ts.track * 16 + ts.sector) * 256; - size_t ok = ::pread(_fd, bp, 256, offset); + size_t ok = ::pread(_file.fd(), bp, 256, offset); // TODO -- EINTR? if (ok != 256) @@ -192,7 +205,7 @@ void RawDevice::write(unsigned block, const void *bp) off_t offset = block * 512; - size_t ok = ::pwrite(_fd, bp, 512, offset); + size_t ok = ::pwrite(_file.fd(), bp, 512, offset); if (ok != 512) throw ok < 0 @@ -214,7 +227,7 @@ void RawDevice::write(TrackSector ts, const void *bp) off_t offset = (ts.track * 16 + ts.sector) * 256; - size_t ok = ::pwrite(_fd, bp, 256, offset); + size_t ok = ::pwrite(_file.fd(), bp, 256, offset); if (ok != 256) throw ok < 0 @@ -233,6 +246,13 @@ bool RawDevice::mapped() return false; } + +unsigned RawDevice::blocks() +{ + return _blocks; +} + + void RawDevice::sync() { #undef __METHOD__ @@ -240,6 +260,6 @@ void RawDevice::sync() if (_readOnly) return; - if (::fsync(_fd) < 0) + if (::fsync(_file.fd()) < 0) throw POSIXException(__METHOD__ ": fsync error.", errno); } \ No newline at end of file diff --git a/Device/RawDevice.h b/Device/RawDevice.h index f39fa70..df711ac 100644 --- a/Device/RawDevice.h +++ b/Device/RawDevice.h @@ -5,16 +5,23 @@ #include +#include + namespace Device { // /dev/xxx -class RawDevice : BlockDevice { +class RawDevice : public BlockDevice { public: RawDevice(const char *name, bool readOnly); + RawDevice(File& file, bool readOnly); + + static RawDevice *Open(const char *name, bool readOnly); + + virtual ~RawDevice(); virtual void read(unsigned block, void *bp); @@ -27,11 +34,13 @@ public: virtual bool mapped(); virtual void sync(); + virtual unsigned blocks(); + private: void devSize(int fd); - int _fd; + File _file; bool _readOnly; uint64_t _size;