diff --git a/pascal/Date.cpp b/pascal/Date.cpp index fa30630..0d393a6 100644 --- a/pascal/Date.cpp +++ b/pascal/Date.cpp @@ -1,4 +1,4 @@ -#include "Date.h" +#include #include using namespace Pascal; @@ -25,6 +25,9 @@ Date::operator std::time_t() const { tm.tm_year = _year; tm.tm_isdst = -1; + // ProDOS standard for dealing w/ y2k. + if (_year <= 39) tm.tm_year += 100; + return std::mktime(&tm); } @@ -40,5 +43,5 @@ Date Date::Today() ::localtime_r(&t, &tm); - return Date(tm.tm_year, tm.tm_mon + 1, tm.tm_mday); + return Date(tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday); } \ No newline at end of file diff --git a/pascal/Entry.cpp b/pascal/Entry.cpp new file mode 100644 index 0000000..b0b5e83 --- /dev/null +++ b/pascal/Entry.cpp @@ -0,0 +1,98 @@ +#include + +#include +#include + +#include +#include + +#include +#include + + +#include +#include +#include +#include + +using namespace LittleEndian; +using namespace Pascal; + + +#pragma mark - +#pragma mark DirEntry + +unsigned Entry::ValidName(const char *cp, unsigned maxLength) +{ + + // any printable char except: + // white space + // $ = ? , (file only) + // : (volume only) + if (!cp || !*cp) return 0; + + for (unsigned i = 0; ; ++i) + { + unsigned c = cp[i]; + if (c == 0) return i; + if (i >= maxLength) return 0; + + switch(c) + { + + case ':': + if (maxLength == 7) return 0; + break; + case '$': + case '=': + case ',': + case '?': + if (maxLength == 15) return 0; + break; + + default: + if (!::isascii(c)) return 0; + if (!std::isgraph(c)) return 0; + } + } + + +} + + +Entry::Entry() +{ + _firstBlock = 0; + _lastBlock = 0; + _fileKind = 0; + _inode = 0; + _parent = NULL; +} + +Entry::Entry(void *vp) +{ + init(vp); +} + +Entry::~Entry() +{ +} + + +void Entry::init(void *vp) +{ + _firstBlock = Read16(vp, 0x00); + _lastBlock = Read16(vp, 0x02); + _fileKind = Read8(vp, 0x04); + + _inode = 0; +} + +void Entry::writeDirectoryEntry(IOBuffer *b) +{ + b->write16(_firstBlock); + b->write16(_lastBlock); + b->write8(_fileKind); +} + + diff --git a/pascal/File.h b/pascal/File.h index 4464f2c..5a3e389 100644 --- a/pascal/File.h +++ b/pascal/File.h @@ -1,7 +1,7 @@ #ifndef __FILE_H__ #define __FILE_H__ -#include "Date.h" +#include #include @@ -79,10 +79,10 @@ class VolumeEntry : public Entry { public: // create new - VolumeEntry(const char *name, ProFUSE::BlockDevice *); + VolumeEntry(const char *name, Device::BlockDevice *); // open existing - VolumeEntry(ProFUSE::BlockDevice *); + VolumeEntry(Device::BlockDevice *); virtual ~VolumeEntry(); const char *name() const { return _fileName; } @@ -124,8 +124,8 @@ private: std::vector _files; unsigned _inodeGenerator; - ProFUSE::BlockDevice *_device; - ProFUSE::AbstractBlockCache *_cache; + Device::BlockDevice *_device; + Device::AbstractBlockCache *_cache; }; diff --git a/pascal/File.cpp b/pascal/FileEntry.cpp similarity index 50% rename from pascal/File.cpp rename to pascal/FileEntry.cpp index b305ae9..2889b56 100644 --- a/pascal/File.cpp +++ b/pascal/FileEntry.cpp @@ -1,11 +1,12 @@ -#include "File.h" -#include "../auto.h" -#include "../Endian.h" -#include "../BlockDevice.h" -#include "../BlockCache.h" -#include "../Exception.h" +#include -#include "IOBuffer.h" +#include +#include + +#include + +#include +#include #include #include @@ -15,325 +16,6 @@ using namespace LittleEndian; using namespace Pascal; -/* -static bool isalpha(char c) -{ - return (c >= 'A' && c <= 'Z') - || (c >= 'a' && c <= 'z') ; -} - -static bool isalnumdot(char c) -{ - return (c >= 'A' && c <= 'Z') - || (c >= 'a' && c <= 'z') - || (c >= '0' && c <='9') - || (c == '.') ; - -} - -static bool islower(char c) -{ - return c >= 'a' && c <= 'z'; -} - - -inline char tolower(char c) { return c | 0x20; } -inline char toupper(char c) { return c & ~0x20; } -*/ - - -#pragma mark - -#pragma mark DirEntry - -unsigned Entry::ValidName(const char *cp, unsigned maxLength) -{ - - // any printable char except: - // white space - // $ = ? , (file only) - // : (volume only) - if (!cp || !*cp) return 0; - - for (unsigned i = 0; ; ++i) - { - unsigned c = cp[i]; - if (c == 0) return i; - if (i >= maxLength) return 0; - - switch(c) - { - - case ':': - if (maxLength == 7) return 0; - break; - case '$': - case '=': - case ',': - case '?': - if (maxLength == 15) return 0; - break; - - default: - if (!::isascii(c)) return 0; - if (!std::isgraph(c)) return 0; - } - } - - -} - - -Entry::Entry() -{ - _firstBlock = 0; - _lastBlock = 0; - _fileKind = 0; - _inode = 0; - _parent = NULL; -} - -Entry::Entry(void *vp) -{ - init(vp); -} - -Entry::~Entry() -{ -} - - -void Entry::init(void *vp) -{ - _firstBlock = Read16(vp, 0x00); - _lastBlock = Read16(vp, 0x02); - _fileKind = Read8(vp, 0x04); - - _inode = 0; -} - -void Entry::writeDirectoryEntry(IOBuffer *b) -{ - b->write16(_firstBlock); - b->write16(_lastBlock); - b->write8(_fileKind); -} - - -#pragma mark - -#pragma mark VolumeEntry - -unsigned VolumeEntry::ValidName(const char *cp) -{ - // 7 chars max. Legal values: ascii, printable, - // no space/tab, - // no $=?,: - - return Entry::ValidName(cp, 7); -} - -VolumeEntry::VolumeEntry() -{ - _fileNameLength = 0; - std::memset(_fileName, 0, 8); - _lastVolumeBlock = 0; - _fileCount = 0; - _accessTime = 0; - - setInode(1); - - _inodeGenerator = 1; - _cache = NULL; - _device = NULL; -} - -VolumeEntry::VolumeEntry(const char *name, ProFUSE::BlockDevice *device) -{ -#undef __METHOD__ -#define __METHOD__ "VolumeEntry::VolumeEntry" - - unsigned length; - length = ValidName(name); - - if (!length) - throw ProFUSE::Exception(__METHOD__ ": Invalid volume name."); - - _firstBlock = 0; - _lastBlock = 6; - _fileKind = kUntypedFile; - _inode = 1; - _inodeGenerator = 1; - - _fileNameLength = length; - - std::memset(_fileName, 0, sizeof(_fileName)); - for (unsigned i = 0; i < _fileNameLength; ++i) - { - _fileName[i] = std::toupper(name[i]); - } - - _lastVolumeBlock = device->blocks(); - _fileCount = 0; - _accessTime = 0; - _lastBoot = Date::Today(); - - _cache = device->blockCache(); - _device = device; - - for (unsigned i = 2; i < 6; ++i) - { - device->zeroBlock(i); - } - - void *vp = _cache->load(2); - IOBuffer b(vp, 0x1a); - - writeDirectoryEntry(&b); - - _cache->unload(2, true); - -} - - -VolumeEntry::VolumeEntry(ProFUSE::BlockDevice *device) -{ - auto_array buffer(new uint8_t[512]); - unsigned blockCount; - - // read the header block, then load up all the header - // blocks. - - _device = device; - _cache = device->blockCache(); - - device->read(2, buffer.get()); - - init(buffer.get()); - - // todo -- verify reasonable values. - - //printf("%u %u\n", blocks(), _lastBlock - _firstBlock); - - // why the fuck didn't this work???? - blockCount = blocks(); - - if (blockCount > 1) - { - buffer.reset(new uint8_t[512 * blockCount]); - - for (unsigned i = 0; i < blockCount; ++i) - { - device->read(2 + i, buffer.get() + 512 * i); - } - } - - // now load up all the children. - // if this throws, memory could be lost... - - - try - { - - for (unsigned i = 1; i <= _fileCount; ++i) - { - std::auto_ptr child; - - // - child.reset(new FileEntry(buffer.get() + i * 0x1a)); - - child->setInode(++_inodeGenerator); - child->_parent = this; - _files.push_back(child.release()); - } - } - catch (...) - { - std::vector::iterator iter; - for(iter = _files.begin(); iter != _files.end(); ++iter) - { - if (*iter) delete *iter; - } - - throw; - } - - -} - -VolumeEntry::~VolumeEntry() -{ - std::vector::iterator iter; - for(iter = _files.begin(); iter != _files.end(); ++iter) - { - if (*iter) delete *iter; - } - - // _blockCache does not need deleting. - delete _device; -} - - -void VolumeEntry::init(void *vp) -{ - Entry::init(vp); - _fileNameLength = Read8(vp, 6); - - // verify filenamelength <= 7 - // verify fileKind == 0 - - std::memcpy(_fileName, 7 + (uint8_t *)vp, _fileNameLength); - - _lastVolumeBlock = Read16(vp, 0x0e); - _fileCount = Read16(vp, 0x10); - _accessTime = Read16(vp, 0x12); - _lastBoot = Date(Read16(vp, 0x14)); - - setInode(1); - _inodeGenerator = 1; -} - - -FileEntry *VolumeEntry::fileAtIndex(unsigned i) const -{ - return i < _files.size() ? _files[i] : NULL; -} - - - -void *VolumeEntry::loadBlock(unsigned block) -{ - return _cache->load(block); -} -void VolumeEntry::unloadBlock(unsigned block, bool dirty) -{ - return _cache->unload(block, dirty); -} - -void VolumeEntry::readBlock(unsigned block, void *buffer) -{ - _device->read(block, buffer); -} -void VolumeEntry::writeBlock(unsigned block, void *buffer) -{ - _device->write(block, buffer); -} - - - -void VolumeEntry::writeDirectoryEntry(IOBuffer *b) -{ - Entry::writeDirectoryEntry(b); - - b->write8(0); // reserved - b->write8(_fileNameLength); - b->writeBytes(_fileName, 7); - b->write16(_lastVolumeBlock); - b->write16(_fileCount); - b->write16(_accessTime); - b->write16(_lastBoot); - - // rest is reserved. - b->writeZero(4); -} #pragma mark - #pragma mark FileEntry @@ -655,4 +337,3 @@ void FileEntry::textInit() _pageSize->push_back(size); } } - diff --git a/pascal/VolumeEntry.cpp b/pascal/VolumeEntry.cpp new file mode 100644 index 0000000..a4d3386 --- /dev/null +++ b/pascal/VolumeEntry.cpp @@ -0,0 +1,228 @@ +#include + +#include +#include + +#include +#include + +#include +#include + +#pragma mark - +#pragma mark VolumeEntry + +unsigned VolumeEntry::ValidName(const char *cp) +{ + // 7 chars max. Legal values: ascii, printable, + // no space/tab, + // no $=?,: + + return Entry::ValidName(cp, 7); +} + +VolumeEntry::VolumeEntry() +{ + _fileNameLength = 0; + std::memset(_fileName, 0, 8); + _lastVolumeBlock = 0; + _fileCount = 0; + _accessTime = 0; + + setInode(1); + + _inodeGenerator = 1; + _cache = NULL; + _device = NULL; +} + +VolumeEntry::VolumeEntry(const char *name, Device::BlockDevice *device) +{ +#undef __METHOD__ +#define __METHOD__ "VolumeEntry::VolumeEntry" + + unsigned length; + length = ValidName(name); + + if (!length) + throw ProFUSE::Exception(__METHOD__ ": Invalid volume name."); + + _firstBlock = 0; + _lastBlock = 6; + _fileKind = kUntypedFile; + _inode = 1; + _inodeGenerator = 1; + + _fileNameLength = length; + + std::memset(_fileName, 0, sizeof(_fileName)); + for (unsigned i = 0; i < _fileNameLength; ++i) + { + _fileName[i] = std::toupper(name[i]); + } + + _lastVolumeBlock = device->blocks(); + _fileCount = 0; + _accessTime = 0; + _lastBoot = Date::Today(); + + _cache = device->blockCache(); + _device = device; + + for (unsigned i = 2; i < 6; ++i) + { + device->zeroBlock(i); + } + + void *vp = _cache->load(2); + IOBuffer b(vp, 0x1a); + + writeDirectoryEntry(&b); + + _cache->unload(2, true); + +} + + +VolumeEntry::VolumeEntry(Device::BlockDevice *device) +{ + auto_array buffer(new uint8_t[512]); + unsigned blockCount; + + // read the header block, then load up all the header + // blocks. + + _device = device; + _cache = device->blockCache(); + + device->read(2, buffer.get()); + + init(buffer.get()); + + // todo -- verify reasonable values. + + //printf("%u %u\n", blocks(), _lastBlock - _firstBlock); + + // why the fuck didn't this work???? + blockCount = blocks(); + + if (blockCount > 1) + { + buffer.reset(new uint8_t[512 * blockCount]); + + for (unsigned i = 0; i < blockCount; ++i) + { + device->read(2 + i, buffer.get() + 512 * i); + } + } + + // now load up all the children. + // if this throws, memory could be lost... + + + try + { + + for (unsigned i = 1; i <= _fileCount; ++i) + { + std::auto_ptr child; + + // + child.reset(new FileEntry(buffer.get() + i * 0x1a)); + + child->setInode(++_inodeGenerator); + child->_parent = this; + _files.push_back(child.release()); + } + } + catch (...) + { + std::vector::iterator iter; + for(iter = _files.begin(); iter != _files.end(); ++iter) + { + if (*iter) delete *iter; + } + + throw; + } + + +} + +VolumeEntry::~VolumeEntry() +{ + std::vector::iterator iter; + for(iter = _files.begin(); iter != _files.end(); ++iter) + { + if (*iter) delete *iter; + } + + // _blockCache does not need deleting. + delete _device; +} + + +void VolumeEntry::init(void *vp) +{ + Entry::init(vp); + _fileNameLength = Read8(vp, 6); + + // verify filenamelength <= 7 + // verify fileKind == 0 + + std::memcpy(_fileName, 7 + (uint8_t *)vp, _fileNameLength); + + _lastVolumeBlock = Read16(vp, 0x0e); + _fileCount = Read16(vp, 0x10); + _accessTime = Read16(vp, 0x12); + _lastBoot = Date(Read16(vp, 0x14)); + + setInode(1); + _inodeGenerator = 1; +} + + +FileEntry *VolumeEntry::fileAtIndex(unsigned i) const +{ + return i < _files.size() ? _files[i] : NULL; +} + + + +void *VolumeEntry::loadBlock(unsigned block) +{ + return _cache->load(block); +} +void VolumeEntry::unloadBlock(unsigned block, bool dirty) +{ + return _cache->unload(block, dirty); +} + +void VolumeEntry::readBlock(unsigned block, void *buffer) +{ + _device->read(block, buffer); +} +void VolumeEntry::writeBlock(unsigned block, void *buffer) +{ + _device->write(block, buffer); +} + + + +void VolumeEntry::writeDirectoryEntry(IOBuffer *b) +{ + Entry::writeDirectoryEntry(b); + + b->write8(0); // reserved + b->write8(_fileNameLength); + b->writeBytes(_fileName, 7); + b->write16(_lastVolumeBlock); + b->write16(_fileCount); + b->write16(_accessTime); + b->write16(_lastBoot); + + // rest is reserved. + b->writeZero(4); +} + +