diff --git a/pascal/File.cpp b/pascal/File.cpp index 7e73cda..7834a4e 100644 --- a/pascal/File.cpp +++ b/pascal/File.cpp @@ -4,6 +4,8 @@ #include "../BlockDevice.h" #include "../BlockCache.h" +#include "IOBuffer.h" + #include #include #include @@ -11,9 +13,54 @@ 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) +{ + unsigned length; + + if (!cp || !*cp) return 0; + + if (!isalpaha(*cp)) return 0; + + for (length = 1; cp[length]; ++length) + { + if (length >= maxLength) return 0; + + if (!isalnumdot(cp[length])) return 0; + } + + return length; + +} + Entry::Entry() { _firstBlock = 0; @@ -42,10 +89,22 @@ void Entry::init(void *vp) _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) +{ + return Entry::ValidName(cp, 7); +} + VolumeEntry::VolumeEntry() { _fileNameLength = 0; @@ -61,6 +120,54 @@ VolumeEntry::VolumeEntry() _device = NULL; } +VolumeEntry::VolumeEntry(const char *name, ProFUSE::BlockDevice *device) +{ +#undef __METHOD__ +#define __METHOD__ "VolumeEntry::VolumeEntry" + + unsigned length; + length = ValidName(name); + + if (!length) + throw Exception(__METHOD__ ": Invalid volume name."); + + _firstBlock = 2; + _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] = 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 = _blockCache->lock(2); + IOBuffer b(vp, 0x1a); + + write(&b); + + _blockCache->unlock(2, true); + +} + + VolumeEntry::VolumeEntry(ProFUSE::BlockDevice *device) { auto_array buffer(new uint8_t[512]); @@ -185,9 +292,30 @@ void VolumeEntry::writeBlock(unsigned block, void *buffer) } + +void VolumeEntry::writeDirectoryEntry(IOBuffer *b) +{ + Entry::writeDirectoryEntry(b); + + b->write8(0); // reserved + b->write8(_fileNameLength); + b->writeBytes(_fileName, 7); + b->write16(_fileCount); + b->write16(_accessTime); + b->write16((unsigned)_lastBoot); + + // rest is reserved. + b->writeZero(4); +} + #pragma mark - #pragma mark FileEntry +unsigned FileEntry::ValidName(const char *cp) +{ + return Entry::ValidName(cp, 15); +} + FileEntry::FileEntry(void *vp) : Entry(vp) { @@ -202,6 +330,31 @@ FileEntry::FileEntry(void *vp) : _pageSize = NULL; } +FileEntry::FileEntry(const char *name, unsigned fileKind) +{ +#undef __METHOD__ +#define __METHOD__ "FileEntry::FileEntry" + + unsigned length = ValidName(name); + + if (!length) + throw Exception(__METHOD__ ": Invalid file name."); + + _fileKind = kind; + _status = 0; + + _fileNameLength = length; + std::memset(_fileName, 0, sizeof(_fileName)); + for (unsigned i = 0; i < length; ++i) + _fileName[i] = toupper(name[i]); + + _modification = Date::Today(); + _lastByte = 0; + + _fileSize = 0; + _pageSize = NULL; +} + FileEntry::~FileEntry() { delete _pageSize; @@ -221,6 +374,16 @@ unsigned FileEntry::fileSize() } } +void FileEntry::writeDirectoryEntry(IOBuffer *b) +{ + Entry::writeDirectoryEntry(b); + + b->write8(_status ? 0x01 : 0x00); + b->write8(_fileNameLength); + b->writeBytes(_fileName, 15); + b->write16(_lastByte); + b->write16(_modification); +} int FileEntry::read(uint8_t *buffer, unsigned size, unsigned offset) { diff --git a/pascal/File.h b/pascal/File.h index 66c2c8b..453126f 100644 --- a/pascal/File.h +++ b/pascal/File.h @@ -10,6 +10,10 @@ namespace ProFUSE { class AbstractBlockCache; } +namespace LittleEndian { + class IOBuffer; +} + namespace Pascal { @@ -48,6 +52,10 @@ public: protected: + + unsigned static ValidName(const char *name, unsigned maxSize); + + virtual void writeDirectoryEntry(LittleEndian::IOBuffer *); Entry(); Entry(void *); @@ -70,6 +78,10 @@ class VolumeEntry : public Entry { public: + // create new + VolumeEntry(const char *name, ProFUSE::BlockDevice *); + + // open existing VolumeEntry(ProFUSE::BlockDevice *); virtual ~VolumeEntry(); @@ -80,6 +92,9 @@ public: Pascal::Date lastBoot() const { return _lastBoot; } FileEntry *fileAtIndex(unsigned i) const; + + void addChild(FileEntry *child, unsigned blocks); + void *loadBlock(unsigned block); @@ -88,6 +103,12 @@ public: void readBlock(unsigned block, void *); void writeBlock(unsigned block, void *); + + static ValidName(const char *); + +protected: + virtual void writeDirectoryEntry(LittleEndian::IOBuffer *); + private: VolumeEntry(); @@ -111,6 +132,7 @@ private: class FileEntry : public Entry { public: + FileEntry(const char *name, unsigned fileKind); FileEntry(void *vp); virtual ~FileEntry(); @@ -118,13 +140,21 @@ class FileEntry : public Entry { unsigned lastByte() const { return _lastByte; } - int read(uint8_t *buffer, unsigned size, unsigned offset); + int read(uint8_t *buffer, unsigned size, unsigned offset); + int write(uint8_t *buffer, unsigned size, unsigned offset); const char *name() const { return _fileName; } Date modification() const { return _modification; } + static ValidName(const char *); + + protected: + virtual void writeDirectoryEntry(LittleEndian::IOBuffer *); + + private: + unsigned _status; unsigned _fileNameLength; diff --git a/pascal/IOBuffer.h b/pascal/IOBuffer.h new file mode 100644 index 0000000..842a65b --- /dev/null +++ b/pascal/IOBuffer.h @@ -0,0 +1,70 @@ +#ifndef __IOBUFFER_H__ +#define __IOBUFFER_H__ + +#include "../Endian.h" + +namespace LittleEndian { + + class IOBuffer { + public: + + IOBuffer(void *vp, unsigned size) + { + _buffer = vp; + _size = size; + _offset = 0; + } + + void write8(uint8_t value) + { + Write8(_buffer, _offset, value); + _offset += 1; + } + void write16(uint16_t value) + { + Write16(_buffer, _offset, value); + _offset += 2; + } + + void write24(uint32_t value) + { + Write24(_buffer, _offset, value); + _offset += 3; + } + void write32(uint32_t value) + { + Write32(_buffer, _offset, value); + _offset += 4; + } + + void writeBytes(const void *value, unsigned count); + { + std::memcpy(_offset + (uint8_t *)_buffer, value, count); + _size += count; + } + + void writeZero(unsigned count) + { + uint8_t *cp = _offset + (uint8_t *)_buffer; + for (unsigned i = 0; i < count; ++i) + { + cp[i] = 0; + } + _offset += count; + } + + unsigned offset() const { return _offset; } + void setOffset(unsigned offset) { _offset = offset; } + + unsinged size() const { return _size; } + + private: + void *_buffer; + unsigned _size; + unsigned _offset; + + }; + +} + +#endif \ No newline at end of file