mirror of
https://github.com/ksherlock/profuse.git
synced 2025-01-10 07:30:09 +00:00
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@178 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
b29c12d047
commit
81e532b25b
@ -1,4 +1,4 @@
|
||||
#include "Date.h"
|
||||
#include <Pascal/Date.h>
|
||||
#include <cstring>
|
||||
|
||||
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);
|
||||
}
|
98
pascal/Entry.cpp
Normal file
98
pascal/Entry.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include <Pascal/File.h>
|
||||
|
||||
#include <ProfUSE/auto.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
#include <Endian/Endian.h>
|
||||
#include <Endian/IOBuffer.h>
|
||||
|
||||
#include <Device/BlockDevice.h>
|
||||
#include <Device/BlockCache.h>
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef __FILE_H__
|
||||
#define __FILE_H__
|
||||
|
||||
#include "Date.h"
|
||||
#include <Pascal/Date.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -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<FileEntry *> _files;
|
||||
unsigned _inodeGenerator;
|
||||
|
||||
ProFUSE::BlockDevice *_device;
|
||||
ProFUSE::AbstractBlockCache *_cache;
|
||||
Device::BlockDevice *_device;
|
||||
Device::AbstractBlockCache *_cache;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include "File.h"
|
||||
#include "../auto.h"
|
||||
#include "../Endian.h"
|
||||
#include "../BlockDevice.h"
|
||||
#include "../BlockCache.h"
|
||||
#include "../Exception.h"
|
||||
#include <Pascal/File.h>
|
||||
|
||||
#include "IOBuffer.h"
|
||||
#include <ProfUSE/auto.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
#include <Endian/Endian.h>
|
||||
|
||||
#include <Device/BlockDevice.h>
|
||||
#include <Device/BlockCache.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@ -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<uint8_t> 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<FileEntry> child;
|
||||
|
||||
//
|
||||
child.reset(new FileEntry(buffer.get() + i * 0x1a));
|
||||
|
||||
child->setInode(++_inodeGenerator);
|
||||
child->_parent = this;
|
||||
_files.push_back(child.release());
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::vector<FileEntry *>::iterator iter;
|
||||
for(iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
if (*iter) delete *iter;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
VolumeEntry::~VolumeEntry()
|
||||
{
|
||||
std::vector<FileEntry *>::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);
|
||||
}
|
||||
}
|
||||
|
228
pascal/VolumeEntry.cpp
Normal file
228
pascal/VolumeEntry.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
#include <Pascal/File.h>
|
||||
|
||||
#include <ProfUSE/auto.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
#include <Endian/Endian.h>
|
||||
#include <Endian/IOBuffer.h>
|
||||
|
||||
#include <Device/BlockDevice.h>
|
||||
#include <Device/BlockCache.h>
|
||||
|
||||
#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<uint8_t> 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<FileEntry> child;
|
||||
|
||||
//
|
||||
child.reset(new FileEntry(buffer.get() + i * 0x1a));
|
||||
|
||||
child->setInode(++_inodeGenerator);
|
||||
child->_parent = this;
|
||||
_files.push_back(child.release());
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::vector<FileEntry *>::iterator iter;
|
||||
for(iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
if (*iter) delete *iter;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
VolumeEntry::~VolumeEntry()
|
||||
{
|
||||
std::vector<FileEntry *>::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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user