mirror of
https://github.com/ksherlock/profuse.git
synced 2026-04-23 22:53:23 +00:00
Compare commits
29 Commits
master
...
profuse_in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
699c44cf15 | ||
|
|
1a0bdd875c | ||
|
|
77e5994908 | ||
|
|
5ab8fd3d87 | ||
|
|
c6165e16d2 | ||
|
|
87d6070dcf | ||
|
|
0e083d53e7 | ||
|
|
78b1b8b242 | ||
|
|
977f0530fc | ||
|
|
24757dc35c | ||
|
|
ac8bbd5265 | ||
|
|
c7c4f13bf7 | ||
|
|
68a7851f33 | ||
|
|
8550923cb3 | ||
|
|
c9b260b753 | ||
|
|
c44145f551 | ||
|
|
3f8e7ad7ae | ||
|
|
4cdfc52c04 | ||
|
|
1fd924ae1b | ||
|
|
40ea9f2289 | ||
|
|
9a6e9150ef | ||
|
|
2bd72b08b9 | ||
|
|
664dee7578 | ||
|
|
ea0d1c198b | ||
|
|
c82cd3f8fa | ||
|
|
5427db9990 | ||
|
|
7fb0604b76 | ||
|
|
14e9b43f32 | ||
|
|
e5f935e435 |
73
Cache/BlockCache.cpp
Normal file
73
Cache/BlockCache.cpp
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <Cache/BlockCache.h>
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
#include <ProFUSE/auto.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
BlockCache::BlockCache(BlockDevicePointer device) :
|
||||||
|
_device(device)
|
||||||
|
{
|
||||||
|
_blocks = device->blocks();
|
||||||
|
_readOnly = device->readOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockCache::~BlockCache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockCache::write(unsigned block, const void *bp)
|
||||||
|
{
|
||||||
|
void *address = acquire(block);
|
||||||
|
std::memcpy(address, bp, 512);
|
||||||
|
release(block, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockCache::read(unsigned block, void *bp)
|
||||||
|
{
|
||||||
|
void *address = acquire(block);
|
||||||
|
std::memcpy(bp, address, 512);
|
||||||
|
release(block, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockCachePointer BlockCache::Create(BlockDevicePointer device)
|
||||||
|
{
|
||||||
|
// this just calls the device virtual function to create a cache.
|
||||||
|
if (!device) return BlockCachePointer();
|
||||||
|
|
||||||
|
return device->createBlockCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BlockCache::zeroBlock(unsigned block)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
void *address = acquire(block);
|
||||||
|
std::memset(address, 0, 512);
|
||||||
|
release(block, true);
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint8_t buffer[512];
|
||||||
|
|
||||||
|
std::memset(buffer, 0, 512);
|
||||||
|
write(block, buffer);
|
||||||
|
}
|
||||||
62
Cache/BlockCache.h
Normal file
62
Cache/BlockCache.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#ifndef __BLOCKCACHE_H__
|
||||||
|
#define __BLOCKCACHE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <Device/Device.h>
|
||||||
|
|
||||||
|
|
||||||
|
class MappedFile;
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
|
||||||
|
enum BlockReleaseFlags {
|
||||||
|
kBlockDirty = 1,
|
||||||
|
kBlockCommitNow = 2,
|
||||||
|
kBlockReuse = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
class BlockCache {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static BlockCachePointer Create(BlockDevicePointer device);
|
||||||
|
|
||||||
|
virtual ~BlockCache();
|
||||||
|
|
||||||
|
bool readOnly() { return _readOnly; }
|
||||||
|
unsigned blocks() { return _blocks; }
|
||||||
|
BlockDevicePointer device() { return _device; }
|
||||||
|
|
||||||
|
|
||||||
|
virtual void sync() = 0;
|
||||||
|
virtual void write(unsigned block, const void *bp);
|
||||||
|
virtual void read(unsigned block, void *bp);
|
||||||
|
|
||||||
|
virtual void *acquire(unsigned block) = 0;
|
||||||
|
virtual void release(unsigned block, int flags) = 0 ;
|
||||||
|
virtual void markDirty(unsigned block) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
virtual void zeroBlock(unsigned block);
|
||||||
|
|
||||||
|
void release(unsigned block) { release(block, 0); }
|
||||||
|
void release(unsigned block, bool dirty)
|
||||||
|
{
|
||||||
|
release(block, dirty ? kBlockDirty : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BlockCache(BlockDevicePointer device);
|
||||||
|
|
||||||
|
BlockDevicePointer _device;
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned _blocks;
|
||||||
|
bool _readOnly;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif
|
||||||
382
Cache/ConcreteBlockCache.cpp
Normal file
382
Cache/ConcreteBlockCache.cpp
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
#include <Cache/ConcreteBlockCache.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
#include <ProFUSE/auto.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note -- everything is assumed to be single-threaded.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The primary purpose of the block cache is not as a cache
|
||||||
|
* (the OS probably does a decent job of that) but rather to
|
||||||
|
* simplify read/writes. Blocks will always be accessed by
|
||||||
|
* pointer, so any updates will be shared.
|
||||||
|
* For memory mapped prodos-order files, MappedBlockCache just
|
||||||
|
* returns a pointer to the memory.
|
||||||
|
* For dos-order, nibblized, or raw devices, ConcreteBlockCache
|
||||||
|
* uses an approach similar to minix (although the buffer pool will
|
||||||
|
* expand if needed).
|
||||||
|
*
|
||||||
|
* _buffers is a vector of all buffers and only exists to make
|
||||||
|
* freeing them easier.
|
||||||
|
* _hashTable is a simple hashtable of loaded blocks.
|
||||||
|
* _first and _last are a double-linked list of unused blocks, stored
|
||||||
|
* in lru order.
|
||||||
|
*
|
||||||
|
* The Entry struct contains the buffer, the block, a dirty flag, and an in-use
|
||||||
|
* count as well as pointer for the hashtable and lru list.
|
||||||
|
* When a block is loaded, it is stored in the _hashTable. It remains in the
|
||||||
|
* hash table when the in-use count goes to 0 (it will also be added to the
|
||||||
|
* end of the lru list).
|
||||||
|
*
|
||||||
|
* dirty buffers are only written to disk in 3 scenarios:
|
||||||
|
* a) sync() is called
|
||||||
|
* b) the cache is deleted
|
||||||
|
* c) a buffer is re-used from the lru list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
//typedef std::vector<ConcreteBlockCache::Entry *>::iterator EntryIter;
|
||||||
|
|
||||||
|
|
||||||
|
BlockCachePointer ConcreteBlockCache::Create(BlockDevicePointer device, unsigned size)
|
||||||
|
{
|
||||||
|
//return BlockCachePointer(new ConcreteBlockCache(device, size));
|
||||||
|
// constructor must be accessible to std::make_shared...
|
||||||
|
|
||||||
|
return MAKE_SHARED(ConcreteBlockCache, device, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcreteBlockCache::ConcreteBlockCache(BlockDevicePointer device, unsigned size) :
|
||||||
|
BlockCache(device)
|
||||||
|
{
|
||||||
|
if (size < 16) size = 16;
|
||||||
|
|
||||||
|
std::memset(_hashTable, 0, sizeof(Entry *) * HashTableSize);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
Entry *e = new Entry;
|
||||||
|
|
||||||
|
std::memset(e, 0, sizeof(Entry));
|
||||||
|
_buffers.push_back(e);
|
||||||
|
}
|
||||||
|
_first = _last = NULL;
|
||||||
|
|
||||||
|
_first = _buffers.front();
|
||||||
|
_last = _buffers.back();
|
||||||
|
// form a chain....
|
||||||
|
for (unsigned i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
Entry *e = _buffers[i];
|
||||||
|
|
||||||
|
if (i > 0) e->prev = _buffers[i - 1];
|
||||||
|
|
||||||
|
if (i < size - 1) e->next = _buffers[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcreteBlockCache::~ConcreteBlockCache()
|
||||||
|
{
|
||||||
|
EntryIter iter;
|
||||||
|
for (iter = _buffers.begin(); iter != _buffers.end(); ++iter)
|
||||||
|
{
|
||||||
|
Entry *e = *iter;
|
||||||
|
|
||||||
|
if (e->dirty)
|
||||||
|
{
|
||||||
|
_device->write(e->block, e->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete e;
|
||||||
|
}
|
||||||
|
_device->sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConcreteBlockCache::sync()
|
||||||
|
{
|
||||||
|
EntryIter iter;
|
||||||
|
for (iter = _buffers.begin(); iter != _buffers.end(); ++iter)
|
||||||
|
{
|
||||||
|
Entry *e = *iter;
|
||||||
|
|
||||||
|
if (e->dirty)
|
||||||
|
{
|
||||||
|
_device->write(e->block, e->buffer);
|
||||||
|
e->dirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_device->sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConcreteBlockCache::write(unsigned block, const void *bp)
|
||||||
|
{
|
||||||
|
Entry *e = findEntry(block);
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
e->dirty = true;
|
||||||
|
std::memcpy(e->buffer, bp, 512);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a new entry not in the hashtable or the linked list.
|
||||||
|
// we add it to both.
|
||||||
|
e = newEntry(block);
|
||||||
|
|
||||||
|
e->count = 0;
|
||||||
|
e->dirty = true;
|
||||||
|
|
||||||
|
std::memcpy(e->buffer, bp, 512);
|
||||||
|
|
||||||
|
addEntry(e);
|
||||||
|
setLast(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ConcreteBlockCache::markDirty(unsigned block)
|
||||||
|
{
|
||||||
|
Entry *e = findEntry(block);
|
||||||
|
|
||||||
|
if (e) e->dirty = true;
|
||||||
|
// error otherwise?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConcreteBlockCache::release(unsigned block, int flags)
|
||||||
|
{
|
||||||
|
Entry *e = findEntry(block);
|
||||||
|
bool dirty = flags & (kBlockDirty | kBlockCommitNow);
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
if (dirty) e->dirty = true;
|
||||||
|
|
||||||
|
decrementCount(e);
|
||||||
|
|
||||||
|
if (flags & kBlockCommitNow)
|
||||||
|
{
|
||||||
|
_device->write(block, e->buffer);
|
||||||
|
e->dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// error otherwise?
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ConcreteBlockCache::acquire(unsigned block)
|
||||||
|
{
|
||||||
|
Entry *e = findEntry(block);
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
incrementCount(e);
|
||||||
|
return e->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a new entry, not in hash table, not in free list.
|
||||||
|
e = newEntry(block);
|
||||||
|
|
||||||
|
_device->read(block, e->buffer);
|
||||||
|
|
||||||
|
addEntry(e);
|
||||||
|
|
||||||
|
return e->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned ConcreteBlockCache::hashFunction(unsigned block)
|
||||||
|
{
|
||||||
|
return block % HashTableSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ConcreteBlockCache::Entry *ConcreteBlockCache::findEntry(unsigned block)
|
||||||
|
{
|
||||||
|
Entry *e;
|
||||||
|
unsigned hash = hashFunction(block);
|
||||||
|
|
||||||
|
e = _hashTable[hash];
|
||||||
|
|
||||||
|
while ((e) && (e->block != block))
|
||||||
|
e = e->nextHash;
|
||||||
|
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remove a block from the hashtable
|
||||||
|
* and write to dick if dirty.
|
||||||
|
*/
|
||||||
|
void ConcreteBlockCache::removeEntry(unsigned block)
|
||||||
|
{
|
||||||
|
Entry *e;
|
||||||
|
Entry *prev;
|
||||||
|
unsigned hash = hashFunction(block);
|
||||||
|
|
||||||
|
e = _hashTable[hash];
|
||||||
|
if (!e) return;
|
||||||
|
|
||||||
|
// head pointer, special case.
|
||||||
|
if (e->block == block)
|
||||||
|
{
|
||||||
|
_hashTable[hash] = e->nextHash;
|
||||||
|
e->nextHash = NULL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
prev = e;
|
||||||
|
e = e->nextHash;
|
||||||
|
|
||||||
|
if (!e) break;
|
||||||
|
if (e->block == block)
|
||||||
|
{
|
||||||
|
prev->nextHash = e->nextHash;
|
||||||
|
e->nextHash = NULL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConcreteBlockCache::addEntry(Entry *e)
|
||||||
|
{
|
||||||
|
unsigned hash = hashFunction(e->block);
|
||||||
|
|
||||||
|
e->nextHash = _hashTable[hash];
|
||||||
|
_hashTable[hash] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment the count and remove from the free list
|
||||||
|
// if necessary.
|
||||||
|
void ConcreteBlockCache::incrementCount(Entry *e)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (e->count == 0)
|
||||||
|
{
|
||||||
|
Entry *prev = e->prev;
|
||||||
|
Entry *next = e->next;
|
||||||
|
|
||||||
|
e->prev = e->next = NULL;
|
||||||
|
|
||||||
|
if (prev) prev->next = next;
|
||||||
|
if (next) next->prev = prev;
|
||||||
|
|
||||||
|
if (_first == e) _first = next;
|
||||||
|
if (_last == e) _last = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->count = e->count + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrement the count. If it goes to 0,
|
||||||
|
// add it as the last block entry.
|
||||||
|
void ConcreteBlockCache::decrementCount(Entry *e)
|
||||||
|
{
|
||||||
|
e->count = e->count - 1;
|
||||||
|
if (e->count == 0)
|
||||||
|
{
|
||||||
|
setLast(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcreteBlockCache::Entry *ConcreteBlockCache::newEntry(unsigned block)
|
||||||
|
{
|
||||||
|
Entry *e;
|
||||||
|
|
||||||
|
if (_first)
|
||||||
|
{
|
||||||
|
e = _first;
|
||||||
|
if (_first == _last)
|
||||||
|
{
|
||||||
|
_first = _last = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_first = e->next;
|
||||||
|
_first->prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (e->dirty)
|
||||||
|
{
|
||||||
|
_device->write(e->block, e->buffer);
|
||||||
|
e->dirty = false;
|
||||||
|
}
|
||||||
|
removeEntry(e->block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e = new Entry;
|
||||||
|
_buffers.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
e->next = NULL;
|
||||||
|
e->prev= NULL;
|
||||||
|
e->nextHash = NULL;
|
||||||
|
e->count = 1;
|
||||||
|
e->block = block;
|
||||||
|
e->dirty = false;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConcreteBlockCache::setLast(Entry *e)
|
||||||
|
{
|
||||||
|
if (_last == NULL)
|
||||||
|
{
|
||||||
|
_first = _last = e;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->prev = _last;
|
||||||
|
_last->next = e;
|
||||||
|
_last = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConcreteBlockCache::setFirst(Entry *e)
|
||||||
|
{
|
||||||
|
if (_first == NULL)
|
||||||
|
{
|
||||||
|
_first = _last = e;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->next = _first;
|
||||||
|
_first->prev = e;
|
||||||
|
_first = e;
|
||||||
|
}
|
||||||
|
|
||||||
75
Cache/ConcreteBlockCache.h
Normal file
75
Cache/ConcreteBlockCache.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#ifndef __CONCRETE_BLOCK_CACHE_H__
|
||||||
|
#define __CONCRETE_BLOCK_CACHE_H__
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Cache/BlockCache.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class ConcreteBlockCache : public BlockCache {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static BlockCachePointer Create(BlockDevicePointer device, unsigned size = 16);
|
||||||
|
|
||||||
|
virtual ~ConcreteBlockCache();
|
||||||
|
|
||||||
|
virtual void sync();
|
||||||
|
virtual void write(unsigned block, const void *vp);
|
||||||
|
|
||||||
|
|
||||||
|
virtual void *acquire(unsigned block);
|
||||||
|
virtual void release(unsigned block, int flags);
|
||||||
|
virtual void markDirty(unsigned block);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
ConcreteBlockCache(BlockDevicePointer device, unsigned size);
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
unsigned block;
|
||||||
|
unsigned count;
|
||||||
|
bool dirty;
|
||||||
|
|
||||||
|
struct Entry *next;
|
||||||
|
struct Entry *prev;
|
||||||
|
struct Entry *nextHash;
|
||||||
|
|
||||||
|
uint8_t buffer[512];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Entry *>::iterator EntryIter;
|
||||||
|
|
||||||
|
enum { HashTableSize = 23 };
|
||||||
|
|
||||||
|
std::vector<Entry *>_buffers;
|
||||||
|
|
||||||
|
Entry *_hashTable[HashTableSize];
|
||||||
|
|
||||||
|
Entry *_first;
|
||||||
|
Entry *_last;
|
||||||
|
|
||||||
|
|
||||||
|
unsigned hashFunction(unsigned block);
|
||||||
|
|
||||||
|
Entry *findEntry(unsigned block);
|
||||||
|
void removeEntry(unsigned block);
|
||||||
|
void addEntry(Entry *);
|
||||||
|
|
||||||
|
Entry *newEntry(unsigned block);
|
||||||
|
|
||||||
|
void pushEntry(Entry *);
|
||||||
|
|
||||||
|
void setLast(Entry *);
|
||||||
|
void setFirst(Entry *);
|
||||||
|
|
||||||
|
void incrementCount(Entry *);
|
||||||
|
void decrementCount(Entry *);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
140
Cache/MappedBlockCache.cpp
Normal file
140
Cache/MappedBlockCache.cpp
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <Cache/MappedBlockCache.h>
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
BlockCachePointer MappedBlockCache::Create(BlockDevicePointer device, void *data)
|
||||||
|
{
|
||||||
|
//return BlockCachePointer(new MappedBlockCache(device, data));
|
||||||
|
return MAKE_SHARED(MappedBlockCache, device, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MappedBlockCache::MappedBlockCache(BlockDevicePointer device, void *data) :
|
||||||
|
BlockCache(device)
|
||||||
|
{
|
||||||
|
_data = (uint8_t *)data;
|
||||||
|
_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MappedBlockCache::~MappedBlockCache()
|
||||||
|
{
|
||||||
|
if (_dirty) sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *MappedBlockCache::acquire(unsigned block)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedBlockCache::load"
|
||||||
|
|
||||||
|
if (block >= blocks())
|
||||||
|
throw Exception(__METHOD__ ": Invalid block.");
|
||||||
|
|
||||||
|
|
||||||
|
return _data + block * 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MappedBlockCache::release(unsigned block, int flags)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedBlockCache::unload"
|
||||||
|
|
||||||
|
// kBlockCommitNow implies kBlockDirty.
|
||||||
|
if (flags & kBlockCommitNow)
|
||||||
|
{
|
||||||
|
sync(block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & kBlockDirty) _dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MappedBlockCache::write(unsigned block, const void *vp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedBlockCache::write"
|
||||||
|
|
||||||
|
if (block >= blocks())
|
||||||
|
throw Exception(__METHOD__ ": Invalid block.");
|
||||||
|
|
||||||
|
_dirty = true;
|
||||||
|
std::memcpy(_data + block * 512, vp, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MappedBlockCache::zeroBlock(unsigned block)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedBlockCache::zeroBlock"
|
||||||
|
|
||||||
|
if (block >= blocks())
|
||||||
|
throw Exception(__METHOD__ ": Invalid block.");
|
||||||
|
|
||||||
|
|
||||||
|
_dirty = true;
|
||||||
|
std::memset(_data + block * 512, 0, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// sync everything.
|
||||||
|
void MappedBlockCache::sync()
|
||||||
|
{
|
||||||
|
_device->sync();
|
||||||
|
_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* sync an individual page.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void MappedBlockCache::sync(unsigned block)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedBlockCache::sync"
|
||||||
|
|
||||||
|
|
||||||
|
int pagesize = ::getpagesize();
|
||||||
|
|
||||||
|
void *start = _data + block * 512;
|
||||||
|
void *end = _data + 512 + block * 512;
|
||||||
|
|
||||||
|
|
||||||
|
start = (void *)((ptrdiff_t)start / pagesize * pagesize);
|
||||||
|
end = (void *)((ptrdiff_t)end / pagesize * pagesize);
|
||||||
|
|
||||||
|
if (::msync(start, pagesize, MS_SYNC) != 0)
|
||||||
|
throw POSIXException(__METHOD__ ": msync", errno);
|
||||||
|
|
||||||
|
if (start != end)
|
||||||
|
{
|
||||||
|
if (::msync(end, pagesize, MS_SYNC) != 0)
|
||||||
|
throw POSIXException(__METHOD__ ": msync", errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MappedBlockCache::markDirty(unsigned block)
|
||||||
|
{
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
38
Cache/MappedBlockCache.h
Normal file
38
Cache/MappedBlockCache.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef __MAPPED_BLOCK_CACHE_H__
|
||||||
|
#define __MAPPED_BLOCK_CACHE_H__
|
||||||
|
|
||||||
|
#include <Cache/BlockCache.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class MappedBlockCache : public BlockCache {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static BlockCachePointer Create(BlockDevicePointer device, void *data);
|
||||||
|
|
||||||
|
virtual ~MappedBlockCache();
|
||||||
|
|
||||||
|
virtual void sync();
|
||||||
|
virtual void write(unsigned block, const void *vp);
|
||||||
|
|
||||||
|
virtual void zeroBlock(unsigned block);
|
||||||
|
|
||||||
|
|
||||||
|
virtual void *acquire(unsigned block);
|
||||||
|
virtual void release(unsigned block, int flags);
|
||||||
|
virtual void markDirty(unsigned block);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MappedBlockCache(BlockDevicePointer device, void *data);
|
||||||
|
|
||||||
|
void sync(unsigned block);
|
||||||
|
|
||||||
|
uint8_t *_data;
|
||||||
|
bool _dirty;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
486
Device/Adaptor.cpp
Normal file
486
Device/Adaptor.cpp
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <Device/Adaptor.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
|
||||||
|
Adaptor::~Adaptor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
POAdaptor::POAdaptor(void *address)
|
||||||
|
{
|
||||||
|
_address = (uint8_t *)address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void POAdaptor::readBlock(unsigned block, void *bp)
|
||||||
|
{
|
||||||
|
std::memcpy(bp, _address + block * 512, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
void POAdaptor::writeBlock(unsigned block, const void *bp)
|
||||||
|
{
|
||||||
|
std::memcpy(_address + block * 512, bp, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned DOAdaptor::Map[] = {
|
||||||
|
0x00, 0x0e, 0x0d, 0x0c,
|
||||||
|
0x0b, 0x0a, 0x09, 0x08,
|
||||||
|
0x07, 0x06, 0x05, 0x04,
|
||||||
|
0x03, 0x02, 0x01, 0x0f
|
||||||
|
};
|
||||||
|
|
||||||
|
DOAdaptor::DOAdaptor(void *address)
|
||||||
|
{
|
||||||
|
_address = (uint8_t *)address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DOAdaptor::readBlock(unsigned block, void *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned track = (block & ~0x07) << 9;
|
||||||
|
unsigned sector = (block & 0x07) << 1;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
size_t offset = track | (Map[sector+i] << 8);
|
||||||
|
|
||||||
|
std::memcpy(bp, _address + offset, 256);
|
||||||
|
|
||||||
|
bp = (uint8_t *)bp + 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DOAdaptor::writeBlock(unsigned block, const void *bp)
|
||||||
|
{
|
||||||
|
unsigned track = (block & ~0x07) << 9;
|
||||||
|
unsigned sector = (block & 0x07) << 1;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
size_t offset = track | (Map[sector+i] << 8);
|
||||||
|
|
||||||
|
std::memcpy(_address + offset, bp, 256);
|
||||||
|
bp = (uint8_t *)bp + 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark NibbleAdaptor
|
||||||
|
|
||||||
|
class CircleBuffer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CircleBuffer(void *address, unsigned length)
|
||||||
|
{
|
||||||
|
_address = (uint8_t *)address;
|
||||||
|
_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t operator[](unsigned i) const
|
||||||
|
{
|
||||||
|
if (i >= _length) i %= _length;
|
||||||
|
return _address[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t& operator[](unsigned i)
|
||||||
|
{
|
||||||
|
if (i >= _length) i %= _length;
|
||||||
|
return _address[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t *_address;
|
||||||
|
unsigned _length;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t NibbleAdaptor::decode44(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
return ((x << 1) | 0x01) & y;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<uint8_t, uint8_t> NibbleAdaptor::encode44(uint8_t val)
|
||||||
|
{
|
||||||
|
uint8_t x = (val >> 1) | 0xaa;
|
||||||
|
uint8_t y = val | 0xaa;
|
||||||
|
|
||||||
|
return std::make_pair(x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t NibbleAdaptor::encode62(uint8_t val)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "NibbleAdaptor::encode62"
|
||||||
|
|
||||||
|
static uint8_t table[64] = {
|
||||||
|
0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6,
|
||||||
|
0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3,
|
||||||
|
|
||||||
|
0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc,
|
||||||
|
0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3,
|
||||||
|
|
||||||
|
0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
|
||||||
|
0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec,
|
||||||
|
|
||||||
|
0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
|
||||||
|
0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
if (val > 0x3f)
|
||||||
|
throw ProFUSE::Exception(__METHOD__ ": Invalid 6-2 value.");
|
||||||
|
|
||||||
|
return table[val];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t NibbleAdaptor::decode62(uint8_t val)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "decode62"
|
||||||
|
|
||||||
|
// auto-generated via perl.
|
||||||
|
static uint8_t table[] = {
|
||||||
|
-1, -1, -1, -1, -1, -1, 0, 1, -1, -1, 2, 3, -1, 4, 5, 6,
|
||||||
|
-1, -1, -1, -1, -1, -1, 7, 8, -1, -1, -1, 9, 10, 11, 12, 13,
|
||||||
|
-1, -1, 14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, 26,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, 28, 29, 30,
|
||||||
|
-1, -1, -1, 31, -1, -1, 32, 33, -1, 34, 35, 36, 37, 38, 39, 40,
|
||||||
|
-1, -1, -1, -1, -1, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50,
|
||||||
|
-1, -1, 51, 52, 53, 54, 55, 56, -1, 57, 58, 59, 60, 61, 62, 63
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((val < 0x90) || (table[val - 0x90] == 0xff))
|
||||||
|
throw ProFUSE::Exception(__METHOD__ ": Invalid 6-2 encoding.");
|
||||||
|
|
||||||
|
return table[val - 0x90];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int FindByte(void *address, uint8_t c, unsigned length, unsigned offset = 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (unsigned i = offset; i < length; ++i)
|
||||||
|
{
|
||||||
|
if ( ((uint8_t *)address)[i] == c) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Address Field:
|
||||||
|
* prologue volume track sector checksum epilogue
|
||||||
|
* D5 AA 96 XX YY XX YY XX YY XX YY DE AA EB
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data Field:
|
||||||
|
* prologue user data checksum epilogue
|
||||||
|
* D5 AA AD [6+2 encoded] XX DE AA EB
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NibbleAdaptor::NibbleAdaptor(void *address, unsigned length)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "NibbleAdaptor::NibbleAdaptor"
|
||||||
|
|
||||||
|
_address = (uint8_t *)address;
|
||||||
|
_length = length;
|
||||||
|
|
||||||
|
|
||||||
|
// build a map of track/sectors.
|
||||||
|
|
||||||
|
unsigned state = 0;
|
||||||
|
|
||||||
|
|
||||||
|
_index.resize(35 * 16, -1);
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
unsigned track = 0;
|
||||||
|
unsigned sector = 0;
|
||||||
|
unsigned volume = 0;
|
||||||
|
unsigned checksum = 0;
|
||||||
|
|
||||||
|
|
||||||
|
CircleBuffer buffer(_address, _length);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
|
||||||
|
offset = FindByte(address, 0xd5, length, offset);
|
||||||
|
if (offset < 0) break;
|
||||||
|
|
||||||
|
if (buffer[offset + 1] == 0xaa && buffer[offset + 2] == 0x96 && buffer[offset + 11] == 0xde && buffer[offset + 12] == 0xaa)
|
||||||
|
{
|
||||||
|
volume = decode44(buffer[offset + 3], buffer[offset + 4]);
|
||||||
|
track = decode44(buffer[offset + 5], buffer[offset + 6]);
|
||||||
|
sector = decode44(buffer[offset + 7], buffer[offset + 8]);
|
||||||
|
checksum = decode44(buffer[offset + 9], buffer[offset + 10]);
|
||||||
|
|
||||||
|
if (volume ^ track ^ sector ^ checksum)
|
||||||
|
throw ProFUSE::Exception(__METHOD__ ": Invalid address checksum.");
|
||||||
|
|
||||||
|
if (track > 35 || sector > 16)
|
||||||
|
throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector.");
|
||||||
|
|
||||||
|
offset += 3 + 8 + 3;
|
||||||
|
|
||||||
|
state = 1;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer[offset + 1] == 0xaa && buffer[offset + 2] == 0xad && state == 1)
|
||||||
|
{
|
||||||
|
if (_index[track * 16 + sector] != -1)
|
||||||
|
{
|
||||||
|
std::fprintf(stderr, "track %u sector %u duplicated.\n", track, sector);
|
||||||
|
}
|
||||||
|
_index[track * 16 + sector] = (offset + 3) % _length;
|
||||||
|
|
||||||
|
//offset += 3 + 342 + 1 + 3;
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
state = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset++; //???
|
||||||
|
// ????
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// possible wraparound.
|
||||||
|
if (state == 1)
|
||||||
|
{
|
||||||
|
offset = FindByte(address, 0xd5, length, 0);
|
||||||
|
|
||||||
|
if (offset >= 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (buffer[offset + 1] == 0xaa && buffer[offset + 2] == 0xad)
|
||||||
|
{
|
||||||
|
_index[track * 16 + sector] = (offset + 3) % _length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// now check _index for offset = -1, which means the sector/track wasn't found.
|
||||||
|
|
||||||
|
for (std::vector<unsigned>::iterator iter = _index.begin(); iter != _index.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (*iter == -1)
|
||||||
|
{
|
||||||
|
int offset = distance(_index.begin(), iter);
|
||||||
|
std::fprintf(stderr, "Error: track %u sector %u missing.\n", offset / 16, offset % 16);
|
||||||
|
//throw ProFUSE::Exception(__METHOD__ ": Sector missing.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NibbleAdaptor::~NibbleAdaptor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void NibbleAdaptor::readBlock(unsigned block, void *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned track = (block & ~0x07) << 9;
|
||||||
|
unsigned b = (block & 0x07) << 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* block sectors
|
||||||
|
* 0 0, 2
|
||||||
|
* 1 4, 6
|
||||||
|
* 2 8, 10
|
||||||
|
* 3 12,14
|
||||||
|
* 4 1, 3
|
||||||
|
* 5 5, 7
|
||||||
|
* 6 9, 11
|
||||||
|
* 7 13, 15
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned sector = b >> 2;
|
||||||
|
if (sector >= 16) sector -= 15;
|
||||||
|
|
||||||
|
|
||||||
|
readTrackSector(TrackSector(track, sector), bp);
|
||||||
|
readTrackSector(TrackSector(track, sector + 1), (uint8_t *)bp + 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NibbleAdaptor::writeBlock(unsigned block, const void *bp)
|
||||||
|
{
|
||||||
|
unsigned track = (block & ~0x07) << 9;
|
||||||
|
unsigned b = (block & 0x07) << 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* block sectors
|
||||||
|
* 0 0, 2
|
||||||
|
* 1 4, 6
|
||||||
|
* 2 8, 10
|
||||||
|
* 3 12,14
|
||||||
|
* 4 1, 3
|
||||||
|
* 5 5, 7
|
||||||
|
* 6 9, 11
|
||||||
|
* 7 13, 15
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned sector = b >> 2;
|
||||||
|
if (sector >= 16) sector -= 15;
|
||||||
|
|
||||||
|
|
||||||
|
writeTrackSector(TrackSector(track, sector), bp);
|
||||||
|
writeTrackSector(TrackSector(track, sector + 1), (const uint8_t *)bp + 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NibbleAdaptor::readTrackSector(TrackSector ts, void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "NibbleAdaptor::readTrackSector"
|
||||||
|
|
||||||
|
if (ts.track > 35 || ts.sector > 16)
|
||||||
|
throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector.");
|
||||||
|
|
||||||
|
|
||||||
|
CircleBuffer buffer(_address, _length);
|
||||||
|
uint8_t bits[86 * 3];
|
||||||
|
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
|
||||||
|
|
||||||
|
unsigned offset = _index[ts.track * 16 + ts.sector];
|
||||||
|
|
||||||
|
if (offset == -1)
|
||||||
|
{
|
||||||
|
throw ProFUSE::Exception(__METHOD__ ": Missing track/sector.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// first 86 bytes are in the auxbuffer, backwards.
|
||||||
|
unsigned index = offset;
|
||||||
|
for (unsigned i = 0; i < 86; ++i)
|
||||||
|
{
|
||||||
|
uint8_t x = buffer[index++];
|
||||||
|
x = decode62(x);
|
||||||
|
|
||||||
|
checksum ^= x;
|
||||||
|
|
||||||
|
uint8_t y = checksum;
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (unsigned j = 0; j < 3; ++j)
|
||||||
|
{
|
||||||
|
//bits[i + j * 86] = ((y & 0x01) << 1) | ((y & 0x02) >> 1);
|
||||||
|
bits[i + j * 86] = "\x00\x01\x02\x03"[y & 0x03];
|
||||||
|
y >>= 2;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
bits[i + 86 * 0] = "\x00\x02\x01\x03"[y & 0x03];
|
||||||
|
bits[i + 86 * 1] = "\x00\x02\x01\x03"[(y >> 2) & 0x03];
|
||||||
|
bits[i + 86 * 2] = "\x00\x02\x01\x03"[(y >> 4) & 0x03];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
uint8_t x = buffer[index++];
|
||||||
|
x = decode62(x);
|
||||||
|
|
||||||
|
checksum ^= x;
|
||||||
|
|
||||||
|
uint8_t y = (checksum << 2) | bits[i];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
((uint8_t *)bp)[i] = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checksum != decode62(buffer[index++]))
|
||||||
|
std::fprintf(stderr, "Invalid checksum on track %u, sector %u\n", ts.track, ts.sector);
|
||||||
|
//throw ProFUSE::Exception(__METHOD__ ": Invalid field checksum.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NibbleAdaptor::writeTrackSector(TrackSector ts, const void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "NibbleAdaptor::writeTrackSector"
|
||||||
|
|
||||||
|
if (ts.track > 35 || ts.sector > 16)
|
||||||
|
throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector.");
|
||||||
|
|
||||||
|
uint8_t auxBuffer[86];
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
|
||||||
|
// create the aux buffer.
|
||||||
|
|
||||||
|
std::memset(auxBuffer, 0, sizeof(auxBuffer));
|
||||||
|
|
||||||
|
for (unsigned i = 0, j = 0, shift = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
uint8_t x = ((const uint8_t *)bp)[i];
|
||||||
|
|
||||||
|
// grab the bottom 2 bytes and reverse them.
|
||||||
|
//uint8_t y = ((x & 0x01) << 1) | ((x & 0x02) >> 1);
|
||||||
|
uint8_t y = "\x00\x02\x01\x03"[x & 0x03];
|
||||||
|
|
||||||
|
auxBuffer[j++] |= (y << shift);
|
||||||
|
|
||||||
|
if (j == 86)
|
||||||
|
{
|
||||||
|
j = 0;
|
||||||
|
shift += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned offset = _index[ts.track * 16 + ts.sector];
|
||||||
|
|
||||||
|
CircleBuffer buffer(_address, _length);
|
||||||
|
// create the checksum while writing to disk..
|
||||||
|
|
||||||
|
// aux buffer
|
||||||
|
for (unsigned i = 0; i < 86; ++i)
|
||||||
|
{
|
||||||
|
uint8_t x = auxBuffer[i];
|
||||||
|
|
||||||
|
buffer[offset + i] = encode62(x ^ checksum);
|
||||||
|
|
||||||
|
checksum = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
uint8_t x = ((const uint8_t *)bp)[i];
|
||||||
|
x >>= 2;
|
||||||
|
|
||||||
|
buffer[offset + 86 + i] = encode62(x ^ checksum);
|
||||||
|
|
||||||
|
checksum = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
buffer[offset + 342] = encode62(checksum);
|
||||||
|
}
|
||||||
|
|
||||||
81
Device/Adaptor.h
Normal file
81
Device/Adaptor.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#ifndef __DEVICE_ADAPTOR_H__
|
||||||
|
#define __DEVICE_ADAPTOR_H__
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <Device/TrackSector.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class Adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Adaptor();
|
||||||
|
virtual void readBlock(unsigned block, void *bp) = 0;
|
||||||
|
virtual void writeBlock(unsigned block, const void *bp) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class POAdaptor : public Adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POAdaptor(void *address);
|
||||||
|
virtual void readBlock(unsigned block, void *bp);
|
||||||
|
virtual void writeBlock(unsigned block, const void *bp);
|
||||||
|
private:
|
||||||
|
uint8_t *_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DOAdaptor : public Adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DOAdaptor(void *address);
|
||||||
|
virtual void readBlock(unsigned block, void *bp);
|
||||||
|
virtual void writeBlock(unsigned block, const void *bp);
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned Map[];
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t *_address;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO -- nibble adaptor.
|
||||||
|
|
||||||
|
|
||||||
|
class NibbleAdaptor : public Adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NibbleAdaptor(void *address, unsigned length);
|
||||||
|
virtual ~NibbleAdaptor();
|
||||||
|
|
||||||
|
virtual void readBlock(unsigned block, void *bp);
|
||||||
|
virtual void writeBlock(unsigned block, const void *bp);
|
||||||
|
|
||||||
|
|
||||||
|
virtual void readTrackSector(TrackSector ts, void *bp);
|
||||||
|
virtual void writeTrackSector(TrackSector ts, const void *bp);
|
||||||
|
|
||||||
|
static std::pair<uint8_t, uint8_t>encode44(uint8_t);
|
||||||
|
static uint8_t decode44(uint8_t, uint8_t);
|
||||||
|
|
||||||
|
static uint8_t encode62(uint8_t);
|
||||||
|
static uint8_t decode62(uint8_t);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t *_address;
|
||||||
|
unsigned _length;
|
||||||
|
|
||||||
|
std::vector<unsigned> _index;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
271
Device/BlockDevice.cpp
Normal file
271
Device/BlockDevice.cpp
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
#include <Cache/ConcreteBlockCache.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
#include <Device/DiskImage.h>
|
||||||
|
#include <Device/UniversalDiskImage.h>
|
||||||
|
#include <Device/DiskCopy42Image.h>
|
||||||
|
#include <Device/DavexDiskImage.h>
|
||||||
|
#include <Device/RawDevice.h>
|
||||||
|
#include <Device/SDKImage.h>
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
unsigned BlockDevice::ImageType(MappedFile *f, unsigned defv)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "BlockDevice::ImageType"
|
||||||
|
|
||||||
|
|
||||||
|
if (UniversalDiskImage::Validate(f, std::nothrow))
|
||||||
|
return '2IMG';
|
||||||
|
|
||||||
|
if (DiskCopy42Image::Validate(f, std::nothrow))
|
||||||
|
return 'DC42';
|
||||||
|
|
||||||
|
if (SDKImage::Validate(f, std::nothrow))
|
||||||
|
return 'SDK_';
|
||||||
|
|
||||||
|
if (ProDOSOrderDiskImage::Validate(f, std::nothrow))
|
||||||
|
return 'PO__';
|
||||||
|
|
||||||
|
if (DOSOrderDiskImage::Validate(f, std::nothrow))
|
||||||
|
return 'DO__';
|
||||||
|
|
||||||
|
return defv;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned BlockDevice::ImageType(const char *type, unsigned defv)
|
||||||
|
{
|
||||||
|
const char *tmp;
|
||||||
|
|
||||||
|
|
||||||
|
if (type == 0 || *type == 0) return defv;
|
||||||
|
|
||||||
|
// type could be a path, eg images/file, disk.images/file
|
||||||
|
|
||||||
|
// unix-specifix.
|
||||||
|
// basename alters the input string
|
||||||
|
tmp = std::strrchr(type, '/');
|
||||||
|
if (tmp) type = tmp + 1;
|
||||||
|
|
||||||
|
// type could be a filename, in which case we check the extension.
|
||||||
|
tmp = std::strrchr(type, '.');
|
||||||
|
if (tmp) type = tmp + 1;
|
||||||
|
if (*type == 0) return defv;
|
||||||
|
|
||||||
|
|
||||||
|
if (::strcasecmp(type, "2mg") == 0)
|
||||||
|
return '2IMG';
|
||||||
|
if (::strcasecmp(type, "2img") == 0)
|
||||||
|
return '2IMG';
|
||||||
|
|
||||||
|
if (::strcasecmp(type, "dc") == 0)
|
||||||
|
return 'DC42';
|
||||||
|
if (::strcasecmp(type, "dc42") == 0)
|
||||||
|
return 'DC42';
|
||||||
|
|
||||||
|
if (::strcasecmp(type, "po") == 0)
|
||||||
|
return 'PO__';
|
||||||
|
if (::strcasecmp(type, "dmg") == 0)
|
||||||
|
return 'PO__';
|
||||||
|
|
||||||
|
if (::strcasecmp(type, "dsk") == 0)
|
||||||
|
return 'DO__';
|
||||||
|
if (::strcasecmp(type, "do") == 0)
|
||||||
|
return 'DO__';
|
||||||
|
|
||||||
|
if (::strcasecmp(type, "dvx") == 0)
|
||||||
|
return 'DVX_';
|
||||||
|
if (::strcasecmp(type, "davex") == 0)
|
||||||
|
return 'DVX_';
|
||||||
|
|
||||||
|
|
||||||
|
// not supported yet.
|
||||||
|
if (::strcasecmp(type, "sdk") == 0)
|
||||||
|
return 'SDK_';
|
||||||
|
if (::strcasecmp(type, "shk") == 0)
|
||||||
|
return 'SDK_';
|
||||||
|
|
||||||
|
return defv;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer BlockDevice::Open(const char *name, File::FileFlags flags, unsigned imageType)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "BlockDevice::Open"
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
std::memset(&st, 0, sizeof(st));
|
||||||
|
|
||||||
|
if (::stat(name, &st) != 0)
|
||||||
|
{
|
||||||
|
throw POSIXException(__METHOD__ ": stat error", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /dev/xxx ignore the type.
|
||||||
|
if (S_ISBLK(st.st_mode))
|
||||||
|
return RawDevice::Open(name, flags);
|
||||||
|
|
||||||
|
MappedFile file(name, flags);
|
||||||
|
|
||||||
|
|
||||||
|
if (!imageType)
|
||||||
|
{
|
||||||
|
imageType = ImageType(&file, 'PO__');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (imageType)
|
||||||
|
{
|
||||||
|
case '2IMG':
|
||||||
|
return UniversalDiskImage::Open(&file);
|
||||||
|
|
||||||
|
case 'DC42':
|
||||||
|
return DiskCopy42Image::Open(&file);
|
||||||
|
|
||||||
|
case 'DO__':
|
||||||
|
return DOSOrderDiskImage::Open(&file);
|
||||||
|
|
||||||
|
case 'PO__':
|
||||||
|
return ProDOSOrderDiskImage::Open(&file);
|
||||||
|
|
||||||
|
case 'DVX_':
|
||||||
|
return DavexDiskImage::Open(&file);
|
||||||
|
|
||||||
|
case 'SDK_':
|
||||||
|
return SDKImage::Open(name);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw an error?
|
||||||
|
return BlockDevicePointer();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return the basename, without an extension.
|
||||||
|
static std::string filename(const std::string& src)
|
||||||
|
{
|
||||||
|
unsigned start;
|
||||||
|
unsigned end;
|
||||||
|
|
||||||
|
|
||||||
|
if (src.empty()) return std::string("");
|
||||||
|
|
||||||
|
start = end = 0;
|
||||||
|
|
||||||
|
for(unsigned i = 0, l = src.length(); i < l; ++i)
|
||||||
|
{
|
||||||
|
char c = src[i];
|
||||||
|
if (c == '/') start = end = i + 1;
|
||||||
|
if (c == '.') end = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start == src.length()) return std::string("");
|
||||||
|
|
||||||
|
if (start == end) return src.substr(start);
|
||||||
|
return src.substr(start, end - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockDevicePointer BlockDevice::Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType)
|
||||||
|
{
|
||||||
|
std::string xname;
|
||||||
|
|
||||||
|
if (!imageType) imageType = ImageType(fname, 'PO__');
|
||||||
|
|
||||||
|
if (vname == NULL)
|
||||||
|
{
|
||||||
|
xname = filename(std::string(fname));
|
||||||
|
vname = xname.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
switch(imageType)
|
||||||
|
{
|
||||||
|
case '2IMG':
|
||||||
|
return UniversalDiskImage::Create(fname, blocks);
|
||||||
|
|
||||||
|
case 'DC42':
|
||||||
|
return DiskCopy42Image::Create(fname, blocks, vname);
|
||||||
|
|
||||||
|
case 'DO__':
|
||||||
|
return DOSOrderDiskImage::Create(fname, blocks);
|
||||||
|
|
||||||
|
case 'PO__':
|
||||||
|
return ProDOSOrderDiskImage::Create(fname, blocks);
|
||||||
|
|
||||||
|
case 'DVX_':
|
||||||
|
return DavexDiskImage::Create(fname, blocks, vname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BlockDevicePointer();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BlockDevice::BlockDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
BlockDevice::~BlockDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockDevice::zeroBlock(unsigned block)
|
||||||
|
{
|
||||||
|
uint8_t bp[512];
|
||||||
|
std::memset(bp, 0, 512);
|
||||||
|
|
||||||
|
write(block, bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool BlockDevice::mapped()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockDevice::sync(unsigned block)
|
||||||
|
{
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void BlockDevice::sync(TrackSector ts)
|
||||||
|
{
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
BlockCachePointer BlockDevice::createBlockCache()
|
||||||
|
{
|
||||||
|
unsigned b = blocks();
|
||||||
|
unsigned size = std::max(16u, b / 16);
|
||||||
|
return ConcreteBlockCache::Create(shared_from_this(), size);
|
||||||
|
}
|
||||||
69
Device/BlockDevice.h
Normal file
69
Device/BlockDevice.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#ifndef __BLOCKDEVICE_H__
|
||||||
|
#define __BLOCKDEVICE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <Device/Device.h>
|
||||||
|
#include <Device/TrackSector.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
#include <ProFUSE/smart_pointers.h>
|
||||||
|
|
||||||
|
#include <File/File.h>
|
||||||
|
|
||||||
|
class MappedFile;
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class BlockDevice : public ENABLE_SHARED_FROM_THIS(BlockDevice) {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
// static methods.
|
||||||
|
static unsigned ImageType(const char *type, unsigned defv = 0);
|
||||||
|
static unsigned ImageType(MappedFile *, unsigned defv = 0);
|
||||||
|
|
||||||
|
|
||||||
|
static BlockDevicePointer Open(const char *name, File::FileFlags flags, unsigned imageType = 0);
|
||||||
|
static BlockDevicePointer Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType = 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual ~BlockDevice();
|
||||||
|
|
||||||
|
virtual BlockCachePointer createBlockCache();
|
||||||
|
|
||||||
|
|
||||||
|
virtual void read(unsigned block, void *bp) = 0;
|
||||||
|
//virtual void read(TrackSector ts, void *bp) = 0
|
||||||
|
|
||||||
|
virtual void write(unsigned block, const void *bp) = 0;
|
||||||
|
//virtual void write(TrackSector ts, const void *bp) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
virtual unsigned blocks() = 0;
|
||||||
|
|
||||||
|
virtual bool mapped();
|
||||||
|
|
||||||
|
virtual bool readOnly() = 0;
|
||||||
|
|
||||||
|
virtual void sync() = 0;
|
||||||
|
virtual void sync(unsigned block);
|
||||||
|
//virtual void sync(TrackSector ts);
|
||||||
|
|
||||||
|
|
||||||
|
void zeroBlock(unsigned block);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BlockDevice();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
176
Device/DavexDiskImage.cpp
Normal file
176
Device/DavexDiskImage.cpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <Device/DavexDiskImage.h>
|
||||||
|
#include <File/MappedFile.h>
|
||||||
|
#include <Device/Adaptor.h>
|
||||||
|
|
||||||
|
#include <Endian/Endian.h>
|
||||||
|
#include <Endian/IOBuffer.h>
|
||||||
|
|
||||||
|
#include <Cache/MappedBlockCache.h>
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
using namespace LittleEndian;
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
/*
|
||||||
|
http://www.umich.edu/~archive/apple2/technotes/ftn/FTN.E0.8004
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char *IdentityCheck = "\x60VSTORE [Davex]\x00";
|
||||||
|
|
||||||
|
|
||||||
|
// private, validation already performed.
|
||||||
|
DavexDiskImage::DavexDiskImage(MappedFile *file) :
|
||||||
|
DiskImage(file)
|
||||||
|
{
|
||||||
|
// at this point, file is no longer valid.
|
||||||
|
|
||||||
|
|
||||||
|
// 512-bytes header
|
||||||
|
setBlocks((length() / 512) - 1);
|
||||||
|
setAdaptor(new POAdaptor(512 + (uint8_t *)address()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DavexDiskImage::~DavexDiskImage()
|
||||||
|
{
|
||||||
|
// scan and update usedBlocks?
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DavexDiskImage::Validate(MappedFile *f, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DavexDiskImage::Validate"
|
||||||
|
|
||||||
|
size_t size = f->length();
|
||||||
|
const void * data = f->address();
|
||||||
|
unsigned blocks = (size / 512) - 1;
|
||||||
|
|
||||||
|
|
||||||
|
if (size < 512) return false;
|
||||||
|
if (size % 512) return false;
|
||||||
|
|
||||||
|
// identity.
|
||||||
|
if (std::memcmp(data, IdentityCheck, 16))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// file format.
|
||||||
|
if (Read8(data, 0x10) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// total blocks
|
||||||
|
if (Read32(data, 33) != blocks)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// file number -- must be 1
|
||||||
|
if (Read8(data, 64) != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DavexDiskImage::Validate(MappedFile *f)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DavexDiskImage::Validate"
|
||||||
|
|
||||||
|
|
||||||
|
if (!Validate(f, std::nothrow))
|
||||||
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer DavexDiskImage::Open(MappedFile *file)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DavexDiskImage::Open"
|
||||||
|
Validate(file);
|
||||||
|
|
||||||
|
//return BlockDevicePointer(new DavexDiskImage(file));
|
||||||
|
|
||||||
|
return MAKE_SHARED(DavexDiskImage, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer DavexDiskImage::Create(const char *name, size_t blocks)
|
||||||
|
{
|
||||||
|
return Create(name, blocks, "Untitled");
|
||||||
|
}
|
||||||
|
BlockDevicePointer DavexDiskImage::Create(const char *name, size_t blocks, const char *vname)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DavexDiskImage::Create"
|
||||||
|
|
||||||
|
uint8_t *data;
|
||||||
|
uint8_t tmp[512];
|
||||||
|
IOBuffer header(tmp,512);
|
||||||
|
|
||||||
|
|
||||||
|
MappedFile *file = MappedFile::Create(name, blocks * 512 + 512);
|
||||||
|
|
||||||
|
data = (uint8_t *)file->address();
|
||||||
|
|
||||||
|
header.writeBytes(IdentityCheck, 16);
|
||||||
|
// file Format
|
||||||
|
header.write8(0);
|
||||||
|
//version
|
||||||
|
header.write8(0);
|
||||||
|
// version
|
||||||
|
header.write8(0x10);
|
||||||
|
|
||||||
|
// reserved.
|
||||||
|
header.setOffset(32, true);
|
||||||
|
|
||||||
|
//deviceNum
|
||||||
|
header.write8(1);
|
||||||
|
|
||||||
|
// total blocks
|
||||||
|
header.write32(blocks);
|
||||||
|
|
||||||
|
// unused blocks
|
||||||
|
header.write32(0);
|
||||||
|
|
||||||
|
// volume Name
|
||||||
|
if (!vname || !*vname) vname = "Untitled";
|
||||||
|
unsigned l = std::strlen(vname);
|
||||||
|
header.write8(std::min(l, 15u));
|
||||||
|
header.writeBytes(vname, std::min(l, 15u));
|
||||||
|
|
||||||
|
// name + reserved.
|
||||||
|
header.setOffset(64, true);
|
||||||
|
|
||||||
|
// file number
|
||||||
|
header.write8(1);
|
||||||
|
|
||||||
|
//starting block
|
||||||
|
header.write32(0);
|
||||||
|
|
||||||
|
// reserved
|
||||||
|
header.setOffset(512, true);
|
||||||
|
|
||||||
|
|
||||||
|
std::memcpy(file->address(), header.buffer(), 512);
|
||||||
|
file->sync();
|
||||||
|
|
||||||
|
//return BlockDevicePointer(new DavexDiskImage(file));
|
||||||
|
|
||||||
|
return MAKE_SHARED(DavexDiskImage, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockCachePointer DavexDiskImage::createBlockCache()
|
||||||
|
{
|
||||||
|
// need a smart pointer, but only have this....
|
||||||
|
return MappedBlockCache::Create(shared_from_this(), 512 + (uint8_t *)address());
|
||||||
|
|
||||||
|
}
|
||||||
43
Device/DavexDiskImage.h
Normal file
43
Device/DavexDiskImage.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef __DAVEXDISKIMAGE_H__
|
||||||
|
#define __DAVEXDISKIMAGE_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
#include <Device/DiskImage.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
// only supports 1 file; may be split over multiple files.
|
||||||
|
|
||||||
|
class DavexDiskImage : public DiskImage {
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~DavexDiskImage();
|
||||||
|
|
||||||
|
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||||
|
static BlockDevicePointer Create(const char *name, size_t blocks, const char *vname);
|
||||||
|
static BlockDevicePointer Open(MappedFile *);
|
||||||
|
|
||||||
|
virtual BlockCachePointer createBlockCache();
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
DavexDiskImage();
|
||||||
|
|
||||||
|
DavexDiskImage(MappedFile *);
|
||||||
|
|
||||||
|
|
||||||
|
bool _changed;
|
||||||
|
std::string _volumeName;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
24
Device/Device.h
Normal file
24
Device/Device.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Device.h
|
||||||
|
// profuse
|
||||||
|
//
|
||||||
|
// Created by Kelvin Sherlock on 2/19/2011.
|
||||||
|
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __DEVICE_DEVICE_H__
|
||||||
|
#define __DEVICE_DEVICE_H__
|
||||||
|
|
||||||
|
#include <ProFUSE/smart_pointers.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class BlockDevice;
|
||||||
|
class BlockCache;
|
||||||
|
|
||||||
|
typedef SHARED_PTR(BlockDevice) BlockDevicePointer;
|
||||||
|
typedef SHARED_PTR(BlockCache) BlockCachePointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
243
Device/DiskCopy42Image.cpp
Normal file
243
Device/DiskCopy42Image.cpp
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <Device/DiskCopy42Image.h>
|
||||||
|
|
||||||
|
#include <Endian/Endian.h>
|
||||||
|
#include <Endian/IOBuffer.h>
|
||||||
|
|
||||||
|
#include <Cache/MappedBlockCache.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
using namespace BigEndian;
|
||||||
|
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
oDataSize = 64,
|
||||||
|
oDataChecksum = 72,
|
||||||
|
oPrivate = 82,
|
||||||
|
oUserData = 84
|
||||||
|
};
|
||||||
|
|
||||||
|
DiskCopy42Image::DiskCopy42Image(MappedFile *f) :
|
||||||
|
DiskImage(f),
|
||||||
|
_changed(false)
|
||||||
|
{
|
||||||
|
setAdaptor(new POAdaptor(oUserData + (uint8_t *)address()));
|
||||||
|
setBlocks(Read32(address(), oDataSize) / 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DiskCopy42Image::~DiskCopy42Image()
|
||||||
|
{
|
||||||
|
if (_changed)
|
||||||
|
{
|
||||||
|
MappedFile *f = file();
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
void *data = f->address();
|
||||||
|
|
||||||
|
uint32_t cs = Checksum(oUserData + (uint8_t *)data, Read32(data, oDataSize));
|
||||||
|
|
||||||
|
Write32(data, oDataChecksum, cs);
|
||||||
|
f->sync();
|
||||||
|
}
|
||||||
|
// TODO -- checksum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DiskCopy42Image::Checksum(void *data, size_t size)
|
||||||
|
{
|
||||||
|
uint32_t rv = 0;
|
||||||
|
uint8_t *dp = (uint8_t *)data;
|
||||||
|
|
||||||
|
if (size & 0x01) return rv;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; i += 2)
|
||||||
|
{
|
||||||
|
rv += dp[i] << 8;
|
||||||
|
rv += dp[i+1];
|
||||||
|
|
||||||
|
rv = (rv >> 1) + (rv << 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer DiskCopy42Image::Open(MappedFile *f)
|
||||||
|
{
|
||||||
|
Validate(f);
|
||||||
|
//return BlockDevicePointer(new DiskCopy42Image(f));
|
||||||
|
|
||||||
|
return MAKE_SHARED(DiskCopy42Image, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t DiskFormat(size_t blocks)
|
||||||
|
{
|
||||||
|
switch (blocks)
|
||||||
|
{
|
||||||
|
case 800: return 0;
|
||||||
|
case 1600: return 1;
|
||||||
|
case 1440: return 2;
|
||||||
|
case 2880: return 3;
|
||||||
|
default: return 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t FormatByte(size_t blocks)
|
||||||
|
{
|
||||||
|
switch(blocks)
|
||||||
|
{
|
||||||
|
case 800: return 0x12;
|
||||||
|
default: return 0x22;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlockDevicePointer DiskCopy42Image::Create(const char *name, size_t blocks)
|
||||||
|
{
|
||||||
|
return Create(name, blocks, "Untitled");
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer DiskCopy42Image::Create(const char *name, size_t blocks, const char *vname)
|
||||||
|
{
|
||||||
|
MappedFile *file = MappedFile::Create(name, blocks * 512 + oUserData);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t tmp[oUserData];
|
||||||
|
IOBuffer header(tmp, oUserData);
|
||||||
|
|
||||||
|
// name -- 64byte pstring.
|
||||||
|
|
||||||
|
if (vname == NULL) vname = "Untitled";
|
||||||
|
unsigned l = std::strlen(vname);
|
||||||
|
header.write8(std::min(l, 63u));
|
||||||
|
header.writeBytes(vname, std::min(l, 63u));
|
||||||
|
|
||||||
|
//header.resize(64);
|
||||||
|
header.setOffset(oDataSize, true);
|
||||||
|
|
||||||
|
// data size -- number of bytes
|
||||||
|
header.write32(blocks * 512);
|
||||||
|
|
||||||
|
// tag size
|
||||||
|
header.write32(0);
|
||||||
|
|
||||||
|
// data checksum
|
||||||
|
// if data is 0, will be 0.
|
||||||
|
//header.push32be(Checksum(file->fileData(), blocks * 512));
|
||||||
|
header.write32(0);
|
||||||
|
|
||||||
|
// tag checksum
|
||||||
|
header.write32(0);
|
||||||
|
|
||||||
|
// disk format.
|
||||||
|
/*
|
||||||
|
* 0 = 400k
|
||||||
|
* 1 = 800k
|
||||||
|
* 2 = 720k
|
||||||
|
* 3 = 1440k
|
||||||
|
* 0xff = other
|
||||||
|
*/
|
||||||
|
header.write8(DiskFormat(blocks));
|
||||||
|
|
||||||
|
// formatbyte
|
||||||
|
/*
|
||||||
|
* 0x12 = 400k
|
||||||
|
* 0x22 = >400k mac
|
||||||
|
* 0x24 = 800k appleII
|
||||||
|
*/
|
||||||
|
header.write8(FormatByte(blocks));
|
||||||
|
|
||||||
|
// private
|
||||||
|
header.write16(0x100);
|
||||||
|
|
||||||
|
std::memcpy(file->address(), header.buffer(), oUserData);
|
||||||
|
file->sync();
|
||||||
|
|
||||||
|
//return BlockDevicePointer(new DiskCopy42Image(file));
|
||||||
|
|
||||||
|
return MAKE_SHARED(DiskCopy42Image, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DiskCopy42Image::Validate(MappedFile *file, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DiskCopy42Image::Validate"
|
||||||
|
|
||||||
|
|
||||||
|
size_t bytes = 0;
|
||||||
|
size_t size = file->length();
|
||||||
|
const void *data = file->address();
|
||||||
|
uint32_t checksum = 0;
|
||||||
|
|
||||||
|
if (size < oUserData)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// name must be < 64
|
||||||
|
if (Read8(data, 0) > 63)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Read16(data, oPrivate) != 0x100)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// bytes, not blocks.
|
||||||
|
bytes = Read32(data, oDataSize);
|
||||||
|
|
||||||
|
if (bytes % 512)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (size < oUserData + bytes)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// todo -- checksum.
|
||||||
|
checksum = Read32(data, oDataChecksum);
|
||||||
|
|
||||||
|
uint32_t cs = Checksum(oUserData + (uint8_t *)data, bytes);
|
||||||
|
|
||||||
|
if (cs != checksum)
|
||||||
|
{
|
||||||
|
fprintf(stderr, __METHOD__ ": Warning: checksum invalid.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DiskCopy42Image::Validate(MappedFile *file)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DiskCopy42Image::Validate"
|
||||||
|
|
||||||
|
|
||||||
|
if (!Validate(file, std::nothrow))
|
||||||
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiskCopy42Image::write(unsigned block, const void *bp)
|
||||||
|
{
|
||||||
|
DiskImage::write(block, bp);
|
||||||
|
_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockCachePointer DiskCopy42Image::createBlockCache()
|
||||||
|
{
|
||||||
|
// if not readonly, mark changed so crc will be updated at close.
|
||||||
|
|
||||||
|
if (!readOnly()) _changed = true;
|
||||||
|
|
||||||
|
return MappedBlockCache::Create(shared_from_this(), address());
|
||||||
|
}
|
||||||
42
Device/DiskCopy42Image.h
Normal file
42
Device/DiskCopy42Image.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef __DISKCOPY42IMAGE_H__
|
||||||
|
#define __DISKCOPY42IMAGE_H__
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
#include <Device/DiskImage.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class DiskCopy42Image : public DiskImage {
|
||||||
|
public:
|
||||||
|
virtual ~DiskCopy42Image();
|
||||||
|
|
||||||
|
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||||
|
static BlockDevicePointer Create(const char *name, size_t blocks, const char *vname);
|
||||||
|
|
||||||
|
static BlockDevicePointer Open(MappedFile *);
|
||||||
|
|
||||||
|
static uint32_t Checksum(void *data, size_t size);
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual void write(unsigned block, const void *bp);
|
||||||
|
|
||||||
|
|
||||||
|
virtual BlockCachePointer createBlockCache();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
DiskCopy42Image();
|
||||||
|
|
||||||
|
DiskCopy42Image(MappedFile *);
|
||||||
|
bool _changed;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
228
Device/DiskImage.cpp
Normal file
228
Device/DiskImage.cpp
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <Device/DiskImage.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <File/MappedFile.h>
|
||||||
|
|
||||||
|
#include <Cache/MappedBlockCache.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
DiskImage::DiskImage(const char *name, bool readOnly)
|
||||||
|
{
|
||||||
|
File fd(name, readOnly ? O_RDONLY : O_RDWR);
|
||||||
|
MappedFile mf(fd, readOnly);
|
||||||
|
_file.adopt(mf);
|
||||||
|
|
||||||
|
_blocks = 0;
|
||||||
|
_readOnly = readOnly;
|
||||||
|
_adaptor = NULL;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
DiskImage::DiskImage(MappedFile *file)
|
||||||
|
{
|
||||||
|
_file.adopt(*file);
|
||||||
|
|
||||||
|
_blocks = 0;
|
||||||
|
_readOnly = _file.readOnly();
|
||||||
|
_adaptor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DiskImage::~DiskImage()
|
||||||
|
{
|
||||||
|
delete _adaptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DiskImage::readOnly()
|
||||||
|
{
|
||||||
|
return _readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned DiskImage::blocks()
|
||||||
|
{
|
||||||
|
return _blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiskImage::setAdaptor(Adaptor *adaptor)
|
||||||
|
{
|
||||||
|
delete _adaptor;
|
||||||
|
_adaptor = adaptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiskImage::read(unsigned block, void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DiskImage::read"
|
||||||
|
|
||||||
|
if (block >= _blocks)
|
||||||
|
throw Exception(__METHOD__ ": Invalid block.");
|
||||||
|
|
||||||
|
_adaptor->readBlock(block, bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiskImage::write(unsigned block, const void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DiskImage::write"
|
||||||
|
|
||||||
|
if (block >= _blocks)
|
||||||
|
throw Exception(__METHOD__ ": Invalid block.");
|
||||||
|
|
||||||
|
_adaptor->writeBlock(block, bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiskImage::sync()
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DiskImage::sync"
|
||||||
|
|
||||||
|
if (_file.isValid()) return _file.sync();
|
||||||
|
|
||||||
|
throw Exception(__METHOD__ ": File not set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ProDOSOrderDiskImage::ProDOSOrderDiskImage(MappedFile *file) :
|
||||||
|
DiskImage(file)
|
||||||
|
{
|
||||||
|
// at this point, file is no longer valid.
|
||||||
|
|
||||||
|
setBlocks(length() / 512);
|
||||||
|
setAdaptor(new POAdaptor(address()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer ProDOSOrderDiskImage::Create(const char *name, size_t blocks)
|
||||||
|
{
|
||||||
|
MappedFile *file = MappedFile::Create(name, blocks * 512);
|
||||||
|
//return BlockDevicePointer(new ProDOSOrderDiskImage(file));
|
||||||
|
return MAKE_SHARED(ProDOSOrderDiskImage, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer ProDOSOrderDiskImage::Open(MappedFile *file)
|
||||||
|
{
|
||||||
|
Validate(file);
|
||||||
|
//return BlockDevicePointer(new ProDOSOrderDiskImage(file));
|
||||||
|
return MAKE_SHARED(ProDOSOrderDiskImage, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ProDOSOrderDiskImage::Validate(MappedFile *f, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "ProDOSOrderDiskImage::Validate"
|
||||||
|
|
||||||
|
|
||||||
|
size_t size = f->length();
|
||||||
|
|
||||||
|
if (size % 512)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProDOSOrderDiskImage::Validate(MappedFile *f)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "ProDOSOrderDiskImage::Validate"
|
||||||
|
|
||||||
|
if (!f || !f->isValid()) throw Exception(__METHOD__ ": File not set.");
|
||||||
|
|
||||||
|
if (!Validate(f, std::nothrow))
|
||||||
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockCachePointer ProDOSOrderDiskImage::createBlockCache()
|
||||||
|
{
|
||||||
|
return MappedBlockCache::Create(shared_from_this(), address());
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark DOS Order Disk Image
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
DOSOrderDiskImage::DOSOrderDiskImage(const char *name, bool readOnly) :
|
||||||
|
DiskImage(name, readOnly)
|
||||||
|
{
|
||||||
|
Validate(file());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DOSOrderDiskImage::DOSOrderDiskImage(MappedFile *file) :
|
||||||
|
DiskImage(file)
|
||||||
|
{
|
||||||
|
// at this point, file is no longer valid.
|
||||||
|
|
||||||
|
setBlocks(length() / 512);
|
||||||
|
setAdaptor(new DOAdaptor(address()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockDevicePointer DOSOrderDiskImage::Create(const char *name, size_t blocks)
|
||||||
|
{
|
||||||
|
MappedFile *file = MappedFile::Create(name, blocks * 512);
|
||||||
|
//return BlockDevicePointer(new DOSOrderDiskImage(file));
|
||||||
|
return MAKE_SHARED(DOSOrderDiskImage, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer DOSOrderDiskImage::Open(MappedFile *file)
|
||||||
|
{
|
||||||
|
Validate(file);
|
||||||
|
//return BlockDevicePointer(new DOSOrderDiskImage(file));
|
||||||
|
return MAKE_SHARED(DOSOrderDiskImage, file);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DOSOrderDiskImage::Validate(MappedFile *f, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DOSOrderDiskImage::Validate"
|
||||||
|
|
||||||
|
size_t size = f->length();
|
||||||
|
|
||||||
|
if (size % 512)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DOSOrderDiskImage::Validate(MappedFile *f)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DOSOrderDiskImage::Validate"
|
||||||
|
|
||||||
|
if (!f || !f->isValid()) throw Exception(__METHOD__ ": File not set.");
|
||||||
|
|
||||||
|
|
||||||
|
if (!Validate(f, std::nothrow))
|
||||||
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
97
Device/DiskImage.h
Normal file
97
Device/DiskImage.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#ifndef __DISKIMAGE_H__
|
||||||
|
#define __DISKIMAGE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
|
||||||
|
#include <Device/Adaptor.h>
|
||||||
|
|
||||||
|
#include <File/MappedFile.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
|
||||||
|
class DiskImage : public BlockDevice {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
virtual ~DiskImage();
|
||||||
|
|
||||||
|
virtual void read(unsigned block, void *bp);
|
||||||
|
virtual void write(unsigned block, const void *bp);
|
||||||
|
virtual void sync();
|
||||||
|
|
||||||
|
virtual bool readOnly();
|
||||||
|
virtual unsigned blocks();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
DiskImage();
|
||||||
|
|
||||||
|
DiskImage(MappedFile *file = 0);
|
||||||
|
|
||||||
|
void setBlocks(unsigned blocks) { _blocks = blocks; }
|
||||||
|
|
||||||
|
void setAdaptor(Adaptor *);
|
||||||
|
|
||||||
|
void *address() const { return _file.address(); }
|
||||||
|
size_t length() const { return _file.length(); }
|
||||||
|
|
||||||
|
MappedFile *file() { return &_file; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MappedFile _file;
|
||||||
|
Adaptor *_adaptor;
|
||||||
|
|
||||||
|
bool _readOnly;
|
||||||
|
unsigned _blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ProDOSOrderDiskImage : public DiskImage {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||||
|
static BlockDevicePointer Open(MappedFile *);
|
||||||
|
|
||||||
|
|
||||||
|
virtual BlockCachePointer createBlockCache();
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProDOSOrderDiskImage();
|
||||||
|
|
||||||
|
ProDOSOrderDiskImage(MappedFile *);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DOSOrderDiskImage : public DiskImage {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||||
|
static BlockDevicePointer Open(MappedFile *);
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DOSOrderDiskImage();
|
||||||
|
|
||||||
|
DOSOrderDiskImage(MappedFile *);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
321
Device/RawDevice.cpp
Normal file
321
Device/RawDevice.cpp
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <sys/disk.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __SUN__
|
||||||
|
#include <sys/dkio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __FREEBSD__
|
||||||
|
#include <sys/disk.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __minix
|
||||||
|
#include <minix/partition.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Device/RawDevice.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
#ifdef __SUN__
|
||||||
|
void RawDevice::devSize(int fd)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::devSize"
|
||||||
|
|
||||||
|
struct dk_minfo minfo;
|
||||||
|
|
||||||
|
if (::ioctl(fd, DKIOCGMEDIAINFO, &minfo) < 0)
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to determine device size.", errno);
|
||||||
|
|
||||||
|
_size = minfo.dki_lbsize * minfo.dki_capacity;
|
||||||
|
_blockSize = 512; // not really, but whatever.
|
||||||
|
_blocks = _size / 512;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
void RawDevice::devSize(int fd)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::devSize"
|
||||||
|
|
||||||
|
uint32_t blockSize; // 32 bit
|
||||||
|
uint64_t blockCount; // 64 bit
|
||||||
|
|
||||||
|
if (::ioctl(fd, DKIOCGETBLOCKSIZE, &blockSize) < 0)
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to determine block size.", errno);
|
||||||
|
|
||||||
|
|
||||||
|
if (::ioctl(fd, DKIOCGETBLOCKCOUNT, &blockCount) < 0)
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to determine block count.", errno);
|
||||||
|
|
||||||
|
_blockSize = blockSize;
|
||||||
|
_size = _blockSize * blockCount;
|
||||||
|
_blocks = _size / 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
void RawDevice::devSize(int fd)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::devSize"
|
||||||
|
|
||||||
|
int blocks;
|
||||||
|
|
||||||
|
if (::ioctl(fd, BLKGETSIZE, &blocks) < 0)
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to determine device size.", errno);
|
||||||
|
|
||||||
|
_size = 512 * blocks;
|
||||||
|
_blockSize = 512; //
|
||||||
|
_blocks = blocks;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO -- FreeBSD/NetBSD/OpenBSD
|
||||||
|
|
||||||
|
#ifdef __FREEBSD__
|
||||||
|
|
||||||
|
void RawDevice::devSize(int fd)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::devSize"
|
||||||
|
|
||||||
|
unsigned blockSize;
|
||||||
|
off_t mediaSize;
|
||||||
|
|
||||||
|
if (::ioctl(fd, DIOCGSECTORSIZE, &blockSize)
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to determine block size.", errno);
|
||||||
|
|
||||||
|
if (::ioctl(fd, DIOCGMEDIASIZE, &mediaSize)
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to determine media size.", errno);
|
||||||
|
|
||||||
|
_blockSize = blockSize;
|
||||||
|
_size = mediaSize;
|
||||||
|
_blocks = mediaSize / 512;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __minix
|
||||||
|
|
||||||
|
void RawDevice::devSize(int fd)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::devSize"
|
||||||
|
|
||||||
|
struct partition entry;
|
||||||
|
|
||||||
|
|
||||||
|
if (::ioctl(fd, DIOCGETP, &entry) < 0)
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to determine device size.", errno);
|
||||||
|
|
||||||
|
_size = entry.size
|
||||||
|
_blockSize = 512; // not really but whatever.
|
||||||
|
_blocks = _size / 512;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RawDevice::RawDevice(const char *name, File::FileFlags flags) :
|
||||||
|
_file(name, flags)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::RawDevice"
|
||||||
|
|
||||||
|
|
||||||
|
if (!_file.isValid())
|
||||||
|
{
|
||||||
|
throw Exception(__METHOD__ ": Invalid file handle.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_readOnly = flags == File::ReadOnly;
|
||||||
|
_size = 0;
|
||||||
|
_blocks = 0;
|
||||||
|
_blockSize = 0;
|
||||||
|
|
||||||
|
|
||||||
|
devSize(_file.fd());
|
||||||
|
}
|
||||||
|
|
||||||
|
RawDevice::RawDevice(File& file, File::FileFlags flags) :
|
||||||
|
_file(file)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::RawDevice"
|
||||||
|
|
||||||
|
|
||||||
|
if (!_file.isValid())
|
||||||
|
{
|
||||||
|
throw Exception(__METHOD__ ": Invalid file handle.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_readOnly = flags == File::ReadOnly;
|
||||||
|
_size = 0;
|
||||||
|
_blocks = 0;
|
||||||
|
_blockSize = 0;
|
||||||
|
|
||||||
|
|
||||||
|
devSize(_file.fd());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RawDevice::~RawDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockDevicePointer RawDevice::Open(const char *name, File::FileFlags flags)
|
||||||
|
{
|
||||||
|
//return BlockDevicePointer(new RawDevice(name, flags));
|
||||||
|
return MAKE_SHARED(RawDevice, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RawDevice::read(unsigned block, void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::read"
|
||||||
|
|
||||||
|
if (block >= _blocks) throw Exception(__METHOD__ ": Invalid block number.");
|
||||||
|
if (bp == 0) throw Exception(__METHOD__ ": Invalid address.");
|
||||||
|
|
||||||
|
// sun -- use pread
|
||||||
|
// apple - read full native block(s) ?
|
||||||
|
|
||||||
|
off_t offset = block * 512;
|
||||||
|
ssize_t ok = ::pread(_file.fd(), bp, 512, offset);
|
||||||
|
|
||||||
|
// TODO -- EINTR?
|
||||||
|
if (ok != 512)
|
||||||
|
throw ok < 0
|
||||||
|
? POSIXException(__METHOD__ ": Error reading block.", errno)
|
||||||
|
: Exception(__METHOD__ ": Error reading block.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RawDevice::read(TrackSector ts, void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::read"
|
||||||
|
|
||||||
|
unsigned block = ts.track * 8 + ts.sector / 2;
|
||||||
|
if (block >= _blocks) throw Exception(__METHOD__ ": Invalid block number.");
|
||||||
|
if (bp == 0) throw Exception(__METHOD__ ": Invalid address.");
|
||||||
|
|
||||||
|
// sun -- use pread
|
||||||
|
// apple - read full native block(s) ?
|
||||||
|
|
||||||
|
off_t offset = (ts.track * 16 + ts.sector) * 256;
|
||||||
|
ssize_t ok = ::pread(_file.fd(), bp, 256, offset);
|
||||||
|
|
||||||
|
// TODO -- EINTR?
|
||||||
|
if (ok != 256)
|
||||||
|
throw ok < 0
|
||||||
|
? POSIXException(__METHOD__ ": Error reading block.", errno)
|
||||||
|
: Exception(__METHOD__ ": Error reading block.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RawDevice::write(unsigned block, const void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::write"
|
||||||
|
|
||||||
|
if (block > _blocks) throw Exception(__METHOD__ ": Invalid block number.");
|
||||||
|
|
||||||
|
if (_readOnly)
|
||||||
|
throw Exception(__METHOD__ ": File is readonly.");
|
||||||
|
|
||||||
|
|
||||||
|
off_t offset = block * 512;
|
||||||
|
ssize_t ok = ::pwrite(_file.fd(), bp, 512, offset);
|
||||||
|
|
||||||
|
if (ok != 512)
|
||||||
|
throw ok < 0
|
||||||
|
? POSIXException(__METHOD__ ": Error writing block.", errno)
|
||||||
|
: Exception(__METHOD__ ": Error writing block.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RawDevice::write(TrackSector ts, const void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::write"
|
||||||
|
|
||||||
|
unsigned block = ts.track * 8 + ts.sector / 2;
|
||||||
|
if (block > _blocks) throw Exception(__METHOD__ ": Invalid block number.");
|
||||||
|
|
||||||
|
if (_readOnly)
|
||||||
|
throw Exception(__METHOD__ ": File is readonly.");
|
||||||
|
|
||||||
|
|
||||||
|
off_t offset = (ts.track * 16 + ts.sector) * 256;
|
||||||
|
ssize_t ok = ::pwrite(_file.fd(), bp, 256, offset);
|
||||||
|
|
||||||
|
if (ok != 256)
|
||||||
|
throw ok < 0
|
||||||
|
? POSIXException(__METHOD__ ": Error writing block.", errno)
|
||||||
|
: Exception(__METHOD__ ": Error writing block.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RawDevice::readOnly()
|
||||||
|
{
|
||||||
|
return _readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RawDevice::mapped()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned RawDevice::blocks()
|
||||||
|
{
|
||||||
|
return _blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RawDevice::sync()
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "RawDevice::sync"
|
||||||
|
|
||||||
|
if (_readOnly) return;
|
||||||
|
|
||||||
|
if (::fsync(_file.fd()) < 0)
|
||||||
|
throw POSIXException(__METHOD__ ": fsync error.", errno);
|
||||||
|
}
|
||||||
|
|
||||||
57
Device/RawDevice.h
Normal file
57
Device/RawDevice.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#ifndef __RAWDEVICE_H__
|
||||||
|
#define __RAWDEVICE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
|
||||||
|
#include <File/File.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
// /dev/xxx
|
||||||
|
|
||||||
|
|
||||||
|
class RawDevice : public BlockDevice {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static BlockDevicePointer Open(const char *name, File::FileFlags flags);
|
||||||
|
|
||||||
|
|
||||||
|
virtual ~RawDevice();
|
||||||
|
|
||||||
|
virtual void read(unsigned block, void *bp);
|
||||||
|
virtual void read(TrackSector ts, void *bp);
|
||||||
|
|
||||||
|
virtual void write(unsigned block, const void *bp);
|
||||||
|
virtual void write(TrackSector ts, const void *bp);
|
||||||
|
|
||||||
|
virtual bool readOnly();
|
||||||
|
virtual bool mapped();
|
||||||
|
virtual void sync();
|
||||||
|
|
||||||
|
virtual unsigned blocks();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
RawDevice(const char *name, File::FileFlags flags);
|
||||||
|
|
||||||
|
RawDevice(File& file, File::FileFlags flags);
|
||||||
|
|
||||||
|
void devSize(int fd);
|
||||||
|
|
||||||
|
File _file;
|
||||||
|
bool _readOnly;
|
||||||
|
|
||||||
|
uint64_t _size; // size of device in bytes.
|
||||||
|
unsigned _blocks; // # of 512k blocks i.e. _size / 512
|
||||||
|
|
||||||
|
unsigned _blockSize; // native block size.
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
249
Device/SDKImage.cpp
Normal file
249
Device/SDKImage.cpp
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
//
|
||||||
|
// SDKImage.cpp
|
||||||
|
// profuse
|
||||||
|
//
|
||||||
|
// Created by Kelvin Sherlock on 3/6/2011.
|
||||||
|
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SDKImage.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#include <NufxLib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <File/File.h>
|
||||||
|
#include <File/MappedFile.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
class NuFXException : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NuFXException(const char *cp, NuError error);
|
||||||
|
NuFXException(const std::string& string, NuError error);
|
||||||
|
|
||||||
|
virtual const char *errorString();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline NuFXException::NuFXException(const char *cp, NuError error) :
|
||||||
|
Exception(cp, error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NuFXException::NuFXException(const std::string& string, NuError error) :
|
||||||
|
Exception(string, error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *NuFXException::errorString()
|
||||||
|
{
|
||||||
|
return ::NuStrError((NuError)error());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
struct record_thread
|
||||||
|
{
|
||||||
|
NuRecordIdx record_index;
|
||||||
|
NuThreadIdx thread_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static record_thread FindDiskImageThread(NuArchive *archive)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "SDKImage::FindThread"
|
||||||
|
|
||||||
|
record_thread rt;
|
||||||
|
NuError e;
|
||||||
|
NuAttr recordCount;
|
||||||
|
|
||||||
|
e = NuGetAttr(archive, kNuAttrNumRecords, &recordCount);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuGetAttr", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned position = 0; position < recordCount; ++position)
|
||||||
|
{
|
||||||
|
NuRecordIdx rIndex;
|
||||||
|
const NuRecord *record;
|
||||||
|
|
||||||
|
e = NuGetRecordIdxByPosition(archive, position, &rIndex);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuGetRecordIdxByPosition", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
e = NuGetRecord(archive, rIndex, &record);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuGetRecord", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < NuRecordGetNumThreads(record); ++i)
|
||||||
|
{
|
||||||
|
const NuThread *thread = NuGetThread(record, i);
|
||||||
|
|
||||||
|
if (NuGetThreadID(thread) == kNuThreadIDDiskImage)
|
||||||
|
{
|
||||||
|
rt.thread_index = thread->threadIdx;
|
||||||
|
rt.record_index = record->recordIdx;
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(__METHOD__ ": not a disk image");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper function to extract SDK image to /tmp and return a
|
||||||
|
* ProDOSDiskImage of the /tmp file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
BlockDevicePointer SDKImage::Open(const char *name)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "SDKImage::Open"
|
||||||
|
|
||||||
|
|
||||||
|
char tmp[] = "/tmp/pfuse.XXXXXXXX";
|
||||||
|
|
||||||
|
int fd = -1;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
NuArchive *archive = NULL;
|
||||||
|
//const NuThread *thread = NULL;
|
||||||
|
//const NuRecord *record = NULL;
|
||||||
|
NuDataSink *sink = NULL;
|
||||||
|
//NuRecordIdx rIndex;
|
||||||
|
//NuThreadIdx tIndex;
|
||||||
|
|
||||||
|
NuError e;
|
||||||
|
|
||||||
|
|
||||||
|
record_thread rt = {0, 0};
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
|
||||||
|
e = NuOpenRO(name, &archive);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuOpenRO", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt = FindDiskImageThread(archive);
|
||||||
|
|
||||||
|
fd = mkstemp(tmp);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
throw POSIXException(__METHOD__ ": mkstemp", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fdopen(fd, "w");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
::close(fd);
|
||||||
|
throw POSIXException(__METHOD__ ": fdopen", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
e = NuCreateDataSinkForFP(true, kNuConvertOff, fp, &sink);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuCreateDataSinkForFP", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
e = NuExtractThread(archive, rt.thread_index, sink);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuExtractThread", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Extracted disk image to %s\n", tmp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
NuClose(archive);
|
||||||
|
NuFreeDataSink(sink);
|
||||||
|
fp = NULL;
|
||||||
|
archive = NULL;
|
||||||
|
sink = NULL;
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
if (fp) fclose(fp);
|
||||||
|
if (archive) NuClose(archive);
|
||||||
|
if (sink) NuFreeDataSink(sink);
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo -- maybe SDKImage should extend ProDOSOrderDiskImage, have destructor
|
||||||
|
// that unklinks the temp file.
|
||||||
|
|
||||||
|
MappedFile file(tmp, File::ReadOnly);
|
||||||
|
|
||||||
|
return ProDOSOrderDiskImage::Open(&file);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool SDKImage::Validate(MappedFile * f, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
|
||||||
|
// NuFile, alternating ASCII.
|
||||||
|
static const char IdentityCheck[6] = { 0x4E, 0xF5, 0x46, 0xE9, 0x6C, 0xE5 };
|
||||||
|
static const char BXYIdentityCheck[3] = { 0x0A, 0x47, 0x4C };
|
||||||
|
|
||||||
|
uint8_t *address = (uint8_t *)f->address();
|
||||||
|
size_t length = f->length();
|
||||||
|
|
||||||
|
// check for a BXY header
|
||||||
|
if (length >= 128
|
||||||
|
&& std::memcmp(address, BXYIdentityCheck, sizeof(BXYIdentityCheck)) == 0)
|
||||||
|
{
|
||||||
|
length -= 128;
|
||||||
|
address += 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (length > sizeof(IdentityCheck)
|
||||||
|
&& std::memcmp(address, IdentityCheck, sizeof(IdentityCheck)) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDKImage::Validate(MappedFile * f)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "SDKImage::Validate"
|
||||||
|
|
||||||
|
if (!Validate(f, std::nothrow))
|
||||||
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
30
Device/SDKImage.h
Normal file
30
Device/SDKImage.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// SDKImage.h
|
||||||
|
// profuse
|
||||||
|
//
|
||||||
|
// Created by Kelvin Sherlock on 3/6/2011.
|
||||||
|
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
#include <Device/DiskImage.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class SDKImage : public DiskImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static BlockDevicePointer Open(const char *name);
|
||||||
|
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDKImage();
|
||||||
|
SDKImage(const SDKImage &);
|
||||||
|
~SDKImage();
|
||||||
|
SDKImage & operator=(const SDKImage &);
|
||||||
|
};
|
||||||
|
}
|
||||||
19
Device/TrackSector.h
Normal file
19
Device/TrackSector.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef __TRACKSECTOR_H__
|
||||||
|
#define __TRACKSECTOR_H__
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
struct TrackSector {
|
||||||
|
TrackSector(unsigned, unsigned);
|
||||||
|
unsigned track;
|
||||||
|
unsigned sector;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline TrackSector::TrackSector(unsigned t, unsigned s)
|
||||||
|
{
|
||||||
|
track = t;
|
||||||
|
sector = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
163
Device/UniversalDiskImage.cpp
Normal file
163
Device/UniversalDiskImage.cpp
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
#include <Device/UniversalDiskImage.h>
|
||||||
|
|
||||||
|
#include <Endian/Endian.h>
|
||||||
|
#include <Endian/IOBuffer.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
#include <Cache/MappedBlockCache.h>
|
||||||
|
#include <Cache/ConcreteBlockCache.h>
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
using namespace LittleEndian;
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UniversalDiskImage::UniversalDiskImage(MappedFile *file) :
|
||||||
|
DiskImage(file)
|
||||||
|
{
|
||||||
|
|
||||||
|
// at this point, file is no longer valid.
|
||||||
|
|
||||||
|
uint8_t * data = (uint8_t *)address();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_format = Read32(data, 0x0c);
|
||||||
|
_flags = Read32(data, 0x10);
|
||||||
|
_blocks = Read32(data, 0x14);
|
||||||
|
|
||||||
|
_dataOffset = Read32(data, 0x18);
|
||||||
|
_dataLength = Read32(data, 0x1c);
|
||||||
|
|
||||||
|
|
||||||
|
setBlocks(_blocks);
|
||||||
|
// TODO -- DO, Nibble support.
|
||||||
|
setAdaptor(new POAdaptor(_dataOffset + data));
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer UniversalDiskImage::Create(const char *name, size_t blocks)
|
||||||
|
{
|
||||||
|
// 64-byte header.
|
||||||
|
MappedFile *file = MappedFile::Create(name, blocks * 512 + 64);
|
||||||
|
|
||||||
|
uint8_t tmp[64];
|
||||||
|
|
||||||
|
IOBuffer header(tmp, 64);
|
||||||
|
|
||||||
|
|
||||||
|
// magic + creator
|
||||||
|
header.writeBytes("2IMGPRFS", 8);
|
||||||
|
|
||||||
|
// header size.
|
||||||
|
header.write16(64);
|
||||||
|
|
||||||
|
// version
|
||||||
|
header.write16(1);
|
||||||
|
|
||||||
|
//image format -- ProDOS order
|
||||||
|
header.write32(1);
|
||||||
|
|
||||||
|
// flags
|
||||||
|
header.write32(0);
|
||||||
|
|
||||||
|
// # blocks. s/b 0 unless prodos-order
|
||||||
|
header.write32(blocks);
|
||||||
|
|
||||||
|
// offset to disk data
|
||||||
|
header.write32(64);
|
||||||
|
|
||||||
|
// data length
|
||||||
|
header.write32(512 * blocks);
|
||||||
|
|
||||||
|
// comment offset, creator, reserved -- 0.
|
||||||
|
header.setOffset(64, true);
|
||||||
|
|
||||||
|
std::memcpy(file->address(), header.buffer(), 64);
|
||||||
|
|
||||||
|
|
||||||
|
//return BlockDevicePointer(new UniversalDiskImage(file));
|
||||||
|
|
||||||
|
return MAKE_SHARED(UniversalDiskImage, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDevicePointer UniversalDiskImage::Open(MappedFile *file)
|
||||||
|
{
|
||||||
|
Validate(file);
|
||||||
|
|
||||||
|
//return BlockDevicePointer(new UniversalDiskImage(file));
|
||||||
|
return MAKE_SHARED(UniversalDiskImage, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO -- support dos-order & nibblized
|
||||||
|
* TODO -- honor read-only flag.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool UniversalDiskImage::Validate(MappedFile *file, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "UniversalDiskImage::Validate"
|
||||||
|
|
||||||
|
const void *data = file->address();
|
||||||
|
size_t size = file->length();
|
||||||
|
|
||||||
|
unsigned blocks = 0;
|
||||||
|
unsigned offset = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (size < 64) return false;
|
||||||
|
|
||||||
|
if (std::memcmp(data, "2IMG", 4)) return false;
|
||||||
|
|
||||||
|
// only prodos supported, for now...
|
||||||
|
// TODO -- Dos Order, Nibble support.
|
||||||
|
if (Read32(data, 0x0c) != 1) return false;
|
||||||
|
|
||||||
|
blocks = Read32(data, 0x14);
|
||||||
|
offset = Read32(data, 0x18);
|
||||||
|
|
||||||
|
// file size == blocks * 512
|
||||||
|
if (Read32(data, 0x1c) != blocks * 512) return false;
|
||||||
|
|
||||||
|
if (offset + blocks * 512 > size) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UniversalDiskImage::Validate(MappedFile *file)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "UniversalDiskImage::Validate"
|
||||||
|
|
||||||
|
if (!Validate(file, std::nothrow))
|
||||||
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool UniversalDiskImage::readOnly()
|
||||||
|
{
|
||||||
|
return (_flags & 0x8000000) || DiskImage::readOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockCachePointer UniversalDiskImage::createBlockCache()
|
||||||
|
{
|
||||||
|
if (_format == 1)
|
||||||
|
{
|
||||||
|
return MappedBlockCache::Create(shared_from_this(), _dataOffset + (uint8_t *)address());
|
||||||
|
}
|
||||||
|
|
||||||
|
return DiskImage::createBlockCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
44
Device/UniversalDiskImage.h
Normal file
44
Device/UniversalDiskImage.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef __UNIVERSALDISKIMAGE_H__
|
||||||
|
#define __UNIVERSALDISKIMAGE_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
#include <Device/DiskImage.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class UniversalDiskImage : public DiskImage {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||||
|
static BlockDevicePointer Open(MappedFile *);
|
||||||
|
|
||||||
|
virtual bool readOnly();
|
||||||
|
|
||||||
|
virtual BlockCachePointer createBlockCache();
|
||||||
|
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
UniversalDiskImage();
|
||||||
|
|
||||||
|
UniversalDiskImage(MappedFile *);
|
||||||
|
|
||||||
|
uint32_t _format;
|
||||||
|
uint32_t _flags;
|
||||||
|
uint32_t _blocks;
|
||||||
|
uint32_t _dataOffset;
|
||||||
|
uint32_t _dataLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
166
Disk.cpp
166
Disk.cpp
@@ -7,8 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Disk.h"
|
#include "Disk.h"
|
||||||
#include "DiskCopy42.h"
|
|
||||||
#include "UniversalDiskImage.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
@@ -24,6 +23,8 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Endian/Endian.h>
|
||||||
|
|
||||||
struct ucmp
|
struct ucmp
|
||||||
{
|
{
|
||||||
bool operator()(unsigned a, unsigned b) const
|
bool operator()(unsigned a, unsigned b) const
|
||||||
@@ -35,127 +36,32 @@ struct ucmp
|
|||||||
using std::set;
|
using std::set;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
|
using namespace LittleEndian;
|
||||||
|
|
||||||
typedef set<unsigned, ucmp> uset;
|
typedef set<unsigned, ucmp> uset;
|
||||||
|
|
||||||
Disk::Disk()
|
Disk::Disk()
|
||||||
{
|
{
|
||||||
_data = (uint8_t *)-1;
|
|
||||||
_blocks = 0;
|
_blocks = 0;
|
||||||
_offset = 0;
|
|
||||||
_size = 0;
|
|
||||||
_flags = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Disk::~Disk()
|
Disk::~Disk()
|
||||||
{
|
{
|
||||||
if (_data != (uint8_t *)-1)
|
|
||||||
munmap(_data, _size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Disk::Disk(Device::BlockDevicePointer device) :
|
||||||
Disk *Disk::OpenFile(const char *file, unsigned flags)
|
_device(device)
|
||||||
{
|
{
|
||||||
int fd;
|
_blocks = _device->blocks();
|
||||||
struct stat st;
|
|
||||||
size_t size;
|
|
||||||
unsigned blocks;
|
|
||||||
|
|
||||||
unsigned offset;
|
|
||||||
|
|
||||||
|
|
||||||
void *map;
|
|
||||||
Disk *d = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fd = open(file, O_RDONLY);
|
|
||||||
if (fd >= 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (fstat(fd, &st) == 0)
|
|
||||||
{
|
|
||||||
size = st.st_size;
|
|
||||||
|
|
||||||
// raw disk images must be a blocksize multiple and <= 32 Meg.
|
|
||||||
|
|
||||||
if ( (size & 0x1ff) == 0
|
|
||||||
&& size > 0
|
|
||||||
&& size <= 32 * 1024 * 1024
|
|
||||||
)
|
|
||||||
{
|
|
||||||
blocks = size >> 9;
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// check for disk copy4.2 / universal disk image.
|
|
||||||
uint8_t buffer[1024];
|
|
||||||
|
|
||||||
if (read(fd, buffer, 1024) != 1024)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok = false;
|
|
||||||
do {
|
|
||||||
|
|
||||||
DiskCopy42 dc;
|
|
||||||
|
|
||||||
if (dc.Load(buffer)
|
|
||||||
&& size == 84 + dc.data_size + dc.tag_size
|
|
||||||
&& (dc.data_size & 0x1ff) == 0)
|
|
||||||
{
|
|
||||||
offset = 84;
|
|
||||||
blocks = dc.data_size >> 9;
|
|
||||||
ok = true;
|
|
||||||
flags |= P8_DC42;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniversalDiskImage udi;
|
|
||||||
|
|
||||||
if (udi.Load(buffer)
|
|
||||||
//&& udi.version == 1
|
|
||||||
&& udi.image_format == UDI_FORMAT_PRODOS_ORDER)
|
|
||||||
{
|
|
||||||
|
|
||||||
blocks = udi.data_blocks;
|
|
||||||
offset = udi.data_offset;
|
|
||||||
ok = true;
|
|
||||||
flags |= P8_2MG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (false);
|
|
||||||
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
map = mmap(NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
|
|
||||||
if (map != (void *)-1)
|
|
||||||
{
|
|
||||||
d = new Disk();
|
|
||||||
d->_size = size;
|
|
||||||
d->_data = (uint8_t *)map;
|
|
||||||
d->_blocks = blocks;
|
|
||||||
d->_offset = offset;
|
|
||||||
d->_flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiskPointer Disk::OpenFile(Device::BlockDevicePointer device)
|
||||||
|
{
|
||||||
|
DiskPointer disk(new Disk(device));
|
||||||
|
|
||||||
|
return disk;
|
||||||
|
}
|
||||||
|
|
||||||
// load the mini entry into the regular entry.
|
// load the mini entry into the regular entry.
|
||||||
int Disk::Normalize(FileEntry &f, unsigned fork, ExtendedEntry *ee)
|
int Disk::Normalize(FileEntry &f, unsigned fork, ExtendedEntry *ee)
|
||||||
@@ -200,31 +106,11 @@ int Disk::Normalize(FileEntry &f, unsigned fork, ExtendedEntry *ee)
|
|||||||
|
|
||||||
int Disk::Read(unsigned block, void *buffer)
|
int Disk::Read(unsigned block, void *buffer)
|
||||||
{
|
{
|
||||||
if (block > _blocks) return -P8_INVALID_BLOCK;
|
|
||||||
|
|
||||||
|
|
||||||
if (_flags & P8_DOS_ORDER)
|
|
||||||
{
|
|
||||||
static unsigned do_map[] = {0x00, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x0f };
|
|
||||||
|
|
||||||
unsigned track = (block & ~0x07) << 9;
|
|
||||||
unsigned sector = (block & 0x07) << 1;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
unsigned offset = track | (do_map[sector+i] << 8);
|
|
||||||
|
|
||||||
memcpy(buffer, _data + _offset + offset, 256);
|
|
||||||
|
|
||||||
buffer = (char *)buffer + 256;
|
|
||||||
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
if (block > _blocks) return -P8_INVALID_BLOCK;
|
||||||
|
|
||||||
|
_device->read(block, buffer);
|
||||||
|
|
||||||
memcpy(buffer, _data + _offset + (block << 9), BLOCK_SIZE);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,8 +344,8 @@ int Disk::ReadVolume(VolumeEntry *volume, std::vector<FileEntry> *files)
|
|||||||
|
|
||||||
if (ok < 0) return ok;
|
if (ok < 0) return ok;
|
||||||
|
|
||||||
prev = load16(&buffer[0x00]);
|
prev = Read16(&buffer[0x00]);
|
||||||
next = load16(&buffer[0x02]);
|
next = Read16(&buffer[0x02]);
|
||||||
|
|
||||||
VolumeEntry v;
|
VolumeEntry v;
|
||||||
v.Load(buffer + 0x04);
|
v.Load(buffer + 0x04);
|
||||||
@@ -505,8 +391,8 @@ int Disk::ReadVolume(VolumeEntry *volume, std::vector<FileEntry> *files)
|
|||||||
if (ok < 0) return ok;
|
if (ok < 0) return ok;
|
||||||
block = next;
|
block = next;
|
||||||
|
|
||||||
prev = load16(&buffer[0x00]);
|
prev = Read16(&buffer[0x00]);
|
||||||
next = load16(&buffer[0x02]);
|
next = Read16(&buffer[0x02]);
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
@@ -535,8 +421,8 @@ int Disk::ReadDirectory(unsigned block, SubdirEntry *dir, std::vector<FileEntry>
|
|||||||
|
|
||||||
if (ok < 0) return ok;
|
if (ok < 0) return ok;
|
||||||
|
|
||||||
prev = load16(&buffer[0x00]);
|
prev = Read16(&buffer[0x00]);
|
||||||
next = load16(&buffer[0x02]);
|
next = Read16(&buffer[0x02]);
|
||||||
|
|
||||||
SubdirEntry v;
|
SubdirEntry v;
|
||||||
v.Load(buffer + 0x04);
|
v.Load(buffer + 0x04);
|
||||||
@@ -585,8 +471,8 @@ int Disk::ReadDirectory(unsigned block, SubdirEntry *dir, std::vector<FileEntry>
|
|||||||
block = next;
|
block = next;
|
||||||
|
|
||||||
|
|
||||||
prev = load16(&buffer[0x00]);
|
prev = Read16(&buffer[0x00]);
|
||||||
next = load16(&buffer[0x02]);
|
next = Read16(&buffer[0x02]);
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
20
Disk.h
20
Disk.h
@@ -13,7 +13,10 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "File.h"
|
#include <ProDOS/File.h>
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
|
||||||
|
#include <tr1/memory>
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -40,6 +43,8 @@ enum {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Disk;
|
||||||
|
typedef std::tr1::shared_ptr<Disk> DiskPointer;
|
||||||
|
|
||||||
class Disk {
|
class Disk {
|
||||||
|
|
||||||
@@ -47,7 +52,7 @@ public:
|
|||||||
~Disk();
|
~Disk();
|
||||||
|
|
||||||
//static Disk *Open2MG(const char *file);
|
//static Disk *Open2MG(const char *file);
|
||||||
static Disk *OpenFile(const char *file, unsigned flags);
|
static DiskPointer OpenFile(Device::BlockDevicePointer device);
|
||||||
|
|
||||||
|
|
||||||
int Normalize(FileEntry &f, unsigned fork, ExtendedEntry *ee = NULL);
|
int Normalize(FileEntry &f, unsigned fork, ExtendedEntry *ee = NULL);
|
||||||
@@ -65,13 +70,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Disk();
|
Disk();
|
||||||
uint8_t *_data;
|
Disk(Device::BlockDevicePointer device);
|
||||||
unsigned _offset;
|
|
||||||
unsigned _blocks;
|
|
||||||
size_t _size;
|
|
||||||
|
|
||||||
unsigned _flags;
|
unsigned _blocks;
|
||||||
|
|
||||||
|
Device::BlockDevicePointer _device;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* DiskCopy42.cpp
|
|
||||||
* profuse
|
|
||||||
*
|
|
||||||
* Created by Kelvin Sherlock on 1/4/09.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "DiskCopy42.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t DiskCopy42::CheckSum(uint8_t *buffer, unsigned length)
|
|
||||||
{
|
|
||||||
uint32_t checksum = 0;
|
|
||||||
if (length & 0x01) return -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* checksum starts at 0
|
|
||||||
* foreach big-endian 16-bit word w:
|
|
||||||
* checksum += w
|
|
||||||
* checksum = checksum rotate right 1 (bit 0 --> bit 31)
|
|
||||||
*/
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < length; i += 2)
|
|
||||||
{
|
|
||||||
checksum += (buffer[i] << 8);
|
|
||||||
checksum += buffer[i + 1];
|
|
||||||
checksum = (checksum >> 1) | (checksum << 31);
|
|
||||||
//if (checksum & 0x01) checksum = (checksum >> 1) | 0x80000000;
|
|
||||||
//else checksum >>= 1;
|
|
||||||
}
|
|
||||||
return checksum;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCopy42::Load(const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
i = buffer[0];
|
|
||||||
if (i >= 64) return false;
|
|
||||||
|
|
||||||
memcpy(disk_name, &buffer[1], i);
|
|
||||||
disk_name[i] = 0;
|
|
||||||
|
|
||||||
|
|
||||||
data_size = load32_be(&buffer[64]);
|
|
||||||
tag_size = load32_be(&buffer[68]);
|
|
||||||
|
|
||||||
data_checksum = load32_be(&buffer[72]);
|
|
||||||
tag_checksum = load32_be(&buffer[76]);
|
|
||||||
|
|
||||||
disk_format = buffer[80];
|
|
||||||
format_byte = buffer[81];
|
|
||||||
private_word = load16_be(&buffer[82]);
|
|
||||||
|
|
||||||
if (private_word != 0x100) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
31
DiskCopy42.h
31
DiskCopy42.h
@@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* DiskCopy42.h
|
|
||||||
* profuse
|
|
||||||
*
|
|
||||||
* Created by Kelvin Sherlock on 1/4/09.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __DISKCOPY42__
|
|
||||||
#define __DISKCOPY42__
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
struct DiskCopy42
|
|
||||||
{
|
|
||||||
bool Load(const uint8_t *buffer);
|
|
||||||
static uint32_t CheckSum(uint8_t *buffer, unsigned length);
|
|
||||||
|
|
||||||
char disk_name[64];
|
|
||||||
uint32_t data_size;
|
|
||||||
uint32_t tag_size;
|
|
||||||
uint32_t data_checksum;
|
|
||||||
uint32_t tag_checksum;
|
|
||||||
unsigned disk_format;
|
|
||||||
unsigned format_byte;
|
|
||||||
unsigned private_word;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
105
Endian/Endian.cpp
Normal file
105
Endian/Endian.cpp
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#include <Endian/Endian.h>
|
||||||
|
|
||||||
|
namespace LittleEndian {
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t Read16(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return p[0] | (p[1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Read24(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0]) | (p[1] << 8) | (p[2] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t Read32(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0]) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Write16(void *vp, uint16_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x) & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write24(void *vp, uint32_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x) & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
p[2] = (x >> 16) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write32(void *vp, uint32_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x) & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
p[2] = (x >> 16) & 0xff;
|
||||||
|
p[3] = (x >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BigEndian {
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t Read16(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0] << 8) | (p[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Read24(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0] << 16) | (p[1] << 8) | (p[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t Read32(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Write16(void *vp, uint16_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x >> 8) & 0xff;
|
||||||
|
p[1] = (x) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write24(void *vp, uint32_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x >> 16) & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
p[2] = (x) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write32(void *vp, uint32_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x >> 24) & 0xff;
|
||||||
|
p[1] = (x >> 16) & 0xff;
|
||||||
|
p[2] = (x >> 8) & 0xff;
|
||||||
|
p[3] = (x) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
159
Endian/Endian.h
Normal file
159
Endian/Endian.h
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
#ifndef __ENDIAN_H__
|
||||||
|
#define __ENDIAN_H__
|
||||||
|
|
||||||
|
// utlities to read/write bytes.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace LittleEndian {
|
||||||
|
|
||||||
|
|
||||||
|
inline uint8_t Read8(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Read16(const void *vp);
|
||||||
|
|
||||||
|
uint32_t Read24(const void *vp);
|
||||||
|
|
||||||
|
uint32_t Read32(const void *vp);
|
||||||
|
|
||||||
|
|
||||||
|
inline uint8_t Read8(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read8(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t Read16(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read16(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t Read24(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read24(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t Read32(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read32(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// write
|
||||||
|
inline void Write8(void *vp, uint8_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write16(void *vp, uint16_t x);
|
||||||
|
|
||||||
|
void Write24(void *vp, uint32_t x);
|
||||||
|
|
||||||
|
void Write32(void *vp, uint32_t x);
|
||||||
|
|
||||||
|
|
||||||
|
inline void Write8(void *vp, unsigned offset, uint8_t x)
|
||||||
|
{
|
||||||
|
Write8(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write16(void *vp, unsigned offset, uint16_t x)
|
||||||
|
{
|
||||||
|
Write16(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write24(void *vp, unsigned offset, uint32_t x)
|
||||||
|
{
|
||||||
|
Write24(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write32(void *vp, unsigned offset, uint32_t x)
|
||||||
|
{
|
||||||
|
Write32(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace BigEndian {
|
||||||
|
|
||||||
|
|
||||||
|
inline uint8_t Read8(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Read16(const void *vp);
|
||||||
|
|
||||||
|
uint32_t Read24(const void *vp);
|
||||||
|
|
||||||
|
uint32_t Read32(const void *vp);
|
||||||
|
|
||||||
|
|
||||||
|
inline uint8_t Read8(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read8(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t Read16(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read16(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t Read24(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read24(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t Read32(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read32(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// write
|
||||||
|
inline void Write8(void *vp, uint8_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write16(void *vp, uint16_t x);
|
||||||
|
|
||||||
|
void Write24(void *vp, uint32_t x);
|
||||||
|
|
||||||
|
void Write32(void *vp, uint32_t x);
|
||||||
|
|
||||||
|
|
||||||
|
inline void Write8(void *vp, unsigned offset, uint8_t x)
|
||||||
|
{
|
||||||
|
Write8(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write16(void *vp, unsigned offset, uint16_t x)
|
||||||
|
{
|
||||||
|
Write16(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write24(void *vp, unsigned offset, uint32_t x)
|
||||||
|
{
|
||||||
|
Write24(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write32(void *vp, unsigned offset, uint32_t x)
|
||||||
|
{
|
||||||
|
Write32(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
103
Endian/IOBuffer.cpp.h
Normal file
103
Endian/IOBuffer.cpp.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
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 *src, unsigned count)
|
||||||
|
{
|
||||||
|
std::memcpy(_offset + (uint8_t *)_buffer, src, count);
|
||||||
|
_offset += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeZero(unsigned count)
|
||||||
|
{
|
||||||
|
std::memset(_offset + (uint8_t *)_buffer, 0, count);
|
||||||
|
|
||||||
|
_offset += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t read8()
|
||||||
|
{
|
||||||
|
uint8_t x = Read8(_buffer, _offset);
|
||||||
|
_offset += 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t read16()
|
||||||
|
{
|
||||||
|
uint16_t x = Read16(_buffer, _offset);
|
||||||
|
_offset += 2;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t read24()
|
||||||
|
{
|
||||||
|
uint32_t x = Read24(_buffer, _offset);
|
||||||
|
_offset += 3;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t read32()
|
||||||
|
{
|
||||||
|
uint32_t x = Read32(_buffer, _offset);
|
||||||
|
_offset += 4;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readBytes(void *dest, unsigned count)
|
||||||
|
{
|
||||||
|
std::memcpy(dest, _offset + (uint8_t *)_buffer, count);
|
||||||
|
_offset += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned offset() const { return _offset; }
|
||||||
|
void setOffset(unsigned offset) { _offset = offset; }
|
||||||
|
|
||||||
|
void setOffset(unsigned offset, bool zero)
|
||||||
|
{
|
||||||
|
if (zero && offset > _offset)
|
||||||
|
{
|
||||||
|
writeZero(offset - _offset);
|
||||||
|
}
|
||||||
|
else setOffset(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned size() const { return _size; }
|
||||||
|
|
||||||
|
void *buffer() const { return _buffer; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *_buffer;
|
||||||
|
unsigned _size;
|
||||||
|
unsigned _offset;
|
||||||
|
|
||||||
|
};
|
||||||
15
Endian/IOBuffer.h
Normal file
15
Endian/IOBuffer.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __IOBUFFER_H__
|
||||||
|
#define __IOBUFFER_H__
|
||||||
|
|
||||||
|
#include <Endian/Endian.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace LittleEndian {
|
||||||
|
#include "IOBuffer.cpp.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BigEndian {
|
||||||
|
#include "IOBuffer.cpp.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
128
File/File.cpp
Normal file
128
File/File.cpp
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#include <File/File.h>
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
File::File()
|
||||||
|
{
|
||||||
|
_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::File(int fd)
|
||||||
|
{
|
||||||
|
_fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::File(File& f)
|
||||||
|
{
|
||||||
|
_fd = f._fd;
|
||||||
|
f._fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::File(const char *name, int flags, const std::nothrow_t&)
|
||||||
|
{
|
||||||
|
_fd = ::open(name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File::File(const char *name, int flags, mode_t mode, const std::nothrow_t&)
|
||||||
|
{
|
||||||
|
_fd = ::open(name, flags, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
File::File(const char *name, FileFlags flags, const std::nothrow_t&)
|
||||||
|
{
|
||||||
|
_fd = ::open(name, flags == ReadOnly ? O_RDONLY : O_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
File::File(const char *name, int flags)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "File::File"
|
||||||
|
|
||||||
|
_fd = ::open(name, flags);
|
||||||
|
if (_fd < 0)
|
||||||
|
throw POSIXException( __METHOD__ ": open", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
File::File(const char *name, int flags, mode_t mode)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "File::File"
|
||||||
|
|
||||||
|
_fd = ::open(name, flags, mode);
|
||||||
|
if (_fd < 0)
|
||||||
|
throw POSIXException( __METHOD__ ": open", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File::File(const char *name, FileFlags flags)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "File::File"
|
||||||
|
|
||||||
|
_fd = ::open(name, flags == ReadOnly ? O_RDONLY : O_RDWR);
|
||||||
|
if (_fd < 0)
|
||||||
|
throw POSIXException( __METHOD__ ": open", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File::~File()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int File::release()
|
||||||
|
{
|
||||||
|
int tmp = _fd;
|
||||||
|
_fd = -1;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::close()
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "File::close"
|
||||||
|
|
||||||
|
if (_fd >= 0)
|
||||||
|
{
|
||||||
|
::close(_fd);
|
||||||
|
_fd = -1;
|
||||||
|
|
||||||
|
// destructor shouldn't throw.
|
||||||
|
/*
|
||||||
|
if (::close(fd) != 0)
|
||||||
|
throw POSIXException(__METHOD__ ": close", errno);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void File::adopt(File &f)
|
||||||
|
{
|
||||||
|
if (&f == this) return;
|
||||||
|
|
||||||
|
close();
|
||||||
|
_fd = f._fd;
|
||||||
|
f._fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::adopt(int fd)
|
||||||
|
{
|
||||||
|
if (fd == _fd) return;
|
||||||
|
close();
|
||||||
|
_fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void File::swap(File &f)
|
||||||
|
{
|
||||||
|
std::swap(_fd, f._fd);
|
||||||
|
}
|
||||||
58
File/File.h
Normal file
58
File/File.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef __FILE_H__
|
||||||
|
#define __FILE_H__
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class File {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum FileFlags {
|
||||||
|
ReadOnly = 1,
|
||||||
|
ReadWrite = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
File();
|
||||||
|
File(File &);
|
||||||
|
File(int fd);
|
||||||
|
|
||||||
|
File(const char *name, int flags);
|
||||||
|
File(const char *name, int flags, mode_t mode);
|
||||||
|
File(const char *name, FileFlags flags);
|
||||||
|
|
||||||
|
File(const char *name, int flags, const std::nothrow_t &);
|
||||||
|
File(const char *name, int flags, mode_t mode, const std::nothrow_t &);
|
||||||
|
File(const char *name, FileFlags flags, const std::nothrow_t &);
|
||||||
|
|
||||||
|
~File();
|
||||||
|
|
||||||
|
bool isValid() const
|
||||||
|
{
|
||||||
|
return _fd >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd() const { return _fd; }
|
||||||
|
|
||||||
|
int release();
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
void adopt(File &f);
|
||||||
|
void adopt(int fd);
|
||||||
|
|
||||||
|
void swap(File &f);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// could call dup() or something.
|
||||||
|
File& operator=(const File &f);
|
||||||
|
int _fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
187
File/MappedFile.cpp
Normal file
187
File/MappedFile.cpp
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <File/MappedFile.h>
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
MappedFile::MappedFile()
|
||||||
|
{
|
||||||
|
_length = -1;
|
||||||
|
_address = MAP_FAILED;
|
||||||
|
_readOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MappedFile::MappedFile(MappedFile &mf)
|
||||||
|
{
|
||||||
|
_address = mf._address;
|
||||||
|
_length = mf._length;
|
||||||
|
_readOnly = mf._readOnly;
|
||||||
|
|
||||||
|
mf._address = MAP_FAILED;
|
||||||
|
mf._length = -1;
|
||||||
|
mf._readOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MappedFile::MappedFile(const File &f, File::FileFlags flags, size_t size)
|
||||||
|
{
|
||||||
|
_length = -1;
|
||||||
|
_address = MAP_FAILED;
|
||||||
|
_readOnly = true;
|
||||||
|
|
||||||
|
init(f, flags == File::ReadOnly, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MappedFile::MappedFile(const char *name, File::FileFlags flags)
|
||||||
|
{
|
||||||
|
File f(name, flags);
|
||||||
|
|
||||||
|
_length = -1;
|
||||||
|
_address = MAP_FAILED;
|
||||||
|
_readOnly = true;
|
||||||
|
|
||||||
|
init(f, flags == File::ReadOnly, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MappedFile::MappedFile(const char *name, File::FileFlags flags, const std::nothrow_t ¬hrow)
|
||||||
|
{
|
||||||
|
File f(name, flags, nothrow);
|
||||||
|
|
||||||
|
_length = -1;
|
||||||
|
_address = MAP_FAILED;
|
||||||
|
_readOnly = true;
|
||||||
|
|
||||||
|
if (f.isValid())
|
||||||
|
init(f, flags == File::ReadOnly, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MappedFile::~MappedFile()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MappedFile::init(const File &f, bool readOnly, size_t size)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedFile::init"
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
int prot = readOnly ? PROT_READ : PROT_READ | PROT_WRITE;
|
||||||
|
int flags = MAP_FILE | MAP_SHARED;
|
||||||
|
|
||||||
|
// close enough
|
||||||
|
if (f.fd() < 0)
|
||||||
|
throw POSIXException( __METHOD__, EBADF);
|
||||||
|
|
||||||
|
|
||||||
|
if (!size)
|
||||||
|
{
|
||||||
|
if (::fstat(f.fd(), &st) != 0)
|
||||||
|
throw POSIXException(__METHOD__ ": fstat", errno);
|
||||||
|
|
||||||
|
if (!S_ISREG(st.st_mode))
|
||||||
|
throw POSIXException(__METHOD__, ENODEV);
|
||||||
|
|
||||||
|
size = st.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
_length = size;
|
||||||
|
_address = ::mmap(0, _length, prot, flags, f.fd(), 0);
|
||||||
|
|
||||||
|
if (_address == MAP_FAILED)
|
||||||
|
throw POSIXException(__METHOD__ ": mmap", errno);
|
||||||
|
|
||||||
|
_readOnly = readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MappedFile::close()
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedFile::close"
|
||||||
|
|
||||||
|
if (_address != MAP_FAILED)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
void *address = _address;
|
||||||
|
size_t length = _length;
|
||||||
|
*/
|
||||||
|
|
||||||
|
::munmap(_address, _length);
|
||||||
|
|
||||||
|
_address = MAP_FAILED;
|
||||||
|
_length = -1;
|
||||||
|
_readOnly = true;
|
||||||
|
|
||||||
|
// destructor shouldn't throw.
|
||||||
|
/*
|
||||||
|
if (::munmap(address, length) != 0)
|
||||||
|
throw POSIXException(__METHOD__ ": munmap", errno);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MappedFile::sync()
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedFile::sync"
|
||||||
|
|
||||||
|
if (_address != MAP_FAILED)
|
||||||
|
{
|
||||||
|
if (::msync(_address, _length, MS_SYNC) != 0)
|
||||||
|
throw POSIXException(__METHOD__ ": msync", errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MappedFile::adopt(MappedFile &mf)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
_address = mf._address;
|
||||||
|
_length = mf._length;
|
||||||
|
_readOnly = mf._readOnly;
|
||||||
|
|
||||||
|
mf._address = MAP_FAILED;
|
||||||
|
mf._length = -1;
|
||||||
|
mf._readOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MappedFile::swap(MappedFile &mf)
|
||||||
|
{
|
||||||
|
std::swap(_address, mf._address);
|
||||||
|
std::swap(_length, mf._length);
|
||||||
|
std::swap(_readOnly, mf._readOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MappedFile *MappedFile::Create(const char *name, size_t size)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "MappedFile::Create"
|
||||||
|
|
||||||
|
File fd(::open(name, O_CREAT | O_TRUNC | O_RDWR, 0644));
|
||||||
|
|
||||||
|
if (!fd.isValid())
|
||||||
|
{
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to create file.", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO -- is ftruncate portable?
|
||||||
|
if (::ftruncate(fd.fd(), size) < 0)
|
||||||
|
{
|
||||||
|
// TODO -- unlink?
|
||||||
|
throw POSIXException(__METHOD__ ": Unable to truncate file.", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MappedFile(fd, File::ReadWrite, size);
|
||||||
|
}
|
||||||
53
File/MappedFile.h
Normal file
53
File/MappedFile.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef __MAPPED_FILE_H__
|
||||||
|
#define __MAPPED_FILE_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <File/File.h>
|
||||||
|
|
||||||
|
class File;
|
||||||
|
|
||||||
|
class MappedFile {
|
||||||
|
public:
|
||||||
|
|
||||||
|
MappedFile();
|
||||||
|
MappedFile(MappedFile&);
|
||||||
|
MappedFile(const File &f, File::FileFlags flags, size_t size = -1);
|
||||||
|
MappedFile(const char *name, File::FileFlags flags);
|
||||||
|
MappedFile(const char *name, File::FileFlags flags, const std::nothrow_t ¬hrow);
|
||||||
|
|
||||||
|
~MappedFile();
|
||||||
|
|
||||||
|
|
||||||
|
static MappedFile *Create(const char *name, size_t size);
|
||||||
|
|
||||||
|
bool isValid() const
|
||||||
|
{
|
||||||
|
return _address != MAP_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sync();
|
||||||
|
void close();
|
||||||
|
|
||||||
|
void *address() const { return _address; }
|
||||||
|
size_t length() const { return _length; }
|
||||||
|
bool readOnly() const { return _readOnly; }
|
||||||
|
|
||||||
|
void swap(MappedFile &);
|
||||||
|
void adopt(MappedFile &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MappedFile& operator=(MappedFile &);
|
||||||
|
|
||||||
|
void init(const File &f, bool readOnly, size_t size);
|
||||||
|
|
||||||
|
void *_address;
|
||||||
|
size_t _length;
|
||||||
|
bool _readOnly;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
200
ProDOS/Bitmap.cpp
Normal file
200
ProDOS/Bitmap.cpp
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <ProDOS/Bitmap.h>
|
||||||
|
#include <ProDOS/BlockDevice.h>
|
||||||
|
#include "auto.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace ProDOS;
|
||||||
|
|
||||||
|
// returns # of 1-bits set (0-8)
|
||||||
|
inline static unsigned popCount(uint8_t x)
|
||||||
|
{
|
||||||
|
#ifdef __GNUC__
|
||||||
|
return __builtin_popcount(x);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Brian Kernighan / Peter Wegner in CACM 3 (1960), 322.
|
||||||
|
|
||||||
|
unsigned count;
|
||||||
|
for (count = 0; x; ++count)
|
||||||
|
{
|
||||||
|
x &= x - 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bitmap::Bitmap(unsigned blocks)
|
||||||
|
{
|
||||||
|
_blocks = _freeBlocks = blocks;
|
||||||
|
|
||||||
|
_bitmapBlocks = (blocks + 4095) / 4096;
|
||||||
|
_freeIndex = 0;
|
||||||
|
|
||||||
|
unsigned bitmapSize = _bitmapBlocks * 512;
|
||||||
|
unsigned blockSize = blocks / 8;
|
||||||
|
|
||||||
|
auto_array<uint8_t> bitmap(new uint8_t[bitmapSize]);
|
||||||
|
|
||||||
|
// mark overflow in use, everything else free.
|
||||||
|
|
||||||
|
std::memset(bitmap, 0xff, blocks / 8);
|
||||||
|
std::memset(bitmap + blockSize, 0x00, bitmapSize - blockSize);
|
||||||
|
|
||||||
|
// edge case
|
||||||
|
unsigned tmp = blocks & 0x07;
|
||||||
|
|
||||||
|
bitmap[blocks / 8] = ~(0xff >> tmp);
|
||||||
|
|
||||||
|
_bitmap = bitmap.release();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap::Bitmap(BlockDevice *device, unsigned keyPointer, unsigned blocks)
|
||||||
|
{
|
||||||
|
_blocks = blocks;
|
||||||
|
_freeBlocks = 0;
|
||||||
|
_freeIndex = 0;
|
||||||
|
|
||||||
|
_bitmapBlocks = (blocks + 4095) / 4096;
|
||||||
|
|
||||||
|
unsigned bitmapSize = _bitmapBlocks * 512;
|
||||||
|
unsigned blockSize = blocks / 8;
|
||||||
|
|
||||||
|
auto_array<uint8_t> bitmap(new uint8_t[bitmapSize]);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < blockSize; ++i)
|
||||||
|
{
|
||||||
|
device->read(keyPointer + i, bitmap + 512 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure all trailing bits are marked in use.
|
||||||
|
|
||||||
|
// edge case
|
||||||
|
unsigned tmp = blocks & 0x07;
|
||||||
|
|
||||||
|
bitmap[blocks / 8] &= ~(0xff >> tmp);
|
||||||
|
|
||||||
|
std::memset(bitmap + blockSize, 0x00, bitmapSize - blockSize);
|
||||||
|
|
||||||
|
// set _freeBlocks and _freeIndex;
|
||||||
|
for (unsigned i = 0; i < (blocks + 7) / 8; ++i)
|
||||||
|
{
|
||||||
|
_freeBlocks += popCount(bitmap[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_freeBlocks)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < (blocks + 7) / 8; ++i)
|
||||||
|
{
|
||||||
|
if (bitmap[i])
|
||||||
|
{
|
||||||
|
_freeIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_bitmap = bitmap.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap::~Bitmap()
|
||||||
|
{
|
||||||
|
if (_bitmap) delete []_bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Bitmap::freeBlock(unsigned block)
|
||||||
|
{
|
||||||
|
if (block >= _blocks) return;
|
||||||
|
|
||||||
|
unsigned index = block / 8;
|
||||||
|
unsigned offset = block & 0x07;
|
||||||
|
unsigned mask = 0x80 >> offset;
|
||||||
|
|
||||||
|
uint8_t tmp = _bitmap[index];
|
||||||
|
|
||||||
|
if ((tmp & mask) == 0)
|
||||||
|
{
|
||||||
|
++_freeBlocks;
|
||||||
|
_bitmap[index] = tmp | mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Bitmap::allocBlock(unsigned block)
|
||||||
|
{
|
||||||
|
if (block >= _blocks) return -1;
|
||||||
|
|
||||||
|
|
||||||
|
unsigned index = block / 8;
|
||||||
|
unsigned offset = block & 0x07;
|
||||||
|
unsigned mask = 0x80 >> offset;
|
||||||
|
|
||||||
|
uint8_t tmp = _bitmap[index];
|
||||||
|
|
||||||
|
if ((tmp & mask))
|
||||||
|
{
|
||||||
|
--_freeBlocks;
|
||||||
|
_bitmap[index] = tmp & ~mask;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Bitmap::allocBlock()
|
||||||
|
{
|
||||||
|
if (!_freeBlocks) return -1;
|
||||||
|
|
||||||
|
unsigned freeIndex = _freeIndex;
|
||||||
|
unsigned maxIndex = (_blocks + 7) / 8;
|
||||||
|
|
||||||
|
|
||||||
|
for (unsigned index = _freeIndex; index < maxIndex; ++index)
|
||||||
|
{
|
||||||
|
uint8_t tmp = _bitmap[index];
|
||||||
|
if (!tmp) continue;
|
||||||
|
|
||||||
|
unsigned mask = 0x80;
|
||||||
|
for (unsigned offset = 0; offset < 8; ++offset)
|
||||||
|
{
|
||||||
|
if (tmp & mask)
|
||||||
|
{
|
||||||
|
_freeIndex = index;
|
||||||
|
_bitmap[index] = tmp & ~mask;
|
||||||
|
--_freeBlocks;
|
||||||
|
return index * 8 + offset;
|
||||||
|
}
|
||||||
|
mask = mask >> 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned index = 0; index < freeIndex; ++index)
|
||||||
|
{
|
||||||
|
uint8_t tmp = _bitmap[index];
|
||||||
|
if (!tmp) continue;
|
||||||
|
|
||||||
|
unsigned mask = 0x80;
|
||||||
|
for (unsigned offset = 0; offset < 8; ++offset)
|
||||||
|
{
|
||||||
|
if (tmp & mask)
|
||||||
|
{
|
||||||
|
_freeIndex = index;
|
||||||
|
_bitmap[index] = tmp & ~mask;
|
||||||
|
--_freeBlocks;
|
||||||
|
return index * 8 + offset;
|
||||||
|
}
|
||||||
|
mask = mask >> 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// should never happen...
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
48
ProDOS/Bitmap.h
Normal file
48
ProDOS/Bitmap.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef __BITMAP_H__
|
||||||
|
#define __BITMAP_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ProDOS {
|
||||||
|
|
||||||
|
class BlockDevice;
|
||||||
|
|
||||||
|
|
||||||
|
class Bitmap {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Bitmap(unsigned blocks);
|
||||||
|
Bitmap(BlockDevice *device, unsigned keyPointer, unsigned blocks);
|
||||||
|
//todo -- constructor by loading from, block device...
|
||||||
|
~Bitmap();
|
||||||
|
|
||||||
|
int allocBlock();
|
||||||
|
int allocBlock(unsigned block);
|
||||||
|
|
||||||
|
void freeBlock(unsigned block);
|
||||||
|
|
||||||
|
|
||||||
|
unsigned freeBlocks() const { return _freeBlocks; }
|
||||||
|
unsigned blocks() const { return _blocks; }
|
||||||
|
unsigned bitmapBlocks() const { return _bitmapBlocks; }
|
||||||
|
unsigned bitmapSize() const { return _bitmapBlocks * 512; }
|
||||||
|
const void *bitmap() const { return _bitmap; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
unsigned _freeIndex;
|
||||||
|
unsigned _freeBlocks;
|
||||||
|
|
||||||
|
unsigned _blocks;
|
||||||
|
unsigned _bitmapBlocks;
|
||||||
|
|
||||||
|
uint8_t *_bitmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#include "DateTime.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace ProDOS {
|
#include <ProDOS/DateTime.h>
|
||||||
|
|
||||||
|
using namespace ProDOS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* date is a 16 bit value:
|
* date is a 16 bit value:
|
||||||
@@ -141,4 +142,3 @@ std::time_t DateTime::toUnix() const
|
|||||||
// convert back via locatime & fudge for dst?
|
// convert back via locatime & fudge for dst?
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
@@ -6,7 +6,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "File.h"
|
#include <ProDOS/File.h>
|
||||||
|
#include <ProDOS/DateTime.h>
|
||||||
|
#include <Endian/Endian.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -14,7 +16,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "DateTime.h"
|
using namespace LittleEndian;
|
||||||
|
|
||||||
|
|
||||||
bool FileEntry::Load(const void *data)
|
bool FileEntry::Load(const void *data)
|
||||||
@@ -31,18 +33,18 @@ bool FileEntry::Load(const void *data)
|
|||||||
|
|
||||||
file_type = cp[0x10];
|
file_type = cp[0x10];
|
||||||
|
|
||||||
key_pointer = load16(&cp[0x11]);
|
key_pointer = Read16(&cp[0x11]);
|
||||||
|
|
||||||
blocks_used = load16(&cp[0x13]);
|
blocks_used = Read16(&cp[0x13]);
|
||||||
|
|
||||||
eof = load24(&cp[0x15]);
|
eof = Read24(&cp[0x15]);
|
||||||
|
|
||||||
creation = ProDOS::DateTime(load16(&cp[0x18]), load16(&cp[0x1a]));
|
creation = ProDOS::DateTime(Read16(&cp[0x18]), Read16(&cp[0x1a]));
|
||||||
|
|
||||||
//version = cp[0x1c];
|
//version = cp[0x1c];
|
||||||
//min_version = cp[0x1d];
|
//min_version = cp[0x1d];
|
||||||
|
|
||||||
unsigned xcase = load16(&cp[0x1c]);
|
unsigned xcase = Read16(&cp[0x1c]);
|
||||||
if (xcase & 0x8000)
|
if (xcase & 0x8000)
|
||||||
{
|
{
|
||||||
// gsos technote #8
|
// gsos technote #8
|
||||||
@@ -59,11 +61,11 @@ bool FileEntry::Load(const void *data)
|
|||||||
access = cp[0x1e];
|
access = cp[0x1e];
|
||||||
|
|
||||||
|
|
||||||
aux_type = load16(&cp[0x1f]);
|
aux_type = Read16(&cp[0x1f]);
|
||||||
|
|
||||||
last_mod = ProDOS::DateTime(load16(&cp[0x21]), load16(&cp[0x23]));
|
last_mod = ProDOS::DateTime(Read16(&cp[0x21]), Read16(&cp[0x23]));
|
||||||
|
|
||||||
header_pointer = load16(&cp[0x25]);
|
header_pointer = Read16(&cp[0x25]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -79,16 +81,16 @@ bool ExtendedEntry::Load(const void *data)
|
|||||||
// offset 0 - mini entry for data fork
|
// offset 0 - mini entry for data fork
|
||||||
|
|
||||||
dataFork.storage_type = cp[0x00] & 0x0f;
|
dataFork.storage_type = cp[0x00] & 0x0f;
|
||||||
dataFork.key_block = load16(&cp[0x01]);
|
dataFork.key_block = Read16(&cp[0x01]);
|
||||||
dataFork.blocks_used = load16(&cp[0x03]);
|
dataFork.blocks_used = Read16(&cp[0x03]);
|
||||||
dataFork.eof = load24(&cp[0x05]);
|
dataFork.eof = Read24(&cp[0x05]);
|
||||||
|
|
||||||
// offset 256 - mini entry for resource fork.
|
// offset 256 - mini entry for resource fork.
|
||||||
|
|
||||||
resourceFork.storage_type = cp[256 + 0x00] & 0x0f;
|
resourceFork.storage_type = cp[256 + 0x00] & 0x0f;
|
||||||
resourceFork.key_block = load16(&cp[256 + 0x01]);
|
resourceFork.key_block = Read16(&cp[256 + 0x01]);
|
||||||
resourceFork.blocks_used = load16(&cp[256 + 0x03]);
|
resourceFork.blocks_used = Read16(&cp[256 + 0x03]);
|
||||||
resourceFork.eof = load24(&cp[256 + 0x05]);
|
resourceFork.eof = Read24(&cp[256 + 0x05]);
|
||||||
|
|
||||||
// xFInfo may be missing.
|
// xFInfo may be missing.
|
||||||
bzero(FInfo, sizeof(FInfo));
|
bzero(FInfo, sizeof(FInfo));
|
||||||
@@ -135,15 +137,15 @@ bool VolumeEntry::Load(const void *data)
|
|||||||
|
|
||||||
// 0x14--0x1b reserved
|
// 0x14--0x1b reserved
|
||||||
|
|
||||||
creation = ProDOS::DateTime(load16(&cp[0x18]), load16(&cp[0x1a]));
|
creation = ProDOS::DateTime(Read16(&cp[0x18]), Read16(&cp[0x1a]));
|
||||||
last_mod = ProDOS::DateTime(load16(&cp[0x12]), load16(&cp[0x14]));
|
last_mod = ProDOS::DateTime(Read16(&cp[0x12]), Read16(&cp[0x14]));
|
||||||
|
|
||||||
if (last_mod == 0) last_mod = creation;
|
if (last_mod == 0) last_mod = creation;
|
||||||
|
|
||||||
//version = cp[0x1c];
|
//version = cp[0x1c];
|
||||||
//min_version = cp[0x1d];
|
//min_version = cp[0x1d];
|
||||||
|
|
||||||
unsigned xcase = load16(&cp[0x16]);
|
unsigned xcase = Read16(&cp[0x16]);
|
||||||
if (xcase & 0x8000)
|
if (xcase & 0x8000)
|
||||||
{
|
{
|
||||||
// gsos technote #8
|
// gsos technote #8
|
||||||
@@ -162,11 +164,11 @@ bool VolumeEntry::Load(const void *data)
|
|||||||
|
|
||||||
entries_per_block = cp[0x20];
|
entries_per_block = cp[0x20];
|
||||||
|
|
||||||
file_count = load16(&cp[0x21]);
|
file_count = Read16(&cp[0x21]);
|
||||||
|
|
||||||
bit_map_pointer = load16(&cp[0x23]);
|
bit_map_pointer = Read16(&cp[0x23]);
|
||||||
|
|
||||||
total_blocks = load16(&cp[0x25]);
|
total_blocks = Read16(&cp[0x25]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -192,7 +194,7 @@ bool SubdirEntry::Load(const void *data)
|
|||||||
|
|
||||||
// 0x145-0x1b reserved
|
// 0x145-0x1b reserved
|
||||||
|
|
||||||
creation = ProDOS::DateTime(load16(&cp[0x18]), load16(&cp[0x1a]));
|
creation = ProDOS::DateTime(Read16(&cp[0x18]), Read16(&cp[0x1a]));
|
||||||
|
|
||||||
//version = cp[0x1c];
|
//version = cp[0x1c];
|
||||||
//min_version = cp[0x1d];
|
//min_version = cp[0x1d];
|
||||||
@@ -216,9 +218,9 @@ bool SubdirEntry::Load(const void *data)
|
|||||||
|
|
||||||
entries_per_block = cp[0x20];
|
entries_per_block = cp[0x20];
|
||||||
|
|
||||||
file_count = load16(&cp[0x21]);
|
file_count = Read16(&cp[0x21]);
|
||||||
|
|
||||||
parent_pointer = load16(&cp[0x23]);
|
parent_pointer = Read16(&cp[0x23]);
|
||||||
|
|
||||||
parent_entry = cp[0x25];
|
parent_entry = cp[0x25];
|
||||||
|
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FILE_H__
|
#ifndef __PRODOS_FILE_H__
|
||||||
#define __FILE_H__
|
#define __PRODOS_FILE_H__
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
148
ProFUSE/Exception.cpp
Normal file
148
ProFUSE/Exception.cpp
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace ProFUSE;
|
||||||
|
|
||||||
|
Exception::~Exception() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Exception::what()
|
||||||
|
{
|
||||||
|
return _string.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Exception::errorString()
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *POSIXException::errorString()
|
||||||
|
{
|
||||||
|
return strerror(error());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ProDOSException::errorString()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
switch (error())
|
||||||
|
{
|
||||||
|
case badSystemCall:
|
||||||
|
return "Bad System Call";
|
||||||
|
case invalidPcount:
|
||||||
|
return "Invalid Parameter Count";
|
||||||
|
case gsosActive:
|
||||||
|
return "GS/OS Active";
|
||||||
|
case devNotFound:
|
||||||
|
return "Device Not Found";
|
||||||
|
case invalidDevNum:
|
||||||
|
return "Invalid Device Number";
|
||||||
|
case drvrBadReq:
|
||||||
|
return "Driver Bad Request";
|
||||||
|
case drvrBadCode:
|
||||||
|
return "Driver Bad Code";
|
||||||
|
case drvrBadParm:
|
||||||
|
return "Driver Bad Parameter";
|
||||||
|
case drvrNotOpen:
|
||||||
|
return "Driver Not Open";
|
||||||
|
case drvrPriorOpen:
|
||||||
|
return "Driver Prior Open";
|
||||||
|
case irqTableFull:
|
||||||
|
return "IRQ Table Full";
|
||||||
|
case drvrNoResrc:
|
||||||
|
return "Driver No Resource";
|
||||||
|
case drvrIOError:
|
||||||
|
return "Driver IO Error";
|
||||||
|
case drvrNoDevice:
|
||||||
|
return "Driver No Device";
|
||||||
|
case drvrBusy:
|
||||||
|
return "Driver Busy";
|
||||||
|
case drvrWrtProt:
|
||||||
|
return "Driver Write Protected";
|
||||||
|
case drvrBadCount:
|
||||||
|
return "Driver Bad Count";
|
||||||
|
case drvrBadBlock:
|
||||||
|
return "Driver Bad Block";
|
||||||
|
case drvrDiskSwitch:
|
||||||
|
return "Driver Disk Switch";
|
||||||
|
case drvrOffLine:
|
||||||
|
return "Driver Off Line";
|
||||||
|
case badPathSyntax:
|
||||||
|
return "Bad Path Syntax";
|
||||||
|
case invalidRefNum:
|
||||||
|
return "Invalid Ref Num";
|
||||||
|
case pathNotFound:
|
||||||
|
return "Path Not Found";
|
||||||
|
case volNotFound:
|
||||||
|
return "Volume Not Found";
|
||||||
|
case fileNotFound:
|
||||||
|
return "File Not Found";
|
||||||
|
case dupPathName:
|
||||||
|
return "Duplicate Path Name";
|
||||||
|
case volumeFull:
|
||||||
|
return "Volume Full";
|
||||||
|
case volDirFull:
|
||||||
|
return "Volume Directory Full";
|
||||||
|
case badFileFormat:
|
||||||
|
return "Bad File Format";
|
||||||
|
case badStoreType:
|
||||||
|
return "Bad Storage Type";
|
||||||
|
case eofEncountered:
|
||||||
|
return "End of File";
|
||||||
|
case outOfRange:
|
||||||
|
return "Out of Range";
|
||||||
|
case invalidAccess:
|
||||||
|
return "Invalid Access";
|
||||||
|
case buffTooSmall:
|
||||||
|
return "Buffer Too Small";
|
||||||
|
case fileBusy:
|
||||||
|
return "File Busy";
|
||||||
|
case dirError:
|
||||||
|
return "Directory Error";
|
||||||
|
case unknownVol:
|
||||||
|
return "Unknown Volume";
|
||||||
|
case paramRangeError:
|
||||||
|
return "Parameter Range Error";
|
||||||
|
case outOfMem:
|
||||||
|
return "Out of Memory";
|
||||||
|
case dupVolume:
|
||||||
|
return "Duplicate Volume";
|
||||||
|
case notBlockDev:
|
||||||
|
return "Not a Block Device";
|
||||||
|
case invalidLevel:
|
||||||
|
return "Invalid Level";
|
||||||
|
case damagedBitMap:
|
||||||
|
return "Damaged Bit Map";
|
||||||
|
case badPathNames:
|
||||||
|
return "Bad Path Names";
|
||||||
|
case notSystemFile:
|
||||||
|
return "Not a System File";
|
||||||
|
case osUnsupported:
|
||||||
|
return "OS Unsupported";
|
||||||
|
case stackOverflow:
|
||||||
|
return "Stack Overflow";
|
||||||
|
case dataUnavail:
|
||||||
|
return "Data Unavailable";
|
||||||
|
case endOfDir:
|
||||||
|
return "End Of Directory";
|
||||||
|
case invalidClass:
|
||||||
|
return "Invalid Class";
|
||||||
|
case resForkNotFound:
|
||||||
|
return "Resource Fork Not Found";
|
||||||
|
case invalidFSTID:
|
||||||
|
return "Invalid FST ID";
|
||||||
|
case devNameErr:
|
||||||
|
return "Device Name Error";
|
||||||
|
case resExistsErr:
|
||||||
|
return "Resource Exists Error";
|
||||||
|
case resAddErr:
|
||||||
|
return "Resource Add Error";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
158
ProFUSE/Exception.h
Normal file
158
ProFUSE/Exception.h
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
#ifndef __EXCEPTION_H__
|
||||||
|
#define __EXCEPTION_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
namespace ProFUSE {
|
||||||
|
|
||||||
|
|
||||||
|
// ProDOS Errors
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
badSystemCall = 0x01,
|
||||||
|
invalidPcount = 0x04,
|
||||||
|
gsosActive = 0x07,
|
||||||
|
devNotFound = 0x10,
|
||||||
|
invalidDevNum = 0x11,
|
||||||
|
drvrBadReq = 0x20,
|
||||||
|
drvrBadCode = 0x21,
|
||||||
|
drvrBadParm = 0x22,
|
||||||
|
drvrNotOpen = 0x23,
|
||||||
|
drvrPriorOpen = 0x24,
|
||||||
|
irqTableFull = 0x25,
|
||||||
|
drvrNoResrc = 0x26,
|
||||||
|
drvrIOError = 0x27,
|
||||||
|
drvrNoDevice = 0x28,
|
||||||
|
drvrBusy = 0x29,
|
||||||
|
drvrWrtProt = 0x2b,
|
||||||
|
drvrBadCount = 0x2c,
|
||||||
|
drvrBadBlock = 0x2d,
|
||||||
|
drvrDiskSwitch = 0x2e,
|
||||||
|
drvrOffLine = 0x2f,
|
||||||
|
badPathSyntax = 0x40,
|
||||||
|
invalidRefNum = 0x43,
|
||||||
|
pathNotFound = 0x44,
|
||||||
|
volNotFound = 0x45,
|
||||||
|
fileNotFound = 0x46,
|
||||||
|
dupPathName = 0x47,
|
||||||
|
volumeFull = 0x48,
|
||||||
|
volDirFull = 0x49,
|
||||||
|
badFileFormat = 0x4a,
|
||||||
|
badStoreType = 0x4b,
|
||||||
|
eofEncountered = 0x4c,
|
||||||
|
outOfRange = 0x4d,
|
||||||
|
invalidAccess = 0x4e,
|
||||||
|
buffTooSmall = 0x4f,
|
||||||
|
fileBusy = 0x50,
|
||||||
|
dirError = 0x51,
|
||||||
|
unknownVol = 0x52,
|
||||||
|
paramRangeError = 0x53,
|
||||||
|
outOfMem = 0x54,
|
||||||
|
dupVolume = 0x57,
|
||||||
|
notBlockDev = 0x58,
|
||||||
|
invalidLevel = 0x59,
|
||||||
|
damagedBitMap = 0x5a,
|
||||||
|
badPathNames = 0x5b,
|
||||||
|
notSystemFile = 0x5c,
|
||||||
|
osUnsupported = 0x5d,
|
||||||
|
stackOverflow = 0x5f,
|
||||||
|
dataUnavail = 0x60,
|
||||||
|
endOfDir = 0x61,
|
||||||
|
invalidClass = 0x62,
|
||||||
|
resForkNotFound = 0x63,
|
||||||
|
invalidFSTID = 0x64,
|
||||||
|
devNameErr = 0x67,
|
||||||
|
resExistsErr = 0x70,
|
||||||
|
resAddErr = 0x71
|
||||||
|
};
|
||||||
|
|
||||||
|
class Exception : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Exception(const char *cp);
|
||||||
|
Exception(const std::string &str);
|
||||||
|
|
||||||
|
|
||||||
|
virtual ~Exception() throw ();
|
||||||
|
|
||||||
|
virtual const char *what();
|
||||||
|
virtual const char *errorString();
|
||||||
|
|
||||||
|
int error() const { return _error; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Exception(const char *cp, int error);
|
||||||
|
Exception(const std::string& string, int error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _error;
|
||||||
|
std::string _string;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class POSIXException : public Exception {
|
||||||
|
public:
|
||||||
|
POSIXException(const char *cp, int error);
|
||||||
|
POSIXException(const std::string& string, int error);
|
||||||
|
|
||||||
|
virtual const char *errorString();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProDOSException : public Exception {
|
||||||
|
public:
|
||||||
|
ProDOSException(const char *cp, int error);
|
||||||
|
ProDOSException(const std::string& string, int error);
|
||||||
|
|
||||||
|
virtual const char *errorString();
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Exception::Exception(const char *cp):
|
||||||
|
_error(0),
|
||||||
|
_string(cp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Exception::Exception(const std::string& string):
|
||||||
|
_error(0),
|
||||||
|
_string(string)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Exception::Exception(const char *cp, int error):
|
||||||
|
_error(error),
|
||||||
|
_string(cp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Exception::Exception(const std::string& string, int error):
|
||||||
|
_error(error),
|
||||||
|
_string(string)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline POSIXException::POSIXException(const char *cp, int error) :
|
||||||
|
Exception(cp, error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline POSIXException::POSIXException(const std::string& string, int error) :
|
||||||
|
Exception(string, error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ProDOSException::ProDOSException(const char *cp, int error) :
|
||||||
|
Exception(cp, error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ProDOSException::ProDOSException(const std::string& string, int error) :
|
||||||
|
Exception(string, error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
28
ProFUSE/Lock.cpp
Normal file
28
ProFUSE/Lock.cpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#include <ProFUSE/Lock.h>
|
||||||
|
|
||||||
|
using namespace ProFUSE;
|
||||||
|
|
||||||
|
Lock::Lock()
|
||||||
|
{
|
||||||
|
pthread_mutex_init(&_mutex, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock::~Lock()
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lock::lock()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lock::unlock()
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lock::tryLock()
|
||||||
|
{
|
||||||
|
return pthread_mutex_trylock(&_mutex) == 0;
|
||||||
|
}
|
||||||
33
ProFUSE/Lock.h
Normal file
33
ProFUSE/Lock.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef __LOCK_H__
|
||||||
|
#define __LOCK_H__
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace ProFUSE {
|
||||||
|
|
||||||
|
class Lock {
|
||||||
|
public:
|
||||||
|
Lock();
|
||||||
|
~Lock();
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
bool tryLock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
pthread_mutex_t _mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Locker {
|
||||||
|
public:
|
||||||
|
Locker(Lock& lock) : _lock(lock) { _lock.lock(); }
|
||||||
|
~Locker() { _lock.unlock(); }
|
||||||
|
private:
|
||||||
|
Lock &_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
104
ProFUSE/auto.h
Normal file
104
ProFUSE/auto.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#ifndef __AUTO_H__
|
||||||
|
#define __AUTO_H__
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace ProFUSE {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class auto_array
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
auto_array() : _t(NULL) {}
|
||||||
|
auto_array(T *t) : _t(t) {}
|
||||||
|
~auto_array() { if (_t) delete []_t; }
|
||||||
|
|
||||||
|
|
||||||
|
T* release()
|
||||||
|
{ T *tmp = _t; _t = NULL; return tmp; }
|
||||||
|
|
||||||
|
T* get() const { return _t; }
|
||||||
|
operator T*() const { return _t; }
|
||||||
|
T& operator[](int index) { return _t[index]; }
|
||||||
|
|
||||||
|
void reset(T *t)
|
||||||
|
{
|
||||||
|
if (t == _t) return;
|
||||||
|
if (_t) delete[] _t;
|
||||||
|
_t = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T *_t;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ::close
|
||||||
|
#if defined(O_CREAT)
|
||||||
|
class auto_fd
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
auto_fd(int fd = -1) : _fd(fd) { }
|
||||||
|
|
||||||
|
~auto_fd() { close(); }
|
||||||
|
|
||||||
|
int release()
|
||||||
|
{ int tmp = _fd; _fd = -1; return tmp; }
|
||||||
|
|
||||||
|
int get() const { return _fd; }
|
||||||
|
operator int() const { return _fd; }
|
||||||
|
|
||||||
|
void reset(int fd)
|
||||||
|
{
|
||||||
|
if (fd != _fd)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
_fd = fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto_fd& operator=(const auto_fd&);
|
||||||
|
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
if (_fd >= 0)
|
||||||
|
{
|
||||||
|
::close(_fd);
|
||||||
|
_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int _fd;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ::mmap, :munmap
|
||||||
|
#if defined(MAP_FAILED)
|
||||||
|
class auto_map
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
auto_map(void *addr, size_t size, int prot, int flags, int fd, off_t offset)
|
||||||
|
:
|
||||||
|
_size(size),
|
||||||
|
_map(::mmap(addr, size, prot, flags, fd, offset))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~auto_map()
|
||||||
|
{ if (_map != MAP_FAILED) ::munmap(_map, _size); }
|
||||||
|
|
||||||
|
void *release()
|
||||||
|
{ void *tmp = _map; _map = MAP_FAILED; return tmp; }
|
||||||
|
|
||||||
|
void *get() const { return _map; }
|
||||||
|
operator void *() const { return _map; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t _size;
|
||||||
|
void *_map;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
35
ProFUSE/smart_pointers.h
Normal file
35
ProFUSE/smart_pointers.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
#ifndef __PROFUSE_SMART_POINTERS_H__
|
||||||
|
#define __PROFUSE_SMART_POINTERS_H__
|
||||||
|
|
||||||
|
#ifdef CPP0X
|
||||||
|
//C++0x
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
#define SHARED_PTR(T) std::shared_ptr<T>
|
||||||
|
#define WEAK_PTR(T) std::weak_ptr<T>
|
||||||
|
|
||||||
|
#define MAKE_SHARED(T, ...) std::make_shared<T>(__VA_ARGS__)
|
||||||
|
#define ENABLE_SHARED_FROM_THIS(T) std::enable_shared_from_this<T>
|
||||||
|
|
||||||
|
#define STATIC_POINTER_CAST(T, ARG) std::static_pointer_cast<T>(ARG)
|
||||||
|
#define DYNAMIC_POINTER_CAST(T, ARG) std::dynamic_pointer_cast<T>(ARG)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// tr1
|
||||||
|
#include <tr1/memory>
|
||||||
|
|
||||||
|
#define SHARED_PTR(T) std::tr1::shared_ptr<T>
|
||||||
|
#define WEAK_PTR(T) std::tr1::weak_ptr<T>
|
||||||
|
|
||||||
|
#define MAKE_SHARED(T, ...) std::tr1::shared_ptr<T>(new T(__VA_ARGS__))
|
||||||
|
#define ENABLE_SHARED_FROM_THIS(T) std::tr1::enable_shared_from_this<T>
|
||||||
|
|
||||||
|
#define STATIC_POINTER_CAST(T, ARG) std::tr1::static_pointer_cast<T>(ARG)
|
||||||
|
#define DYNAMIC_POINTER_CAST(T, ARG) std::tr1::dynamic_pointer_cast<T>(ARG)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* UniversalDiskImage.cpp
|
|
||||||
* profuse
|
|
||||||
*
|
|
||||||
* Created by Kelvin Sherlock on 1/6/09.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "UniversalDiskImage.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
bool UniversalDiskImage::Load(const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
if (strncmp((const char *)buffer, "2IMG", 4) != 0) return false;
|
|
||||||
|
|
||||||
// all numbers little-endian.
|
|
||||||
|
|
||||||
magic_word = load32(&buffer[0]);
|
|
||||||
|
|
||||||
creator = load32(&buffer[0x04]);
|
|
||||||
|
|
||||||
header_size = load16(&buffer[0x08]);
|
|
||||||
|
|
||||||
version = load16(&buffer[0x0a]);
|
|
||||||
|
|
||||||
image_format = load32(&buffer[0x0c]);
|
|
||||||
|
|
||||||
flags = load32(&buffer[0x10]);
|
|
||||||
|
|
||||||
data_blocks = load32(&buffer[0x14]);
|
|
||||||
|
|
||||||
data_offset = load32(&buffer[0x18]);
|
|
||||||
data_size = load32(&buffer[0x1c]);
|
|
||||||
|
|
||||||
|
|
||||||
comment_offset = load32(&buffer[0x20]);
|
|
||||||
comment_size = load32(&buffer[0x24]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
creator_data_offset = load32(&buffer[0x28]);
|
|
||||||
creator_data_size = load32(&buffer[0x2c]);
|
|
||||||
|
|
||||||
// 16 bytes reserved.
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* UniversalDiskImage.h
|
|
||||||
* profuse
|
|
||||||
*
|
|
||||||
* Created by Kelvin Sherlock on 1/6/09.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __UNIVERSAL_DISK_IMAGE_H__
|
|
||||||
#define __UNIVERSAL_DISK_IMAGE_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define UDI_FORMAT_DOS_ORDER 0
|
|
||||||
#define UDI_FORMAT_PRODOS_ORDER 1
|
|
||||||
#define UDI_FORMAT_NIBBLIZED 2
|
|
||||||
|
|
||||||
struct UniversalDiskImage
|
|
||||||
{
|
|
||||||
bool Load(const uint8_t * buffer);
|
|
||||||
|
|
||||||
uint32_t magic_word;
|
|
||||||
uint32_t creator;
|
|
||||||
unsigned header_size;
|
|
||||||
unsigned version;
|
|
||||||
unsigned image_format;
|
|
||||||
uint32_t flags;
|
|
||||||
unsigned data_blocks;
|
|
||||||
unsigned data_offset;
|
|
||||||
unsigned data_size;
|
|
||||||
unsigned comment_offset;
|
|
||||||
unsigned comment_size;
|
|
||||||
unsigned creator_data_offset;
|
|
||||||
unsigned creator_data_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
30
common.h
30
common.h
@@ -13,36 +13,6 @@
|
|||||||
|
|
||||||
#define BLOCK_SIZE 512
|
#define BLOCK_SIZE 512
|
||||||
|
|
||||||
// little endian.
|
|
||||||
|
|
||||||
inline unsigned load16(const uint8_t *cp)
|
|
||||||
{
|
|
||||||
return (cp[1] << 8 ) | cp[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned load24(const uint8_t *cp)
|
|
||||||
{
|
|
||||||
return (cp[2] << 16 ) | (cp[1] << 8) | (cp[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned load32(const uint8_t *cp)
|
|
||||||
{
|
|
||||||
return (cp[3] << 24) | (cp[2] << 16 ) | (cp[1] << 8) | (cp[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// big endian format.
|
|
||||||
inline unsigned load16_be(const uint8_t *cp)
|
|
||||||
{
|
|
||||||
return (cp[0] << 8) | (cp[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned load32_be(const uint8_t *cp)
|
|
||||||
{
|
|
||||||
return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | (cp[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
189
main.cpp
189
main.cpp
@@ -14,29 +14,39 @@
|
|||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
#include <ctype.h>
|
#include <cctype>
|
||||||
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <tr1/memory>
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
|
||||||
|
|
||||||
#include "profuse.h"
|
#include "profuse.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using std::tr1::shared_ptr;
|
||||||
|
|
||||||
Disk *disk = NULL;
|
|
||||||
char *dfile = NULL;
|
/*
|
||||||
|
* globals variables.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::string fDiskImage;
|
||||||
|
|
||||||
|
|
||||||
|
DiskPointer disk;
|
||||||
VolumeEntry volume;
|
VolumeEntry volume;
|
||||||
|
|
||||||
bool dos_order = false;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool validProdosName(const char *name)
|
bool validProdosName(const char *name)
|
||||||
{
|
{
|
||||||
// OS X looks for hidden files that don't exist (and aren't legal prodos names)
|
// OS X looks for hidden files that don't exist (and aren't legal prodos names)
|
||||||
@@ -70,46 +80,82 @@ static struct fuse_lowlevel_ops prodos_oper;
|
|||||||
enum {
|
enum {
|
||||||
PRODOS_OPT_HELP,
|
PRODOS_OPT_HELP,
|
||||||
PRODOS_OPT_VERSION,
|
PRODOS_OPT_VERSION,
|
||||||
PRODOS_OPT_DOS_ORDER
|
PRODOS_OPT_WRITE,
|
||||||
|
PRODOS_OPT_FORMAT,
|
||||||
|
PRODOS_OPT_VERBOSE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct options {
|
||||||
|
char *format;
|
||||||
|
int readOnly;
|
||||||
|
int readWrite;
|
||||||
|
int verbose;
|
||||||
|
int debug;
|
||||||
|
|
||||||
|
} options;
|
||||||
|
|
||||||
|
#define PRODOS_OPT_KEY(T, P, V) {T, offsetof(struct options, P), V}
|
||||||
|
|
||||||
|
|
||||||
static struct fuse_opt prodos_opts[] = {
|
static struct fuse_opt prodos_opts[] = {
|
||||||
FUSE_OPT_KEY("-h", PRODOS_OPT_HELP),
|
FUSE_OPT_KEY("-h", PRODOS_OPT_HELP),
|
||||||
FUSE_OPT_KEY("--help", PRODOS_OPT_HELP),
|
FUSE_OPT_KEY("--help", PRODOS_OPT_HELP),
|
||||||
|
|
||||||
FUSE_OPT_KEY("-V", PRODOS_OPT_VERSION),
|
FUSE_OPT_KEY("-V", PRODOS_OPT_VERSION),
|
||||||
FUSE_OPT_KEY("--version", PRODOS_OPT_VERSION),
|
FUSE_OPT_KEY("--version", PRODOS_OPT_VERSION),
|
||||||
FUSE_OPT_KEY("--dos-order", PRODOS_OPT_DOS_ORDER),
|
|
||||||
|
PRODOS_OPT_KEY("-v", verbose, 1),
|
||||||
|
|
||||||
|
PRODOS_OPT_KEY("-w", readWrite, 1),
|
||||||
|
PRODOS_OPT_KEY("rw", readWrite, 1),
|
||||||
|
|
||||||
|
PRODOS_OPT_KEY("-d", debug, 1),
|
||||||
|
|
||||||
|
PRODOS_OPT_KEY("--format=%s", format, 0),
|
||||||
|
PRODOS_OPT_KEY("format=%s", format, 0),
|
||||||
{0, 0, 0}
|
{0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usage()
|
static void usage()
|
||||||
{
|
{
|
||||||
fprintf(stderr, "profuse [options] disk_image mountpoint\n");
|
fprintf(stderr, "profuse [options] disk_image [mountpoint]\n"
|
||||||
|
|
||||||
|
"Options:\n"
|
||||||
|
" -d debug\n"
|
||||||
|
" -r readonly\n"
|
||||||
|
" -w mount writable [not yet]\n"
|
||||||
|
" -v verbose\n"
|
||||||
|
" --format=format specify the disk image format. Valid values are:\n"
|
||||||
|
" dc42 DiskCopy 4.2 Image\n"
|
||||||
|
" davex Davex Disk Image\n"
|
||||||
|
" sdk ShrinkIt Disk Image\n"
|
||||||
|
" 2img Universal Disk Image\n"
|
||||||
|
" do DOS Order Disk Image\n"
|
||||||
|
" po ProDOS Order Disk Image (default)\n"
|
||||||
|
" -o opt1,opt2... other mount parameters.\n"
|
||||||
|
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prodos_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs)
|
static int prodos_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs)
|
||||||
{
|
{
|
||||||
switch(key)
|
switch(key)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
case PRODOS_OPT_HELP:
|
case PRODOS_OPT_HELP:
|
||||||
usage();
|
usage();
|
||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
*/
|
|
||||||
case PRODOS_OPT_VERSION:
|
case PRODOS_OPT_VERSION:
|
||||||
// TODO
|
// TODO
|
||||||
exit(1);
|
exit(1);
|
||||||
break;
|
break;
|
||||||
case PRODOS_OPT_DOS_ORDER:
|
|
||||||
dos_order = true;
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FUSE_OPT_KEY_NONOPT:
|
case FUSE_OPT_KEY_NONOPT:
|
||||||
if (dfile == NULL)
|
// first arg is the disk image.
|
||||||
|
if (fDiskImage.empty())
|
||||||
{
|
{
|
||||||
dfile = strdup(arg);
|
fDiskImage = arg;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -159,15 +205,25 @@ int main(int argc, char *argv[])
|
|||||||
struct fuse_chan *ch;
|
struct fuse_chan *ch;
|
||||||
char *mountpoint = NULL;
|
char *mountpoint = NULL;
|
||||||
int err = -1;
|
int err = -1;
|
||||||
|
struct options options;
|
||||||
|
|
||||||
|
unsigned format = 0;
|
||||||
|
|
||||||
|
int foreground = false;
|
||||||
|
int multithread = false;
|
||||||
|
|
||||||
|
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
string mountpath;
|
string mountpath;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
disk = NULL;
|
|
||||||
|
|
||||||
bzero(&prodos_oper, sizeof(prodos_oper));
|
|
||||||
|
std::memset(&prodos_oper, 0, sizeof(prodos_oper));
|
||||||
|
|
||||||
|
std::memset(&options, 0, sizeof(options));
|
||||||
|
|
||||||
|
|
||||||
prodos_oper.listxattr = prodos_listxattr;
|
prodos_oper.listxattr = prodos_listxattr;
|
||||||
prodos_oper.getxattr = prodos_getxattr;
|
prodos_oper.getxattr = prodos_getxattr;
|
||||||
@@ -183,25 +239,54 @@ int main(int argc, char *argv[])
|
|||||||
prodos_oper.release = prodos_release;
|
prodos_oper.release = prodos_release;
|
||||||
prodos_oper.read = prodos_read;
|
prodos_oper.read = prodos_read;
|
||||||
|
|
||||||
|
prodos_oper.statfs = prodos_statfs;
|
||||||
|
|
||||||
|
|
||||||
// scan the argument list, looking for the name of the disk image.
|
// scan the argument list, looking for the name of the disk image.
|
||||||
if (fuse_opt_parse(&args, NULL , prodos_opts, prodos_opt_proc) == -1)
|
if (fuse_opt_parse(&args, &options , prodos_opts, prodos_opt_proc) == -1)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
if (dfile == NULL || *dfile == 0)
|
if (fDiskImage.empty())
|
||||||
{
|
{
|
||||||
usage();
|
usage();
|
||||||
exit(0);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
disk = Disk::OpenFile(dfile, dos_order);
|
// default prodos-order disk image.
|
||||||
|
if (options.format)
|
||||||
if (!disk)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Unable to mount disk %s\n", dfile);
|
format = Device::BlockDevice::ImageType(options.format);
|
||||||
exit(1);
|
if (!format)
|
||||||
}
|
std::fprintf(stderr, "Warning: Unknown image type ``%s''\n", options.format);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Device::BlockDevicePointer device;
|
||||||
|
|
||||||
|
device = Device::BlockDevice::Open(fDiskImage.c_str(), File::ReadOnly, format);
|
||||||
|
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
std::fprintf(stderr, "Error: Unknown or unsupported device type.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
disk = Disk::OpenFile(device);
|
||||||
|
|
||||||
|
if (!disk)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to mount disk %s\n", fDiskImage.c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (ProFUSE::Exception &e)
|
||||||
|
{
|
||||||
|
std::fprintf(stderr, "%s\n", e.what());
|
||||||
|
std::fprintf(stderr, "%s\n", e.errorString());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
disk->ReadVolume(&volume, NULL);
|
disk->ReadVolume(&volume, NULL);
|
||||||
@@ -235,6 +320,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
foreground = options.debug;
|
||||||
|
|
||||||
|
|
||||||
if (mountpoint == NULL || *mountpoint == 0)
|
if (mountpoint == NULL || *mountpoint == 0)
|
||||||
@@ -244,26 +330,32 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ( (ch = fuse_mount(mountpoint, &args)) != NULL)
|
if ( (ch = fuse_mount(mountpoint, &args)) != NULL)
|
||||||
{
|
{
|
||||||
struct fuse_session *se;
|
struct fuse_session *se;
|
||||||
|
|
||||||
se = fuse_lowlevel_new(&args, &prodos_oper, sizeof(prodos_oper), NULL);
|
se = fuse_lowlevel_new(&args, &prodos_oper, sizeof(prodos_oper), NULL);
|
||||||
if (se != NULL)
|
if (se != NULL) do {
|
||||||
{
|
|
||||||
if (fuse_set_signal_handlers(se) != -1)
|
err = fuse_daemonize(foreground);
|
||||||
{
|
if (err < 0 ) break;
|
||||||
fuse_session_add_chan(se, ch);
|
|
||||||
err = fuse_session_loop(se);
|
|
||||||
fuse_remove_signal_handlers(se);
|
|
||||||
fuse_session_remove_chan(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
fuse_session_destroy(se);
|
err = fuse_set_signal_handlers(se);
|
||||||
}
|
if (err < 0) break;
|
||||||
|
|
||||||
|
|
||||||
|
fuse_session_add_chan(se, ch);
|
||||||
|
|
||||||
|
if (multithread) err = fuse_session_loop_mt(se);
|
||||||
|
else err = fuse_session_loop(se);
|
||||||
|
|
||||||
|
fuse_remove_signal_handlers(se);
|
||||||
|
fuse_session_remove_chan(ch);
|
||||||
|
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
if (se) fuse_session_destroy(se);
|
||||||
fuse_unmount(mountpoint, ch);
|
fuse_unmount(mountpoint, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,9 +363,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
fuse_opt_free_args(&args);
|
fuse_opt_free_args(&args);
|
||||||
|
|
||||||
if (disk) delete disk;
|
disk.reset();
|
||||||
|
|
||||||
if (dfile) free(dfile);
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (mountpath.size()) rmdir(mountpath.c_str());
|
if (mountpath.size()) rmdir(mountpath.c_str());
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#ifndef __PROFUSE_H__
|
#ifndef __PROFUSE_H__
|
||||||
#define __PROFUSE_H__
|
#define __PROFUSE_H__
|
||||||
|
|
||||||
#include "File.h"
|
#include <ProDOS/File.h>
|
||||||
#include "Disk.h"
|
#include "Disk.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
#define ERROR(cond,errno) if ( (cond) ){ fuse_reply_err(req, errno); return; }
|
#define ERROR(cond,errno) if ( (cond) ){ fuse_reply_err(req, errno); return; }
|
||||||
|
|
||||||
|
|
||||||
extern Disk *disk;
|
extern DiskPointer disk;
|
||||||
|
|
||||||
bool validProdosName(const char *name);
|
bool validProdosName(const char *name);
|
||||||
|
|
||||||
@@ -40,6 +40,9 @@ void prodos_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, stru
|
|||||||
void prodos_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
|
void prodos_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
|
||||||
void prodos_lookup(fuse_req_t req, fuse_ino_t parent, const char *name);
|
void prodos_lookup(fuse_req_t req, fuse_ino_t parent, const char *name);
|
||||||
|
|
||||||
|
void prodos_statfs(fuse_req_t req, fuse_ino_t ino);
|
||||||
|
|
||||||
|
|
||||||
// file io.
|
// file io.
|
||||||
void prodos_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
|
void prodos_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
|
||||||
void prodos_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
|
void prodos_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||||
activeArchitecturePreference = i386;
|
activeArchitecturePreference = i386;
|
||||||
activeBuildConfigurationName = "Debug 10.6";
|
activeBuildConfigurationName = "Debug Universal";
|
||||||
activeExecutable = B60E914A0EFB3612000E4348 /* profuse */;
|
activeExecutable = B60E914A0EFB3612000E4348 /* profuse */;
|
||||||
activeSDKPreference = macosx10.6;
|
activeSDKPreference = macosx10.6;
|
||||||
activeTarget = 8DD76F620486A84900D96B5E /* profuse */;
|
activeTarget = 8DD76F620486A84900D96B5E /* profuse */;
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
);
|
);
|
||||||
breakpoints = (
|
breakpoints = (
|
||||||
B60E91C10EFD8049000E4348 /* xmain.cpp:129 */,
|
B60E91C10EFD8049000E4348 /* xmain.cpp:129 */,
|
||||||
B60E92720EFDA086000E4348 /* File.cpp:74 */,
|
|
||||||
B6D81E5B0EFDE859000219B7 /* xmain.cpp:163 */,
|
B6D81E5B0EFDE859000219B7 /* xmain.cpp:163 */,
|
||||||
B6AE1CFF0F0335FC00D36ADB /* main.cpp:20 */,
|
B6AE1CFF0F0335FC00D36ADB /* main.cpp:20 */,
|
||||||
);
|
);
|
||||||
@@ -40,7 +39,7 @@
|
|||||||
PBXFileTableDataSourceColumnWidthsKey = (
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
22,
|
22,
|
||||||
300,
|
300,
|
||||||
742,
|
583,
|
||||||
);
|
);
|
||||||
PBXFileTableDataSourceColumnsKey = (
|
PBXFileTableDataSourceColumnsKey = (
|
||||||
PBXExecutablesDataSource_ActiveFlagID,
|
PBXExecutablesDataSource_ActiveFlagID,
|
||||||
@@ -53,7 +52,7 @@
|
|||||||
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
||||||
PBXFileTableDataSourceColumnWidthsKey = (
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
20,
|
20,
|
||||||
854,
|
695,
|
||||||
20,
|
20,
|
||||||
48,
|
48,
|
||||||
43,
|
43,
|
||||||
@@ -99,7 +98,7 @@
|
|||||||
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
||||||
PBXFileTableDataSourceColumnWidthsKey = (
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
20,
|
20,
|
||||||
665,
|
655,
|
||||||
60,
|
60,
|
||||||
20,
|
20,
|
||||||
48,
|
48,
|
||||||
@@ -116,33 +115,27 @@
|
|||||||
PBXFileDataSource_Warnings_ColumnID,
|
PBXFileDataSource_Warnings_ColumnID,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
PBXPerProjectTemplateStateSaveDate = 274161393;
|
PBXPerProjectTemplateStateSaveDate = 320562725;
|
||||||
PBXWorkspaceStateSaveDate = 274161393;
|
PBXWorkspaceStateSaveDate = 320562725;
|
||||||
};
|
};
|
||||||
perUserProjectItems = {
|
perUserProjectItems = {
|
||||||
B6108A660FDA0E0700D2D63B = B6108A660FDA0E0700D2D63B /* PBXTextBookmark */;
|
B61BCF86131B6627002DE159 /* PBXTextBookmark */ = B61BCF86131B6627002DE159 /* PBXTextBookmark */;
|
||||||
B642F1540F133632001F7696 = B642F1540F133632001F7696 /* PBXTextBookmark */;
|
B61BCF96131B6643002DE159 /* PBXTextBookmark */ = B61BCF96131B6643002DE159 /* PBXTextBookmark */;
|
||||||
B642F16A0F1341D4001F7696 = B642F16A0F1341D4001F7696 /* PBXTextBookmark */;
|
B61BCF97131B6643002DE159 /* PBXBookmark */ = B61BCF97131B6643002DE159 /* PBXBookmark */;
|
||||||
B64E307E0F2C0D2F000543FE = B64E307E0F2C0D2F000543FE /* PBXTextBookmark */;
|
B61BCF98131B6643002DE159 /* PBXTextBookmark */ = B61BCF98131B6643002DE159 /* PBXTextBookmark */;
|
||||||
B64E309A0F2CD8F2000543FE = B64E309A0F2CD8F2000543FE /* PBXTextBookmark */;
|
B61BCFA3131B6741002DE159 /* PBXTextBookmark */ = B61BCFA3131B6741002DE159 /* PBXTextBookmark */;
|
||||||
B6706BEC10575D48004C8120 = B6706BEC10575D48004C8120 /* PBXTextBookmark */;
|
B61BCFA4131B6741002DE159 /* XCBuildMessageTextBookmark */ = B61BCFA4131B6741002DE159 /* XCBuildMessageTextBookmark */;
|
||||||
B67F097510575F0E00A13214 /* PBXTextBookmark */ = B67F097510575F0E00A13214 /* PBXTextBookmark */;
|
B61BCFA5131B6741002DE159 /* PBXTextBookmark */ = B61BCFA5131B6741002DE159 /* PBXTextBookmark */;
|
||||||
B67F09AC1057622100A13214 /* PBXTextBookmark */ = B67F09AC1057622100A13214 /* PBXTextBookmark */;
|
B6A53BB3131A17AF00C9070F = B6A53BB3131A17AF00C9070F /* PBXTextBookmark */;
|
||||||
B67F09AD1057622100A13214 /* PBXTextBookmark */ = B67F09AD1057622100A13214 /* PBXTextBookmark */;
|
B6A53BE3131B434600C9070F = B6A53BE3131B434600C9070F /* PBXTextBookmark */;
|
||||||
B67F09AE1057622100A13214 /* PBXTextBookmark */ = B67F09AE1057622100A13214 /* PBXTextBookmark */;
|
B6A53BE4131B434600C9070F = B6A53BE4131B434600C9070F /* PBXTextBookmark */;
|
||||||
B67F09AF1057622100A13214 /* XCBuildMessageTextBookmark */ = B67F09AF1057622100A13214 /* XCBuildMessageTextBookmark */;
|
B6A53C48131B634600C9070F = B6A53C48131B634600C9070F /* PBXTextBookmark */;
|
||||||
B67F09B01057622100A13214 /* PBXTextBookmark */ = B67F09B01057622100A13214 /* PBXTextBookmark */;
|
B6A53C49131B634600C9070F = B6A53C49131B634600C9070F /* PBXTextBookmark */;
|
||||||
B6B767C80F0FFA3900D819C9 = B6B767C80F0FFA3900D819C9 /* PBXTextBookmark */;
|
B6A53C4A131B634600C9070F = B6A53C4A131B634600C9070F /* PBXTextBookmark */;
|
||||||
B6C786E50F2A5FF300053681 = B6C786E50F2A5FF300053681 /* PBXTextBookmark */;
|
B6A53C4B131B634600C9070F = B6A53C4B131B634600C9070F /* PBXTextBookmark */;
|
||||||
B6C786EE0F2A612600053681 = B6C786EE0F2A612600053681 /* PBXTextBookmark */;
|
B6A53C4C131B634600C9070F = B6A53C4C131B634600C9070F /* PBXTextBookmark */;
|
||||||
B6C786EF0F2A612600053681 = B6C786EF0F2A612600053681 /* PBXTextBookmark */;
|
B6A53C4D131B634600C9070F = B6A53C4D131B634600C9070F /* PBXTextBookmark */;
|
||||||
B6C786F70F2A64CC00053681 = B6C786F70F2A64CC00053681 /* PBXTextBookmark */;
|
B6A53C4E131B634600C9070F = B6A53C4E131B634600C9070F /* PBXTextBookmark */;
|
||||||
B6C786F90F2A64CC00053681 = B6C786F90F2A64CC00053681 /* PBXTextBookmark */;
|
|
||||||
B6C786FA0F2A64CC00053681 = B6C786FA0F2A64CC00053681 /* PBXTextBookmark */;
|
|
||||||
B6DA6C190FA6AFE90027FC1D = B6DA6C190FA6AFE90027FC1D /* PBXTextBookmark */;
|
|
||||||
B6E345420F2BB60B00B7FC78 = B6E345420F2BB60B00B7FC78 /* PBXTextBookmark */;
|
|
||||||
B6E345610F2BC07F00B7FC78 = B6E345610F2BC07F00B7FC78 /* PBXTextBookmark */;
|
|
||||||
B6F4740F0F2ACB4700CB75DA = B6F4740F0F2ACB4700CB75DA /* PBXTextBookmark */;
|
|
||||||
};
|
};
|
||||||
sourceControlManager = B60E91500EFB3628000E4348 /* Source Control */;
|
sourceControlManager = B60E91500EFB3628000E4348 /* Source Control */;
|
||||||
userBuildSettings = {
|
userBuildSettings = {
|
||||||
@@ -197,22 +190,6 @@
|
|||||||
"xcase-unsigned int-FileEntry::FileEntry" = 3;
|
"xcase-unsigned int-FileEntry::FileEntry" = 3;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
B60E914D0EFB3627000E4348 /* File.h */ = {
|
|
||||||
uiCtxt = {
|
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {996, 1974}}";
|
|
||||||
sepNavSelRange = "{273, 23}";
|
|
||||||
sepNavVisRange = "{0, 1003}";
|
|
||||||
sepNavWindowFrame = "{{95, -86}, {555, 1173}}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
B60E914E0EFB3628000E4348 /* File.cpp */ = {
|
|
||||||
uiCtxt = {
|
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1032, 2977}}";
|
|
||||||
sepNavSelRange = "{3323, 0}";
|
|
||||||
sepNavVisRange = "{1039, 1166}";
|
|
||||||
sepNavWindowFrame = "{{667, -9}, {555, 1173}}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
B60E91500EFB3628000E4348 /* Source Control */ = {
|
B60E91500EFB3628000E4348 /* Source Control */ = {
|
||||||
isa = PBXSourceControlManager;
|
isa = PBXSourceControlManager;
|
||||||
fallbackIsa = XCSourceControlManager;
|
fallbackIsa = XCSourceControlManager;
|
||||||
@@ -230,9 +207,9 @@
|
|||||||
};
|
};
|
||||||
B60E91530EFB51FE000E4348 /* Disk.h */ = {
|
B60E91530EFB51FE000E4348 /* Disk.h */ = {
|
||||||
uiCtxt = {
|
uiCtxt = {
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1250, 1092}}";
|
sepNavIntBoundsRect = "{{0, 0}, {1245, 1092}}";
|
||||||
sepNavSelRange = "{1300, 0}";
|
sepNavSelRange = "{1156, 11}";
|
||||||
sepNavVisRange = "{178, 1128}";
|
sepNavVisRange = "{76, 1374}";
|
||||||
sepNavWindowFrame = "{{77, 7}, {692, 1171}}";
|
sepNavWindowFrame = "{{77, 7}, {692, 1171}}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -270,180 +247,197 @@
|
|||||||
originalNumberOfMultipleMatches = 0;
|
originalNumberOfMultipleMatches = 0;
|
||||||
state = 2;
|
state = 2;
|
||||||
};
|
};
|
||||||
B60E92720EFDA086000E4348 /* File.cpp:74 */ = {
|
B61BCF86131B6627002DE159 /* PBXTextBookmark */ = {
|
||||||
isa = PBXFileBreakpoint;
|
|
||||||
actions = (
|
|
||||||
);
|
|
||||||
breakpointStyle = 0;
|
|
||||||
continueAfterActions = 0;
|
|
||||||
countType = 0;
|
|
||||||
delayBeforeContinue = 0;
|
|
||||||
fileReference = B60E914E0EFB3628000E4348 /* File.cpp */;
|
|
||||||
functionName = "FileEntry::FileEntry(const void *data)";
|
|
||||||
hitCount = 0;
|
|
||||||
ignoreCount = 0;
|
|
||||||
lineNumber = 74;
|
|
||||||
location = "ProDOS-Fuse";
|
|
||||||
modificationTime = 251949619.113693;
|
|
||||||
originalNumberOfMultipleMatches = 0;
|
|
||||||
state = 2;
|
|
||||||
};
|
|
||||||
B6108A660FDA0E0700D2D63B /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
|
fRef = B6DA7037131047D100E42AA6 /* DiskCopy42Image.cpp */;
|
||||||
name = "profuse_xattr.cpp: 178";
|
name = "DiskCopy42Image.cpp: 49";
|
||||||
rLen = 0;
|
rLen = 12;
|
||||||
rLoc = 4165;
|
rLoc = 763;
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 1035;
|
vrLen = 851;
|
||||||
vrLoc = 3525;
|
vrLoc = 395;
|
||||||
};
|
};
|
||||||
B642F1290F132FA3001F7696 /* UniversalDiskImage.h */ = {
|
B61BCF8F131B6633002DE159 /* smart_pointers.h */ = {
|
||||||
uiCtxt = {
|
uiCtxt = {
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1250, 831}}";
|
sepNavIntBoundsRect = "{{0, 0}, {873, 521}}";
|
||||||
sepNavSelRange = "{217, 34}";
|
sepNavSelRange = "{0, 0}";
|
||||||
sepNavVisRange = "{0, 708}";
|
sepNavVisRange = "{0, 903}";
|
||||||
sepNavWindowFrame = "{{15, 249}, {1412, 924}}";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */ = {
|
B61BCF96131B6643002DE159 /* PBXTextBookmark */ = {
|
||||||
uiCtxt = {
|
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1250, 831}}";
|
|
||||||
sepNavSelRange = "{820, 0}";
|
|
||||||
sepNavVisRange = "{0, 966}";
|
|
||||||
sepNavWindowFrame = "{{668, 219}, {1412, 924}}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
B642F1540F133632001F7696 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B6B17FA00F1138830060F7AA /* DiskCopy42.h */;
|
fRef = B6DA7037131047D100E42AA6 /* DiskCopy42Image.cpp */;
|
||||||
name = "DiskCopy42.h: 1";
|
name = "DiskCopy42Image.cpp: 49";
|
||||||
|
rLen = 12;
|
||||||
|
rLoc = 763;
|
||||||
|
rType = 0;
|
||||||
|
vrLen = 851;
|
||||||
|
vrLoc = 395;
|
||||||
|
};
|
||||||
|
B61BCF97131B6643002DE159 /* PBXBookmark */ = {
|
||||||
|
isa = PBXBookmark;
|
||||||
|
fRef = B61BCF8F131B6633002DE159 /* smart_pointers.h */;
|
||||||
|
};
|
||||||
|
B61BCF98131B6643002DE159 /* PBXTextBookmark */ = {
|
||||||
|
isa = PBXTextBookmark;
|
||||||
|
fRef = B61BCF8F131B6633002DE159 /* smart_pointers.h */;
|
||||||
|
name = "smart_pointers.h: 1";
|
||||||
rLen = 0;
|
rLen = 0;
|
||||||
rLoc = 0;
|
rLoc = 0;
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 355;
|
vrLen = 903;
|
||||||
vrLoc = 0;
|
vrLoc = 0;
|
||||||
};
|
};
|
||||||
B642F16A0F1341D4001F7696 /* PBXTextBookmark */ = {
|
B61BCFA3131B6741002DE159 /* PBXTextBookmark */ = {
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B60E91580EFD77E3000E4348 /* common.h */;
|
fRef = B61BCF8F131B6633002DE159 /* smart_pointers.h */;
|
||||||
name = "common.h: 40";
|
name = "smart_pointers.h: 1";
|
||||||
rLen = 0;
|
rLen = 0;
|
||||||
rLoc = 627;
|
rLoc = 0;
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 313;
|
vrLen = 903;
|
||||||
vrLoc = 0;
|
vrLoc = 0;
|
||||||
};
|
};
|
||||||
B64E307E0F2C0D2F000543FE /* PBXTextBookmark */ = {
|
B61BCFA4131B6741002DE159 /* XCBuildMessageTextBookmark */ = {
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B60E914E0EFB3628000E4348 /* File.cpp */;
|
comments = "No matching function for call to 'std::tr1::shared_ptr<Device::BlockDevice>::reset(Device::BlockDevicePointer)'";
|
||||||
name = "File.cpp: 156";
|
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
|
||||||
rLen = 0;
|
fallbackIsa = XCBuildMessageTextBookmark;
|
||||||
rLoc = 3323;
|
rLen = 1;
|
||||||
rType = 0;
|
rLoc = 264;
|
||||||
vrLen = 523;
|
rType = 1;
|
||||||
vrLoc = 1285;
|
|
||||||
};
|
};
|
||||||
B64E309A0F2CD8F2000543FE /* PBXTextBookmark */ = {
|
B61BCFA5131B6741002DE159 /* PBXTextBookmark */ = {
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B60E914D0EFB3627000E4348 /* File.h */;
|
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
|
||||||
name = "File.h: 30";
|
name = "main.cpp: 275";
|
||||||
rLen = 0;
|
rLen = 0;
|
||||||
rLoc = 414;
|
rLoc = 5894;
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 440;
|
vrLen = 1313;
|
||||||
vrLoc = 1197;
|
vrLoc = 1695;
|
||||||
};
|
};
|
||||||
B6706BEC10575D48004C8120 /* PBXTextBookmark */ = {
|
B650C2C3131090D200046FAD /* File.cpp */ = {
|
||||||
isa = PBXTextBookmark;
|
uiCtxt = {
|
||||||
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
|
sepNavIntBoundsRect = "{{0, 0}, {1245, 2990}}";
|
||||||
name = "profuse_xattr.cpp: 178";
|
sepNavSelRange = "{0, 0}";
|
||||||
rLen = 0;
|
sepNavVisRange = "{1306, 1844}";
|
||||||
rLoc = 4165;
|
};
|
||||||
rType = 0;
|
};
|
||||||
vrLen = 1154;
|
B650C2C4131090D200046FAD /* File.h */ = {
|
||||||
vrLoc = 3442;
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {1245, 1742}}";
|
||||||
|
sepNavSelRange = "{1591, 0}";
|
||||||
|
sepNavVisRange = "{864, 1333}";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
B679E4A70F02E79300FB3F0C /* main.cpp */ = {
|
B679E4A70F02E79300FB3F0C /* main.cpp */ = {
|
||||||
uiCtxt = {
|
uiCtxt = {
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {759, 3948}}";
|
sepNavIntBoundsRect = "{{0, 0}, {873, 4888}}";
|
||||||
sepNavSelRange = "{1950, 0}";
|
sepNavSelRange = "{5894, 0}";
|
||||||
sepNavVisRange = "{3049, 226}";
|
sepNavVisRange = "{1695, 1313}";
|
||||||
sepNavWindowFrame = "{{342, 156}, {1412, 924}}";
|
sepNavWindowFrame = "{{342, 156}, {1412, 924}}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
B67F097510575F0E00A13214 /* PBXTextBookmark */ = {
|
B6A53BB3131A17AF00C9070F /* PBXTextBookmark */ = {
|
||||||
|
isa = PBXTextBookmark;
|
||||||
|
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
|
||||||
|
name = "main.cpp: 253";
|
||||||
|
rLen = 11;
|
||||||
|
rLoc = 4534;
|
||||||
|
rType = 0;
|
||||||
|
vrLen = 241;
|
||||||
|
vrLoc = 4525;
|
||||||
|
};
|
||||||
|
B6A53BE3131B434600C9070F /* PBXTextBookmark */ = {
|
||||||
|
isa = PBXTextBookmark;
|
||||||
|
fRef = B60E91530EFB51FE000E4348 /* Disk.h */;
|
||||||
|
name = "Disk.h: 70";
|
||||||
|
rLen = 0;
|
||||||
|
rLoc = 1300;
|
||||||
|
rType = 0;
|
||||||
|
vrLen = 269;
|
||||||
|
vrLoc = 1042;
|
||||||
|
};
|
||||||
|
B6A53BE4131B434600C9070F /* PBXTextBookmark */ = {
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
|
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
|
||||||
name = "profuse_xattr.cpp: 178";
|
name = "profuse_xattr.cpp: 56";
|
||||||
rLen = 0;
|
rLen = 5;
|
||||||
rLoc = 4165;
|
rLoc = 1034;
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 1073;
|
vrLen = 1279;
|
||||||
vrLoc = 3523;
|
vrLoc = 998;
|
||||||
};
|
};
|
||||||
B67F097810575F8300A13214 /* DateTime.cpp */ = {
|
B6A53C48131B634600C9070F /* PBXTextBookmark */ = {
|
||||||
uiCtxt = {
|
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1032, 1924}}";
|
|
||||||
sepNavSelRange = "{0, 0}";
|
|
||||||
sepNavVisRange = "{0, 1083}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
B67F097A10575FD900A13214 /* DateTime.h */ = {
|
|
||||||
uiCtxt = {
|
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1032, 1170}}";
|
|
||||||
sepNavSelRange = "{0, 0}";
|
|
||||||
sepNavVisRange = "{0, 947}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
B67F09AC1057622100A13214 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B67F097A10575FD900A13214 /* DateTime.h */;
|
fRef = B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */;
|
||||||
name = "DateTime.h: 1";
|
name = "profuse_stat.cpp: 167";
|
||||||
|
rLen = 0;
|
||||||
|
rLoc = 3263;
|
||||||
|
rType = 0;
|
||||||
|
vrLen = 1000;
|
||||||
|
vrLoc = 2706;
|
||||||
|
};
|
||||||
|
B6A53C49131B634600C9070F /* PBXTextBookmark */ = {
|
||||||
|
isa = PBXTextBookmark;
|
||||||
|
fRef = B6DA703E131047D100E42AA6 /* UniversalDiskImage.cpp */;
|
||||||
|
name = "UniversalDiskImage.cpp: 1";
|
||||||
rLen = 0;
|
rLen = 0;
|
||||||
rLoc = 0;
|
rLoc = 0;
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 947;
|
vrLen = 807;
|
||||||
vrLoc = 0;
|
vrLoc = 0;
|
||||||
};
|
};
|
||||||
B67F09AD1057622100A13214 /* PBXTextBookmark */ = {
|
B6A53C4A131B634600C9070F /* PBXTextBookmark */ = {
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B67F097810575F8300A13214 /* DateTime.cpp */;
|
fRef = B6DA7035131047D100E42AA6 /* DavexDiskImage.cpp */;
|
||||||
name = "DateTime.cpp: 1";
|
name = "DavexDiskImage.cpp: 56";
|
||||||
|
rLen = 12;
|
||||||
|
rLoc = 1104;
|
||||||
|
rType = 0;
|
||||||
|
vrLen = 856;
|
||||||
|
vrLoc = 684;
|
||||||
|
};
|
||||||
|
B6A53C4B131B634600C9070F /* PBXTextBookmark */ = {
|
||||||
|
isa = PBXTextBookmark;
|
||||||
|
fRef = B6DA703A131047D100E42AA6 /* DiskImage.h */;
|
||||||
|
name = "DiskImage.h: 1";
|
||||||
rLen = 0;
|
rLen = 0;
|
||||||
rLoc = 0;
|
rLoc = 0;
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 1083;
|
vrLen = 756;
|
||||||
vrLoc = 0;
|
vrLoc = 0;
|
||||||
};
|
};
|
||||||
B67F09AE1057622100A13214 /* PBXTextBookmark */ = {
|
B6A53C4C131B634600C9070F /* PBXTextBookmark */ = {
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
fRef = B60E914E0EFB3628000E4348 /* File.cpp */;
|
fRef = B6DA7038131047D100E42AA6 /* DiskCopy42Image.h */;
|
||||||
name = "File.cpp: 151";
|
name = "DiskCopy42Image.h: 1";
|
||||||
rLen = 0;
|
rLen = 0;
|
||||||
rLoc = 3323;
|
rLoc = 0;
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 1166;
|
vrLen = 778;
|
||||||
vrLoc = 1039;
|
vrLoc = 0;
|
||||||
};
|
};
|
||||||
B67F09AF1057622100A13214 /* XCBuildMessageTextBookmark */ = {
|
B6A53C4D131B634600C9070F /* PBXTextBookmark */ = {
|
||||||
isa = PBXTextBookmark;
|
isa = PBXTextBookmark;
|
||||||
comments = "Format '%u' expects type 'unsigned int', but argument 3 has type 'fuse_ino_t'";
|
fRef = B6DA7037131047D100E42AA6 /* DiskCopy42Image.cpp */;
|
||||||
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
|
name = "DiskCopy42Image.cpp: 49";
|
||||||
fallbackIsa = XCBuildMessageTextBookmark;
|
rLen = 12;
|
||||||
rLen = 1;
|
rLoc = 763;
|
||||||
rLoc = 377;
|
|
||||||
rType = 1;
|
|
||||||
};
|
|
||||||
B67F09B01057622100A13214 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
|
|
||||||
name = "profuse_xattr.cpp: 378";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 8340;
|
|
||||||
rType = 0;
|
rType = 0;
|
||||||
vrLen = 948;
|
vrLen = 851;
|
||||||
vrLoc = 7739;
|
vrLoc = 395;
|
||||||
|
};
|
||||||
|
B6A53C4E131B634600C9070F /* PBXTextBookmark */ = {
|
||||||
|
isa = PBXTextBookmark;
|
||||||
|
fRef = B6DA7037131047D100E42AA6 /* DiskCopy42Image.cpp */;
|
||||||
|
name = "DiskCopy42Image.cpp: 49";
|
||||||
|
rLen = 12;
|
||||||
|
rLoc = 763;
|
||||||
|
rType = 0;
|
||||||
|
vrLen = 851;
|
||||||
|
vrLoc = 395;
|
||||||
};
|
};
|
||||||
B6AE1CFF0F0335FC00D36ADB /* main.cpp:20 */ = {
|
B6AE1CFF0F0335FC00D36ADB /* main.cpp:20 */ = {
|
||||||
isa = PBXFileBreakpoint;
|
isa = PBXFileBreakpoint;
|
||||||
@@ -463,51 +457,18 @@
|
|||||||
originalNumberOfMultipleMatches = 0;
|
originalNumberOfMultipleMatches = 0;
|
||||||
state = 2;
|
state = 2;
|
||||||
};
|
};
|
||||||
B6B17F820F103AA70060F7AA /* fuse_common.h */ = {
|
|
||||||
isa = PBXFileReference;
|
|
||||||
lastKnownFileType = sourcecode.c.h;
|
|
||||||
name = fuse_common.h;
|
|
||||||
path = /usr/local/include/fuse/fuse_common.h;
|
|
||||||
sourceTree = "<absolute>";
|
|
||||||
};
|
|
||||||
B6B17FA00F1138830060F7AA /* DiskCopy42.h */ = {
|
|
||||||
uiCtxt = {
|
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1353, 796}}";
|
|
||||||
sepNavSelRange = "{226, 0}";
|
|
||||||
sepNavVisRange = "{0, 434}";
|
|
||||||
sepNavWindowFrame = "{{310, 58}, {1412, 924}}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */ = {
|
|
||||||
uiCtxt = {
|
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {883, 616}}";
|
|
||||||
sepNavSelRange = "{150, 0}";
|
|
||||||
sepNavVisRange = "{0, 333}";
|
|
||||||
sepNavWindowFrame = "{{299, 31}, {1412, 924}}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
B6B767C80F0FFA3900D819C9 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */;
|
|
||||||
name = "profuse.1: 10";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 429;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 722;
|
|
||||||
vrLoc = 2400;
|
|
||||||
};
|
|
||||||
B6C786B30F2A59AF00053681 /* profuse.h */ = {
|
B6C786B30F2A59AF00053681 /* profuse.h */ = {
|
||||||
uiCtxt = {
|
uiCtxt = {
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {796, 728}}";
|
sepNavIntBoundsRect = "{{0, 0}, {1245, 1011}}";
|
||||||
sepNavSelRange = "{1382, 0}";
|
sepNavSelRange = "{1165, 0}";
|
||||||
sepNavVisRange = "{243, 1139}";
|
sepNavVisRange = "{0, 1449}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */ = {
|
B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */ = {
|
||||||
uiCtxt = {
|
uiCtxt = {
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1032, 7618}}";
|
sepNavIntBoundsRect = "{{0, 0}, {873, 7371}}";
|
||||||
sepNavSelRange = "{8340, 0}";
|
sepNavSelRange = "{1034, 5}";
|
||||||
sepNavVisRange = "{7739, 948}";
|
sepNavVisRange = "{998, 1279}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */ = {
|
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */ = {
|
||||||
@@ -519,9 +480,9 @@
|
|||||||
};
|
};
|
||||||
B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */ = {
|
B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */ = {
|
||||||
uiCtxt = {
|
uiCtxt = {
|
||||||
sepNavIntBoundsRect = "{{0, 0}, {1198, 3016}}";
|
sepNavIntBoundsRect = "{{0, 0}, {1245, 3146}}";
|
||||||
sepNavSelRange = "{3216, 0}";
|
sepNavSelRange = "{5137, 0}";
|
||||||
sepNavVisRange = "{2120, 1512}";
|
sepNavVisRange = "{3413, 2039}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */ = {
|
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */ = {
|
||||||
@@ -531,66 +492,6 @@
|
|||||||
sepNavVisRange = "{1323, 1590}";
|
sepNavVisRange = "{1323, 1590}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
B6C786E50F2A5FF300053681 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
|
|
||||||
name = "main.cpp: 33";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 323;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 330;
|
|
||||||
vrLoc = 441;
|
|
||||||
};
|
|
||||||
B6C786EE0F2A612600053681 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B6B17F820F103AA70060F7AA /* fuse_common.h */;
|
|
||||||
name = "fuse_common.h: 266";
|
|
||||||
rLen = 63;
|
|
||||||
rLoc = 6850;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 708;
|
|
||||||
vrLoc = 5837;
|
|
||||||
};
|
|
||||||
B6C786EF0F2A612600053681 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */;
|
|
||||||
name = "UniversalDiskImage.cpp: 42";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 820;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 463;
|
|
||||||
vrLoc = 500;
|
|
||||||
};
|
|
||||||
B6C786F70F2A64CC00053681 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */;
|
|
||||||
name = "DiskCopy42.cpp: 11";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 150;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 333;
|
|
||||||
vrLoc = 0;
|
|
||||||
};
|
|
||||||
B6C786F90F2A64CC00053681 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */;
|
|
||||||
name = "profuse_stat.cpp: 15";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 181;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 303;
|
|
||||||
vrLoc = 0;
|
|
||||||
};
|
|
||||||
B6C786FA0F2A64CC00053681 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B6C786C30F2A5DCE00053681 /* profuse_file.cpp */;
|
|
||||||
name = "profuse_file.cpp: 11";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 132;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 365;
|
|
||||||
vrLoc = 0;
|
|
||||||
};
|
|
||||||
B6D81E5B0EFDE859000219B7 /* xmain.cpp:163 */ = {
|
B6D81E5B0EFDE859000219B7 /* xmain.cpp:163 */ = {
|
||||||
isa = PBXFileBreakpoint;
|
isa = PBXFileBreakpoint;
|
||||||
actions = (
|
actions = (
|
||||||
@@ -609,15 +510,47 @@
|
|||||||
originalNumberOfMultipleMatches = 0;
|
originalNumberOfMultipleMatches = 0;
|
||||||
state = 2;
|
state = 2;
|
||||||
};
|
};
|
||||||
B6DA6C190FA6AFE90027FC1D /* PBXTextBookmark */ = {
|
B6DA7035131047D100E42AA6 /* DavexDiskImage.cpp */ = {
|
||||||
isa = PBXTextBookmark;
|
uiCtxt = {
|
||||||
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
|
sepNavIntBoundsRect = "{{0, 0}, {873, 2210}}";
|
||||||
name = "Disk.cpp: 243";
|
sepNavSelRange = "{1104, 12}";
|
||||||
rLen = 0;
|
sepNavVisRange = "{684, 856}";
|
||||||
rLoc = 5390;
|
};
|
||||||
rType = 0;
|
};
|
||||||
vrLen = 1006;
|
B6DA7037131047D100E42AA6 /* DiskCopy42Image.cpp */ = {
|
||||||
vrLoc = 4914;
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {873, 3094}}";
|
||||||
|
sepNavSelRange = "{763, 12}";
|
||||||
|
sepNavVisRange = "{395, 851}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
B6DA7038131047D100E42AA6 /* DiskCopy42Image.h */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {873, 529}}";
|
||||||
|
sepNavSelRange = "{0, 0}";
|
||||||
|
sepNavVisRange = "{0, 778}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
B6DA7039131047D100E42AA6 /* DiskImage.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {1245, 2743}}";
|
||||||
|
sepNavSelRange = "{197, 0}";
|
||||||
|
sepNavVisRange = "{0, 1141}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
B6DA703A131047D100E42AA6 /* DiskImage.h */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {1245, 1144}}";
|
||||||
|
sepNavSelRange = "{0, 0}";
|
||||||
|
sepNavVisRange = "{0, 1475}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
B6DA703E131047D100E42AA6 /* UniversalDiskImage.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {1245, 2080}}";
|
||||||
|
sepNavSelRange = "{0, 0}";
|
||||||
|
sepNavVisRange = "{0, 1547}";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */ = {
|
B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */ = {
|
||||||
uiCtxt = {
|
uiCtxt = {
|
||||||
@@ -627,34 +560,4 @@
|
|||||||
sepNavWindowFrame = "{{15, 249}, {1412, 924}}";
|
sepNavWindowFrame = "{{15, 249}, {1412, 924}}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
B6E345420F2BB60B00B7FC78 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B60E91530EFB51FE000E4348 /* Disk.h */;
|
|
||||||
name = "Disk.h: 65";
|
|
||||||
rLen = 21;
|
|
||||||
rLoc = 1281;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 597;
|
|
||||||
vrLoc = 627;
|
|
||||||
};
|
|
||||||
B6E345610F2BC07F00B7FC78 /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B6C786B30F2A59AF00053681 /* profuse.h */;
|
|
||||||
name = "profuse.h: 48";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 1372;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 973;
|
|
||||||
vrLoc = 409;
|
|
||||||
};
|
|
||||||
B6F4740F0F2ACB4700CB75DA /* PBXTextBookmark */ = {
|
|
||||||
isa = PBXTextBookmark;
|
|
||||||
fRef = B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */;
|
|
||||||
name = "profuse_dirent.cpp: 16";
|
|
||||||
rLen = 0;
|
|
||||||
rLoc = 193;
|
|
||||||
rType = 0;
|
|
||||||
vrLen = 368;
|
|
||||||
vrLoc = 0;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,16 +7,29 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
B60E914F0EFB3628000E4348 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B60E914E0EFB3628000E4348 /* File.cpp */; };
|
|
||||||
B60E91550EFB51FE000E4348 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B60E91540EFB51FE000E4348 /* Disk.cpp */; };
|
B60E91550EFB51FE000E4348 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B60E91540EFB51FE000E4348 /* Disk.cpp */; };
|
||||||
B642F12B0F132FA3001F7696 /* UniversalDiskImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */; };
|
B650C2C5131090D200046FAD /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B650C2C3131090D200046FAD /* File.cpp */; };
|
||||||
B679E4A80F02E79300FB3F0C /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B679E4A70F02E79300FB3F0C /* main.cpp */; };
|
B679E4A80F02E79300FB3F0C /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B679E4A70F02E79300FB3F0C /* main.cpp */; };
|
||||||
B67F097910575F8300A13214 /* DateTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B67F097810575F8300A13214 /* DateTime.cpp */; };
|
|
||||||
B6B17FA20F1138830060F7AA /* DiskCopy42.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */; };
|
|
||||||
B6C786B50F2A59FF00053681 /* profuse_xattr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */; };
|
B6C786B50F2A59FF00053681 /* profuse_xattr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */; };
|
||||||
B6C786BC0F2A5C0800053681 /* profuse_dirent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */; };
|
B6C786BC0F2A5C0800053681 /* profuse_dirent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */; };
|
||||||
B6C786C00F2A5CC000053681 /* profuse_stat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */; };
|
B6C786C00F2A5CC000053681 /* profuse_stat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */; };
|
||||||
B6C786C40F2A5DCE00053681 /* profuse_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786C30F2A5DCE00053681 /* profuse_file.cpp */; };
|
B6C786C40F2A5DCE00053681 /* profuse_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786C30F2A5DCE00053681 /* profuse_file.cpp */; };
|
||||||
|
B6DA702D131047CA00E42AA6 /* BlockCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7027131047CA00E42AA6 /* BlockCache.cpp */; };
|
||||||
|
B6DA702E131047CA00E42AA6 /* ConcreteBlockCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7029131047CA00E42AA6 /* ConcreteBlockCache.cpp */; };
|
||||||
|
B6DA702F131047CA00E42AA6 /* MappedBlockCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA702B131047CA00E42AA6 /* MappedBlockCache.cpp */; };
|
||||||
|
B6DA7040131047D100E42AA6 /* Adaptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7031131047D100E42AA6 /* Adaptor.cpp */; };
|
||||||
|
B6DA7041131047D100E42AA6 /* BlockDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7033131047D100E42AA6 /* BlockDevice.cpp */; };
|
||||||
|
B6DA7042131047D100E42AA6 /* DavexDiskImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7035131047D100E42AA6 /* DavexDiskImage.cpp */; };
|
||||||
|
B6DA7043131047D100E42AA6 /* DiskCopy42Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7037131047D100E42AA6 /* DiskCopy42Image.cpp */; };
|
||||||
|
B6DA7044131047D100E42AA6 /* DiskImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7039131047D100E42AA6 /* DiskImage.cpp */; };
|
||||||
|
B6DA7045131047D100E42AA6 /* RawDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA703B131047D100E42AA6 /* RawDevice.cpp */; };
|
||||||
|
B6DA7046131047D100E42AA6 /* UniversalDiskImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA703E131047D100E42AA6 /* UniversalDiskImage.cpp */; };
|
||||||
|
B6DA704C131047F400E42AA6 /* Endian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7048131047F400E42AA6 /* Endian.cpp */; };
|
||||||
|
B6DA7052131047FA00E42AA6 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA704E131047FA00E42AA6 /* File.cpp */; };
|
||||||
|
B6DA7053131047FA00E42AA6 /* MappedFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA7050131047FA00E42AA6 /* MappedFile.cpp */; };
|
||||||
|
B6DA705A1310551500E42AA6 /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA70561310551500E42AA6 /* Exception.cpp */; };
|
||||||
|
B6DA705B1310551500E42AA6 /* Lock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA70581310551500E42AA6 /* Lock.cpp */; };
|
||||||
|
B6DA706E1310571B00E42AA6 /* DateTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DA706B1310571B00E42AA6 /* DateTime.cpp */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
@@ -33,23 +46,55 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
8DD76F6C0486A84900D96B5E /* profuse */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = profuse; sourceTree = BUILT_PRODUCTS_DIR; };
|
8DD76F6C0486A84900D96B5E /* profuse */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = profuse; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B60E914D0EFB3627000E4348 /* File.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = File.h; sourceTree = "<group>"; };
|
|
||||||
B60E914E0EFB3628000E4348 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = File.cpp; sourceTree = "<group>"; };
|
|
||||||
B60E91530EFB51FE000E4348 /* Disk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Disk.h; sourceTree = "<group>"; };
|
B60E91530EFB51FE000E4348 /* Disk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Disk.h; sourceTree = "<group>"; };
|
||||||
B60E91540EFB51FE000E4348 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Disk.cpp; sourceTree = "<group>"; };
|
B60E91540EFB51FE000E4348 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Disk.cpp; sourceTree = "<group>"; };
|
||||||
B60E91580EFD77E3000E4348 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
|
B60E91580EFD77E3000E4348 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
|
||||||
B642F1290F132FA3001F7696 /* UniversalDiskImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UniversalDiskImage.h; sourceTree = "<group>"; };
|
B61BCF8F131B6633002DE159 /* smart_pointers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = smart_pointers.h; sourceTree = "<group>"; };
|
||||||
B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UniversalDiskImage.cpp; sourceTree = "<group>"; };
|
B650C2C3131090D200046FAD /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = File.cpp; sourceTree = "<group>"; };
|
||||||
|
B650C2C4131090D200046FAD /* File.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = File.h; sourceTree = "<group>"; };
|
||||||
|
B650C2C6131095C200046FAD /* Device.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Device.h; sourceTree = "<group>"; };
|
||||||
B679E4A70F02E79300FB3F0C /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
|
B679E4A70F02E79300FB3F0C /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
|
||||||
B67F097810575F8300A13214 /* DateTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DateTime.cpp; sourceTree = "<group>"; };
|
|
||||||
B67F097A10575FD900A13214 /* DateTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateTime.h; sourceTree = "<group>"; };
|
|
||||||
B6B17FA00F1138830060F7AA /* DiskCopy42.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskCopy42.h; sourceTree = "<group>"; };
|
|
||||||
B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskCopy42.cpp; sourceTree = "<group>"; };
|
|
||||||
B6C786B30F2A59AF00053681 /* profuse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = profuse.h; sourceTree = "<group>"; };
|
B6C786B30F2A59AF00053681 /* profuse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = profuse.h; sourceTree = "<group>"; };
|
||||||
B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_xattr.cpp; sourceTree = "<group>"; };
|
B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_xattr.cpp; sourceTree = "<group>"; };
|
||||||
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_dirent.cpp; sourceTree = "<group>"; };
|
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_dirent.cpp; sourceTree = "<group>"; };
|
||||||
B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_stat.cpp; sourceTree = "<group>"; };
|
B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_stat.cpp; sourceTree = "<group>"; };
|
||||||
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_file.cpp; sourceTree = "<group>"; };
|
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_file.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA7027131047CA00E42AA6 /* BlockCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlockCache.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA7028131047CA00E42AA6 /* BlockCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockCache.h; sourceTree = "<group>"; };
|
||||||
|
B6DA7029131047CA00E42AA6 /* ConcreteBlockCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConcreteBlockCache.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA702A131047CA00E42AA6 /* ConcreteBlockCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConcreteBlockCache.h; sourceTree = "<group>"; };
|
||||||
|
B6DA702B131047CA00E42AA6 /* MappedBlockCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MappedBlockCache.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA702C131047CA00E42AA6 /* MappedBlockCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MappedBlockCache.h; sourceTree = "<group>"; };
|
||||||
|
B6DA7031131047D100E42AA6 /* Adaptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Adaptor.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA7032131047D100E42AA6 /* Adaptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Adaptor.h; sourceTree = "<group>"; };
|
||||||
|
B6DA7033131047D100E42AA6 /* BlockDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlockDevice.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA7034131047D100E42AA6 /* BlockDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockDevice.h; sourceTree = "<group>"; };
|
||||||
|
B6DA7035131047D100E42AA6 /* DavexDiskImage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DavexDiskImage.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA7036131047D100E42AA6 /* DavexDiskImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DavexDiskImage.h; sourceTree = "<group>"; };
|
||||||
|
B6DA7037131047D100E42AA6 /* DiskCopy42Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskCopy42Image.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA7038131047D100E42AA6 /* DiskCopy42Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskCopy42Image.h; sourceTree = "<group>"; };
|
||||||
|
B6DA7039131047D100E42AA6 /* DiskImage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskImage.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA703A131047D100E42AA6 /* DiskImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskImage.h; sourceTree = "<group>"; };
|
||||||
|
B6DA703B131047D100E42AA6 /* RawDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RawDevice.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA703C131047D100E42AA6 /* RawDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RawDevice.h; sourceTree = "<group>"; };
|
||||||
|
B6DA703D131047D100E42AA6 /* TrackSector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackSector.h; sourceTree = "<group>"; };
|
||||||
|
B6DA703E131047D100E42AA6 /* UniversalDiskImage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UniversalDiskImage.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA703F131047D100E42AA6 /* UniversalDiskImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UniversalDiskImage.h; sourceTree = "<group>"; };
|
||||||
|
B6DA7048131047F400E42AA6 /* Endian.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Endian.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA7049131047F400E42AA6 /* Endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Endian.h; sourceTree = "<group>"; };
|
||||||
|
B6DA704A131047F400E42AA6 /* IOBuffer.cpp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOBuffer.cpp.h; sourceTree = "<group>"; };
|
||||||
|
B6DA704B131047F400E42AA6 /* IOBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOBuffer.h; sourceTree = "<group>"; };
|
||||||
|
B6DA704E131047FA00E42AA6 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = File.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA704F131047FA00E42AA6 /* File.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = File.h; sourceTree = "<group>"; };
|
||||||
|
B6DA7050131047FA00E42AA6 /* MappedFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MappedFile.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA7051131047FA00E42AA6 /* MappedFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MappedFile.h; sourceTree = "<group>"; };
|
||||||
|
B6DA70551310551500E42AA6 /* auto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = auto.h; sourceTree = "<group>"; };
|
||||||
|
B6DA70561310551500E42AA6 /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Exception.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA70571310551500E42AA6 /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = "<group>"; };
|
||||||
|
B6DA70581310551500E42AA6 /* Lock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lock.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA70591310551500E42AA6 /* Lock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lock.h; sourceTree = "<group>"; };
|
||||||
|
B6DA706B1310571B00E42AA6 /* DateTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DateTime.cpp; sourceTree = "<group>"; };
|
||||||
|
B6DA706C1310571B00E42AA6 /* DateTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateTime.h; sourceTree = "<group>"; };
|
||||||
B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = profuse.1; sourceTree = "<group>"; };
|
B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = profuse.1; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@@ -78,18 +123,16 @@
|
|||||||
08FB7795FE84155DC02AAC07 /* Source */ = {
|
08FB7795FE84155DC02AAC07 /* Source */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
B67F097810575F8300A13214 /* DateTime.cpp */,
|
B6DA70681310571B00E42AA6 /* ProDOS */,
|
||||||
B67F097A10575FD900A13214 /* DateTime.h */,
|
B6DA70541310551500E42AA6 /* ProFUSE */,
|
||||||
B642F1290F132FA3001F7696 /* UniversalDiskImage.h */,
|
B6DA704D131047FA00E42AA6 /* File */,
|
||||||
B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */,
|
B6DA7047131047F400E42AA6 /* Endian */,
|
||||||
|
B6DA7030131047D100E42AA6 /* Device */,
|
||||||
|
B6DA7026131047CA00E42AA6 /* Cache */,
|
||||||
B60E91580EFD77E3000E4348 /* common.h */,
|
B60E91580EFD77E3000E4348 /* common.h */,
|
||||||
B60E91530EFB51FE000E4348 /* Disk.h */,
|
B60E91530EFB51FE000E4348 /* Disk.h */,
|
||||||
B60E91540EFB51FE000E4348 /* Disk.cpp */,
|
B60E91540EFB51FE000E4348 /* Disk.cpp */,
|
||||||
B60E914D0EFB3627000E4348 /* File.h */,
|
|
||||||
B60E914E0EFB3628000E4348 /* File.cpp */,
|
|
||||||
B679E4A70F02E79300FB3F0C /* main.cpp */,
|
B679E4A70F02E79300FB3F0C /* main.cpp */,
|
||||||
B6B17FA00F1138830060F7AA /* DiskCopy42.h */,
|
|
||||||
B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */,
|
|
||||||
B6C786B30F2A59AF00053681 /* profuse.h */,
|
B6C786B30F2A59AF00053681 /* profuse.h */,
|
||||||
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */,
|
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */,
|
||||||
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */,
|
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */,
|
||||||
@@ -114,6 +157,88 @@
|
|||||||
name = Libraries;
|
name = Libraries;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B6DA7026131047CA00E42AA6 /* Cache */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B6DA7027131047CA00E42AA6 /* BlockCache.cpp */,
|
||||||
|
B6DA7028131047CA00E42AA6 /* BlockCache.h */,
|
||||||
|
B6DA7029131047CA00E42AA6 /* ConcreteBlockCache.cpp */,
|
||||||
|
B6DA702A131047CA00E42AA6 /* ConcreteBlockCache.h */,
|
||||||
|
B6DA702B131047CA00E42AA6 /* MappedBlockCache.cpp */,
|
||||||
|
B6DA702C131047CA00E42AA6 /* MappedBlockCache.h */,
|
||||||
|
);
|
||||||
|
path = Cache;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B6DA7030131047D100E42AA6 /* Device */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B6DA7031131047D100E42AA6 /* Adaptor.cpp */,
|
||||||
|
B6DA7032131047D100E42AA6 /* Adaptor.h */,
|
||||||
|
B6DA7033131047D100E42AA6 /* BlockDevice.cpp */,
|
||||||
|
B6DA7034131047D100E42AA6 /* BlockDevice.h */,
|
||||||
|
B6DA7035131047D100E42AA6 /* DavexDiskImage.cpp */,
|
||||||
|
B6DA7036131047D100E42AA6 /* DavexDiskImage.h */,
|
||||||
|
B6DA7037131047D100E42AA6 /* DiskCopy42Image.cpp */,
|
||||||
|
B6DA7038131047D100E42AA6 /* DiskCopy42Image.h */,
|
||||||
|
B6DA7039131047D100E42AA6 /* DiskImage.cpp */,
|
||||||
|
B6DA703A131047D100E42AA6 /* DiskImage.h */,
|
||||||
|
B6DA703B131047D100E42AA6 /* RawDevice.cpp */,
|
||||||
|
B6DA703C131047D100E42AA6 /* RawDevice.h */,
|
||||||
|
B6DA703D131047D100E42AA6 /* TrackSector.h */,
|
||||||
|
B6DA703E131047D100E42AA6 /* UniversalDiskImage.cpp */,
|
||||||
|
B6DA703F131047D100E42AA6 /* UniversalDiskImage.h */,
|
||||||
|
B650C2C6131095C200046FAD /* Device.h */,
|
||||||
|
);
|
||||||
|
path = Device;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B6DA7047131047F400E42AA6 /* Endian */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B6DA7048131047F400E42AA6 /* Endian.cpp */,
|
||||||
|
B6DA7049131047F400E42AA6 /* Endian.h */,
|
||||||
|
B6DA704A131047F400E42AA6 /* IOBuffer.cpp.h */,
|
||||||
|
B6DA704B131047F400E42AA6 /* IOBuffer.h */,
|
||||||
|
);
|
||||||
|
path = Endian;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B6DA704D131047FA00E42AA6 /* File */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B6DA704E131047FA00E42AA6 /* File.cpp */,
|
||||||
|
B6DA704F131047FA00E42AA6 /* File.h */,
|
||||||
|
B6DA7050131047FA00E42AA6 /* MappedFile.cpp */,
|
||||||
|
B6DA7051131047FA00E42AA6 /* MappedFile.h */,
|
||||||
|
);
|
||||||
|
path = File;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B6DA70541310551500E42AA6 /* ProFUSE */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B6DA70551310551500E42AA6 /* auto.h */,
|
||||||
|
B61BCF8F131B6633002DE159 /* smart_pointers.h */,
|
||||||
|
B6DA70561310551500E42AA6 /* Exception.cpp */,
|
||||||
|
B6DA70571310551500E42AA6 /* Exception.h */,
|
||||||
|
B6DA70581310551500E42AA6 /* Lock.cpp */,
|
||||||
|
B6DA70591310551500E42AA6 /* Lock.h */,
|
||||||
|
);
|
||||||
|
path = ProFUSE;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B6DA70681310571B00E42AA6 /* ProDOS */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B650C2C3131090D200046FAD /* File.cpp */,
|
||||||
|
B650C2C4131090D200046FAD /* File.h */,
|
||||||
|
B6DA706B1310571B00E42AA6 /* DateTime.cpp */,
|
||||||
|
B6DA706C1310571B00E42AA6 /* DateTime.h */,
|
||||||
|
);
|
||||||
|
path = ProDOS;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
C6859E8C029090F304C91782 /* Documentation */ = {
|
C6859E8C029090F304C91782 /* Documentation */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -150,7 +275,11 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "profuse" */;
|
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "profuse" */;
|
||||||
compatibilityVersion = "Xcode 3.1";
|
compatibilityVersion = "Xcode 3.1";
|
||||||
|
developmentRegion = English;
|
||||||
hasScannedForEncodings = 1;
|
hasScannedForEncodings = 1;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
);
|
||||||
mainGroup = 08FB7794FE84155DC02AAC07 /* ProDOS-Fuse */;
|
mainGroup = 08FB7794FE84155DC02AAC07 /* ProDOS-Fuse */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
@@ -165,16 +294,29 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
B60E914F0EFB3628000E4348 /* File.cpp in Sources */,
|
|
||||||
B60E91550EFB51FE000E4348 /* Disk.cpp in Sources */,
|
B60E91550EFB51FE000E4348 /* Disk.cpp in Sources */,
|
||||||
B679E4A80F02E79300FB3F0C /* main.cpp in Sources */,
|
B679E4A80F02E79300FB3F0C /* main.cpp in Sources */,
|
||||||
B6B17FA20F1138830060F7AA /* DiskCopy42.cpp in Sources */,
|
|
||||||
B642F12B0F132FA3001F7696 /* UniversalDiskImage.cpp in Sources */,
|
|
||||||
B6C786B50F2A59FF00053681 /* profuse_xattr.cpp in Sources */,
|
B6C786B50F2A59FF00053681 /* profuse_xattr.cpp in Sources */,
|
||||||
B6C786BC0F2A5C0800053681 /* profuse_dirent.cpp in Sources */,
|
B6C786BC0F2A5C0800053681 /* profuse_dirent.cpp in Sources */,
|
||||||
B6C786C00F2A5CC000053681 /* profuse_stat.cpp in Sources */,
|
B6C786C00F2A5CC000053681 /* profuse_stat.cpp in Sources */,
|
||||||
B6C786C40F2A5DCE00053681 /* profuse_file.cpp in Sources */,
|
B6C786C40F2A5DCE00053681 /* profuse_file.cpp in Sources */,
|
||||||
B67F097910575F8300A13214 /* DateTime.cpp in Sources */,
|
B6DA702D131047CA00E42AA6 /* BlockCache.cpp in Sources */,
|
||||||
|
B6DA702E131047CA00E42AA6 /* ConcreteBlockCache.cpp in Sources */,
|
||||||
|
B6DA702F131047CA00E42AA6 /* MappedBlockCache.cpp in Sources */,
|
||||||
|
B6DA7040131047D100E42AA6 /* Adaptor.cpp in Sources */,
|
||||||
|
B6DA7041131047D100E42AA6 /* BlockDevice.cpp in Sources */,
|
||||||
|
B6DA7042131047D100E42AA6 /* DavexDiskImage.cpp in Sources */,
|
||||||
|
B6DA7043131047D100E42AA6 /* DiskCopy42Image.cpp in Sources */,
|
||||||
|
B6DA7044131047D100E42AA6 /* DiskImage.cpp in Sources */,
|
||||||
|
B6DA7045131047D100E42AA6 /* RawDevice.cpp in Sources */,
|
||||||
|
B6DA7046131047D100E42AA6 /* UniversalDiskImage.cpp in Sources */,
|
||||||
|
B6DA704C131047F400E42AA6 /* Endian.cpp in Sources */,
|
||||||
|
B6DA7052131047FA00E42AA6 /* File.cpp in Sources */,
|
||||||
|
B6DA7053131047FA00E42AA6 /* MappedFile.cpp in Sources */,
|
||||||
|
B6DA705A1310551500E42AA6 /* Exception.cpp in Sources */,
|
||||||
|
B6DA705B1310551500E42AA6 /* Lock.cpp in Sources */,
|
||||||
|
B6DA706E1310571B00E42AA6 /* DateTime.cpp in Sources */,
|
||||||
|
B650C2C5131090D200046FAD /* File.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -190,10 +332,8 @@
|
|||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||||
GCC_MODEL_TUNING = G5;
|
GCC_MODEL_TUNING = G5;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||||
"_GLIBCXX_DEBUG=1",
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
"_GLIBCXX_DEBUG_PEDANTIC=1",
|
|
||||||
);
|
|
||||||
INSTALL_PATH = /usr/local/bin;
|
INSTALL_PATH = /usr/local/bin;
|
||||||
PRODUCT_NAME = profuse;
|
PRODUCT_NAME = profuse;
|
||||||
};
|
};
|
||||||
@@ -205,6 +345,7 @@
|
|||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
GCC_MODEL_TUNING = G5;
|
GCC_MODEL_TUNING = G5;
|
||||||
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
INSTALL_PATH = /usr/local/bin;
|
INSTALL_PATH = /usr/local/bin;
|
||||||
PRODUCT_NAME = "ProDOS-Fuse";
|
PRODUCT_NAME = "ProDOS-Fuse";
|
||||||
};
|
};
|
||||||
@@ -217,9 +358,13 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "";
|
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||||
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
HEADER_SEARCH_PATHS = /usr/local/include/fuse;
|
HEADER_SEARCH_PATHS = (
|
||||||
|
/usr/local/include/fuse,
|
||||||
|
.,
|
||||||
|
);
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
"-D__FreeBSD__=10",
|
"-D__FreeBSD__=10",
|
||||||
@@ -232,7 +377,7 @@
|
|||||||
"-lfuse_ino64",
|
"-lfuse_ino64",
|
||||||
);
|
);
|
||||||
PREBINDING = NO;
|
PREBINDING = NO;
|
||||||
SDKROOT = macosx10.5;
|
SDKROOT = macosx;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -241,10 +386,11 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
PREBINDING = NO;
|
PREBINDING = NO;
|
||||||
SDKROOT = macosx10.5;
|
SDKROOT = macosx;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -255,9 +401,13 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "";
|
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||||
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
HEADER_SEARCH_PATHS = /usr/local/include/fuse;
|
HEADER_SEARCH_PATHS = (
|
||||||
|
/usr/local/include/fuse,
|
||||||
|
.,
|
||||||
|
);
|
||||||
ONLY_ACTIVE_ARCH = NO;
|
ONLY_ACTIVE_ARCH = NO;
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
"-D__FreeBSD__=10",
|
"-D__FreeBSD__=10",
|
||||||
@@ -270,7 +420,7 @@
|
|||||||
"-lfuse_ino64",
|
"-lfuse_ino64",
|
||||||
);
|
);
|
||||||
PREBINDING = NO;
|
PREBINDING = NO;
|
||||||
SDKROOT = macosx10.5;
|
SDKROOT = macosx;
|
||||||
};
|
};
|
||||||
name = "Debug Universal";
|
name = "Debug Universal";
|
||||||
};
|
};
|
||||||
@@ -283,10 +433,8 @@
|
|||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||||
GCC_MODEL_TUNING = G5;
|
GCC_MODEL_TUNING = G5;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||||
"_GLIBCXX_DEBUG=1",
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
"_GLIBCXX_DEBUG_PEDANTIC=1",
|
|
||||||
);
|
|
||||||
INSTALL_PATH = /usr/local/bin;
|
INSTALL_PATH = /usr/local/bin;
|
||||||
PRODUCT_NAME = profuse;
|
PRODUCT_NAME = profuse;
|
||||||
};
|
};
|
||||||
@@ -299,9 +447,13 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "";
|
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||||
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
HEADER_SEARCH_PATHS = /usr/local/include/fuse;
|
HEADER_SEARCH_PATHS = (
|
||||||
|
/usr/local/include/fuse,
|
||||||
|
.,
|
||||||
|
);
|
||||||
ONLY_ACTIVE_ARCH = NO;
|
ONLY_ACTIVE_ARCH = NO;
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
"-D__FreeBSD__=10",
|
"-D__FreeBSD__=10",
|
||||||
@@ -314,7 +466,7 @@
|
|||||||
"-lfuse_ino64",
|
"-lfuse_ino64",
|
||||||
);
|
);
|
||||||
PREBINDING = NO;
|
PREBINDING = NO;
|
||||||
SDKROOT = macosx10.6;
|
SDKROOT = macosx;
|
||||||
VALID_ARCHS = "i386 x86_64";
|
VALID_ARCHS = "i386 x86_64";
|
||||||
};
|
};
|
||||||
name = "Debug 10.6";
|
name = "Debug 10.6";
|
||||||
@@ -328,10 +480,8 @@
|
|||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||||
GCC_MODEL_TUNING = G5;
|
GCC_MODEL_TUNING = G5;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||||
"_GLIBCXX_DEBUG=1",
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
"_GLIBCXX_DEBUG_PEDANTIC=1",
|
|
||||||
);
|
|
||||||
INSTALL_PATH = /usr/local/bin;
|
INSTALL_PATH = /usr/local/bin;
|
||||||
PRODUCT_NAME = profuse;
|
PRODUCT_NAME = profuse;
|
||||||
};
|
};
|
||||||
@@ -344,9 +494,14 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "";
|
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||||
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
HEADER_SEARCH_PATHS = /usr/local/include/fuse;
|
HEADER_SEARCH_PATHS = (
|
||||||
|
/usr/local/include/fuse,
|
||||||
|
.,
|
||||||
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.4;
|
||||||
ONLY_ACTIVE_ARCH = NO;
|
ONLY_ACTIVE_ARCH = NO;
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
"-D__FreeBSD__=10",
|
"-D__FreeBSD__=10",
|
||||||
@@ -357,7 +512,7 @@
|
|||||||
"-lfuse",
|
"-lfuse",
|
||||||
);
|
);
|
||||||
PREBINDING = NO;
|
PREBINDING = NO;
|
||||||
SDKROOT = macosx10.4;
|
SDKROOT = macosx;
|
||||||
};
|
};
|
||||||
name = "Debug Universal 10.4";
|
name = "Debug Universal 10.4";
|
||||||
};
|
};
|
||||||
@@ -370,10 +525,8 @@
|
|||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||||
GCC_MODEL_TUNING = G5;
|
GCC_MODEL_TUNING = G5;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||||
"_GLIBCXX_DEBUG=1",
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
"_GLIBCXX_DEBUG_PEDANTIC=1",
|
|
||||||
);
|
|
||||||
INSTALL_PATH = /usr/local/bin;
|
INSTALL_PATH = /usr/local/bin;
|
||||||
PRODUCT_NAME = profuse;
|
PRODUCT_NAME = profuse;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
@@ -217,3 +219,34 @@ void prodos_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
|
|||||||
fuse_reply_entry(req, &entry);
|
fuse_reply_entry(req, &entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void prodos_statfs(fuse_req_t req, fuse_ino_t ino)
|
||||||
|
{
|
||||||
|
struct statvfs vst;
|
||||||
|
|
||||||
|
VolumeEntry volume;
|
||||||
|
|
||||||
|
|
||||||
|
disk->ReadVolume(&volume, NULL);
|
||||||
|
|
||||||
|
// returns statvfs for the mount path or any file in the fs
|
||||||
|
// therefore, ignore ino.
|
||||||
|
std::memset(&vst, 0, sizeof(vst));
|
||||||
|
|
||||||
|
vst.f_bsize = 512; // fs block size
|
||||||
|
vst.f_frsize = 512; // fundamental fs block size
|
||||||
|
vst.f_blocks = volume.total_blocks;
|
||||||
|
vst.f_bfree = 0; // free blocks
|
||||||
|
vst.f_bavail = 0; // free blocks (non-root)
|
||||||
|
vst.f_files = 0; // ?
|
||||||
|
vst.f_ffree = -1; // free inodes.
|
||||||
|
vst.f_favail = -1; // free inodes (non-root)
|
||||||
|
vst.f_fsid = 0; // file system id?
|
||||||
|
vst.f_flag = ST_RDONLY | ST_NOSUID;
|
||||||
|
vst.f_namemax = 15;
|
||||||
|
|
||||||
|
fuse_reply_statfs(req, &vst);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,13 @@
|
|||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define NO_ATTRIBUTE ENOATTR
|
||||||
|
#else
|
||||||
|
#define NO_ATTRIBUTE EOPNOTSUPP
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool isTextFile(unsigned ftype, unsigned auxtype)
|
static bool isTextFile(unsigned ftype, unsigned auxtype)
|
||||||
{
|
{
|
||||||
if (ftype == 0x04) return true; // ascii text
|
if (ftype == 0x04) return true; // ascii text
|
||||||
@@ -186,7 +193,7 @@ static void xattr_charset(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
|||||||
const char attr[] = "macintosh";
|
const char attr[] = "macintosh";
|
||||||
unsigned attr_size = sizeof(attr) - 1;
|
unsigned attr_size = sizeof(attr) - 1;
|
||||||
|
|
||||||
ERROR(!isTextFile(e.file_type, e.aux_type), ENOENT)
|
ERROR(!isTextFile(e.file_type, e.aux_type), NO_ATTRIBUTE)
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
@@ -205,7 +212,7 @@ static void xattr_textencoding(FileEntry& e, fuse_req_t req, size_t size, off_t
|
|||||||
const char attr[] = "MACINTOSH;0";
|
const char attr[] = "MACINTOSH;0";
|
||||||
unsigned attr_size = sizeof(attr) - 1;
|
unsigned attr_size = sizeof(attr) - 1;
|
||||||
|
|
||||||
ERROR(!isTextFile(e.file_type, e.aux_type), ENOENT)
|
ERROR(!isTextFile(e.file_type, e.aux_type), NO_ATTRIBUTE)
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
@@ -223,7 +230,7 @@ static void xattr_rfork(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
|||||||
int ok;
|
int ok;
|
||||||
unsigned level;
|
unsigned level;
|
||||||
|
|
||||||
ERROR (e.storage_type != EXTENDED_FILE, ENOENT)
|
ERROR (e.storage_type != EXTENDED_FILE, NO_ATTRIBUTE)
|
||||||
|
|
||||||
ok = disk->Normalize(e, 1);
|
ok = disk->Normalize(e, 1);
|
||||||
ERROR(ok < 0, EIO)
|
ERROR(ok < 0, EIO)
|
||||||
@@ -306,7 +313,7 @@ static void xattr_finfo(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR(true, ENOENT);
|
ERROR(true, NO_ATTRIBUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -347,7 +354,7 @@ static void xattr_mimetype(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
|||||||
{
|
{
|
||||||
unsigned attr_size;
|
unsigned attr_size;
|
||||||
const char *mime = mimeType(e.file_type, e.aux_type);
|
const char *mime = mimeType(e.file_type, e.aux_type);
|
||||||
ERROR(!mime, ENOENT);
|
ERROR(!mime, NO_ATTRIBUTE);
|
||||||
|
|
||||||
attr_size = strlen(mime);
|
attr_size = strlen(mime);
|
||||||
|
|
||||||
@@ -478,11 +485,7 @@ return; \
|
|||||||
*/
|
*/
|
||||||
void prodos_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size, uint32_t off)
|
void prodos_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size, uint32_t off)
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
|
||||||
#define NO_ATTRIBUTE ENOENT
|
|
||||||
#else
|
|
||||||
#define NO_ATTRIBUTE EOPNOTSUPP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fprintf(stderr, "getxattr: %u %s %u %u \n", (unsigned)ino, name, (unsigned)size, (unsigned)off);
|
fprintf(stderr, "getxattr: %u %s %u %u \n", (unsigned)ino, name, (unsigned)size, (unsigned)off);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user