2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
#include <cerrno>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <cstdio>
|
2009-11-26 15:58:10 +00:00
|
|
|
#include <algorithm>
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
#include <Device/DavexDiskImage.h>
|
2010-05-18 02:58:26 +00:00
|
|
|
#include <File/MappedFile.h>
|
|
|
|
#include <Device/Adaptor.h>
|
2009-12-16 01:33:28 +00:00
|
|
|
|
|
|
|
#include <Endian/Endian.h>
|
|
|
|
#include <Endian/IOBuffer.h>
|
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
#include <Cache/MappedBlockCache.h>
|
2009-12-16 01:33:28 +00:00
|
|
|
|
|
|
|
using namespace Device;
|
2009-11-24 03:56:19 +00:00
|
|
|
using namespace LittleEndian;
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
using ProFUSE::Exception;
|
|
|
|
using ProFUSE::POSIXException;
|
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
/*
|
|
|
|
http://www.umich.edu/~archive/apple2/technotes/ftn/FTN.E0.8004
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const char *IdentityCheck = "\x60VSTORE [Davex]\x00";
|
|
|
|
|
|
|
|
|
|
|
|
// private, validation already performed.
|
2010-05-18 02:58:26 +00:00
|
|
|
DavexDiskImage::DavexDiskImage(MappedFile *file) :
|
|
|
|
DiskImage(file)
|
2009-11-21 01:45:08 +00:00
|
|
|
{
|
2010-05-19 17:50:18 +00:00
|
|
|
// at this point, file is no longer valid.
|
|
|
|
|
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
// 512-bytes header
|
2010-05-19 17:50:18 +00:00
|
|
|
setBlocks((length() / 512) - 1);
|
|
|
|
setAdaptor(new POAdaptor(512 + (uint8_t *)address()));
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DavexDiskImage::~DavexDiskImage()
|
|
|
|
{
|
|
|
|
// scan and update usedBlocks?
|
|
|
|
}
|
|
|
|
|
|
|
|
void DavexDiskImage::Validate(MappedFile *f)
|
|
|
|
{
|
|
|
|
#undef __METHOD__
|
|
|
|
#define __METHOD__ "DavexDiskImage::Validate"
|
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
size_t size = f->length();
|
|
|
|
const void * data = f->address();
|
2009-11-21 01:45:08 +00:00
|
|
|
bool ok = false;
|
|
|
|
unsigned blocks = (size / 512) - 1;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (size < 512) break;
|
|
|
|
if (size % 512) break;
|
|
|
|
|
|
|
|
// identity.
|
|
|
|
if (std::memcmp(data, IdentityCheck, 16))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// file format.
|
2009-11-24 03:56:19 +00:00
|
|
|
if (Read8(data, 0x10) != 0)
|
2009-11-21 01:45:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// total blocks
|
2009-11-24 03:56:19 +00:00
|
|
|
if (Read32(data, 33) != blocks)
|
2009-11-21 01:45:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// file number -- must be 1
|
2009-11-24 03:56:19 +00:00
|
|
|
if (Read8(data, 64) != 1)
|
2009-11-21 01:45:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
ok = true;
|
|
|
|
} while (false);
|
|
|
|
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
throw Exception(__METHOD__ ": Invalid file format.");
|
|
|
|
}
|
|
|
|
|
|
|
|
DavexDiskImage *DavexDiskImage::Open(MappedFile *file)
|
|
|
|
{
|
|
|
|
#undef __METHOD__
|
|
|
|
#define __METHOD__ "DavexDiskImage::Open"
|
|
|
|
Validate(file);
|
|
|
|
|
|
|
|
return new DavexDiskImage(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
DavexDiskImage *DavexDiskImage::Create(const char *name, size_t blocks)
|
2009-11-26 15:58:10 +00:00
|
|
|
{
|
|
|
|
return Create(name, blocks, "Untitled");
|
|
|
|
}
|
|
|
|
DavexDiskImage *DavexDiskImage::Create(const char *name, size_t blocks, const char *vname)
|
2009-11-21 01:45:08 +00:00
|
|
|
{
|
|
|
|
#undef __METHOD__
|
|
|
|
#define __METHOD__ "DavexDiskImage::Create"
|
|
|
|
|
|
|
|
uint8_t *data;
|
2009-12-16 01:33:28 +00:00
|
|
|
uint8_t tmp[512];
|
|
|
|
IOBuffer header(tmp,512);
|
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-29 19:29:59 +00:00
|
|
|
MappedFile *file = MappedFile::Create(name, blocks * 512 + 512);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
data = (uint8_t *)file->address();
|
2009-12-16 01:33:28 +00:00
|
|
|
|
|
|
|
header.writeBytes(IdentityCheck, 16);
|
2009-11-21 01:45:08 +00:00
|
|
|
// file Format
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(0);
|
2009-11-21 01:45:08 +00:00
|
|
|
//version
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(0);
|
2009-11-21 01:45:08 +00:00
|
|
|
// version
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(0x10);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// reserved.
|
2009-12-16 01:33:28 +00:00
|
|
|
header.setOffset(32, true);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
//deviceNum
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(1);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// total blocks
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(blocks);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// unused blocks
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(0);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// volume Name
|
2009-11-26 15:58:10 +00:00
|
|
|
if (!vname || !*vname) vname = "Untitled";
|
|
|
|
unsigned l = std::strlen(vname);
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(std::min(l, 15u));
|
|
|
|
header.writeBytes(vname, std::min(l, 15u));
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// name + reserved.
|
2009-12-16 01:33:28 +00:00
|
|
|
header.setOffset(64, true);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// file number
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(1);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
//starting block
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(0);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// reserved
|
2009-12-16 01:33:28 +00:00
|
|
|
header.setOffset(512, true);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
std::memcpy(file->address(), header.buffer(), 512);
|
2009-11-21 01:45:08 +00:00
|
|
|
file->sync();
|
|
|
|
|
|
|
|
return new DavexDiskImage(file);
|
|
|
|
}
|
2010-05-18 19:59:18 +00:00
|
|
|
|
|
|
|
|
2010-05-18 21:26:07 +00:00
|
|
|
BlockCache *DavexDiskImage::createBlockCache()
|
2010-05-18 19:59:18 +00:00
|
|
|
{
|
|
|
|
return new MappedBlockCache(this, 512 + (uint8_t *)address());
|
|
|
|
|
|
|
|
}
|