mirror of
https://github.com/ksherlock/profuse.git
synced 2026-04-23 18:20:12 +00:00
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@179 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
#include <Pascal/Date.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace Pascal;
|
||||
|
||||
|
||||
|
||||
Date::Date(unsigned val)
|
||||
{
|
||||
// yyyy yyym mmmm dddd
|
||||
_month = val & 0xf;
|
||||
_day = (val >> 4) & 0x1f;
|
||||
_year = (val >> 9) & 0x7f;
|
||||
}
|
||||
|
||||
Date::operator std::time_t() const {
|
||||
struct tm tm;
|
||||
|
||||
if (_day == 0 || _month == 0) return (std::time_t)-1;
|
||||
|
||||
std::memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_hour = 12;
|
||||
tm.tm_mday = _day;
|
||||
tm.tm_mon = _month;
|
||||
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);
|
||||
}
|
||||
|
||||
Date::operator uint16_t() const {
|
||||
// year must be 0 .. 127
|
||||
return (_year << 9) | (_day << 4) | _month;
|
||||
}
|
||||
|
||||
Date Date::Today()
|
||||
{
|
||||
struct tm tm;
|
||||
std::time_t t = std::time(NULL);
|
||||
|
||||
::localtime_r(&t, &tm);
|
||||
|
||||
return Date(tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef __PASCAL_DATE_H__
|
||||
#define __PASCAL_DATE_H__
|
||||
|
||||
#include <ctime>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Pascal {
|
||||
|
||||
class Date {
|
||||
public:
|
||||
|
||||
static Date Today();
|
||||
|
||||
Date();
|
||||
Date(unsigned yy, unsigned mm, unsigned dd);
|
||||
Date(unsigned);
|
||||
|
||||
operator std::time_t() const;
|
||||
operator uint16_t() const;
|
||||
|
||||
unsigned month() const { return _month; }
|
||||
unsigned day() const { return _day; }
|
||||
unsigned year() const { return _year; }
|
||||
|
||||
private:
|
||||
unsigned _year;
|
||||
unsigned _month;
|
||||
unsigned _day;
|
||||
};
|
||||
|
||||
|
||||
inline Date::Date()
|
||||
{
|
||||
_year = 0;
|
||||
_month = 0;
|
||||
_day = 0;
|
||||
}
|
||||
|
||||
inline Date::Date(unsigned yy, unsigned mm, unsigned dd)
|
||||
{
|
||||
_year = yy;
|
||||
_month = mm;
|
||||
_day = dd;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
#ifndef __FILE_H__
|
||||
#define __FILE_H__
|
||||
|
||||
#include <Pascal/Date.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ProFUSE {
|
||||
class BlockDevice;
|
||||
class AbstractBlockCache;
|
||||
}
|
||||
|
||||
namespace LittleEndian {
|
||||
class IOBuffer;
|
||||
}
|
||||
|
||||
namespace Pascal {
|
||||
|
||||
|
||||
enum {
|
||||
kUntypedFile,
|
||||
kBadBlockFile,
|
||||
kCodeFile,
|
||||
kTextFile,
|
||||
kInfoFile,
|
||||
kDataFile,
|
||||
kGrafFile,
|
||||
kFotoFile,
|
||||
kSecureDir
|
||||
};
|
||||
|
||||
class FileEntry;
|
||||
class VolumeEntry;
|
||||
|
||||
class Entry {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Entry();
|
||||
|
||||
unsigned blocks() const { return _lastBlock - _firstBlock; }
|
||||
|
||||
unsigned firstBlock() const { return _firstBlock; }
|
||||
unsigned lastBlock() const { return _lastBlock; }
|
||||
|
||||
unsigned fileKind() const { return _fileKind; }
|
||||
|
||||
unsigned inode() const { return _inode; }
|
||||
void setInode(unsigned inode) { _inode = inode; }
|
||||
|
||||
VolumeEntry *parent() { return _parent; }
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
static unsigned ValidName(const char *name, unsigned maxSize);
|
||||
|
||||
virtual void writeDirectoryEntry(LittleEndian::IOBuffer *);
|
||||
|
||||
Entry();
|
||||
Entry(void *);
|
||||
void init(void *);
|
||||
|
||||
unsigned _firstBlock;
|
||||
unsigned _lastBlock;
|
||||
unsigned _fileKind;
|
||||
|
||||
unsigned _inode;
|
||||
|
||||
private:
|
||||
friend class VolumeEntry;
|
||||
VolumeEntry *_parent;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class VolumeEntry : public Entry {
|
||||
|
||||
public:
|
||||
|
||||
// create new
|
||||
VolumeEntry(const char *name, Device::BlockDevice *);
|
||||
|
||||
// open existing
|
||||
VolumeEntry(Device::BlockDevice *);
|
||||
virtual ~VolumeEntry();
|
||||
|
||||
const char *name() const { return _fileName; }
|
||||
unsigned fileCount() const { return _fileCount; }
|
||||
unsigned volumeBlocks() const { return _lastVolumeBlock; }
|
||||
|
||||
Pascal::Date lastBoot() const { return _lastBoot; }
|
||||
|
||||
FileEntry *fileAtIndex(unsigned i) const;
|
||||
|
||||
void addChild(FileEntry *child, unsigned blocks);
|
||||
|
||||
|
||||
|
||||
void *loadBlock(unsigned block);
|
||||
void unloadBlock(unsigned block, bool dirty = false);
|
||||
|
||||
void readBlock(unsigned block, void *);
|
||||
void writeBlock(unsigned block, void *);
|
||||
|
||||
|
||||
unsigned static ValidName(const char *);
|
||||
|
||||
protected:
|
||||
virtual void writeDirectoryEntry(LittleEndian::IOBuffer *);
|
||||
|
||||
private:
|
||||
VolumeEntry();
|
||||
|
||||
void init(void *);
|
||||
|
||||
unsigned _fileNameLength;
|
||||
char _fileName[8];
|
||||
unsigned _lastVolumeBlock;
|
||||
unsigned _fileCount;
|
||||
unsigned _accessTime;
|
||||
Pascal::Date _lastBoot;
|
||||
|
||||
std::vector<FileEntry *> _files;
|
||||
unsigned _inodeGenerator;
|
||||
|
||||
Device::BlockDevice *_device;
|
||||
Device::AbstractBlockCache *_cache;
|
||||
};
|
||||
|
||||
|
||||
class FileEntry : public Entry {
|
||||
public:
|
||||
|
||||
FileEntry(const char *name, unsigned fileKind);
|
||||
FileEntry(void *vp);
|
||||
virtual ~FileEntry();
|
||||
|
||||
unsigned fileSize();
|
||||
|
||||
unsigned lastByte() const { return _lastByte; }
|
||||
|
||||
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; }
|
||||
|
||||
unsigned static ValidName(const char *);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
virtual void writeDirectoryEntry(LittleEndian::IOBuffer *);
|
||||
|
||||
private:
|
||||
|
||||
unsigned _status;
|
||||
|
||||
unsigned _fileNameLength;
|
||||
char _fileName[16];
|
||||
|
||||
unsigned _lastByte;
|
||||
Date _modification;
|
||||
|
||||
// non-text files
|
||||
unsigned dataFileSize();
|
||||
int dataRead(uint8_t *buffer, unsigned size, unsigned offset);
|
||||
|
||||
// for text files.
|
||||
void textInit();
|
||||
unsigned textFileSize();
|
||||
int textRead(uint8_t *buffer, unsigned size, unsigned offset);
|
||||
|
||||
unsigned textReadPage(unsigned block, uint8_t *in);
|
||||
unsigned textDecodePage(unsigned block, uint8_t *out);
|
||||
|
||||
std::vector<unsigned> *_pageSize;
|
||||
unsigned _fileSize;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,339 @@
|
||||
#include <Pascal/File.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>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
|
||||
using namespace LittleEndian;
|
||||
using namespace Pascal;
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark FileEntry
|
||||
|
||||
unsigned FileEntry::ValidName(const char *cp)
|
||||
{
|
||||
return Entry::ValidName(cp, 15);
|
||||
}
|
||||
|
||||
FileEntry::FileEntry(void *vp) :
|
||||
Entry(vp)
|
||||
{
|
||||
_status = Read8(vp, 0x05) & 0x01;
|
||||
_fileNameLength = Read8(vp, 0x06);
|
||||
std::memset(_fileName, 0, 16);
|
||||
std::memcpy(_fileName, 0x07 + (uint8_t *)vp, _fileNameLength);
|
||||
_lastByte = Read16(vp, 0x16);
|
||||
_modification = Date(Read16(vp, 0x18));
|
||||
|
||||
_fileSize = 0;
|
||||
_pageSize = NULL;
|
||||
}
|
||||
|
||||
FileEntry::FileEntry(const char *name, unsigned fileKind)
|
||||
{
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "FileEntry::FileEntry"
|
||||
|
||||
unsigned length = ValidName(name);
|
||||
|
||||
if (!length)
|
||||
throw ProFUSE::Exception(__METHOD__ ": Invalid file name.");
|
||||
|
||||
_fileKind = fileKind;
|
||||
_status = 0;
|
||||
|
||||
_fileNameLength = length;
|
||||
std::memset(_fileName, 0, sizeof(_fileName));
|
||||
for (unsigned i = 0; i < length; ++i)
|
||||
_fileName[i] = std::toupper(name[i]);
|
||||
|
||||
_modification = Date::Today();
|
||||
_lastByte = 0;
|
||||
|
||||
_fileSize = 0;
|
||||
_pageSize = NULL;
|
||||
}
|
||||
|
||||
FileEntry::~FileEntry()
|
||||
{
|
||||
delete _pageSize;
|
||||
}
|
||||
|
||||
|
||||
unsigned FileEntry::fileSize()
|
||||
{
|
||||
switch(fileKind())
|
||||
{
|
||||
case kTextFile:
|
||||
return textFileSize();
|
||||
break;
|
||||
default:
|
||||
return dataFileSize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned fsize = fileSize();
|
||||
|
||||
if (offset + size > fsize) size = fsize - offset;
|
||||
if (offset >= fsize) return 0;
|
||||
|
||||
switch(fileKind())
|
||||
{
|
||||
case kTextFile:
|
||||
return textRead(buffer, size, offset);
|
||||
break;
|
||||
default:
|
||||
return dataRead(buffer, size, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned FileEntry::dataFileSize()
|
||||
{
|
||||
return blocks() * 512 - 512 + _lastByte;
|
||||
}
|
||||
|
||||
unsigned FileEntry::textFileSize()
|
||||
{
|
||||
if (!_pageSize) textInit();
|
||||
return _fileSize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int FileEntry::dataRead(uint8_t *buffer, unsigned size, unsigned offset)
|
||||
{
|
||||
uint8_t tmp[512];
|
||||
|
||||
unsigned count = 0;
|
||||
unsigned block = 0;
|
||||
|
||||
block = _firstBlock + (offset / 512);
|
||||
|
||||
// returned value (count) is equal to size at this point.
|
||||
// (no partial reads).
|
||||
|
||||
/*
|
||||
* 1. Block align everything
|
||||
*/
|
||||
|
||||
if (offset % 512)
|
||||
{
|
||||
unsigned bytes = std::min(offset % 512, size);
|
||||
|
||||
parent()->readBlock(block++, tmp);
|
||||
|
||||
std::memcpy(buffer, tmp + 512 - bytes, bytes);
|
||||
|
||||
buffer += bytes;
|
||||
count += bytes;
|
||||
size -= bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. read full blocks into the buffer.
|
||||
*/
|
||||
|
||||
while (size >= 512)
|
||||
{
|
||||
parent()->readBlock(block++, buffer);
|
||||
|
||||
buffer += 512;
|
||||
count += 512;
|
||||
size -= 512;
|
||||
}
|
||||
|
||||
/*
|
||||
* 3. Read any trailing blocks.
|
||||
*/
|
||||
if (size)
|
||||
{
|
||||
parent()->readBlock(block, tmp);
|
||||
std::memcpy(buffer, tmp, size);
|
||||
|
||||
count += size;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int FileEntry::textRead(uint8_t *buffer, unsigned size, unsigned offset)
|
||||
{
|
||||
unsigned page = 0;
|
||||
unsigned to = 0;
|
||||
unsigned block;
|
||||
unsigned l;
|
||||
unsigned count = 0;
|
||||
|
||||
auto_array<uint8_t> tmp;
|
||||
unsigned tmpSize = 0;
|
||||
|
||||
if (!_pageSize) textInit();
|
||||
|
||||
l = _pageSize->size();
|
||||
|
||||
|
||||
// find the first page.
|
||||
for (page = 0; page < l; ++page)
|
||||
{
|
||||
unsigned pageSize = (*_pageSize)[page];
|
||||
if (to + pageSize > offset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
to += pageSize;
|
||||
}
|
||||
|
||||
|
||||
block = _firstBlock + 2 + (page * 2);
|
||||
|
||||
|
||||
// offset not needed anymore,
|
||||
// convert to offset from *this* page.
|
||||
offset -= to;
|
||||
|
||||
while (size)
|
||||
{
|
||||
unsigned pageSize = (*_pageSize)[page];
|
||||
unsigned bytes = std::min(size, pageSize - offset);
|
||||
|
||||
if (pageSize > tmpSize)
|
||||
{
|
||||
tmp.reset(new uint8_t[pageSize]);
|
||||
tmpSize = pageSize;
|
||||
}
|
||||
|
||||
|
||||
// can decode straight to buffer if size >= bytes && offset = 0.
|
||||
textDecodePage(block, tmp.get());
|
||||
|
||||
|
||||
std::memcpy(buffer, tmp.get() + offset, bytes);
|
||||
|
||||
|
||||
block += 2;
|
||||
page += 1;
|
||||
|
||||
size -= bytes;
|
||||
buffer += bytes;
|
||||
count += bytes;
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned FileEntry::textDecodePage(unsigned block, uint8_t *out)
|
||||
{
|
||||
uint8_t buffer[1024];
|
||||
unsigned size = 0;
|
||||
bool dle = false;
|
||||
|
||||
unsigned bytes = textReadPage(block, buffer);
|
||||
|
||||
for (unsigned i = 0; i < bytes; ++i)
|
||||
{
|
||||
uint8_t c = buffer[i];
|
||||
|
||||
if (!c) continue;
|
||||
|
||||
|
||||
if (dle)
|
||||
{
|
||||
if (c > 32)
|
||||
{
|
||||
unsigned x = c - 32;
|
||||
size += x;
|
||||
if (out) for (unsigned j = 0; j < x; ++j)
|
||||
*out++ = ' ';
|
||||
}
|
||||
dle = false;
|
||||
continue;
|
||||
}
|
||||
if (c == 16) { dle = true; continue; }
|
||||
|
||||
//if (c & 0x80) continue; // ascii only.
|
||||
|
||||
|
||||
if (c == 0x0d) c = 0x0a; // convert to unix format.
|
||||
if (out) *out++ = c;
|
||||
size += 1;
|
||||
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
unsigned FileEntry::textReadPage(unsigned block, uint8_t *in)
|
||||
{
|
||||
// reads up to 2 blocks.
|
||||
// assumes block within _startBlock ... _lastBlock - 1
|
||||
|
||||
parent()->readBlock(block, in);
|
||||
if (block + 1 == _lastBlock)
|
||||
{
|
||||
return _lastByte;
|
||||
}
|
||||
|
||||
parent()->readBlock(block + 1, in + 512);
|
||||
if (block +2 == _lastBlock)
|
||||
{
|
||||
return 512 + _lastByte;
|
||||
}
|
||||
|
||||
return 1024;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FileEntry::textInit()
|
||||
{
|
||||
// calculate the file size and page offsets.
|
||||
_pageSize = new std::vector<unsigned>;
|
||||
_pageSize->reserve((_lastBlock - _firstBlock + 1 - 2) / 2);
|
||||
|
||||
_fileSize = 0;
|
||||
for (unsigned block = _firstBlock + 2; block < _lastBlock; block += 2)
|
||||
{
|
||||
unsigned size = textDecodePage(block, NULL);
|
||||
printf("%u: %u\n", block, size);
|
||||
_fileSize += size;
|
||||
_pageSize->push_back(size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
CC = g++
|
||||
CPPFLAGS += -Wall -O2 -g -fexceptions \
|
||||
-D__FreeBSD__=10 \
|
||||
-D_FILE_OFFSET_BITS=64 \
|
||||
-D__DARWIN_64_BIT_INO_T=1 \
|
||||
-DHAVE_STAT_BIRTHTIME
|
||||
|
||||
LDFLAGS += -L/usr/local/lib -lfuse_ino64
|
||||
|
||||
|
||||
newfs_pascal: \
|
||||
newfs_pascal.o \
|
||||
Date.o \
|
||||
File.o \
|
||||
../Exception.o \
|
||||
../BlockDevice.o \
|
||||
../BlockCache.o \
|
||||
../DiskCopy42Image.o \
|
||||
../RawDevice.o \
|
||||
../MappedFile.o \
|
||||
../Buffer.o
|
||||
|
||||
|
||||
fileman : \
|
||||
FileMan.o \
|
||||
Date.o \
|
||||
File.o \
|
||||
../Exception.o \
|
||||
../BlockDevice.o \
|
||||
../BlockCache.o \
|
||||
../DiskCopy42Image.o \
|
||||
../RawDevice.o \
|
||||
../MappedFile.o \
|
||||
../Buffer.o
|
||||
|
||||
|
||||
profuse_pascal : \
|
||||
profuse_pascal.o \
|
||||
profuse_pascal_ops.o \
|
||||
Date.o \
|
||||
File.o \
|
||||
../Exception.o \
|
||||
../BlockDevice.o \
|
||||
../BlockCache.o \
|
||||
../DiskCopy42Image.o \
|
||||
../RawDevice.o \
|
||||
../MappedFile.o \
|
||||
../Buffer.o
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
|
||||
|
||||
class TextFile {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
unsigned size() const;
|
||||
|
||||
unsigned read(void *buffer, unsigned size, unsigned offset);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
static unsigned decodeBlock(uint8_t *in, unsigned inSize, uint8_t *out);
|
||||
|
||||
unsigned _size;
|
||||
std::vector<unsigned> _pageSize
|
||||
};
|
||||
|
||||
|
||||
unsigned decodeBlock(uint8_t *in, unsigned inSize, uint8_t *out)
|
||||
{
|
||||
const unsigned DLE = 16;
|
||||
|
||||
unsigned size = 0;
|
||||
|
||||
for (unsigned i = 0; i < inSize; ++i)
|
||||
{
|
||||
uint8_t c = in[i];
|
||||
if (!c) break;
|
||||
|
||||
if ((c == DLE) && (i + 1 < inSize))
|
||||
{
|
||||
unsigned x = in[++i] - 32;
|
||||
|
||||
if (out)
|
||||
{
|
||||
for (unsigned i = 0; i < x; ++i)
|
||||
*out++ = ' ';
|
||||
}
|
||||
size += x;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (out) *out++ = c;
|
||||
++size;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
|
||||
// first 2 blocks are header information
|
||||
|
||||
_fileSize = 0;
|
||||
|
||||
unsigned pages = (_endBlock - _startBlock - 2) >> 1
|
||||
uint8_t buffer[1024];
|
||||
unsigned offset = 0;
|
||||
|
||||
for (unsigned i _startBlock + 2; i <= _endBlock; i += 2)
|
||||
{
|
||||
uint8_t buffer[1024];
|
||||
unsigned dataSize = 0;
|
||||
unsigned offset = 0;
|
||||
unsigned size;
|
||||
|
||||
// load a 2-block page.
|
||||
for (j = i; j <= _endBlock; ++j)
|
||||
{
|
||||
_device->readBlock(j, buffer + offset);
|
||||
dataSize += j == _endBlock ? _lastByte : 512;
|
||||
|
||||
}
|
||||
|
||||
size = decodeBlock(buffer, dataSize, NULL);
|
||||
|
||||
_pageSize.push_back(size);
|
||||
_fileSize += size;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user