#include #include #include #include #include #include #include #pragma mark - #pragma mark VolumeEntry using namespace LittleEndian; using namespace Pascal; 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) { ProFUSE::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); }