mirror of
https://github.com/ksherlock/profuse.git
synced 2026-04-23 06:31:22 +00:00
Compare commits
88 Commits
pascal_r2_
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cc4d44292 | ||
|
|
936c9b3983 | ||
|
|
4cf3294c26 | ||
|
|
3ae1edd5a9 | ||
|
|
a6531a0a61 | ||
|
|
0b7d67de2b | ||
|
|
1971c33ddf | ||
|
|
a40d29590a | ||
|
|
b4ce209d83 | ||
|
|
3885c06698 | ||
|
|
184b69747a | ||
|
|
5d1b81ecca | ||
|
|
d4a7107bde | ||
|
|
25ad5cf7f5 | ||
|
|
818ab5f602 | ||
|
|
9ad93a51a7 | ||
|
|
ef1874977b | ||
|
|
7508097176 | ||
|
|
1dd7becb2f | ||
|
|
5d219195bb | ||
|
|
e3aea1657f | ||
|
|
a686f7d646 | ||
|
|
3af649af7c | ||
|
|
82ecf63db6 | ||
|
|
1fe6327ab1 | ||
|
|
b39aeba7ce | ||
|
|
8778d0dcf2 | ||
|
|
b4db3e59ab | ||
|
|
02e3c4c532 | ||
|
|
ad6fd87c3e | ||
|
|
304164ecfa | ||
|
|
84e0c8e08c | ||
|
|
e6f655a2c9 | ||
|
|
c3f02b28da | ||
|
|
f70b5897de | ||
|
|
32bb5d79b9 | ||
|
|
5f893f78fc | ||
|
|
3a671f985c | ||
|
|
5930e28f54 | ||
|
|
efd5e7bd98 | ||
|
|
e68854ff58 | ||
|
|
9746117f71 | ||
|
|
89e80dcc10 | ||
|
|
e71ab41481 | ||
|
|
011c3b7b44 | ||
|
|
2243d8d136 | ||
|
|
78d35bba08 | ||
|
|
e36eb445bf | ||
|
|
caea19006a | ||
|
|
0d39e94245 | ||
|
|
dd0703bd09 | ||
|
|
4360263a1a | ||
|
|
d296abe203 | ||
|
|
00b6063040 | ||
|
|
592b56c8a5 | ||
|
|
bd808a1d6e | ||
|
|
8fb94c9850 | ||
|
|
560f1b56fa | ||
|
|
d57f04fa0b | ||
|
|
bfe481b412 | ||
|
|
2458262bac | ||
|
|
f91b71448a | ||
|
|
6d6a988208 | ||
|
|
cdef6cbc04 | ||
|
|
1768d932ee | ||
|
|
e73d7e82ff | ||
|
|
abab7d0b9e | ||
|
|
465a813cca | ||
|
|
d9f6b903a8 | ||
|
|
911347ac13 | ||
|
|
aa8d1b0699 | ||
|
|
23d9d31132 | ||
|
|
0b5ef674f2 | ||
|
|
b510ef3ec4 | ||
|
|
e971546b2a | ||
|
|
a83fc6df28 | ||
|
|
3b72264d30 | ||
|
|
f6018484ce | ||
|
|
4ee26d864c | ||
|
|
e5e91ed130 | ||
|
|
ad6b4d5c32 | ||
|
|
d1b16d9010 | ||
|
|
1b6a7fab18 | ||
|
|
193e1ab933 | ||
|
|
ef3aa273b3 | ||
|
|
29533054d0 | ||
|
|
bc7c5d73bb | ||
|
|
90bf49881f |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.o
|
||||
o/
|
||||
11
.travis.yml
Normal file
11
.travis.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
language: cpp
|
||||
# trusty has gcc 4.8
|
||||
sudo: required
|
||||
dist: trusty
|
||||
compiler:
|
||||
- clang++
|
||||
- g++
|
||||
script: make
|
||||
before_install:
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get install -y fuse libfuse-dev
|
||||
@@ -11,28 +11,25 @@
|
||||
#include <Cache/BlockCache.h>
|
||||
#include <Device/BlockDevice.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <ProFUSE/auto.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/auto.h>
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace Device;
|
||||
|
||||
using ProFUSE::Exception;
|
||||
using ProFUSE::POSIXException;
|
||||
|
||||
|
||||
BlockCache::BlockCache(BlockDevice *device)
|
||||
BlockCache::BlockCache(BlockDevicePointer device) :
|
||||
_device(device)
|
||||
{
|
||||
_device = device;
|
||||
_blocks = device->blocks();
|
||||
_readOnly = device->readOnly();
|
||||
}
|
||||
|
||||
BlockCache::~BlockCache()
|
||||
{
|
||||
delete _device;
|
||||
}
|
||||
|
||||
void BlockCache::write(unsigned block, const void *bp)
|
||||
@@ -50,9 +47,10 @@ void BlockCache::read(unsigned block, void *bp)
|
||||
}
|
||||
|
||||
|
||||
BlockCache *BlockCache::Create(BlockDevice *device)
|
||||
BlockCachePointer BlockCache::Create(BlockDevicePointer device)
|
||||
{
|
||||
if (!device) return NULL;
|
||||
// this just calls the device virtual function to create a cache.
|
||||
if (!device) return BlockCachePointer();
|
||||
|
||||
return device->createBlockCache();
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <Device/Device.h>
|
||||
|
||||
|
||||
class MappedFile;
|
||||
|
||||
namespace Device {
|
||||
|
||||
class BlockDevice;
|
||||
|
||||
enum BlockReleaseFlags {
|
||||
kBlockDirty = 1,
|
||||
@@ -19,13 +20,13 @@ enum BlockReleaseFlags {
|
||||
class BlockCache {
|
||||
public:
|
||||
|
||||
static BlockCache *Create(BlockDevice *device);
|
||||
static BlockCachePointer Create(BlockDevicePointer device);
|
||||
|
||||
virtual ~BlockCache();
|
||||
|
||||
bool readOnly() { return _readOnly; }
|
||||
unsigned blocks() { return _blocks; }
|
||||
BlockDevice *device() { return _device; }
|
||||
BlockDevicePointer device() { return _device; }
|
||||
|
||||
|
||||
virtual void sync() = 0;
|
||||
@@ -46,16 +47,16 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
BlockCache(BlockDevice *device);
|
||||
BlockCache(BlockDevicePointer device);
|
||||
|
||||
BlockDevice *_device;
|
||||
BlockDevicePointer _device;
|
||||
|
||||
private:
|
||||
unsigned _blocks;
|
||||
bool _readOnly;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include <Device/BlockDevice.h>
|
||||
#include <Cache/ConcreteBlockCache.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <ProFUSE/auto.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/auto.h>
|
||||
|
||||
|
||||
/*
|
||||
@@ -51,15 +51,20 @@
|
||||
|
||||
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(BlockDevice *device, unsigned size) :
|
||||
ConcreteBlockCache::ConcreteBlockCache(BlockDevicePointer device, unsigned size) :
|
||||
BlockCache(device)
|
||||
{
|
||||
if (size < 16) size = 16;
|
||||
|
||||
@@ -9,7 +9,9 @@ namespace Device {
|
||||
|
||||
class ConcreteBlockCache : public BlockCache {
|
||||
public:
|
||||
ConcreteBlockCache(BlockDevice *device, unsigned size = 16);
|
||||
|
||||
static BlockCachePointer Create(BlockDevicePointer device, unsigned size = 16);
|
||||
|
||||
virtual ~ConcreteBlockCache();
|
||||
|
||||
virtual void sync();
|
||||
@@ -20,9 +22,14 @@ public:
|
||||
virtual void release(unsigned block, int flags);
|
||||
virtual void markDirty(unsigned block);
|
||||
|
||||
|
||||
|
||||
// public so make_shared can access it.
|
||||
ConcreteBlockCache(BlockDevicePointer device, unsigned size);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
struct Entry {
|
||||
unsigned block;
|
||||
unsigned count;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -10,17 +11,21 @@
|
||||
#include <Cache/MappedBlockCache.h>
|
||||
#include <Device/BlockDevice.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
#include <Common/Exception.h>
|
||||
#include <POSIX/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(BlockDevice *device, void *data) :
|
||||
MappedBlockCache::MappedBlockCache(BlockDevicePointer device, void *data) :
|
||||
BlockCache(device)
|
||||
{
|
||||
_data = (uint8_t *)data;
|
||||
@@ -118,12 +123,12 @@ void MappedBlockCache::sync(unsigned block)
|
||||
end = (void *)((ptrdiff_t)end / pagesize * pagesize);
|
||||
|
||||
if (::msync(start, pagesize, MS_SYNC) != 0)
|
||||
throw POSIXException(__METHOD__ ": msync", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": msync", errno);
|
||||
|
||||
if (start != end)
|
||||
{
|
||||
if (::msync(end, pagesize, MS_SYNC) != 0)
|
||||
throw POSIXException(__METHOD__ ": msync", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": msync", errno);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ namespace Device {
|
||||
class MappedBlockCache : public BlockCache {
|
||||
public:
|
||||
|
||||
MappedBlockCache(BlockDevice *, void *data);
|
||||
static BlockCachePointer Create(BlockDevicePointer device, void *data);
|
||||
|
||||
virtual ~MappedBlockCache();
|
||||
|
||||
virtual void sync();
|
||||
@@ -21,8 +22,12 @@ class MappedBlockCache : public BlockCache {
|
||||
virtual void release(unsigned block, int flags);
|
||||
virtual void markDirty(unsigned block);
|
||||
|
||||
|
||||
// public so make_shared can access it.
|
||||
MappedBlockCache(BlockDevicePointer device, void *data);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void sync(unsigned block);
|
||||
|
||||
uint8_t *_data;
|
||||
|
||||
44
Common/Exception.cpp
Normal file
44
Common/Exception.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
#include "Exception.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
Exception::Exception(const char *cp):
|
||||
_error(0),
|
||||
_string(cp)
|
||||
{
|
||||
}
|
||||
|
||||
Exception::Exception(const std::string& string):
|
||||
_error(0),
|
||||
_string(string)
|
||||
{
|
||||
}
|
||||
|
||||
Exception::Exception(const char *cp, int error):
|
||||
_error(error),
|
||||
_string(cp)
|
||||
{
|
||||
}
|
||||
|
||||
Exception::Exception(const std::string& string, int error):
|
||||
_error(error),
|
||||
_string(string)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Exception::~Exception() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char *Exception::what() const throw()
|
||||
{
|
||||
return _string.c_str();
|
||||
}
|
||||
|
||||
const char *Exception::errorString()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
36
Common/Exception.h
Normal file
36
Common/Exception.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef __COMMON_EXCEPTION_H__
|
||||
#define __COMMON_EXCEPTION_H__
|
||||
|
||||
#include <string>
|
||||
#include <exception>
|
||||
|
||||
|
||||
class Exception : public std::exception
|
||||
{
|
||||
public:
|
||||
Exception(const char *cp);
|
||||
Exception(const std::string &str);
|
||||
|
||||
|
||||
virtual ~Exception() throw ();
|
||||
|
||||
virtual const char *what() const throw();
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <ProFUSE/Lock.h>
|
||||
#include "Lock.h"
|
||||
|
||||
using namespace ProFUSE;
|
||||
|
||||
Lock::Lock()
|
||||
{
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace ProFUSE {
|
||||
|
||||
class Lock {
|
||||
public:
|
||||
@@ -28,6 +27,4 @@ private:
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace ProFUSE {
|
||||
|
||||
template <class T>
|
||||
class auto_array
|
||||
@@ -98,7 +97,6 @@ private:
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
35
Common/smart_pointers.h
Normal file
35
Common/smart_pointers.h
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
#ifndef __COMMON_SMART_POINTERS_H__
|
||||
#define __COMMON_SMART_POINTERS_H__
|
||||
|
||||
#if 1
|
||||
//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
|
||||
14
Common/unordered_map.h
Normal file
14
Common/unordered_map.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef __COMMON_UNORDERED_MAP_H__
|
||||
#define __COMMON_UNORDERED_MAP_H__
|
||||
|
||||
#if 1
|
||||
//c++0x
|
||||
#include <unordered_map>
|
||||
#define UNORDERED_MAP(...) std::unordered_map(__VA_ARGS__)
|
||||
#else
|
||||
// tr1
|
||||
#include <tr1/unordered_map>
|
||||
#define UNORDERED_MAP(...) std::tr1::unordered_map(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <Device/Adaptor.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
using namespace Device;
|
||||
|
||||
@@ -141,7 +142,7 @@ uint8_t NibbleAdaptor::encode62(uint8_t val)
|
||||
};
|
||||
|
||||
if (val > 0x3f)
|
||||
throw ProFUSE::Exception(__METHOD__ ": Invalid 6-2 value.");
|
||||
throw ::Exception(__METHOD__ ": Invalid 6-2 value.");
|
||||
|
||||
return table[val];
|
||||
}
|
||||
@@ -164,7 +165,7 @@ uint8_t NibbleAdaptor::decode62(uint8_t val)
|
||||
};
|
||||
|
||||
if ((val < 0x90) || (table[val - 0x90] == 0xff))
|
||||
throw ProFUSE::Exception(__METHOD__ ": Invalid 6-2 encoding.");
|
||||
throw ::Exception(__METHOD__ ": Invalid 6-2 encoding.");
|
||||
|
||||
return table[val - 0x90];
|
||||
}
|
||||
@@ -237,10 +238,10 @@ NibbleAdaptor::NibbleAdaptor(void *address, unsigned length)
|
||||
checksum = decode44(buffer[offset + 9], buffer[offset + 10]);
|
||||
|
||||
if (volume ^ track ^ sector ^ checksum)
|
||||
throw ProFUSE::Exception(__METHOD__ ": Invalid address checksum.");
|
||||
throw ::Exception(__METHOD__ ": Invalid address checksum.");
|
||||
|
||||
if (track > 35 || sector > 16)
|
||||
throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector.");
|
||||
throw ::Exception(__METHOD__ ": Invalid track/sector.");
|
||||
|
||||
offset += 3 + 8 + 3;
|
||||
|
||||
@@ -293,7 +294,7 @@ NibbleAdaptor::NibbleAdaptor(void *address, unsigned length)
|
||||
{
|
||||
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.");
|
||||
//throw ::Exception(__METHOD__ ": Sector missing.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +361,7 @@ void NibbleAdaptor::readTrackSector(TrackSector ts, void *bp)
|
||||
#define __METHOD__ "NibbleAdaptor::readTrackSector"
|
||||
|
||||
if (ts.track > 35 || ts.sector > 16)
|
||||
throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector.");
|
||||
throw ::Exception(__METHOD__ ": Invalid track/sector.");
|
||||
|
||||
|
||||
CircleBuffer buffer(_address, _length);
|
||||
@@ -373,7 +374,7 @@ void NibbleAdaptor::readTrackSector(TrackSector ts, void *bp)
|
||||
|
||||
if (offset == -1)
|
||||
{
|
||||
throw ProFUSE::Exception(__METHOD__ ": Missing track/sector.");
|
||||
throw ::Exception(__METHOD__ ": Missing track/sector.");
|
||||
}
|
||||
|
||||
// first 86 bytes are in the auxbuffer, backwards.
|
||||
@@ -417,7 +418,7 @@ void NibbleAdaptor::readTrackSector(TrackSector ts, void *bp)
|
||||
|
||||
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.");
|
||||
//throw ::Exception(__METHOD__ ": Invalid field checksum.");
|
||||
|
||||
}
|
||||
|
||||
@@ -427,7 +428,7 @@ void NibbleAdaptor::writeTrackSector(TrackSector ts, const void *bp)
|
||||
#define __METHOD__ "NibbleAdaptor::writeTrackSector"
|
||||
|
||||
if (ts.track > 35 || ts.sector > 16)
|
||||
throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector.");
|
||||
throw ::Exception(__METHOD__ ": Invalid track/sector.");
|
||||
|
||||
uint8_t auxBuffer[86];
|
||||
uint8_t checksum = 0;
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
#include <Device/BlockDevice.h>
|
||||
#include <Cache/ConcreteBlockCache.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <POSIX/Exception.h>
|
||||
|
||||
#include <Device/DiskImage.h>
|
||||
#include <Device/UniversalDiskImage.h>
|
||||
@@ -20,12 +21,40 @@
|
||||
#include <Device/DavexDiskImage.h>
|
||||
#include <Device/RawDevice.h>
|
||||
|
||||
#ifdef HAVE_NUFX
|
||||
#include <Device/SDKImage.h>
|
||||
#endif
|
||||
|
||||
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';
|
||||
|
||||
#ifdef HAVE_NUFX
|
||||
if (SDKImage::Validate(f, std::nothrow))
|
||||
return 'SDK_';
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -51,7 +80,9 @@ unsigned BlockDevice::ImageType(const char *type, unsigned defv)
|
||||
return '2IMG';
|
||||
if (::strcasecmp(type, "2img") == 0)
|
||||
return '2IMG';
|
||||
|
||||
|
||||
if (::strcasecmp(type, "dc") == 0)
|
||||
return 'DC42';
|
||||
if (::strcasecmp(type, "dc42") == 0)
|
||||
return 'DC42';
|
||||
|
||||
@@ -70,15 +101,18 @@ unsigned BlockDevice::ImageType(const char *type, unsigned defv)
|
||||
if (::strcasecmp(type, "davex") == 0)
|
||||
return 'DVX_';
|
||||
|
||||
|
||||
// not supported yet.
|
||||
|
||||
#ifdef HAVE_NUFX
|
||||
if (::strcasecmp(type, "sdk") == 0)
|
||||
return 'SDK_';
|
||||
|
||||
if (::strcasecmp(type, "shk") == 0)
|
||||
return 'SDK_';
|
||||
#endif
|
||||
|
||||
return defv;
|
||||
}
|
||||
|
||||
BlockDevice *BlockDevice::Open(const char *name, File::FileFlags flags, unsigned imageType)
|
||||
BlockDevicePointer BlockDevice::Open(const char *name, File::FileFlags flags, unsigned imageType)
|
||||
{
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "BlockDevice::Open"
|
||||
@@ -89,25 +123,22 @@ BlockDevice *BlockDevice::Open(const char *name, File::FileFlags flags, unsigned
|
||||
|
||||
if (::stat(name, &st) != 0)
|
||||
{
|
||||
throw POSIXException(__METHOD__ ": stat error", errno);
|
||||
throw POSIX::Exception(__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)
|
||||
{
|
||||
// /dev/xxxx
|
||||
if (S_ISBLK(st.st_mode))
|
||||
return RawDevice::Open(name, flags);
|
||||
|
||||
|
||||
imageType = ImageType(name, 'PO__');
|
||||
imageType = ImageType(&file, 'PO__');
|
||||
}
|
||||
|
||||
|
||||
// TODO -- if no image type, guess based on file size?
|
||||
|
||||
MappedFile file(name, flags);
|
||||
|
||||
|
||||
|
||||
switch (imageType)
|
||||
{
|
||||
case '2IMG':
|
||||
@@ -124,11 +155,17 @@ BlockDevice *BlockDevice::Open(const char *name, File::FileFlags flags, unsigned
|
||||
|
||||
case 'DVX_':
|
||||
return DavexDiskImage::Open(&file);
|
||||
|
||||
|
||||
#if HAVE_NUFX
|
||||
case 'SDK_':
|
||||
return SDKImage::Open(name);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
// throw an error?
|
||||
return NULL;
|
||||
return BlockDevicePointer();
|
||||
|
||||
}
|
||||
|
||||
@@ -158,7 +195,7 @@ static std::string filename(const std::string& src)
|
||||
}
|
||||
|
||||
|
||||
BlockDevice *BlockDevice::Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType)
|
||||
BlockDevicePointer BlockDevice::Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType)
|
||||
{
|
||||
std::string xname;
|
||||
|
||||
@@ -191,7 +228,7 @@ BlockDevice *BlockDevice::Create(const char *fname, const char *vname, unsigned
|
||||
return DavexDiskImage::Create(fname, blocks, vname);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return BlockDevicePointer();
|
||||
|
||||
}
|
||||
|
||||
@@ -233,9 +270,9 @@ void BlockDevice::sync(TrackSector ts)
|
||||
}
|
||||
*/
|
||||
|
||||
BlockCache *BlockDevice::createBlockCache()
|
||||
BlockCachePointer BlockDevice::createBlockCache()
|
||||
{
|
||||
unsigned b = blocks();
|
||||
unsigned size = std::max(16u, b / 16);
|
||||
return new ConcreteBlockCache(this, size);
|
||||
return ConcreteBlockCache::Create(shared_from_this(), size);
|
||||
}
|
||||
|
||||
@@ -4,25 +4,29 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
#include <Device/Device.h>
|
||||
#include <Device/TrackSector.h>
|
||||
|
||||
#include <Cache/BlockCache.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/smart_pointers.h>
|
||||
|
||||
#include <File/File.h>
|
||||
|
||||
class MappedFile;
|
||||
|
||||
namespace Device {
|
||||
|
||||
class BlockDevice {
|
||||
class BlockDevice : public ENABLE_SHARED_FROM_THIS(BlockDevice) {
|
||||
public:
|
||||
|
||||
|
||||
// static methods.
|
||||
static unsigned ImageType(const char *type, unsigned defv = 0);
|
||||
|
||||
static BlockDevice *Open(const char *name, File::FileFlags flags, unsigned imageType = 0);
|
||||
static BlockDevice *Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType = 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);
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +34,7 @@ public:
|
||||
|
||||
virtual ~BlockDevice();
|
||||
|
||||
virtual BlockCache *createBlockCache();
|
||||
virtual BlockCachePointer createBlockCache();
|
||||
|
||||
|
||||
virtual void read(unsigned block, void *bp) = 0;
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
using namespace Device;
|
||||
using namespace LittleEndian;
|
||||
|
||||
using ProFUSE::Exception;
|
||||
using ProFUSE::POSIXException;
|
||||
|
||||
/*
|
||||
http://www.umich.edu/~archive/apple2/technotes/ftn/FTN.E0.8004
|
||||
@@ -47,58 +45,66 @@ DavexDiskImage::~DavexDiskImage()
|
||||
// scan and update usedBlocks?
|
||||
}
|
||||
|
||||
void DavexDiskImage::Validate(MappedFile *f)
|
||||
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"
|
||||
|
||||
size_t size = f->length();
|
||||
const void * data = f->address();
|
||||
bool ok = false;
|
||||
unsigned blocks = (size / 512) - 1;
|
||||
|
||||
if (!Validate(f, std::nothrow))
|
||||
throw ::Exception(__METHOD__ ": Invalid file format.");
|
||||
|
||||
do {
|
||||
if (size < 512) break;
|
||||
if (size % 512) break;
|
||||
|
||||
// identity.
|
||||
if (std::memcmp(data, IdentityCheck, 16))
|
||||
break;
|
||||
|
||||
// file format.
|
||||
if (Read8(data, 0x10) != 0)
|
||||
break;
|
||||
|
||||
// total blocks
|
||||
if (Read32(data, 33) != blocks)
|
||||
break;
|
||||
|
||||
// file number -- must be 1
|
||||
if (Read8(data, 64) != 1)
|
||||
break;
|
||||
|
||||
ok = true;
|
||||
} while (false);
|
||||
|
||||
|
||||
if (!ok)
|
||||
throw Exception(__METHOD__ ": Invalid file format.");
|
||||
return true;
|
||||
}
|
||||
|
||||
DavexDiskImage *DavexDiskImage::Open(MappedFile *file)
|
||||
BlockDevicePointer DavexDiskImage::Open(MappedFile *file)
|
||||
{
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "DavexDiskImage::Open"
|
||||
Validate(file);
|
||||
|
||||
return new DavexDiskImage(file);
|
||||
//return BlockDevicePointer(new DavexDiskImage(file));
|
||||
|
||||
return MAKE_SHARED(DavexDiskImage, file);
|
||||
}
|
||||
|
||||
DavexDiskImage *DavexDiskImage::Create(const char *name, size_t blocks)
|
||||
BlockDevicePointer DavexDiskImage::Create(const char *name, size_t blocks)
|
||||
{
|
||||
return Create(name, blocks, "Untitled");
|
||||
}
|
||||
DavexDiskImage *DavexDiskImage::Create(const char *name, size_t blocks, const char *vname)
|
||||
BlockDevicePointer DavexDiskImage::Create(const char *name, size_t blocks, const char *vname)
|
||||
{
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "DavexDiskImage::Create"
|
||||
@@ -154,12 +160,15 @@ DavexDiskImage *DavexDiskImage::Create(const char *name, size_t blocks, const ch
|
||||
std::memcpy(file->address(), header.buffer(), 512);
|
||||
file->sync();
|
||||
|
||||
return new DavexDiskImage(file);
|
||||
//return BlockDevicePointer(new DavexDiskImage(file));
|
||||
|
||||
return MAKE_SHARED(DavexDiskImage, file);
|
||||
}
|
||||
|
||||
|
||||
BlockCache *DavexDiskImage::createBlockCache()
|
||||
BlockCachePointer DavexDiskImage::createBlockCache()
|
||||
{
|
||||
return new MappedBlockCache(this, 512 + (uint8_t *)address());
|
||||
// need a smart pointer, but only have this....
|
||||
return MappedBlockCache::Create(shared_from_this(), 512 + (uint8_t *)address());
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __DAVEXDISKIMAGE_H__
|
||||
|
||||
#include <string>
|
||||
#include <new>
|
||||
|
||||
#include <Device/BlockDevice.h>
|
||||
#include <Device/DiskImage.h>
|
||||
@@ -16,18 +17,19 @@ public:
|
||||
|
||||
virtual ~DavexDiskImage();
|
||||
|
||||
static DavexDiskImage *Create(const char *name, size_t blocks);
|
||||
static DavexDiskImage *Create(const char *name, size_t blocks, const char *vname);
|
||||
static DavexDiskImage *Open(MappedFile *);
|
||||
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 BlockCache *createBlockCache();
|
||||
virtual BlockCachePointer createBlockCache();
|
||||
|
||||
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||
static bool Validate(MappedFile *);
|
||||
|
||||
private:
|
||||
|
||||
DavexDiskImage();
|
||||
|
||||
DavexDiskImage(MappedFile *);
|
||||
static void Validate(MappedFile *);
|
||||
private:
|
||||
DavexDiskImage();
|
||||
|
||||
bool _changed;
|
||||
std::string _volumeName;
|
||||
|
||||
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 <Common/smart_pointers.h>
|
||||
|
||||
namespace Device {
|
||||
|
||||
class BlockDevice;
|
||||
class BlockCache;
|
||||
|
||||
typedef SHARED_PTR(BlockDevice) BlockDevicePointer;
|
||||
typedef SHARED_PTR(BlockCache) BlockCachePointer;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -16,9 +16,6 @@ using namespace Device;
|
||||
using namespace BigEndian;
|
||||
|
||||
|
||||
using ProFUSE::Exception;
|
||||
using ProFUSE::POSIXException;
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
@@ -32,8 +29,8 @@ DiskCopy42Image::DiskCopy42Image(MappedFile *f) :
|
||||
DiskImage(f),
|
||||
_changed(false)
|
||||
{
|
||||
setAdaptor(new POAdaptor(oUserData + (uint8_t *)f->address()));
|
||||
setBlocks(Read32(f->address(), oDataSize) / 512);
|
||||
setAdaptor(new POAdaptor(oUserData + (uint8_t *)address()));
|
||||
setBlocks(Read32(address(), oDataSize) / 512);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,10 +72,12 @@ uint32_t DiskCopy42Image::Checksum(void *data, size_t size)
|
||||
return rv;
|
||||
}
|
||||
|
||||
DiskCopy42Image *DiskCopy42Image::Open(MappedFile *f)
|
||||
BlockDevicePointer DiskCopy42Image::Open(MappedFile *f)
|
||||
{
|
||||
Validate(f);
|
||||
return new DiskCopy42Image(f);
|
||||
//return BlockDevicePointer(new DiskCopy42Image(f));
|
||||
|
||||
return MAKE_SHARED(DiskCopy42Image, f);
|
||||
}
|
||||
|
||||
static uint8_t DiskFormat(size_t blocks)
|
||||
@@ -101,12 +100,12 @@ static uint8_t FormatByte(size_t blocks)
|
||||
default: return 0x22;
|
||||
}
|
||||
}
|
||||
DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks)
|
||||
BlockDevicePointer DiskCopy42Image::Create(const char *name, size_t blocks)
|
||||
{
|
||||
return Create(name, blocks, "Untitled");
|
||||
}
|
||||
|
||||
DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks, const char *vname)
|
||||
BlockDevicePointer DiskCopy42Image::Create(const char *name, size_t blocks, const char *vname)
|
||||
{
|
||||
MappedFile *file = MappedFile::Create(name, blocks * 512 + oUserData);
|
||||
|
||||
@@ -163,44 +162,43 @@ DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks, const
|
||||
std::memcpy(file->address(), header.buffer(), oUserData);
|
||||
file->sync();
|
||||
|
||||
return new DiskCopy42Image(file);
|
||||
//return BlockDevicePointer(new DiskCopy42Image(file));
|
||||
|
||||
return MAKE_SHARED(DiskCopy42Image, file);
|
||||
}
|
||||
|
||||
void DiskCopy42Image::Validate(MappedFile *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();
|
||||
bool ok = false;
|
||||
uint32_t checksum = 0;
|
||||
|
||||
do {
|
||||
if (size < oUserData) break;
|
||||
|
||||
// name must be < 64
|
||||
if (Read8(data, 0) > 63) break;
|
||||
|
||||
if (Read32(data, oPrivate) != 0x100)
|
||||
break;
|
||||
|
||||
// bytes, not blocks.
|
||||
bytes = Read32(data, oDataSize);
|
||||
|
||||
if (bytes % 512) break;
|
||||
|
||||
if (size < oUserData + bytes) break;
|
||||
|
||||
// todo -- checksum.
|
||||
checksum = Read32(data, oDataChecksum);
|
||||
|
||||
ok = true;
|
||||
} while (false);
|
||||
if (size < oUserData)
|
||||
return false;
|
||||
|
||||
if (!ok)
|
||||
throw Exception(__METHOD__ ": Invalid file format.");
|
||||
// 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);
|
||||
|
||||
@@ -208,7 +206,21 @@ void DiskCopy42Image::Validate(MappedFile *file)
|
||||
{
|
||||
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)
|
||||
@@ -218,11 +230,11 @@ void DiskCopy42Image::write(unsigned block, const void *bp)
|
||||
}
|
||||
|
||||
|
||||
BlockCache *DiskCopy42Image::createBlockCache()
|
||||
BlockCachePointer DiskCopy42Image::createBlockCache()
|
||||
{
|
||||
// if not readonly, mark changed so crc will be updated at close.
|
||||
|
||||
if (!readOnly()) _changed = true;
|
||||
|
||||
return new MappedBlockCache(this, address());
|
||||
return MappedBlockCache::Create(shared_from_this(), address());
|
||||
}
|
||||
@@ -12,24 +12,29 @@ class DiskCopy42Image : public DiskImage {
|
||||
public:
|
||||
virtual ~DiskCopy42Image();
|
||||
|
||||
static DiskCopy42Image *Create(const char *name, size_t blocks);
|
||||
static DiskCopy42Image *Create(const char *name, size_t blocks, const char *vname);
|
||||
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||
static BlockDevicePointer Create(const char *name, size_t blocks, const char *vname);
|
||||
|
||||
static DiskCopy42Image *Open(MappedFile *);
|
||||
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 BlockCache *createBlockCache();
|
||||
|
||||
private:
|
||||
virtual BlockCachePointer createBlockCache();
|
||||
|
||||
|
||||
DiskCopy42Image();
|
||||
DiskCopy42Image(MappedFile *);
|
||||
|
||||
private:
|
||||
|
||||
DiskCopy42Image(MappedFile *);
|
||||
static void Validate(MappedFile *);
|
||||
bool _changed;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,13 +14,11 @@
|
||||
|
||||
#include <Cache/MappedBlockCache.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
|
||||
using namespace Device;
|
||||
|
||||
using ProFUSE::Exception;
|
||||
using ProFUSE::POSIXException;
|
||||
|
||||
|
||||
/*
|
||||
@@ -74,7 +72,7 @@ void DiskImage::read(unsigned block, void *bp)
|
||||
#define __METHOD__ "DiskImage::read"
|
||||
|
||||
if (block >= _blocks)
|
||||
throw Exception(__METHOD__ ": Invalid block.");
|
||||
throw ::Exception(__METHOD__ ": Invalid block.");
|
||||
|
||||
_adaptor->readBlock(block, bp);
|
||||
}
|
||||
@@ -85,7 +83,7 @@ void DiskImage::write(unsigned block, const void *bp)
|
||||
#define __METHOD__ "DiskImage::write"
|
||||
|
||||
if (block >= _blocks)
|
||||
throw Exception(__METHOD__ ": Invalid block.");
|
||||
throw ::Exception(__METHOD__ ": Invalid block.");
|
||||
|
||||
_adaptor->writeBlock(block, bp);
|
||||
}
|
||||
@@ -97,7 +95,7 @@ void DiskImage::sync()
|
||||
|
||||
if (_file.isValid()) return _file.sync();
|
||||
|
||||
throw Exception(__METHOD__ ": File not set.");
|
||||
throw ::Exception(__METHOD__ ": File not set.");
|
||||
}
|
||||
|
||||
|
||||
@@ -112,35 +110,52 @@ ProDOSOrderDiskImage::ProDOSOrderDiskImage(MappedFile *file) :
|
||||
setAdaptor(new POAdaptor(address()));
|
||||
}
|
||||
|
||||
ProDOSOrderDiskImage *ProDOSOrderDiskImage::Create(const char *name, size_t blocks)
|
||||
BlockDevicePointer ProDOSOrderDiskImage::Create(const char *name, size_t blocks)
|
||||
{
|
||||
MappedFile *file = MappedFile::Create(name, blocks * 512);
|
||||
return new ProDOSOrderDiskImage(file);
|
||||
//return BlockDevicePointer(new ProDOSOrderDiskImage(file));
|
||||
return MAKE_SHARED(ProDOSOrderDiskImage, file);
|
||||
}
|
||||
|
||||
ProDOSOrderDiskImage *ProDOSOrderDiskImage::Open(MappedFile *file)
|
||||
BlockDevicePointer ProDOSOrderDiskImage::Open(MappedFile *file)
|
||||
{
|
||||
Validate(file);
|
||||
return new ProDOSOrderDiskImage(file);
|
||||
//return BlockDevicePointer(new ProDOSOrderDiskImage(file));
|
||||
return MAKE_SHARED(ProDOSOrderDiskImage, file);
|
||||
}
|
||||
|
||||
void ProDOSOrderDiskImage::Validate(MappedFile *f)
|
||||
|
||||
bool ProDOSOrderDiskImage::Validate(MappedFile *f, const std::nothrow_t &)
|
||||
{
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "ProDOSOrderDiskImage::Validate"
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "ProDOSOrderDiskImage::Validate"
|
||||
|
||||
if (!f || !f->isValid()) throw Exception(__METHOD__ ": File not set.");
|
||||
|
||||
size_t size = f->length();
|
||||
|
||||
if (size % 512)
|
||||
throw Exception(__METHOD__ ": Invalid file format.");
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
BlockCache *ProDOSOrderDiskImage::createBlockCache()
|
||||
bool ProDOSOrderDiskImage::Validate(MappedFile *f)
|
||||
{
|
||||
return new MappedBlockCache(this, address());
|
||||
#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 -
|
||||
@@ -155,6 +170,8 @@ DOSOrderDiskImage::DOSOrderDiskImage(const char *name, bool readOnly) :
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
DOSOrderDiskImage::DOSOrderDiskImage(MappedFile *file) :
|
||||
DiskImage(file)
|
||||
{
|
||||
@@ -165,28 +182,45 @@ DOSOrderDiskImage::DOSOrderDiskImage(MappedFile *file) :
|
||||
}
|
||||
|
||||
|
||||
DOSOrderDiskImage *DOSOrderDiskImage::Create(const char *name, size_t blocks)
|
||||
BlockDevicePointer DOSOrderDiskImage::Create(const char *name, size_t blocks)
|
||||
{
|
||||
MappedFile *file = MappedFile::Create(name, blocks * 512);
|
||||
return new DOSOrderDiskImage(file);
|
||||
//return BlockDevicePointer(new DOSOrderDiskImage(file));
|
||||
return MAKE_SHARED(DOSOrderDiskImage, file);
|
||||
}
|
||||
|
||||
DOSOrderDiskImage *DOSOrderDiskImage::Open(MappedFile *file)
|
||||
BlockDevicePointer DOSOrderDiskImage::Open(MappedFile *file)
|
||||
{
|
||||
Validate(file);
|
||||
return new DOSOrderDiskImage(file);
|
||||
//return BlockDevicePointer(new DOSOrderDiskImage(file));
|
||||
return MAKE_SHARED(DOSOrderDiskImage, file);
|
||||
|
||||
}
|
||||
|
||||
void DOSOrderDiskImage::Validate(MappedFile *f)
|
||||
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 (!f || !f->isValid()) throw ::Exception(__METHOD__ ": File not set.");
|
||||
|
||||
size_t size = f->length();
|
||||
|
||||
if (size % 512)
|
||||
throw Exception(__METHOD__ ": Invalid file format.");
|
||||
if (!Validate(f, std::nothrow))
|
||||
throw ::Exception(__METHOD__ ": Invalid file format.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
#include <Device/BlockDevice.h>
|
||||
|
||||
#include <Device/Adaptor.h>
|
||||
@@ -57,32 +55,37 @@ class ProDOSOrderDiskImage : public DiskImage {
|
||||
public:
|
||||
|
||||
|
||||
static ProDOSOrderDiskImage *Create(const char *name, size_t blocks);
|
||||
static ProDOSOrderDiskImage *Open(MappedFile *);
|
||||
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||
static BlockDevicePointer Open(MappedFile *);
|
||||
|
||||
|
||||
virtual BlockCache *createBlockCache();
|
||||
|
||||
virtual BlockCachePointer createBlockCache();
|
||||
|
||||
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||
static bool Validate(MappedFile *);
|
||||
|
||||
|
||||
ProDOSOrderDiskImage(MappedFile *);
|
||||
private:
|
||||
ProDOSOrderDiskImage();
|
||||
|
||||
|
||||
ProDOSOrderDiskImage(MappedFile *);
|
||||
static void Validate(MappedFile *);
|
||||
};
|
||||
|
||||
class DOSOrderDiskImage : public DiskImage {
|
||||
public:
|
||||
|
||||
|
||||
static DOSOrderDiskImage *Create(const char *name, size_t blocks);
|
||||
static DOSOrderDiskImage *Open(MappedFile *);
|
||||
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 *);
|
||||
|
||||
|
||||
DOSOrderDiskImage(MappedFile *);
|
||||
private:
|
||||
DOSOrderDiskImage();
|
||||
|
||||
DOSOrderDiskImage(MappedFile *);
|
||||
static void Validate(MappedFile *);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -31,12 +31,11 @@
|
||||
|
||||
#include <Device/RawDevice.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <POSIX/Exception.h>
|
||||
|
||||
using namespace Device;
|
||||
|
||||
using ProFUSE::Exception;
|
||||
using ProFUSE::POSIXException;
|
||||
|
||||
#ifdef __SUN__
|
||||
void RawDevice::devSize(int fd)
|
||||
@@ -47,7 +46,7 @@ void RawDevice::devSize(int fd)
|
||||
struct dk_minfo minfo;
|
||||
|
||||
if (::ioctl(fd, DKIOCGMEDIAINFO, &minfo) < 0)
|
||||
throw POSIXException(__METHOD__ ": Unable to determine device size.", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": Unable to determine device size.", errno);
|
||||
|
||||
_size = minfo.dki_lbsize * minfo.dki_capacity;
|
||||
_blockSize = 512; // not really, but whatever.
|
||||
@@ -66,11 +65,11 @@ void RawDevice::devSize(int fd)
|
||||
uint64_t blockCount; // 64 bit
|
||||
|
||||
if (::ioctl(fd, DKIOCGETBLOCKSIZE, &blockSize) < 0)
|
||||
throw POSIXException(__METHOD__ ": Unable to determine block size.", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": Unable to determine block size.", errno);
|
||||
|
||||
|
||||
if (::ioctl(fd, DKIOCGETBLOCKCOUNT, &blockCount) < 0)
|
||||
throw POSIXException(__METHOD__ ": Unable to determine block count.", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": Unable to determine block count.", errno);
|
||||
|
||||
_blockSize = blockSize;
|
||||
_size = _blockSize * blockCount;
|
||||
@@ -90,7 +89,7 @@ void RawDevice::devSize(int fd)
|
||||
int blocks;
|
||||
|
||||
if (::ioctl(fd, BLKGETSIZE, &blocks) < 0)
|
||||
throw POSIXException(__METHOD__ ": Unable to determine device size.", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": Unable to determine device size.", errno);
|
||||
|
||||
_size = 512 * blocks;
|
||||
_blockSize = 512; //
|
||||
@@ -113,10 +112,10 @@ void RawDevice::devSize(int fd)
|
||||
off_t mediaSize;
|
||||
|
||||
if (::ioctl(fd, DIOCGSECTORSIZE, &blockSize)
|
||||
throw POSIXException(__METHOD__ ": Unable to determine block size.", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": Unable to determine block size.", errno);
|
||||
|
||||
if (::ioctl(fd, DIOCGMEDIASIZE, &mediaSize)
|
||||
throw POSIXException(__METHOD__ ": Unable to determine media size.", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": Unable to determine media size.", errno);
|
||||
|
||||
_blockSize = blockSize;
|
||||
_size = mediaSize;
|
||||
@@ -138,7 +137,7 @@ void RawDevice::devSize(int fd)
|
||||
|
||||
|
||||
if (::ioctl(fd, DIOCGETP, &entry) < 0)
|
||||
throw POSIXException(__METHOD__ ": Unable to determine device size.", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": Unable to determine device size.", errno);
|
||||
|
||||
_size = entry.size
|
||||
_blockSize = 512; // not really but whatever.
|
||||
@@ -157,7 +156,7 @@ RawDevice::RawDevice(const char *name, File::FileFlags flags) :
|
||||
|
||||
if (!_file.isValid())
|
||||
{
|
||||
throw Exception(__METHOD__ ": Invalid file handle.");
|
||||
throw ::Exception(__METHOD__ ": Invalid file handle.");
|
||||
}
|
||||
|
||||
_readOnly = flags == File::ReadOnly;
|
||||
@@ -178,7 +177,7 @@ RawDevice::RawDevice(File& file, File::FileFlags flags) :
|
||||
|
||||
if (!_file.isValid())
|
||||
{
|
||||
throw Exception(__METHOD__ ": Invalid file handle.");
|
||||
throw ::Exception(__METHOD__ ": Invalid file handle.");
|
||||
}
|
||||
|
||||
_readOnly = flags == File::ReadOnly;
|
||||
@@ -196,9 +195,10 @@ RawDevice::~RawDevice()
|
||||
}
|
||||
|
||||
|
||||
RawDevice *RawDevice::Open(const char *name, File::FileFlags flags)
|
||||
BlockDevicePointer RawDevice::Open(const char *name, File::FileFlags flags)
|
||||
{
|
||||
return new RawDevice(name, flags);
|
||||
//return BlockDevicePointer(new RawDevice(name, flags));
|
||||
return MAKE_SHARED(RawDevice, name, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -207,8 +207,8 @@ 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.");
|
||||
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) ?
|
||||
@@ -219,8 +219,8 @@ void RawDevice::read(unsigned block, void *bp)
|
||||
// TODO -- EINTR?
|
||||
if (ok != 512)
|
||||
throw ok < 0
|
||||
? POSIXException(__METHOD__ ": Error reading block.", errno)
|
||||
: Exception(__METHOD__ ": Error reading block.");
|
||||
? POSIX::Exception(__METHOD__ ": Error reading block.", errno)
|
||||
: ::Exception(__METHOD__ ": Error reading block.");
|
||||
}
|
||||
|
||||
|
||||
@@ -230,8 +230,8 @@ void RawDevice::read(TrackSector ts, void *bp)
|
||||
#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.");
|
||||
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) ?
|
||||
@@ -242,8 +242,8 @@ void RawDevice::read(TrackSector ts, void *bp)
|
||||
// TODO -- EINTR?
|
||||
if (ok != 256)
|
||||
throw ok < 0
|
||||
? POSIXException(__METHOD__ ": Error reading block.", errno)
|
||||
: Exception(__METHOD__ ": Error reading block.");
|
||||
? POSIX::Exception(__METHOD__ ": Error reading block.", errno)
|
||||
: ::Exception(__METHOD__ ": Error reading block.");
|
||||
}
|
||||
|
||||
|
||||
@@ -252,10 +252,10 @@ void RawDevice::write(unsigned block, const void *bp)
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "RawDevice::write"
|
||||
|
||||
if (block > _blocks) throw Exception(__METHOD__ ": Invalid block number.");
|
||||
if (block > _blocks) throw ::Exception(__METHOD__ ": Invalid block number.");
|
||||
|
||||
if (_readOnly)
|
||||
throw Exception(__METHOD__ ": File is readonly.");
|
||||
throw ::Exception(__METHOD__ ": File is readonly.");
|
||||
|
||||
|
||||
off_t offset = block * 512;
|
||||
@@ -263,8 +263,8 @@ void RawDevice::write(unsigned block, const void *bp)
|
||||
|
||||
if (ok != 512)
|
||||
throw ok < 0
|
||||
? POSIXException(__METHOD__ ": Error writing block.", errno)
|
||||
: Exception(__METHOD__ ": Error writing block.");
|
||||
? POSIX::Exception(__METHOD__ ": Error writing block.", errno)
|
||||
: ::Exception(__METHOD__ ": Error writing block.");
|
||||
}
|
||||
|
||||
|
||||
@@ -274,10 +274,10 @@ void RawDevice::write(TrackSector ts, const void *bp)
|
||||
#define __METHOD__ "RawDevice::write"
|
||||
|
||||
unsigned block = ts.track * 8 + ts.sector / 2;
|
||||
if (block > _blocks) throw Exception(__METHOD__ ": Invalid block number.");
|
||||
if (block > _blocks) throw ::Exception(__METHOD__ ": Invalid block number.");
|
||||
|
||||
if (_readOnly)
|
||||
throw Exception(__METHOD__ ": File is readonly.");
|
||||
throw ::Exception(__METHOD__ ": File is readonly.");
|
||||
|
||||
|
||||
off_t offset = (ts.track * 16 + ts.sector) * 256;
|
||||
@@ -285,8 +285,8 @@ void RawDevice::write(TrackSector ts, const void *bp)
|
||||
|
||||
if (ok != 256)
|
||||
throw ok < 0
|
||||
? POSIXException(__METHOD__ ": Error writing block.", errno)
|
||||
: Exception(__METHOD__ ": Error writing block.");
|
||||
? POSIX::Exception(__METHOD__ ": Error writing block.", errno)
|
||||
: ::Exception(__METHOD__ ": Error writing block.");
|
||||
}
|
||||
|
||||
|
||||
@@ -315,6 +315,6 @@ void RawDevice::sync()
|
||||
if (_readOnly) return;
|
||||
|
||||
if (::fsync(_file.fd()) < 0)
|
||||
throw POSIXException(__METHOD__ ": fsync error.", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": fsync error.", errno);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
|
||||
|
||||
|
||||
static RawDevice *Open(const char *name, File::FileFlags flags);
|
||||
static BlockDevicePointer Open(const char *name, File::FileFlags flags);
|
||||
|
||||
|
||||
virtual ~RawDevice();
|
||||
@@ -33,13 +33,11 @@ public:
|
||||
virtual void sync();
|
||||
|
||||
virtual unsigned blocks();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
RawDevice(const char *name, File::FileFlags flags);
|
||||
|
||||
|
||||
RawDevice(const char *name, File::FileFlags flags);
|
||||
RawDevice(File& file, File::FileFlags flags);
|
||||
private:
|
||||
|
||||
void devSize(int fd);
|
||||
|
||||
|
||||
220
Device/SDKImage.cpp
Normal file
220
Device/SDKImage.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
//
|
||||
// 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 <cstring>
|
||||
|
||||
#include <NufxLib.h>
|
||||
|
||||
|
||||
#include <File/File.h>
|
||||
#include <File/MappedFile.h>
|
||||
|
||||
#include <Common/Exception.h>
|
||||
#include <NuFX/Exception.h>
|
||||
#include <POSIX/Exception.h>
|
||||
|
||||
|
||||
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 NuFX::Exception(__METHOD__ ": NuGetAttr", e);
|
||||
}
|
||||
|
||||
for (unsigned position = 0; position < recordCount; ++position)
|
||||
{
|
||||
NuRecordIdx rIndex;
|
||||
const NuRecord *record;
|
||||
|
||||
e = NuGetRecordIdxByPosition(archive, position, &rIndex);
|
||||
if (e)
|
||||
{
|
||||
throw NuFX::Exception(__METHOD__ ": NuGetRecordIdxByPosition", e);
|
||||
}
|
||||
|
||||
e = NuGetRecord(archive, rIndex, &record);
|
||||
if (e)
|
||||
{
|
||||
throw NuFX::Exception(__METHOD__ ": NuGetRecord", e);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < NuRecordGetNumThreads(record); ++i)
|
||||
{
|
||||
const NuThread *thread = NuGetThread(record, i);
|
||||
|
||||
if (thread && 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 NuFX::Exception(__METHOD__ ": NuOpenRO", e);
|
||||
}
|
||||
|
||||
rt = FindDiskImageThread(archive);
|
||||
|
||||
fd = mkstemp(tmp);
|
||||
if (fd < 0)
|
||||
{
|
||||
throw POSIX::Exception(__METHOD__ ": mkstemp", errno);
|
||||
}
|
||||
|
||||
fp = fdopen(fd, "w");
|
||||
if (!fp)
|
||||
{
|
||||
::close(fd);
|
||||
throw POSIX::Exception(__METHOD__ ": fdopen", errno);
|
||||
}
|
||||
|
||||
e = NuCreateDataSinkForFP(true, kNuConvertOff, fp, &sink);
|
||||
if (e)
|
||||
{
|
||||
throw NuFX::Exception(__METHOD__ ": NuCreateDataSinkForFP", e);
|
||||
}
|
||||
|
||||
|
||||
e = NuExtractThread(archive, rt.thread_index, sink);
|
||||
if (e)
|
||||
{
|
||||
throw NuFX::Exception(__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 &);
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <Endian/Endian.h>
|
||||
#include <Endian/IOBuffer.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
#include <Cache/MappedBlockCache.h>
|
||||
#include <Cache/ConcreteBlockCache.h>
|
||||
@@ -11,10 +11,6 @@
|
||||
using namespace Device;
|
||||
using namespace LittleEndian;
|
||||
|
||||
using ProFUSE::Exception;
|
||||
using ProFUSE::POSIXException;
|
||||
|
||||
|
||||
|
||||
|
||||
UniversalDiskImage::UniversalDiskImage(MappedFile *file) :
|
||||
@@ -41,7 +37,7 @@ UniversalDiskImage::UniversalDiskImage(MappedFile *file) :
|
||||
setAdaptor(new POAdaptor(_dataOffset + data));
|
||||
}
|
||||
|
||||
UniversalDiskImage *UniversalDiskImage::Create(const char *name, size_t blocks)
|
||||
BlockDevicePointer UniversalDiskImage::Create(const char *name, size_t blocks)
|
||||
{
|
||||
// 64-byte header.
|
||||
MappedFile *file = MappedFile::Create(name, blocks * 512 + 64);
|
||||
@@ -81,13 +77,17 @@ UniversalDiskImage *UniversalDiskImage::Create(const char *name, size_t blocks)
|
||||
std::memcpy(file->address(), header.buffer(), 64);
|
||||
|
||||
|
||||
return new UniversalDiskImage(file);
|
||||
//return BlockDevicePointer(new UniversalDiskImage(file));
|
||||
|
||||
return MAKE_SHARED(UniversalDiskImage, file);
|
||||
}
|
||||
|
||||
UniversalDiskImage *UniversalDiskImage::Open(MappedFile *file)
|
||||
BlockDevicePointer UniversalDiskImage::Open(MappedFile *file)
|
||||
{
|
||||
Validate(file);
|
||||
return new UniversalDiskImage(file);
|
||||
|
||||
//return BlockDevicePointer(new UniversalDiskImage(file));
|
||||
return MAKE_SHARED(UniversalDiskImage, file);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,42 +96,51 @@ UniversalDiskImage *UniversalDiskImage::Open(MappedFile *file)
|
||||
* TODO -- honor read-only flag.
|
||||
*
|
||||
*/
|
||||
void UniversalDiskImage::Validate(MappedFile *file)
|
||||
|
||||
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();
|
||||
bool ok = false;
|
||||
|
||||
unsigned blocks = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
do {
|
||||
|
||||
if (size < 64) break;
|
||||
|
||||
if (std::memcmp(data, "2IMG", 4)) break;
|
||||
|
||||
// only prodos supported, for now...
|
||||
// TODO -- Dos Order, Nibble support.
|
||||
if (Read32(data, 0x0c) != 1) break;
|
||||
|
||||
blocks = Read32(data, 0x14);
|
||||
offset = Read32(data, 0x18);
|
||||
|
||||
// file size == blocks * 512
|
||||
if (Read32(data, 0x1c) != blocks * 512) break;
|
||||
|
||||
if (offset + blocks * 512 > size) break;
|
||||
|
||||
ok = true;
|
||||
} while (false);
|
||||
|
||||
if (!ok)
|
||||
throw Exception(__METHOD__ ": Invalid file format.");
|
||||
unsigned fileSize = 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
|
||||
// file size blank in some cases.
|
||||
//if (Read32(data, 0x1c) != blocks * 512) return false;
|
||||
fileSize = Read32(data, 0x1c);
|
||||
if (fileSize != 0 && fileSize != 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,11 +150,11 @@ bool UniversalDiskImage::readOnly()
|
||||
}
|
||||
|
||||
|
||||
BlockCache *UniversalDiskImage::createBlockCache()
|
||||
BlockCachePointer UniversalDiskImage::createBlockCache()
|
||||
{
|
||||
if (_format == 1)
|
||||
{
|
||||
return new MappedBlockCache(this, _dataOffset + (uint8_t *)address());
|
||||
return MappedBlockCache::Create(shared_from_this(), _dataOffset + (uint8_t *)address());
|
||||
}
|
||||
|
||||
return DiskImage::createBlockCache();
|
||||
|
||||
@@ -14,20 +14,22 @@ public:
|
||||
|
||||
|
||||
|
||||
static UniversalDiskImage *Create(const char *name, size_t blocks);
|
||||
static UniversalDiskImage *Open(MappedFile *);
|
||||
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||
static BlockDevicePointer Open(MappedFile *);
|
||||
|
||||
virtual bool readOnly();
|
||||
|
||||
virtual BlockCache *createBlockCache();
|
||||
virtual BlockCachePointer createBlockCache();
|
||||
|
||||
|
||||
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||
static bool Validate(MappedFile *);
|
||||
|
||||
|
||||
UniversalDiskImage(MappedFile *);
|
||||
private:
|
||||
|
||||
UniversalDiskImage();
|
||||
|
||||
UniversalDiskImage(MappedFile *);
|
||||
static void Validate(MappedFile *);
|
||||
|
||||
uint32_t _format;
|
||||
uint32_t _flags;
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
#include <cerrno>
|
||||
|
||||
#include <File/File.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
|
||||
|
||||
using ProFUSE::Exception;
|
||||
using ProFUSE::POSIXException;
|
||||
#include <Common/Exception.h>
|
||||
#include <POSIX/Exception.h>
|
||||
|
||||
|
||||
File::File()
|
||||
@@ -49,7 +45,7 @@ File::File(const char *name, int flags)
|
||||
|
||||
_fd = ::open(name, flags);
|
||||
if (_fd < 0)
|
||||
throw POSIXException( __METHOD__ ": open", errno);
|
||||
throw POSIX::Exception( __METHOD__ ": open", errno);
|
||||
}
|
||||
|
||||
File::File(const char *name, int flags, mode_t mode)
|
||||
@@ -59,7 +55,7 @@ File::File(const char *name, int flags, mode_t mode)
|
||||
|
||||
_fd = ::open(name, flags, mode);
|
||||
if (_fd < 0)
|
||||
throw POSIXException( __METHOD__ ": open", errno);
|
||||
throw POSIX::Exception( __METHOD__ ": open", errno);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +66,7 @@ File::File(const char *name, FileFlags flags)
|
||||
|
||||
_fd = ::open(name, flags == ReadOnly ? O_RDONLY : O_RDWR);
|
||||
if (_fd < 0)
|
||||
throw POSIXException( __METHOD__ ": open", errno);
|
||||
throw POSIX::Exception( __METHOD__ ": open", errno);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +95,7 @@ void File::close()
|
||||
// destructor shouldn't throw.
|
||||
/*
|
||||
if (::close(fd) != 0)
|
||||
throw POSIXException(__METHOD__ ": close", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": close", errno);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <File/MappedFile.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
|
||||
using ProFUSE::POSIXException;
|
||||
#include <Common/Exception.h>
|
||||
#include <POSIX/Exception.h>
|
||||
|
||||
MappedFile::MappedFile()
|
||||
{
|
||||
@@ -81,16 +79,16 @@ void MappedFile::init(const File &f, bool readOnly, size_t size)
|
||||
|
||||
// close enough
|
||||
if (f.fd() < 0)
|
||||
throw POSIXException( __METHOD__, EBADF);
|
||||
throw POSIX::Exception( __METHOD__, EBADF);
|
||||
|
||||
|
||||
if (!size)
|
||||
{
|
||||
if (::fstat(f.fd(), &st) != 0)
|
||||
throw POSIXException(__METHOD__ ": fstat", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": fstat", errno);
|
||||
|
||||
if (!S_ISREG(st.st_mode))
|
||||
throw POSIXException(__METHOD__, ENODEV);
|
||||
throw POSIX::Exception(__METHOD__, ENODEV);
|
||||
|
||||
size = st.st_size;
|
||||
}
|
||||
@@ -99,7 +97,7 @@ void MappedFile::init(const File &f, bool readOnly, size_t size)
|
||||
_address = ::mmap(0, _length, prot, flags, f.fd(), 0);
|
||||
|
||||
if (_address == MAP_FAILED)
|
||||
throw POSIXException(__METHOD__ ": mmap", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": mmap", errno);
|
||||
|
||||
_readOnly = readOnly;
|
||||
}
|
||||
@@ -127,7 +125,7 @@ void MappedFile::close()
|
||||
// destructor shouldn't throw.
|
||||
/*
|
||||
if (::munmap(address, length) != 0)
|
||||
throw POSIXException(__METHOD__ ": munmap", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": munmap", errno);
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -140,7 +138,7 @@ void MappedFile::sync()
|
||||
if (_address != MAP_FAILED)
|
||||
{
|
||||
if (::msync(_address, _length, MS_SYNC) != 0)
|
||||
throw POSIXException(__METHOD__ ": msync", errno);
|
||||
throw POSIX::Exception(__METHOD__ ": msync", errno);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,14 +171,14 @@ MappedFile *MappedFile::Create(const char *name, size_t size)
|
||||
|
||||
if (!fd.isValid())
|
||||
{
|
||||
throw POSIXException(__METHOD__ ": Unable to create file.", errno);
|
||||
throw POSIX::Exception(__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);
|
||||
throw POSIX::Exception(__METHOD__ ": Unable to truncate file.", errno);
|
||||
}
|
||||
|
||||
return new MappedFile(fd, File::ReadWrite, size);
|
||||
|
||||
188
Makefile
188
Makefile
@@ -1,7 +1,26 @@
|
||||
CC = g++
|
||||
CPPFLAGS += -Wall -W -Wno-multichar -I. -O2 -g
|
||||
LDFLAGS += -lpthread
|
||||
fuse_pascal_LDFLAGS += -lfuse
|
||||
CC = c++
|
||||
CPPFLAGS += -Wall -W -Wno-multichar -Wno-unused-parameter -Wno-unknown-pragmas -Wno-narrowing -I. -O2 -g -std=c++11
|
||||
LDFLAGS += -pthread
|
||||
UNAME = $(shell uname -s)
|
||||
|
||||
ifeq ($(UNAME),Darwin)
|
||||
# should use pkg-config but it may not be installed.
|
||||
FUSE_LIBS += -losxfuse -pthread -liconv
|
||||
CPPFLAGS += -I/usr/local/include/osxfuse/fuse -D_FILE_OFFSET_BITS=64 -D_DARWIN_USE_64_BIT_INODE
|
||||
else
|
||||
CPPFLAGS += $(shell pkg-config --cflags fuse)
|
||||
FUSE_LIBS += $(shell pkg-config --libs fuse)
|
||||
endif
|
||||
|
||||
ifdef HAVE_NUFX
|
||||
DEVICE_OBJECTS += Device/SDKImage.o
|
||||
EXCEPTION_OBJECTS += NuFX/Exception.o
|
||||
LDFLAGS += -L/usr/local/lib/
|
||||
LIBS += -lnufx -lz
|
||||
|
||||
CPPFLAGS += -DHAVE_NUFX=1
|
||||
endif
|
||||
|
||||
|
||||
OBJECTS += ${wildcard *.o}
|
||||
OBJECTS += ${wildcard bin/*.o}
|
||||
@@ -10,9 +29,13 @@ OBJECTS += ${wildcard Device/*.o}
|
||||
OBJECTS += ${wildcard Endian/*.o}
|
||||
OBJECTS += ${wildcard File/*.o}
|
||||
OBJECTS += ${wildcard Pascal/*.o}
|
||||
OBJECTS += ${wildcard ProFUSE/*.o}
|
||||
OBJECTS += ${wildcard Common/*.o}
|
||||
OBJECTS += ${wildcard ProDOS/*.o}
|
||||
OBJECTS += ${wildcard POSIX/*.o}
|
||||
OBJECTS += ${wildcard NuFX/*.o}
|
||||
|
||||
TARGETS = apfm newfs_pascal profuse_pascal xattr
|
||||
|
||||
TARGETS = o/apfm o/newfs_pascal o/fuse_pascal o/profuse o/xattr
|
||||
|
||||
BIN_OBJECTS += bin/apfm.o
|
||||
BIN_OBJECTS += bin/fuse_pascal_ops.o
|
||||
@@ -20,6 +43,13 @@ BIN_OBJECTS += bin/newfs_prodos.o
|
||||
BIN_OBJECTS += bin/fuse_pascal.o
|
||||
BIN_OBJECTS += bin/newfs_pascal.o
|
||||
BIN_OBJECTS += bin/xattr.o
|
||||
BIN_OBJECTS += bin/profuse.o
|
||||
BIN_OBJECTS += bin/profuse_dirent.o
|
||||
BIN_OBJECTS += bin/profuse_file.o
|
||||
BIN_OBJECTS += bin/profuse_stat.o
|
||||
BIN_OBJECTS += bin/profuse_xattr.o
|
||||
|
||||
|
||||
|
||||
CACHE_OBJECTS += Cache/BlockCache.o
|
||||
CACHE_OBJECTS += Cache/ConcreteBlockCache.o
|
||||
@@ -33,6 +63,7 @@ DEVICE_OBJECTS += Device/DiskImage.o
|
||||
DEVICE_OBJECTS += Device/RawDevice.o
|
||||
DEVICE_OBJECTS += Device/UniversalDiskImage.o
|
||||
|
||||
|
||||
ENDIAN_OBJECTS += Endian/Endian.o
|
||||
|
||||
FILE_OBJECTS += File/File.o
|
||||
@@ -44,41 +75,84 @@ PASCAL_OBJECTS += Pascal/TextWriter.o
|
||||
PASCAL_OBJECTS += Pascal/Entry.o
|
||||
PASCAL_OBJECTS += Pascal/VolumeEntry.o
|
||||
|
||||
PROFUSE_OBJECTS += ProFUSE/Exception.o
|
||||
PROFUSE_OBJECTS += ProFUSE/Lock.o
|
||||
COMMON_OBJECTS += Common/Lock.o
|
||||
|
||||
PRODOS_OBJECTS += ProDOS/DateTime.o
|
||||
PRODOS_OBJECTS += ProDOS/Disk.o
|
||||
PRODOS_OBJECTS += ProDOS/File.o
|
||||
|
||||
EXCEPTION_OBJECTS += Common/Exception.o
|
||||
EXCEPTION_OBJECTS += ProDOS/Exception.o
|
||||
EXCEPTION_OBJECTS += POSIX/Exception.o
|
||||
|
||||
|
||||
|
||||
xattr: bin/xattr.o
|
||||
$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
newfs_pascal: bin/newfs_pascal.o \
|
||||
all: $(TARGETS)
|
||||
|
||||
apfm: o/apfm
|
||||
@true
|
||||
|
||||
fuse_pascal: o/fuse_pascal
|
||||
@true
|
||||
|
||||
newfs_pascal: o/newfs_pascal
|
||||
@true
|
||||
|
||||
profuse: o/profuse
|
||||
@true
|
||||
|
||||
xattr: o/xattr
|
||||
@true
|
||||
|
||||
o:
|
||||
mkdir $@
|
||||
|
||||
o/xattr: bin/xattr.o | o
|
||||
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
|
||||
|
||||
o/newfs_pascal: bin/newfs_pascal.o \
|
||||
${CACHE_OBJECTS} \
|
||||
${DEVICE_OBJECTS} \
|
||||
${ENDIAN_OBJECTS} \
|
||||
${FILE_OBJECTS} \
|
||||
${PROFUSE_OBJECTS} \
|
||||
${PASCAL_OBJECTS}
|
||||
$(CC) $(LDFLAGS) $^ -o $@
|
||||
${COMMON_OBJECTS} \
|
||||
${EXCEPTION_OBJECTS} \
|
||||
${PASCAL_OBJECTS} | o
|
||||
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
|
||||
|
||||
apfm: bin/apfm.o \
|
||||
o/apfm: bin/apfm.o \
|
||||
${CACHE_OBJECTS} \
|
||||
${DEVICE_OBJECTS} \
|
||||
${ENDIAN_OBJECTS} \
|
||||
${FILE_OBJECTS} \
|
||||
${PROFUSE_OBJECTS} \
|
||||
${PASCAL_OBJECTS}
|
||||
$(CC) $(LDFLAGS) $^ -o $@
|
||||
${COMMON_OBJECTS} \
|
||||
${EXCEPTION_OBJECTS} \
|
||||
${PASCAL_OBJECTS} | o
|
||||
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
|
||||
|
||||
|
||||
fuse_pascal: bin/fuse_pascal.o bin/fuse_pascal_ops.o \
|
||||
o/fuse_pascal: bin/fuse_pascal.o bin/fuse_pascal_ops.o \
|
||||
${CACHE_OBJECTS} \
|
||||
${DEVICE_OBJECTS} \
|
||||
${ENDIAN_OBJECTS} \
|
||||
${FILE_OBJECTS} \
|
||||
${PROFUSE_OBJECTS} \
|
||||
${PASCAL_OBJECTS}
|
||||
$(CC) -lfuse $(LDFLAGS) $^ -o $@
|
||||
${COMMON_OBJECTS} \
|
||||
${EXCEPTION_OBJECTS} \
|
||||
${PASCAL_OBJECTS} | o
|
||||
$(CC) $(LDFLAGS) $^ $(LIBS) $(FUSE_LIBS) -o $@
|
||||
|
||||
|
||||
o/profuse: bin/profuse.o bin/profuse_dirent.o bin/profuse_file.o \
|
||||
bin/profuse_stat.o bin/profuse_xattr.o \
|
||||
${CACHE_OBJECTS} \
|
||||
${DEVICE_OBJECTS} \
|
||||
${ENDIAN_OBJECTS} \
|
||||
${FILE_OBJECTS} \
|
||||
${COMMON_OBJECTS} \
|
||||
${EXCEPTION_OBJECTS} \
|
||||
${PRODOS_OBJECTS} | o
|
||||
$(CC) $(LDFLAGS) $^ $(LIBS) $(FUSE_LIBS) -o $@
|
||||
|
||||
|
||||
clean:
|
||||
@@ -86,59 +160,59 @@ clean:
|
||||
|
||||
xattr.o: bin/xattr.cpp
|
||||
|
||||
newfs_pascal.o: bin/newfs_pascal.cpp Device/BlockDevice.h ProFUSE/Exception.h \
|
||||
newfs_pascal.o: bin/newfs_pascal.cpp Device/BlockDevice.h Common/Exception.h \
|
||||
Device/TrackSector.h Cache/BlockCache.h Device/RawDevice.h File/File.h \
|
||||
Pascal/Pascal.h Pascal/Date.h
|
||||
|
||||
fuse_pascal.o: bin/fuse_pascal.cpp Pascal/Pascal.h Pascal/Date.h \
|
||||
ProFUSE/Exception.h Device/BlockDevice.h Device/TrackSector.h \
|
||||
Common/Exception.h Device/BlockDevice.h Device/TrackSector.h \
|
||||
Cache/BlockCache.h
|
||||
|
||||
fuse_pascal_ops.o: bin/fuse_pascal_ops.cpp Pascal/Pascal.h Pascal/Date.h \
|
||||
ProFUSE/auto.h ProFUSE/Exception.h
|
||||
Common/auto.h Common/Exception.h
|
||||
|
||||
apfm.o: bin/apfm.cpp Pascal/Pascal.h Pascal/Date.h Device/BlockDevice.h \
|
||||
ProFUSE/Exception.h Device/TrackSector.h Cache/BlockCache.h
|
||||
Common/Exception.h Device/TrackSector.h Cache/BlockCache.h
|
||||
|
||||
File/File.o: File/File.cpp File/File.h ProFUSE/Exception.h
|
||||
File/File.o: File/File.cpp File/File.h Common/Exception.h
|
||||
|
||||
File/MappedFile.o: File/MappedFile.cpp File/MappedFile.h File/File.h \
|
||||
ProFUSE/Exception.h
|
||||
Common/Exception.h
|
||||
|
||||
Device/Adaptor.o: Device/Adaptor.cpp Device/Adaptor.h Device/TrackSector.h \
|
||||
ProFUSE/Exception.h
|
||||
Common/Exception.h
|
||||
|
||||
Device/BlockDevice.o: Device/BlockDevice.cpp Device/BlockDevice.h \
|
||||
ProFUSE/Exception.h Device/TrackSector.h Cache/BlockCache.h \
|
||||
Common/Exception.h Device/TrackSector.h Cache/BlockCache.h \
|
||||
Cache/ConcreteBlockCache.h Device/DiskImage.h Device/Adaptor.h \
|
||||
File/MappedFile.h File/File.h Device/UniversalDiskImage.h \
|
||||
Device/DiskCopy42Image.h Device/DavexDiskImage.h Device/RawDevice.h
|
||||
|
||||
Device/DavexDiskImage.o: Device/DavexDiskImage.cpp \
|
||||
Device/DavexDiskImage.h \
|
||||
Device/BlockDevice.h ProFUSE/Exception.h Device/TrackSector.h \
|
||||
Device/BlockDevice.h Common/Exception.h Device/TrackSector.h \
|
||||
Cache/BlockCache.h Device/DiskImage.h Device/Adaptor.h \
|
||||
File/MappedFile.h File/File.h Endian/Endian.h Endian/IOBuffer.h \
|
||||
Endian/IOBuffer.cpp.h Cache/MappedBlockCache.h
|
||||
|
||||
Device/DiskCopy42Image.o: Device/DiskCopy42Image.cpp \
|
||||
Device/DiskCopy42Image.h \
|
||||
Device/BlockDevice.h ProFUSE/Exception.h Device/TrackSector.h \
|
||||
Device/BlockDevice.h Common/Exception.h Device/TrackSector.h \
|
||||
Cache/BlockCache.h Device/DiskImage.h Device/Adaptor.h \
|
||||
File/MappedFile.h File/File.h Endian/Endian.h Endian/IOBuffer.h \
|
||||
Endian/IOBuffer.cpp.h Cache/MappedBlockCache.h
|
||||
|
||||
Device/DiskImage.o: Device/DiskImage.cpp Device/DiskImage.h \
|
||||
ProFUSE/Exception.h \
|
||||
Common/Exception.h \
|
||||
Device/BlockDevice.h Device/TrackSector.h Cache/BlockCache.h \
|
||||
Device/Adaptor.h File/MappedFile.h File/File.h Cache/MappedBlockCache.h
|
||||
|
||||
Device/RawDevice.o: Device/RawDevice.cpp Device/RawDevice.h \
|
||||
Device/BlockDevice.h \
|
||||
ProFUSE/Exception.h Device/TrackSector.h Cache/BlockCache.h File/File.h
|
||||
Common/Exception.h Device/TrackSector.h Cache/BlockCache.h File/File.h
|
||||
|
||||
Device/UniversalDiskImage.o: Device/UniversalDiskImage.cpp \
|
||||
Device/UniversalDiskImage.h Device/BlockDevice.h ProFUSE/Exception.h \
|
||||
Device/UniversalDiskImage.h Device/BlockDevice.h Common/Exception.h \
|
||||
Device/TrackSector.h Cache/BlockCache.h Device/DiskImage.h \
|
||||
Device/Adaptor.h File/MappedFile.h File/File.h Endian/Endian.h \
|
||||
Endian/IOBuffer.h Endian/IOBuffer.cpp.h Cache/MappedBlockCache.h \
|
||||
@@ -147,42 +221,60 @@ Device/UniversalDiskImage.o: Device/UniversalDiskImage.cpp \
|
||||
Endian/Endian.o: Endian/Endian.cpp Endian/Endian.h
|
||||
|
||||
Cache/BlockCache.o: Cache/BlockCache.cpp Cache/BlockCache.h \
|
||||
Device/BlockDevice.h ProFUSE/Exception.h Device/TrackSector.h \
|
||||
ProFUSE/auto.h
|
||||
Device/BlockDevice.h Common/Exception.h Device/TrackSector.h \
|
||||
Common/auto.h
|
||||
|
||||
Cache/ConcreteBlockCache.o: Cache/ConcreteBlockCache.cpp \
|
||||
Device/BlockDevice.h \
|
||||
ProFUSE/Exception.h Device/TrackSector.h Cache/BlockCache.h \
|
||||
Cache/ConcreteBlockCache.h ProFUSE/auto.h
|
||||
Common/Exception.h Device/TrackSector.h Cache/BlockCache.h \
|
||||
Cache/ConcreteBlockCache.h Common/auto.h
|
||||
|
||||
Cache/MappedBlockCache.o: Cache/MappedBlockCache.cpp \
|
||||
Cache/MappedBlockCache.h \
|
||||
Cache/BlockCache.h Device/BlockDevice.h ProFUSE/Exception.h \
|
||||
Cache/BlockCache.h Device/BlockDevice.h Common/Exception.h \
|
||||
Device/TrackSector.h
|
||||
|
||||
ProFUSE/Exception.o: ProFUSE/Exception.cpp ProFUSE/Exception.h
|
||||
Common/Exception.o: Common/Exception.cpp Common/Exception.h
|
||||
|
||||
ProFUSE/Lock.o: ProFUSE/Lock.cpp ProFUSE/Lock.h
|
||||
Common/Lock.o: Common/Lock.cpp Common/Lock.h
|
||||
|
||||
|
||||
Pascal/Date.o: Pascal/Date.cpp Pascal/Date.h
|
||||
|
||||
Pascal/Entry.o: Pascal/Entry.cpp Pascal/Entry.h Pascal/Date.h \
|
||||
ProFUSE/Exception.h Endian/Endian.h Endian/IOBuffer.h \
|
||||
Common/Exception.h Endian/Endian.h Endian/IOBuffer.h \
|
||||
Endian/IOBuffer.cpp.h Device/BlockDevice.h Device/TrackSector.h \
|
||||
Cache/BlockCache.h
|
||||
|
||||
Pascal/FileEntry.o: Pascal/FileEntry.cpp Pascal/Pascal.h Pascal/Date.h \
|
||||
Pascal/Entry.h Pascal/FileEntry.h Pascal/VolumeEntry.h ProFUSE/auto.h \
|
||||
ProFUSE/Exception.h Endian/Endian.h Endian/IOBuffer.h \
|
||||
Pascal/Entry.h Pascal/FileEntry.h Pascal/VolumeEntry.h Common/auto.h \
|
||||
Common/Exception.h Endian/Endian.h Endian/IOBuffer.h \
|
||||
Endian/IOBuffer.cpp.h Device/BlockDevice.h Device/TrackSector.h \
|
||||
Cache/BlockCache.h Pascal/TextWriter.h
|
||||
|
||||
Pascal/VolumeEntry.o: Pascal/VolumeEntry.cpp Pascal/Pascal.h Pascal/Date.h \
|
||||
Pascal/Entry.h Pascal/FileEntry.h Pascal/VolumeEntry.h ProFUSE/auto.h \
|
||||
ProFUSE/Exception.h Endian/Endian.h Endian/IOBuffer.h \
|
||||
Pascal/Entry.h Pascal/FileEntry.h Pascal/VolumeEntry.h Common/auto.h \
|
||||
Common/Exception.h Endian/Endian.h Endian/IOBuffer.h \
|
||||
Endian/IOBuffer.cpp.h Device/BlockDevice.h Device/TrackSector.h \
|
||||
Cache/BlockCache.h
|
||||
|
||||
Pascal/TextWriter.o: Pascal/TextWriter.cpp Pascal/TextWriter.h \
|
||||
Pascal/FileEntry.h Pascal/Entry.h Pascal/Date.h ProFUSE/Exception.h
|
||||
Pascal/FileEntry.h Pascal/Entry.h Pascal/Date.h Common/Exception.h
|
||||
|
||||
|
||||
|
||||
ProDOS/DateTime.o: ProDOS/DateTime.cpp ProDOS/DateTime.h
|
||||
|
||||
ProDOS/Disk.o: ProDOS/Disk.cpp ProDOS/Disk.h
|
||||
|
||||
ProDOS/File.o: ProDOS/File.cpp ProDOS/File.h
|
||||
|
||||
|
||||
ProDOS/Exception.o: ProDOS/Exception.cpp ProDOS/Exception.h Common/Exception.h
|
||||
|
||||
NuFX/Exception.o: NuFX/Exception.cpp NuFX/Exception.h Common/Exception.h
|
||||
|
||||
POSIX/Exception.o: POSIX/Exception.cpp POSIX/Exception.h Common/Exception.h
|
||||
|
||||
|
||||
|
||||
|
||||
63
NuFX/DirectoryEntry.cpp
Normal file
63
NuFX/DirectoryEntry.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "DirectoryEntry.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace NuFX;
|
||||
|
||||
EntryPointer DirectoryEntry::lookup(const std::string& name) const
|
||||
{
|
||||
EntryIterator iter;
|
||||
|
||||
for (iter = _children.begin(); iter != _children.end(); ++iter)
|
||||
{
|
||||
|
||||
EntryPointer e = *iter;
|
||||
|
||||
if (e->name() == name) return e;
|
||||
}
|
||||
|
||||
return EntryPointer(); // empty.
|
||||
}
|
||||
|
||||
DirectoryEntryPointer DirectoryEntry::dir_lookup(const std::string &name)
|
||||
{
|
||||
EntryIterator iter;
|
||||
|
||||
for (iter = _children.begin(); iter != _children.end(); ++iter)
|
||||
{
|
||||
|
||||
EntryPointer e = *iter;
|
||||
|
||||
if (e->name() == name)
|
||||
{
|
||||
// dynamic cast, will return as empty pointer if
|
||||
// not a directory.
|
||||
|
||||
return DYNAMIC_POINTER_CAST(DirectoryEntryPointer, e);
|
||||
}
|
||||
}
|
||||
|
||||
// not found, insert it..
|
||||
|
||||
DirectoryEntryPointer e(new DirectoryEntryPointer(name));
|
||||
VolumeEntryPointer v = volume().lock();
|
||||
|
||||
_children.add(e);
|
||||
|
||||
if (v)
|
||||
{
|
||||
v->addEntry(e);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark fuse-support
|
||||
|
||||
EntryPointer DirectoryEntry::childAtIndex(unsigned index) const
|
||||
{
|
||||
if (index >= _children.size()) return EntryPointer();
|
||||
|
||||
return _children[index];
|
||||
}
|
||||
38
NuFX/DirectoryEntry.h
Normal file
38
NuFX/DirectoryEntry.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef __NUFX_DIRECTORYENTRY_H__
|
||||
#define __NUFX_DIRECTORYENTRY_H__
|
||||
|
||||
#include "Entry.h"
|
||||
|
||||
#include <vector>
|
||||
#include <dirent.t>
|
||||
|
||||
namespace NuFX {
|
||||
|
||||
|
||||
class DirectoryEntry : public Entry
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
EntryPointer lookup(const std::string & name) const;
|
||||
|
||||
EntryPointer childAtIndex(unsigned index) const;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// creates directory if it does not exist.
|
||||
DirectoryEntryPointer dir_lookup(const std::string &name);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
std::vector<EntryPointer> _children;
|
||||
|
||||
typedef std::vector<EntryPointer>::iterator EntryIterator;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
66
NuFX/Entry.cpp
Normal file
66
NuFX/Entry.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "Entry.h"
|
||||
#include "Exception.h"
|
||||
|
||||
using namespace NuFX;
|
||||
|
||||
|
||||
Entry::Entry() :
|
||||
_inode(0)
|
||||
{
|
||||
}
|
||||
|
||||
Entry::Entry(const std::string& name) :
|
||||
_name(name), _inode(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Entry::~Entry()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unsigned Entry::inode() const
|
||||
{
|
||||
return _inode;
|
||||
}
|
||||
|
||||
const std::string& Entry::name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
void Entry::setName(const std::string& name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
VolumeEntryWeakPointer Entry::volume() const
|
||||
{
|
||||
return _volume;
|
||||
}
|
||||
|
||||
void Entry::setVolume(VolumeEntryWeakPointer volume)
|
||||
{
|
||||
_volume = volume;
|
||||
}
|
||||
|
||||
int Entry::stat(struct stat *st) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t Entry::read(size_t size, off_t offset) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t Entry::listxattr(char *namebuf, size_t size, int options) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t Entry::getxattr(const std::string &name, void *value, size_t size, u_int32_t position, int options) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
69
NuFX/Entry.h
Normal file
69
NuFX/Entry.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef __NUFX_ENTRY_H__
|
||||
#define __NUFX_ENTRY_H__
|
||||
|
||||
|
||||
#include <Common/smart_pointers.h>
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#include <NufxLib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <dirent.h>
|
||||
|
||||
namespace NuFX {
|
||||
|
||||
class DirectoryEntry;
|
||||
class Entry;
|
||||
class FileEntry;
|
||||
class VolumeEntry;
|
||||
|
||||
typedef SHARED_PTR(DirectoryEntry) DirectoryEntryPointer;
|
||||
typedef SHARED_PTR(Entry) EntryPointer;
|
||||
typedef SHARED_PTR(FileEntry) FileEntryPointer;
|
||||
typedef SHARED_PTR(VolumeEntry) VolumeEntryPointer;
|
||||
|
||||
typedef WEAK_PTR(Entry) EntryWeakPointer;
|
||||
typedef WEAK_PTR(VolumeEntry) VolumeEntryWeakPointer;
|
||||
|
||||
class Entry : public ENABLE_SHARED_FROM_THIS(Entry) {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Entry();
|
||||
|
||||
virtual unsigned inode() const;
|
||||
virtual const std::string& name() const;
|
||||
|
||||
|
||||
// operations...
|
||||
virtual int stat(VolumeEntryPointer, struct stat *) const;
|
||||
virtual ssize_t read(VolumeEntryPointer, size_t size, off_t offset) const;
|
||||
virtual ssize_t listxattr(VolumeEntryPointer, char *namebuf, size_t size, int options) const;
|
||||
virtual ssize_t getxattr(VolumeEntryPointer, const std::string &name, void *value, size_t size, u_int32_t position, int options) const;
|
||||
|
||||
virtual int open(VolumeEntryPointer, int flags);
|
||||
virtual int close(VolumeEntryPointer);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
Entry();
|
||||
Entry(const std::string& name);
|
||||
|
||||
void setName(const std::string&);
|
||||
|
||||
private:
|
||||
Entry(const Entry&);
|
||||
Entry& operator=(const Entry&);
|
||||
|
||||
friend VolumeEntry;
|
||||
|
||||
std::string _name;
|
||||
unsigned _inode;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
10
NuFX/Exception.cpp
Normal file
10
NuFX/Exception.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "Exception.h"
|
||||
|
||||
namespace NuFX {
|
||||
|
||||
const char *NuFX::Exception::errorString()
|
||||
{
|
||||
return ::NuStrError((NuError)error());
|
||||
}
|
||||
|
||||
}
|
||||
35
NuFX/Exception.h
Normal file
35
NuFX/Exception.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __NUFX_EXCEPTION_H__
|
||||
#define __NUFX_EXCEPTION_H__
|
||||
|
||||
#include <Common/Exception.h>
|
||||
#include <NufxLib.h>
|
||||
|
||||
namespace NuFX {
|
||||
|
||||
|
||||
class Exception : public ::Exception
|
||||
{
|
||||
public:
|
||||
Exception(const char *cp, NuError error);
|
||||
Exception(const std::string& string, NuError error);
|
||||
|
||||
virtual const char *errorString();
|
||||
|
||||
private:
|
||||
typedef ::Exception super;
|
||||
};
|
||||
|
||||
|
||||
inline Exception::Exception(const char *cp, NuError error) :
|
||||
super(cp, error)
|
||||
{
|
||||
}
|
||||
|
||||
inline Exception::Exception(const std::string& string, NuError error) :
|
||||
super(string, error)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
23
NuFX/FileEntry.h
Normal file
23
NuFX/FileEntry.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef __NUFX_FILEENTRY_H__
|
||||
#define __NUFX_FILEENTRY_H__
|
||||
|
||||
#include "Entry.h"
|
||||
#include <NufxLib.h>
|
||||
|
||||
namespace NuFX {
|
||||
|
||||
|
||||
class FileEntry : public Entry
|
||||
{
|
||||
public:
|
||||
|
||||
private:
|
||||
|
||||
NuRecordIdx _recordID;
|
||||
unsigned _flags; // threads
|
||||
size_t _size; // data size
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
14
NuFX/VolumeEntry.cpp
Normal file
14
NuFX/VolumeEntry.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "VolumeEntry.h"
|
||||
|
||||
using namespace NuFX;
|
||||
|
||||
void VolumeEntry::addEntry(EntryPointer e)
|
||||
{
|
||||
if (!e) return;
|
||||
|
||||
e->setVolume(pointer());
|
||||
|
||||
_inodeIndex->push_back(e);
|
||||
|
||||
e->_inode = _inodeIndex->length() + 100 - 1;
|
||||
}
|
||||
35
NuFX/VolumeEntry.h
Normal file
35
NuFX/VolumeEntry.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __NUFX_VOLUMEENTRY_H__
|
||||
#define __NUFX_VOLUMEENTRY_H__
|
||||
|
||||
#include "DirectoryEntry.h"
|
||||
|
||||
#include <Common/unordered_map.h>
|
||||
|
||||
namespace NuFX {
|
||||
|
||||
|
||||
class VolumeEntry : public DirectoryEntry
|
||||
{
|
||||
public:
|
||||
|
||||
void addEntry(EntryPointer);
|
||||
|
||||
private:
|
||||
|
||||
VolumeEntryPointer pointer() const
|
||||
{
|
||||
return STATIC_POINTER_CAST(VolumeEntryPointer, shared_from_this());
|
||||
}
|
||||
|
||||
void parse();
|
||||
|
||||
NuArchive *_archive;
|
||||
|
||||
//unsigned _inodeGenerator;
|
||||
|
||||
std::vector<WeakPointer> _inodeIndex;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
13
POSIX/Exception.cpp
Normal file
13
POSIX/Exception.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
#include "Exception.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
namespace POSIX {
|
||||
|
||||
const char *Exception::errorString()
|
||||
{
|
||||
return strerror(error());
|
||||
}
|
||||
|
||||
}
|
||||
34
POSIX/Exception.h
Normal file
34
POSIX/Exception.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef __POSIX_EXCEPTION_H__
|
||||
#define __POSIX_EXCEPTION_H__
|
||||
|
||||
#include <Common/Exception.h>
|
||||
|
||||
namespace POSIX {
|
||||
|
||||
|
||||
class Exception : public ::Exception {
|
||||
public:
|
||||
Exception(const char *cp, int error);
|
||||
Exception(const std::string& string, int error);
|
||||
|
||||
virtual const char *errorString();
|
||||
|
||||
private:
|
||||
typedef ::Exception super;
|
||||
};
|
||||
|
||||
|
||||
inline Exception::Exception(const char *cp, int error) :
|
||||
super(cp, error)
|
||||
{
|
||||
}
|
||||
|
||||
inline Exception::Exception(const std::string& string, int error) :
|
||||
super(string, error)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <Pascal/Entry.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
#include <Endian/Endian.h>
|
||||
#include <Endian/IOBuffer.h>
|
||||
@@ -64,7 +64,6 @@ Entry::Entry()
|
||||
_lastBlock = 0;
|
||||
_fileKind = 0;
|
||||
_inode = 0;
|
||||
_parent = NULL;
|
||||
_address = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __PASCAL_ENTRY_H__
|
||||
#define __PASCAL_ENTRY_H__
|
||||
|
||||
#include <Pascal/Date.h>
|
||||
#include <Common/smart_pointers.h>
|
||||
|
||||
|
||||
namespace Device {
|
||||
@@ -31,7 +31,14 @@ namespace Pascal {
|
||||
class FileEntry;
|
||||
class VolumeEntry;
|
||||
|
||||
class Entry {
|
||||
|
||||
typedef SHARED_PTR(FileEntry) FileEntryPointer;
|
||||
typedef SHARED_PTR(VolumeEntry) VolumeEntryPointer;
|
||||
|
||||
typedef WEAK_PTR(FileEntry) FileEntryWeakPointer;
|
||||
typedef WEAK_PTR(VolumeEntry) VolumeEntryWeakPointer;
|
||||
|
||||
class Entry : public ENABLE_SHARED_FROM_THIS(Entry) {
|
||||
|
||||
public:
|
||||
|
||||
@@ -47,7 +54,7 @@ namespace Pascal {
|
||||
unsigned inode() const { return _inode; }
|
||||
void setInode(unsigned inode) { _inode = inode; }
|
||||
|
||||
VolumeEntry *parent() { return _parent; }
|
||||
VolumeEntryWeakPointer parent() { return _parent; }
|
||||
|
||||
|
||||
protected:
|
||||
@@ -70,7 +77,7 @@ namespace Pascal {
|
||||
|
||||
friend class VolumeEntry;
|
||||
|
||||
VolumeEntry *_parent;
|
||||
VolumeEntryWeakPointer _parent;
|
||||
unsigned _address;
|
||||
|
||||
};
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include <Pascal/Pascal.h>
|
||||
#include <Pascal/TextWriter.h>
|
||||
|
||||
#include <ProFUSE/auto.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/auto.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <ProDOS/Exception.h>
|
||||
|
||||
#include <Endian/Endian.h>
|
||||
#include <Endian/IOBuffer.h>
|
||||
@@ -42,6 +43,18 @@ unsigned FileEntry::ValidName(const char *cp)
|
||||
return Entry::ValidName(cp, 15);
|
||||
}
|
||||
|
||||
FileEntryPointer FileEntry::Open(void *vp)
|
||||
{
|
||||
//return FileEntryPointer(new FileEntry(vp));
|
||||
return MAKE_SHARED(FileEntry, vp);
|
||||
}
|
||||
|
||||
FileEntryPointer FileEntry::Create(const char *name, unsigned fileKind)
|
||||
{
|
||||
//return FileEntryPointer(new FileEntry(name, fileKind));
|
||||
return MAKE_SHARED(FileEntry, name, fileKind);
|
||||
}
|
||||
|
||||
FileEntry::FileEntry(void *vp) :
|
||||
Entry(vp)
|
||||
{
|
||||
@@ -65,7 +78,7 @@ FileEntry::FileEntry(const char *name, unsigned fileKind)
|
||||
unsigned length = ValidName(name);
|
||||
|
||||
if (!length)
|
||||
throw ProFUSE::Exception(__METHOD__ ": Invalid file name.");
|
||||
throw ::Exception(__METHOD__ ": Invalid file name.");
|
||||
|
||||
_fileKind = fileKind;
|
||||
_status = 0;
|
||||
@@ -99,7 +112,10 @@ void FileEntry::setFileKind(unsigned kind)
|
||||
_pageSize = NULL;
|
||||
}
|
||||
|
||||
parent()->writeEntry(this);
|
||||
VolumeEntryPointer v = parent().lock();
|
||||
|
||||
// throw if expired?
|
||||
if (v) v->writeEntry(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +127,7 @@ void FileEntry::setName(const char *name)
|
||||
unsigned length = ValidName(name);
|
||||
|
||||
if (!length)
|
||||
throw ProFUSE::ProDOSException(__METHOD__ ": Invalid file name.", ProFUSE::badPathSyntax);
|
||||
throw ProDOS::Exception(__METHOD__ ": Invalid file name.", ProDOS::badPathSyntax);
|
||||
|
||||
_fileNameLength = length;
|
||||
for (unsigned i = 0; i < length; ++i)
|
||||
@@ -194,7 +210,9 @@ int FileEntry::truncate(unsigned newSize)
|
||||
return -1;
|
||||
|
||||
_modification = Date::Today();
|
||||
parent()->writeEntry(this);
|
||||
|
||||
VolumeEntryPointer v = parent().lock();
|
||||
if (v) v->writeEntry(this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -211,6 +229,8 @@ int FileEntry::truncateCommon(unsigned newSize)
|
||||
|
||||
unsigned currentSize = fileSize();
|
||||
|
||||
VolumeEntryPointer v = parent().lock();
|
||||
|
||||
if (newSize == currentSize) return 0;
|
||||
if (newSize > currentSize)
|
||||
{
|
||||
@@ -228,12 +248,13 @@ int FileEntry::truncateCommon(unsigned newSize)
|
||||
{
|
||||
// last page not full
|
||||
unsigned count = std::min(512 - _lastByte, remainder);
|
||||
uint8_t *address = (uint8_t *)parent()->loadBlock(block);
|
||||
|
||||
std::memset(address + _lastByte, 0, count);
|
||||
|
||||
parent()->unloadBlock(block, true);
|
||||
|
||||
if (v)
|
||||
{
|
||||
uint8_t *address = (uint8_t *)v->loadBlock(block);
|
||||
std::memset(address + _lastByte, 0, count);
|
||||
v->unloadBlock(block, true);
|
||||
}
|
||||
remainder -= count;
|
||||
}
|
||||
block++;
|
||||
@@ -241,12 +262,12 @@ int FileEntry::truncateCommon(unsigned newSize)
|
||||
while (remainder)
|
||||
{
|
||||
unsigned count = std::min(512u, remainder);
|
||||
uint8_t *address = (uint8_t *)parent()->loadBlock(block);
|
||||
|
||||
std::memset(address, 0, count);
|
||||
|
||||
parent()->unloadBlock(block, true);
|
||||
|
||||
if (v)
|
||||
{
|
||||
uint8_t *address = (uint8_t *)v->loadBlock(block);
|
||||
std::memset(address, 0, count);
|
||||
v->unloadBlock(block, true);
|
||||
}
|
||||
remainder -= count;
|
||||
block++;
|
||||
}
|
||||
@@ -264,7 +285,15 @@ int FileEntry::write(TextWriter &text)
|
||||
{
|
||||
unsigned blocks = text.blocks();
|
||||
|
||||
if (parent()->readOnly())
|
||||
VolumeEntryPointer v = parent().lock();
|
||||
if (!v)
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (v->readOnly())
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
@@ -286,7 +315,7 @@ int FileEntry::write(TextWriter &text)
|
||||
for (unsigned i = 0; i < blocks; ++i)
|
||||
{
|
||||
void *buffer = text.data(i);
|
||||
parent()->writeBlock(_firstBlock + i, buffer);
|
||||
v->writeBlock(_firstBlock + i, buffer);
|
||||
|
||||
}
|
||||
|
||||
@@ -294,8 +323,8 @@ int FileEntry::write(TextWriter &text)
|
||||
|
||||
setFileSize(blocks * 512);
|
||||
|
||||
parent()->writeEntry(this);
|
||||
parent()->sync();
|
||||
v->writeEntry(this);
|
||||
v->sync();
|
||||
|
||||
return blocks * 512;
|
||||
}
|
||||
@@ -304,8 +333,15 @@ int FileEntry::write(const uint8_t *buffer, unsigned size, unsigned offset)
|
||||
{
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "FileEntry::write"
|
||||
|
||||
if (parent()->readOnly())
|
||||
|
||||
VolumeEntryPointer v = parent().lock();
|
||||
if (!v)
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (v->readOnly())
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
@@ -342,10 +378,10 @@ int FileEntry::write(const uint8_t *buffer, unsigned size, unsigned offset)
|
||||
if (start)
|
||||
{
|
||||
unsigned count = std::min(512 - start, remainder);
|
||||
uint8_t *address = (uint8_t *)parent()->loadBlock(block);
|
||||
uint8_t *address = (uint8_t *)v->loadBlock(block);
|
||||
|
||||
std::memcpy(address + start, buffer, count);
|
||||
parent()->unloadBlock(block, true);
|
||||
v->unloadBlock(block, true);
|
||||
|
||||
remainder -= count;
|
||||
buffer += count;
|
||||
@@ -354,12 +390,12 @@ int FileEntry::write(const uint8_t *buffer, unsigned size, unsigned offset)
|
||||
|
||||
while (remainder)
|
||||
{
|
||||
uint8_t *address = (uint8_t *)parent()->loadBlock(block);
|
||||
uint8_t *address = (uint8_t *)v->loadBlock(block);
|
||||
|
||||
unsigned count = std::min(512u, size);
|
||||
|
||||
std::memcpy(address, buffer, count);
|
||||
parent()->unloadBlock(block, true);
|
||||
v->unloadBlock(block, true);
|
||||
|
||||
remainder -= count;
|
||||
buffer += count;
|
||||
@@ -371,7 +407,7 @@ int FileEntry::write(const uint8_t *buffer, unsigned size, unsigned offset)
|
||||
|
||||
|
||||
_modification = Date::Today();
|
||||
parent()->writeEntry(this);
|
||||
v->writeEntry(this);
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -419,6 +455,13 @@ int FileEntry::dataRead(uint8_t *buffer, unsigned size, unsigned offset)
|
||||
|
||||
unsigned count = 0;
|
||||
unsigned block = 0;
|
||||
|
||||
VolumeEntryPointer v = parent().lock();
|
||||
if (!v)
|
||||
{
|
||||
errno = EROFS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
block = _firstBlock + (offset / 512);
|
||||
|
||||
@@ -433,7 +476,7 @@ int FileEntry::dataRead(uint8_t *buffer, unsigned size, unsigned offset)
|
||||
{
|
||||
unsigned bytes = std::min(offset % 512, size);
|
||||
|
||||
parent()->readBlock(block++, tmp);
|
||||
v->readBlock(block++, tmp);
|
||||
|
||||
std::memcpy(buffer, tmp + 512 - bytes, bytes);
|
||||
|
||||
@@ -448,7 +491,7 @@ int FileEntry::dataRead(uint8_t *buffer, unsigned size, unsigned offset)
|
||||
|
||||
while (size >= 512)
|
||||
{
|
||||
parent()->readBlock(block++, buffer);
|
||||
v->readBlock(block++, buffer);
|
||||
|
||||
buffer += 512;
|
||||
count += 512;
|
||||
@@ -460,7 +503,7 @@ int FileEntry::dataRead(uint8_t *buffer, unsigned size, unsigned offset)
|
||||
*/
|
||||
if (size)
|
||||
{
|
||||
parent()->readBlock(block, tmp);
|
||||
v->readBlock(block, tmp);
|
||||
std::memcpy(buffer, tmp, size);
|
||||
|
||||
count += size;
|
||||
@@ -481,7 +524,7 @@ int FileEntry::textRead(uint8_t *buffer, unsigned size, unsigned offset)
|
||||
unsigned l;
|
||||
unsigned count = 0;
|
||||
|
||||
ProFUSE::auto_array<uint8_t> tmp;
|
||||
::auto_array<uint8_t> tmp;
|
||||
unsigned tmpSize = 0;
|
||||
|
||||
if (!_pageSize) textInit();
|
||||
@@ -589,13 +632,20 @@ unsigned FileEntry::textReadPage(unsigned block, uint8_t *in)
|
||||
// reads up to 2 blocks.
|
||||
// assumes block within _startBlock ... _lastBlock - 1
|
||||
|
||||
parent()->readBlock(block, in);
|
||||
VolumeEntryPointer v = parent().lock();
|
||||
if (!v)
|
||||
{
|
||||
errno = EROFS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
v->readBlock(block, in);
|
||||
if (block + 1 == _lastBlock)
|
||||
{
|
||||
return _lastByte;
|
||||
}
|
||||
|
||||
parent()->readBlock(block + 1, in + 512);
|
||||
v->readBlock(block + 1, in + 512);
|
||||
if (block +2 == _lastBlock)
|
||||
{
|
||||
return 512 + _lastByte;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __PASCAL_FILEENTRY_H__
|
||||
|
||||
#include <Pascal/Entry.h>
|
||||
#include <Pascal/Date.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -22,8 +23,10 @@ namespace Pascal {
|
||||
static bool Uncompress(std::string& text);
|
||||
|
||||
|
||||
FileEntry(const char *name, unsigned fileKind);
|
||||
FileEntry(void *vp);
|
||||
static FileEntryPointer Create(const char *name, unsigned fileKind);
|
||||
static FileEntryPointer Open(void *vp);
|
||||
|
||||
|
||||
|
||||
virtual ~FileEntry();
|
||||
|
||||
@@ -44,7 +47,10 @@ namespace Pascal {
|
||||
|
||||
int truncate(unsigned newSize);
|
||||
|
||||
|
||||
|
||||
FileEntry(const char *name, unsigned fileKind);
|
||||
FileEntry(void *vp);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void writeDirectoryEntry(LittleEndian::IOBuffer *);
|
||||
@@ -54,6 +60,13 @@ namespace Pascal {
|
||||
|
||||
friend class VolumeEntry;
|
||||
|
||||
|
||||
FileEntryPointer thisPointer()
|
||||
{
|
||||
return STATIC_POINTER_CAST(FileEntry, shared_from_this());
|
||||
}
|
||||
|
||||
|
||||
void setName(const char *name);
|
||||
|
||||
int truncateCommon(unsigned newSize);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <Pascal/TextWriter.h>
|
||||
#include <Pascal/FileEntry.h>
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
@@ -89,7 +89,7 @@ void TextWriter::writeLine(const char *line, unsigned length)
|
||||
|
||||
if (length > 1024)
|
||||
{
|
||||
throw ProFUSE::Exception(__METHOD__ ": String is too long.");
|
||||
throw ::Exception(__METHOD__ ": String is too long.");
|
||||
}
|
||||
if (_offset + length > 1024)
|
||||
{
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
#include <Pascal/Pascal.h>
|
||||
|
||||
#include <ProFUSE/auto.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/auto.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <ProDOS/Exception.h>
|
||||
|
||||
#include <Endian/Endian.h>
|
||||
#include <Endian/IOBuffer.h>
|
||||
@@ -21,9 +22,6 @@ using namespace Pascal;
|
||||
|
||||
using namespace Device;
|
||||
|
||||
using ProFUSE::Exception;
|
||||
using ProFUSE::ProDOSException;
|
||||
using ProFUSE::POSIXException;
|
||||
|
||||
enum {
|
||||
kMaxFiles = 77
|
||||
@@ -61,6 +59,31 @@ unsigned VolumeEntry::ValidName(const char *cp)
|
||||
return Entry::ValidName(cp, 7);
|
||||
}
|
||||
|
||||
|
||||
VolumeEntryPointer VolumeEntry::Open(Device::BlockDevicePointer device)
|
||||
{
|
||||
VolumeEntryPointer ptr;
|
||||
|
||||
//ptr = new VolumeEntry(device));
|
||||
ptr = MAKE_SHARED(VolumeEntry, device);
|
||||
|
||||
// set up the weak references from the file entry to this.
|
||||
if (ptr) ptr->setParents();
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
VolumeEntryPointer VolumeEntry::Create(Device::BlockDevicePointer device, const char *name)
|
||||
{
|
||||
VolumeEntryPointer ptr;
|
||||
|
||||
//ptr = new VolumeEntry(device, name);
|
||||
ptr = MAKE_SHARED(VolumeEntry, device, name);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
VolumeEntry::VolumeEntry()
|
||||
{
|
||||
_fileNameLength = 0;
|
||||
@@ -71,12 +94,11 @@ VolumeEntry::VolumeEntry()
|
||||
|
||||
setInode(1);
|
||||
|
||||
_inodeGenerator = 1;
|
||||
_cache = NULL;
|
||||
_device = NULL;
|
||||
_inodeGenerator = 1;
|
||||
}
|
||||
|
||||
VolumeEntry::VolumeEntry(const char *name, Device::BlockDevice *device)
|
||||
VolumeEntry::VolumeEntry(Device::BlockDevicePointer device, const char *name) :
|
||||
_device(device)
|
||||
{
|
||||
#undef __METHOD__
|
||||
#define __METHOD__ "VolumeEntry::VolumeEntry"
|
||||
@@ -87,13 +109,13 @@ VolumeEntry::VolumeEntry(const char *name, Device::BlockDevice *device)
|
||||
|
||||
deviceBlocks = std::min(0xffffu, deviceBlocks);
|
||||
if (deviceBlocks < 6)
|
||||
throw Exception(__METHOD__ ": device too small.");
|
||||
throw ::Exception(__METHOD__ ": device too small.");
|
||||
|
||||
|
||||
length = ValidName(name);
|
||||
|
||||
if (!length)
|
||||
throw ProDOSException(__METHOD__ ": Invalid volume name.", ProFUSE::badPathSyntax);
|
||||
throw ProDOS::Exception(__METHOD__ ": Invalid volume name.", ProDOS::badPathSyntax);
|
||||
|
||||
_firstBlock = 0;
|
||||
_lastBlock = 6;
|
||||
@@ -114,8 +136,8 @@ VolumeEntry::VolumeEntry(const char *name, Device::BlockDevice *device)
|
||||
_accessTime = 0;
|
||||
_lastBoot = Date::Today();
|
||||
|
||||
_cache = BlockCache::Create(device);
|
||||
_device = device;
|
||||
_cache = BlockCache::Create(device);
|
||||
|
||||
_address = 512 * 2;
|
||||
|
||||
@@ -136,11 +158,11 @@ VolumeEntry::VolumeEntry(const char *name, Device::BlockDevice *device)
|
||||
}
|
||||
|
||||
|
||||
VolumeEntry::VolumeEntry(Device::BlockDevice *device)
|
||||
VolumeEntry::VolumeEntry(Device::BlockDevicePointer device)
|
||||
{
|
||||
unsigned blockCount;
|
||||
unsigned deviceBlocks = device->blocks();
|
||||
ProFUSE::auto_array<uint8_t> buffer(new uint8_t[512]);
|
||||
//unsigned deviceBlocks = device->blocks();
|
||||
::auto_array<uint8_t> buffer(new uint8_t[512]);
|
||||
|
||||
|
||||
// read the header block, then load up all the header
|
||||
@@ -167,91 +189,79 @@ VolumeEntry::VolumeEntry(Device::BlockDevice *device)
|
||||
}
|
||||
|
||||
// now load up all the children.
|
||||
// if this throws, memory could be lost...
|
||||
|
||||
// the parent cannot be set (yet), since we need a shared_ptr to create a weak_ptr.
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
std::vector<FileEntry *>::iterator iter;
|
||||
|
||||
unsigned block;
|
||||
|
||||
for (unsigned i = 1; i <= _fileCount; ++i)
|
||||
{
|
||||
std::auto_ptr<FileEntry> child;
|
||||
|
||||
//
|
||||
child.reset(new FileEntry(buffer.get() + i * 0x1a));
|
||||
|
||||
child->setInode(++_inodeGenerator);
|
||||
child->_parent = this;
|
||||
child->_address = 512 * 2 + i * 0x1a;
|
||||
|
||||
_files.push_back(child.release());
|
||||
}
|
||||
|
||||
// sanity check _firstBlock, _lastBlock?
|
||||
|
||||
block = _lastBlock;
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
FileEntry *e = *iter;
|
||||
bool error = false;
|
||||
if (e->_firstBlock > e->_lastBlock)
|
||||
error = true;
|
||||
std::vector<FileEntryPointer>::iterator iter;
|
||||
|
||||
if (e->_firstBlock >= _lastVolumeBlock)
|
||||
error = true;
|
||||
|
||||
if (e->_lastBlock > _lastVolumeBlock)
|
||||
error = true;
|
||||
|
||||
if (e->_firstBlock < block)
|
||||
error = true;
|
||||
|
||||
if (error)
|
||||
throw ProDOSException(__METHOD__ ": Invalid file entry.", ProFUSE::dirError);
|
||||
|
||||
block = e->_lastBlock;
|
||||
|
||||
}
|
||||
|
||||
|
||||
calcMaxFileSize();
|
||||
|
||||
}
|
||||
catch (...)
|
||||
unsigned block;
|
||||
|
||||
for (unsigned i = 1; i <= _fileCount; ++i)
|
||||
{
|
||||
std::vector<FileEntry *>::iterator iter;
|
||||
|
||||
for(iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
if (*iter) delete *iter;
|
||||
}
|
||||
|
||||
throw;
|
||||
FileEntryPointer child;
|
||||
|
||||
//
|
||||
child = FileEntry::Open(buffer.get() + i * 0x1a);
|
||||
|
||||
child->setInode(++_inodeGenerator);
|
||||
// need to set later....
|
||||
//child->_parent = this;
|
||||
child->_address = 512 * 2 + i * 0x1a;
|
||||
|
||||
_files.push_back(child);
|
||||
}
|
||||
|
||||
// sanity check _firstBlock, _lastBlock?
|
||||
|
||||
block = _lastBlock;
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
FileEntryPointer e = *iter;
|
||||
bool error = false;
|
||||
if (e->_firstBlock > e->_lastBlock)
|
||||
error = true;
|
||||
|
||||
if (e->_firstBlock >= _lastVolumeBlock)
|
||||
error = true;
|
||||
|
||||
if (e->_lastBlock > _lastVolumeBlock)
|
||||
error = true;
|
||||
|
||||
if (e->_firstBlock < block)
|
||||
error = true;
|
||||
|
||||
if (error)
|
||||
throw ProDOS::Exception(__METHOD__ ": Invalid file entry.", ProDOS::dirError);
|
||||
|
||||
block = e->_lastBlock;
|
||||
|
||||
}
|
||||
|
||||
|
||||
calcMaxFileSize();
|
||||
}
|
||||
|
||||
VolumeEntry::~VolumeEntry()
|
||||
{
|
||||
|
||||
std::vector<FileEntry *>::iterator iter;
|
||||
for(iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
if (*iter) delete *iter;
|
||||
}
|
||||
|
||||
delete _cache;
|
||||
// _device is deleted by _cache.
|
||||
//delete _device;
|
||||
}
|
||||
|
||||
|
||||
void VolumeEntry::setParents()
|
||||
{
|
||||
// parent is this....
|
||||
|
||||
VolumeEntryWeakPointer parent(thisPointer());
|
||||
std::vector<FileEntryPointer>::iterator iter;
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
FileEntryPointer e = *iter;
|
||||
|
||||
e->_parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeEntry::init(void *vp)
|
||||
{
|
||||
#undef __METHOD__
|
||||
@@ -262,7 +272,7 @@ void VolumeEntry::init(void *vp)
|
||||
|
||||
// verify filenamelength <= 7
|
||||
if (_fileNameLength > 7)
|
||||
throw ProDOSException(__METHOD__ ": invalid name length", ProFUSE::badPathSyntax);
|
||||
throw ProDOS::Exception(__METHOD__ ": invalid name length", ProDOS::badPathSyntax);
|
||||
|
||||
// verify fileKind == 0
|
||||
// verify _fileCount reasonable
|
||||
@@ -282,20 +292,20 @@ void VolumeEntry::init(void *vp)
|
||||
}
|
||||
|
||||
|
||||
FileEntry *VolumeEntry::fileAtIndex(unsigned i) const
|
||||
FileEntryPointer VolumeEntry::fileAtIndex(unsigned i) const
|
||||
{
|
||||
return i < _files.size() ? _files[i] : NULL;
|
||||
return i < _files.size() ? _files[i] : FileEntryPointer();
|
||||
}
|
||||
|
||||
FileEntry *VolumeEntry::fileByName(const char *name) const
|
||||
FileEntryPointer VolumeEntry::fileByName(const char *name) const
|
||||
{
|
||||
std::vector<FileEntry *>::const_iterator iter;
|
||||
std::vector<FileEntryPointer>::const_iterator iter;
|
||||
for(iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
FileEntry *e = *iter;
|
||||
FileEntryPointer e = *iter;
|
||||
if (::strcasecmp(name, e->name()) == 0) return e;
|
||||
}
|
||||
return NULL;
|
||||
return FileEntryPointer();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -307,7 +317,7 @@ int VolumeEntry::unlink(const char *name)
|
||||
{
|
||||
unsigned index;
|
||||
|
||||
std::vector<FileEntry *>::iterator iter;
|
||||
std::vector<FileEntryPointer>::iterator iter;
|
||||
|
||||
if (_device->readOnly())
|
||||
{
|
||||
@@ -319,7 +329,7 @@ int VolumeEntry::unlink(const char *name)
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
FileEntry *e = *iter;
|
||||
FileEntryPointer e = *iter;
|
||||
if (::strcasecmp(name, e->name()) == 0)
|
||||
{
|
||||
|
||||
@@ -327,12 +337,11 @@ int VolumeEntry::unlink(const char *name)
|
||||
// _maxFileSize.
|
||||
if (iter != _files.begin())
|
||||
{
|
||||
FileEntry *prev = iter[-1];
|
||||
FileEntryPointer prev = iter[-1];
|
||||
prev->_maxFileSize += e->_maxFileSize;
|
||||
}
|
||||
|
||||
delete e;
|
||||
*iter = NULL;
|
||||
iter->reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -351,12 +360,12 @@ int VolumeEntry::unlink(const char *name)
|
||||
// reset addresses.
|
||||
for ( ; iter != _files.end(); ++iter)
|
||||
{
|
||||
FileEntry *e = *iter;
|
||||
FileEntryPointer e = *iter;
|
||||
e->_address -= 0x1a;
|
||||
}
|
||||
|
||||
// need to update the header blocks.
|
||||
ProFUSE::auto_array<uint8_t> buffer(readDirectoryHeader());
|
||||
::auto_array<uint8_t> buffer(readDirectoryHeader());
|
||||
|
||||
|
||||
// update the filecount.
|
||||
@@ -384,7 +393,7 @@ int VolumeEntry::unlink(const char *name)
|
||||
*/
|
||||
int VolumeEntry::rename(const char *oldName, const char *newName)
|
||||
{
|
||||
FileEntry *e;
|
||||
FileEntryPointer e;
|
||||
|
||||
|
||||
// check if read only.
|
||||
@@ -421,7 +430,7 @@ int VolumeEntry::rename(const char *oldName, const char *newName)
|
||||
|
||||
// and commit to disk.
|
||||
|
||||
writeEntry(e);
|
||||
writeEntry(e.get());
|
||||
_cache->sync();
|
||||
|
||||
return 0;
|
||||
@@ -435,8 +444,8 @@ int VolumeEntry::rename(const char *oldName, const char *newName)
|
||||
*/
|
||||
int VolumeEntry::copy(const char *oldName, const char *newName)
|
||||
{
|
||||
FileEntry *oldEntry;
|
||||
FileEntry *newEntry;
|
||||
FileEntryPointer oldEntry;
|
||||
FileEntryPointer newEntry;
|
||||
// check if read only.
|
||||
if (_device->readOnly())
|
||||
{
|
||||
@@ -486,14 +495,14 @@ int VolumeEntry::copy(const char *oldName, const char *newName)
|
||||
return -1;
|
||||
}
|
||||
|
||||
newEntry = NULL;
|
||||
newEntry.reset();
|
||||
|
||||
if (unlink(newName) != 0) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (newEntry == NULL)
|
||||
if (!newEntry)
|
||||
{
|
||||
// newName does not exist (or was just deleted), so create a new file (if possible) and write to it.
|
||||
if (maxContiguousBlocks() < blocks)
|
||||
@@ -538,7 +547,7 @@ int VolumeEntry::copy(const char *oldName, const char *newName)
|
||||
*
|
||||
*
|
||||
*/
|
||||
FileEntry *VolumeEntry::create(const char *name, unsigned blocks)
|
||||
FileEntryPointer VolumeEntry::create(const char *name, unsigned blocks)
|
||||
{
|
||||
// 0. check read only access.
|
||||
// 1. verify < 77 file names.
|
||||
@@ -551,48 +560,47 @@ FileEntry *VolumeEntry::create(const char *name, unsigned blocks)
|
||||
unsigned lastBlock = _lastBlock;
|
||||
|
||||
|
||||
std::auto_ptr<FileEntry>entry;
|
||||
FileEntry *prev = NULL;
|
||||
FileEntry *curr = NULL;
|
||||
std::vector<FileEntry *>::iterator iter;
|
||||
FileEntryPointer entry;
|
||||
FileEntryPointer prev;
|
||||
FileEntryPointer curr;
|
||||
std::vector<FileEntryPointer>::iterator iter;
|
||||
|
||||
|
||||
if (readOnly())
|
||||
{
|
||||
errno = EROFS;
|
||||
return NULL;
|
||||
return FileEntryPointer();
|
||||
}
|
||||
|
||||
if (_fileCount == kMaxFiles)
|
||||
{
|
||||
errno = ENOSPC;
|
||||
return NULL;
|
||||
return FileEntryPointer();
|
||||
}
|
||||
|
||||
|
||||
if (!FileEntry::ValidName(name))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
return FileEntryPointer();
|
||||
}
|
||||
|
||||
if (fileByName(name))
|
||||
{
|
||||
errno = EEXIST;
|
||||
return NULL;
|
||||
return FileEntryPointer();
|
||||
}
|
||||
|
||||
|
||||
entry.reset(new FileEntry(name, kUntypedFile));
|
||||
entry = FileEntry::Create(name, kUntypedFile);
|
||||
|
||||
|
||||
std::auto_ptr<uint8_t> buffer(readDirectoryHeader());
|
||||
::auto_array<uint8_t> buffer(readDirectoryHeader());
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
FileEntry *e = *iter;
|
||||
FileEntryPointer e = *iter;
|
||||
|
||||
unsigned freeSpace = e->_firstBlock - _lastBlock;
|
||||
unsigned freeSpace = e->_firstBlock - lastBlock;
|
||||
// this could do something stupid like selecting a slot with only 1 free block but too bad.
|
||||
|
||||
if (freeSpace < blocks)
|
||||
@@ -615,12 +623,13 @@ FileEntry *VolumeEntry::create(const char *name, unsigned blocks)
|
||||
// keep track of the index *before* the insert.
|
||||
unsigned index = distance(_files.begin(), iter); // current index.
|
||||
|
||||
iter = _files.insert(iter, entry.get());
|
||||
iter = _files.insert(iter, entry);
|
||||
++_fileCount;
|
||||
|
||||
curr = entry.release();
|
||||
curr = entry;
|
||||
|
||||
curr->_parent = this;
|
||||
//curr->_parent = this;
|
||||
curr->_parent = VolumeEntryWeakPointer(thisPointer());
|
||||
curr->_firstBlock = lastBlock;
|
||||
curr->_lastBlock = lastBlock + 1;
|
||||
curr->_lastByte = 0;
|
||||
@@ -642,15 +651,16 @@ FileEntry *VolumeEntry::create(const char *name, unsigned blocks)
|
||||
if (freeSpace < blocks)
|
||||
{
|
||||
errno = ENOSPC;
|
||||
return NULL;
|
||||
return FileEntryPointer();
|
||||
}
|
||||
|
||||
_files.push_back(entry.get());
|
||||
_files.push_back(entry);
|
||||
_fileCount++;
|
||||
|
||||
curr = entry.release();
|
||||
curr = entry;
|
||||
|
||||
curr->_parent = this;
|
||||
//curr->_parent = this;
|
||||
curr->_parent = VolumeEntryWeakPointer(thisPointer());
|
||||
curr->_firstBlock = lastBlock;
|
||||
curr->_lastBlock = lastBlock + 1;
|
||||
curr->_lastByte = 0;
|
||||
@@ -662,7 +672,7 @@ FileEntry *VolumeEntry::create(const char *name, unsigned blocks)
|
||||
prev->_maxFileSize = prev->blocks() * 512;
|
||||
}
|
||||
|
||||
writeEntry(curr);
|
||||
writeEntry(curr.get());
|
||||
writeEntry(); // header.
|
||||
|
||||
}
|
||||
@@ -674,7 +684,7 @@ FileEntry *VolumeEntry::create(const char *name, unsigned blocks)
|
||||
unsigned address = 2 * 512 + 0x1a;
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter, address += 0x1a)
|
||||
{
|
||||
FileEntry *e = *iter;
|
||||
FileEntryPointer e = *iter;
|
||||
e->_address = address;
|
||||
}
|
||||
|
||||
@@ -710,7 +720,7 @@ int VolumeEntry::krunch()
|
||||
{
|
||||
unsigned prevBlock;
|
||||
|
||||
std::vector<FileEntry *>::const_iterator iter;
|
||||
std::vector<FileEntryPointer>::const_iterator iter;
|
||||
|
||||
bool gap = false;
|
||||
|
||||
@@ -720,7 +730,7 @@ int VolumeEntry::krunch()
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
FileEntry *e = *iter;
|
||||
FileEntryPointer e = *iter;
|
||||
|
||||
unsigned first = e->firstBlock();
|
||||
unsigned last = e->lastBlock();
|
||||
@@ -728,13 +738,13 @@ int VolumeEntry::krunch()
|
||||
if (first != prevBlock) gap = true;
|
||||
|
||||
if (first < prevBlock)
|
||||
return ProFUSE::damagedBitMap;
|
||||
return ProDOS::damagedBitMap;
|
||||
|
||||
if (last < first)
|
||||
return ProFUSE::damagedBitMap;
|
||||
return ProDOS::damagedBitMap;
|
||||
|
||||
if (first < volumeBlocks())
|
||||
return ProFUSE::damagedBitMap;
|
||||
return ProDOS::damagedBitMap;
|
||||
|
||||
|
||||
prevBlock = last;
|
||||
@@ -746,7 +756,7 @@ int VolumeEntry::krunch()
|
||||
|
||||
|
||||
// need to update the header blocks.
|
||||
ProFUSE::auto_array<uint8_t> buffer(readDirectoryHeader());
|
||||
::auto_array<uint8_t> buffer(readDirectoryHeader());
|
||||
IOBuffer b(buffer.get(), 512 * blocks());
|
||||
|
||||
|
||||
@@ -755,7 +765,7 @@ int VolumeEntry::krunch()
|
||||
unsigned offset = 0;
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter, ++offset)
|
||||
{
|
||||
FileEntry *e = *iter;
|
||||
FileEntryPointer e = *iter;
|
||||
|
||||
b.setOffset(0x1a + 0x1a * offset);
|
||||
|
||||
@@ -816,13 +826,13 @@ unsigned VolumeEntry::freeBlocks(bool krunched) const
|
||||
|
||||
if (krunched)
|
||||
{
|
||||
std::vector<FileEntry *>::const_iterator iter;
|
||||
std::vector<FileEntryPointer>::const_iterator iter;
|
||||
|
||||
lastBlock = _lastBlock;
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
const FileEntry *e = *iter;
|
||||
const FileEntryPointer e = *iter;
|
||||
freeBlocks += e->_firstBlock - lastBlock;
|
||||
lastBlock = e->_lastBlock;
|
||||
}
|
||||
@@ -846,13 +856,13 @@ unsigned VolumeEntry::freeBlocks(bool krunched) const
|
||||
bool VolumeEntry::canKrunch() const
|
||||
{
|
||||
|
||||
std::vector<FileEntry *>::const_iterator iter;
|
||||
std::vector<FileEntryPointer>::const_iterator iter;
|
||||
|
||||
unsigned lastBlock = _lastBlock;
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
const FileEntry *e = *iter;
|
||||
const FileEntryPointer e = *iter;
|
||||
if (e->_lastBlock != lastBlock) return true;
|
||||
lastBlock = e->_lastBlock;
|
||||
}
|
||||
@@ -868,13 +878,13 @@ unsigned VolumeEntry::maxContiguousBlocks() const
|
||||
{
|
||||
unsigned max = 0;
|
||||
|
||||
std::vector<FileEntry *>::const_iterator iter;
|
||||
std::vector<FileEntryPointer>::const_iterator iter;
|
||||
|
||||
unsigned lastBlock = _lastBlock;
|
||||
|
||||
for (iter = _files.begin(); iter != _files.end(); ++iter)
|
||||
{
|
||||
const FileEntry *e = *iter;
|
||||
const FileEntryPointer e = *iter;
|
||||
unsigned free = e->_firstBlock - lastBlock;
|
||||
max = std::max(max, free);
|
||||
|
||||
@@ -944,7 +954,7 @@ void VolumeEntry::writeDirectoryHeader(void *buffer)
|
||||
|
||||
uint8_t *VolumeEntry::readBlocks(unsigned startingBlock, unsigned count)
|
||||
{
|
||||
ProFUSE::auto_array<uint8_t> buffer(new uint8_t[512 * count]);
|
||||
::auto_array<uint8_t> buffer(new uint8_t[512 * count]);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
_cache->read(startingBlock + i, buffer.get() + 512 * i);
|
||||
@@ -989,7 +999,7 @@ void VolumeEntry::writeEntry(FileEntry *e)
|
||||
else
|
||||
{
|
||||
// crosses page boundaries.
|
||||
ProFUSE::auto_array<uint8_t> buffer(readBlocks(startBlock, 2));
|
||||
::auto_array<uint8_t> buffer(readBlocks(startBlock, 2));
|
||||
|
||||
IOBuffer b(buffer.get() + offset, 0x1a);
|
||||
|
||||
@@ -1003,11 +1013,11 @@ void VolumeEntry::writeEntry(FileEntry *e)
|
||||
// set _maxFileSize for all entries.
|
||||
void VolumeEntry::calcMaxFileSize()
|
||||
{
|
||||
std::vector<FileEntry *>::reverse_iterator riter;
|
||||
std::vector<FileEntryPointer>::reverse_iterator riter;
|
||||
unsigned block = _lastVolumeBlock;
|
||||
for (riter = _files.rbegin(); riter != _files.rend(); ++riter)
|
||||
{
|
||||
FileEntry *e = *riter;
|
||||
FileEntryPointer e = *riter;
|
||||
e->_maxFileSize = (block - e->_firstBlock) * 512;
|
||||
block = e->_firstBlock;
|
||||
}
|
||||
|
||||
@@ -9,20 +9,18 @@
|
||||
|
||||
namespace Pascal {
|
||||
|
||||
class FileEntry;
|
||||
|
||||
class VolumeEntry : public Entry {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
static unsigned ValidName(const char *);
|
||||
|
||||
static VolumeEntryPointer Open(Device::BlockDevicePointer);
|
||||
static VolumeEntryPointer Create(Device::BlockDevicePointer, const char *name);
|
||||
|
||||
//
|
||||
|
||||
// create new
|
||||
VolumeEntry(const char *name, Device::BlockDevice *);
|
||||
|
||||
// open existing
|
||||
VolumeEntry(Device::BlockDevice *);
|
||||
virtual ~VolumeEntry();
|
||||
|
||||
const char *name() const { return _fileName; }
|
||||
@@ -36,8 +34,8 @@ namespace Pascal {
|
||||
bool canKrunch() const;
|
||||
|
||||
|
||||
FileEntry *fileAtIndex(unsigned i) const;
|
||||
FileEntry *fileByName(const char *name) const;
|
||||
FileEntryPointer fileAtIndex(unsigned i) const;
|
||||
FileEntryPointer fileByName(const char *name) const;
|
||||
|
||||
|
||||
void *loadBlock(unsigned block);
|
||||
@@ -53,11 +51,13 @@ namespace Pascal {
|
||||
int unlink(const char *name);
|
||||
int rename(const char *oldName, const char *newName);
|
||||
int copy(const char *oldName, const char *newName);
|
||||
FileEntry *create(const char *name, unsigned blocks);
|
||||
FileEntryPointer create(const char *name, unsigned blocks);
|
||||
|
||||
|
||||
int krunch();
|
||||
|
||||
VolumeEntry(Device::BlockDevicePointer, const char *name);
|
||||
VolumeEntry(Device::BlockDevicePointer);
|
||||
|
||||
protected:
|
||||
virtual void writeDirectoryEntry(LittleEndian::IOBuffer *);
|
||||
@@ -65,10 +65,20 @@ namespace Pascal {
|
||||
private:
|
||||
|
||||
friend class FileEntry;
|
||||
|
||||
|
||||
VolumeEntry();
|
||||
|
||||
|
||||
|
||||
VolumeEntryPointer thisPointer()
|
||||
{
|
||||
return STATIC_POINTER_CAST(VolumeEntry, shared_from_this());
|
||||
}
|
||||
|
||||
void init(void *);
|
||||
void setParents();
|
||||
|
||||
|
||||
|
||||
|
||||
uint8_t *readDirectoryHeader();
|
||||
@@ -90,11 +100,11 @@ namespace Pascal {
|
||||
unsigned _accessTime;
|
||||
Pascal::Date _lastBoot;
|
||||
|
||||
std::vector<FileEntry *> _files;
|
||||
std::vector<FileEntryPointer> _files;
|
||||
unsigned _inodeGenerator;
|
||||
|
||||
Device::BlockDevice *_device;
|
||||
Device::BlockCache *_cache;
|
||||
Device::BlockDevicePointer _device;
|
||||
Device::BlockCachePointer _cache;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#include <cstring>
|
||||
|
||||
#include <ProDOS/Bitmap.h>
|
||||
#include <ProDOS/BlockDevice.h>
|
||||
#include "auto.h"
|
||||
|
||||
#include <Device/BlockDevice.h>
|
||||
#include <Cache/BlockCache.h>
|
||||
|
||||
using namespace ProDOS;
|
||||
|
||||
@@ -34,26 +33,25 @@ Bitmap::Bitmap(unsigned blocks)
|
||||
_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);
|
||||
_bitmap.reserve(bitmapSize);
|
||||
|
||||
// edge case
|
||||
unsigned tmp = blocks & 0x07;
|
||||
// mark blocks as free..
|
||||
_bitmap.resize(blocks / 8, 0xff);
|
||||
|
||||
bitmap[blocks / 8] = ~(0xff >> tmp);
|
||||
// edge case...
|
||||
|
||||
_bitmap = bitmap.release();
|
||||
if (blocks & 0x0f)
|
||||
{
|
||||
_bitmap.push_back( ~(0xff >> (blocks & 0x0f)) );
|
||||
}
|
||||
|
||||
// mark any trailing blocks as in use.
|
||||
|
||||
_bitmap.resize(bitmapSize, 0x00);
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(BlockDevice *device, unsigned keyPointer, unsigned blocks)
|
||||
Bitmap::Bitmap(Device::BlockCache *cache, unsigned keyPointer, unsigned blocks)
|
||||
{
|
||||
_blocks = blocks;
|
||||
_freeBlocks = 0;
|
||||
@@ -64,47 +62,68 @@ Bitmap::Bitmap(BlockDevice *device, unsigned keyPointer, unsigned blocks)
|
||||
unsigned bitmapSize = _bitmapBlocks * 512;
|
||||
unsigned blockSize = blocks / 8;
|
||||
|
||||
auto_array<uint8_t> bitmap(new uint8_t[bitmapSize]);
|
||||
_bitmap.reserve(bitmapSize);
|
||||
|
||||
|
||||
// load the full block(s).
|
||||
for (unsigned i = 0; i < blockSize; ++i)
|
||||
{
|
||||
device->read(keyPointer + i, bitmap + 512 * i);
|
||||
uint8_t *buffer = (uint8_t *)cache->acquire(keyPointer);
|
||||
|
||||
_bitmap.insert(_bitmap.end(), buffer, buffer + 512);
|
||||
|
||||
cache->release(keyPointer);
|
||||
|
||||
keyPointer++;
|
||||
}
|
||||
|
||||
// make sure all trailing bits are marked in use.
|
||||
|
||||
// edge case
|
||||
unsigned tmp = blocks & 0x07;
|
||||
// and any remaining partial block.
|
||||
|
||||
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)
|
||||
if (blocks & 4095)
|
||||
{
|
||||
_freeBlocks += popCount(bitmap[i]);
|
||||
}
|
||||
|
||||
if (_freeBlocks)
|
||||
{
|
||||
for (unsigned i = 0; i < (blocks + 7) / 8; ++i)
|
||||
|
||||
uint8_t *buffer = (uint8_t *)cache->acquire(keyPointer);
|
||||
|
||||
unsigned bits = blocks & 4095;
|
||||
unsigned bytes = bits / 8;
|
||||
|
||||
//for (unsigned i = 0; i < bits / 8; ++i) _bitmap.push_back(buffer[i]);
|
||||
|
||||
_bitmap.insert(_bitmap.end(), buffer, buffer + bytes);
|
||||
// partial...
|
||||
|
||||
if (blocks & 0x0f)
|
||||
{
|
||||
if (bitmap[i])
|
||||
{
|
||||
_freeIndex = i;
|
||||
break;
|
||||
}
|
||||
uint8_t tmp = buffer[bytes];
|
||||
tmp &= ~(0xff >> (blocks & 0x0f));
|
||||
|
||||
_bitmap.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
// remainder set to in use.
|
||||
_bitmap.resize(bitmapSize, 0x00);
|
||||
|
||||
cache->release(keyPointer);
|
||||
|
||||
keyPointer++;
|
||||
|
||||
}
|
||||
|
||||
_bitmap = bitmap.release();
|
||||
|
||||
// now set _freeBlocks and _freeIndex;
|
||||
std::vector<uint8_t>::iterator iter;
|
||||
|
||||
_freeIndex = -1;
|
||||
for (iter = _bitmap.begin(); iter != _bitmap.end(); ++iter)
|
||||
{
|
||||
_freeBlocks += popCount(*iter);
|
||||
if (_freeIndex == -1 && *iter)
|
||||
_freeIndex = std::distance(_bitmap.begin(), iter);
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap::~Bitmap()
|
||||
{
|
||||
if (_bitmap) delete []_bitmap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,20 +2,25 @@
|
||||
#define __BITMAP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Device
|
||||
{
|
||||
class BlockDevice;
|
||||
class BlockCache;
|
||||
}
|
||||
|
||||
|
||||
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(Device::BlockCache *cache, unsigned keyPointer, unsigned blocks);
|
||||
|
||||
~Bitmap();
|
||||
|
||||
int allocBlock();
|
||||
@@ -28,7 +33,7 @@ public:
|
||||
unsigned blocks() const { return _blocks; }
|
||||
unsigned bitmapBlocks() const { return _bitmapBlocks; }
|
||||
unsigned bitmapSize() const { return _bitmapBlocks * 512; }
|
||||
const void *bitmap() const { return _bitmap; }
|
||||
const void *bitmap() const { return &_bitmap[0]; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -38,7 +43,7 @@ private:
|
||||
unsigned _blocks;
|
||||
unsigned _bitmapBlocks;
|
||||
|
||||
uint8_t *_bitmap;
|
||||
std::vector<uint8_t> _bitmap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
486
ProDOS/Disk.cpp
Normal file
486
ProDOS/Disk.cpp
Normal file
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* Disk.cpp
|
||||
* ProFUSE
|
||||
*
|
||||
* Created by Kelvin Sherlock on 12/18/08.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Disk.h"
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <Endian/Endian.h>
|
||||
|
||||
struct ucmp
|
||||
{
|
||||
bool operator()(unsigned a, unsigned b) const
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
using std::set;
|
||||
using std::vector;
|
||||
|
||||
using namespace LittleEndian;
|
||||
|
||||
typedef set<unsigned, ucmp> uset;
|
||||
|
||||
Disk::Disk()
|
||||
{
|
||||
_blocks = 0;
|
||||
|
||||
}
|
||||
|
||||
Disk::~Disk()
|
||||
{
|
||||
}
|
||||
|
||||
Disk::Disk(Device::BlockDevicePointer device) :
|
||||
_device(device)
|
||||
{
|
||||
_blocks = _device->blocks();
|
||||
}
|
||||
|
||||
DiskPointer Disk::OpenFile(Device::BlockDevicePointer device)
|
||||
{
|
||||
DiskPointer disk(new Disk(device));
|
||||
|
||||
return disk;
|
||||
}
|
||||
|
||||
// load the mini entry into the regular entry.
|
||||
int Disk::Normalize(FileEntry &f, unsigned fork, ExtendedEntry *ee)
|
||||
{
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
int ok;
|
||||
|
||||
if (fork > 1) return -P8_INVALID_FORK;
|
||||
|
||||
if (f.storage_type != EXTENDED_FILE)
|
||||
{
|
||||
return fork == 0 ? 0 : -P8_INVALID_FORK;
|
||||
}
|
||||
|
||||
ok = Read(f.key_pointer, buffer);
|
||||
if (ok < 0) return ok;
|
||||
|
||||
ExtendedEntry e;
|
||||
e.Load(buffer);
|
||||
|
||||
if (fork == 0)
|
||||
{
|
||||
f.storage_type = e.dataFork.storage_type;
|
||||
f.key_pointer = e.dataFork.key_block;
|
||||
f.eof = e.dataFork.eof;
|
||||
f.blocks_used = e.dataFork.blocks_used;
|
||||
}
|
||||
else
|
||||
{
|
||||
f.storage_type = e.resourceFork.storage_type;
|
||||
f.key_pointer = e.resourceFork.key_block;
|
||||
f.eof = e.resourceFork.eof;
|
||||
f.blocks_used = e.resourceFork.blocks_used;
|
||||
}
|
||||
|
||||
if (ee) *ee = e;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int Disk::Read(unsigned block, void *buffer)
|
||||
{
|
||||
|
||||
if (block > _blocks) return -P8_INVALID_BLOCK;
|
||||
|
||||
_device->read(block, buffer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void *Disk::ReadFile(const FileEntry &f, unsigned fork, uint32_t *size, int *error)
|
||||
{
|
||||
|
||||
#define SET_ERROR(x) if (error) *error = (x)
|
||||
#define SET_SIZE(x) if (size) *size = (x)
|
||||
|
||||
|
||||
SET_ERROR(0);
|
||||
SET_SIZE(0);
|
||||
|
||||
if (fork != P8_DATA_FORK && fork != P8_RESOURCE_FORK)
|
||||
{
|
||||
SET_ERROR(-P8_INVALID_FORK);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
int ok;
|
||||
uint32_t eof;
|
||||
uint32_t alloc;
|
||||
unsigned blocks;
|
||||
unsigned storage_type;
|
||||
unsigned key_block;
|
||||
|
||||
switch(f.storage_type)
|
||||
{
|
||||
case SEEDLING_FILE:
|
||||
case SAPLING_FILE:
|
||||
case TREE_FILE:
|
||||
if (fork != P8_DATA_FORK)
|
||||
{
|
||||
SET_ERROR(1);
|
||||
return NULL;
|
||||
}
|
||||
storage_type = f.storage_type;
|
||||
eof = f.eof;
|
||||
key_block = f.key_pointer;
|
||||
break;
|
||||
|
||||
case EXTENDED_FILE:
|
||||
{
|
||||
ok = Read(f.key_pointer, buffer);
|
||||
if (ok < 0)
|
||||
{
|
||||
SET_ERROR(ok);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ExtendedEntry entry;
|
||||
entry.Load(buffer);
|
||||
|
||||
if (fork == P8_DATA_FORK)
|
||||
{
|
||||
storage_type = entry.dataFork.storage_type;
|
||||
eof = entry.dataFork.eof;
|
||||
key_block = entry.dataFork.key_block;
|
||||
}
|
||||
else
|
||||
{
|
||||
storage_type = entry.resourceFork.storage_type;
|
||||
eof = entry.resourceFork.eof;
|
||||
key_block = entry.resourceFork.key_block;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SET_ERROR(-P8_INVALID_STORAGE_TYPE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (eof == 0)
|
||||
{
|
||||
SET_ERROR(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blocks = (eof + BLOCK_SIZE - 1) >> 9;
|
||||
alloc = (eof + BLOCK_SIZE - 1) & (~BLOCK_SIZE);
|
||||
uint8_t* data = new uint8_t[alloc];
|
||||
|
||||
|
||||
switch (storage_type)
|
||||
{
|
||||
case SEEDLING_FILE:
|
||||
ok = Read(key_block, data);
|
||||
break;
|
||||
case SAPLING_FILE:
|
||||
ok = ReadIndex(f.key_pointer, buffer, 1, 0, blocks);
|
||||
break;
|
||||
case TREE_FILE:
|
||||
ok = ReadIndex(f.key_pointer, buffer, 2, 0, blocks);
|
||||
break;
|
||||
|
||||
default:
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok < 0)
|
||||
{
|
||||
SET_ERROR(ok);
|
||||
delete[] data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bzero(data + eof, alloc - eof);
|
||||
SET_SIZE(eof);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
int Disk::ReadFile(const FileEntry &f, void *buffer)
|
||||
{
|
||||
int blocks = (f.eof + BLOCK_SIZE - 1) >> 9;
|
||||
int ok;
|
||||
|
||||
switch(f.storage_type)
|
||||
{
|
||||
case TREE_FILE:
|
||||
ok = ReadIndex(f.key_pointer, buffer, 2, 0, blocks);
|
||||
break;
|
||||
case SAPLING_FILE:
|
||||
ok = ReadIndex(f.key_pointer, buffer, 1, 0, blocks);
|
||||
break;
|
||||
case SEEDLING_FILE:
|
||||
ok = Read(f.key_pointer, buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -P8_INVALID_STORAGE_TYPE;
|
||||
}
|
||||
|
||||
if (ok >= 0)
|
||||
{
|
||||
bzero((uint8_t *)buffer + f.eof, (blocks << 9) - f.eof);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
int Disk::ReadIndex(unsigned block, void *buffer, unsigned level, off_t offset, unsigned blocks)
|
||||
{
|
||||
if (level == 0)
|
||||
{
|
||||
// data level
|
||||
if (block == 0) // sparse file
|
||||
{
|
||||
bzero(buffer, BLOCK_SIZE);
|
||||
return 1;
|
||||
}
|
||||
return Read(block, buffer);
|
||||
}
|
||||
|
||||
|
||||
unsigned blockCount;
|
||||
unsigned readSize;
|
||||
unsigned first;
|
||||
//unsigned last;
|
||||
|
||||
|
||||
switch(level)
|
||||
{
|
||||
case 1:
|
||||
first = (offset >> 9) & 0xff;
|
||||
blockCount = 1;
|
||||
readSize = BLOCK_SIZE;
|
||||
offset = 0;
|
||||
break;
|
||||
case 2:
|
||||
first = (offset >> 17) & 0xff;
|
||||
blockCount = 256;
|
||||
readSize = BLOCK_SIZE << 8;
|
||||
offset &= 0x1ffff;
|
||||
break;
|
||||
default:
|
||||
return -P8_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int ok;
|
||||
uint8_t key[BLOCK_SIZE];
|
||||
|
||||
if (block) // not sparse.
|
||||
{
|
||||
ok = Read(block, key);
|
||||
if (ok < 0 ) return ok;
|
||||
}
|
||||
else
|
||||
{
|
||||
// sparse -- zero it out so code below works w/o special cases.
|
||||
bzero(key, BLOCK_SIZE);
|
||||
}
|
||||
|
||||
for (unsigned i = first; blocks; i++)
|
||||
{
|
||||
// block pointers are split up since 8-bit indexing is limited to 256.
|
||||
unsigned newBlock = (key[i]) | (key[256 + i] << 8);
|
||||
|
||||
unsigned b = std::min(blocks, blockCount);
|
||||
|
||||
ok = ReadIndex(newBlock, buffer, level - 1, offset, b);
|
||||
if (ok < 0) return ok;
|
||||
offset = 0;
|
||||
buffer = ((char *)buffer) + readSize;
|
||||
blocks -= b;
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Disk::ReadVolume(VolumeEntry *volume, std::vector<FileEntry> *files)
|
||||
{
|
||||
if (files) files->resize(0);
|
||||
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
int ok;
|
||||
unsigned prev;
|
||||
unsigned next;
|
||||
|
||||
uset blocks;
|
||||
|
||||
unsigned block = 2;
|
||||
blocks.insert(block);
|
||||
ok = Read(block, buffer);
|
||||
|
||||
if (ok < 0) return ok;
|
||||
|
||||
prev = Read16(&buffer[0x00]);
|
||||
next = Read16(&buffer[0x02]);
|
||||
|
||||
VolumeEntry v;
|
||||
v.Load(buffer + 0x04);
|
||||
|
||||
if (v.storage_type != VOLUME_HEADER) return -P8_INVALID_STORAGE_TYPE;
|
||||
|
||||
if (volume) *volume = v;
|
||||
|
||||
if (!files) return 1;
|
||||
|
||||
if (v.file_count)
|
||||
{
|
||||
files->reserve(v.file_count);
|
||||
//files->resize(v.file_count);
|
||||
|
||||
//unsigned count = 0;
|
||||
unsigned index = 1; // skip the header.
|
||||
for(;;)
|
||||
{
|
||||
//
|
||||
if ( (buffer[0x04 + v.entry_length * index] >> 4) != DELETED_FILE)
|
||||
{
|
||||
unsigned offset = v.entry_length * index + 0x4;
|
||||
FileEntry f;
|
||||
f.Load(buffer + offset);
|
||||
f.address = (block << 9) + offset;
|
||||
|
||||
files->push_back(f);
|
||||
//if (++count == v.file_count) break;
|
||||
}
|
||||
index++;
|
||||
if (index >= v.entries_per_block)
|
||||
{
|
||||
if (!next) break; // all done!
|
||||
|
||||
|
||||
if (blocks.insert(next).second == false)
|
||||
{
|
||||
return -P8_CYCLICAL_BLOCK;
|
||||
}
|
||||
|
||||
ok = Read(next, buffer);
|
||||
if (ok < 0) return ok;
|
||||
block = next;
|
||||
|
||||
prev = Read16(&buffer[0x00]);
|
||||
next = Read16(&buffer[0x02]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int Disk::ReadDirectory(unsigned block, SubdirEntry *dir, std::vector<FileEntry> *files)
|
||||
{
|
||||
if (files) files->resize(0);
|
||||
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
int ok;
|
||||
unsigned prev;
|
||||
unsigned next;
|
||||
|
||||
// keep a list of blocks to prevent cyclical problems.
|
||||
uset blocks;
|
||||
|
||||
blocks.insert(block);
|
||||
|
||||
ok = Read(block, buffer);
|
||||
|
||||
if (ok < 0) return ok;
|
||||
|
||||
prev = Read16(&buffer[0x00]);
|
||||
next = Read16(&buffer[0x02]);
|
||||
|
||||
SubdirEntry v;
|
||||
v.Load(buffer + 0x04);
|
||||
|
||||
if (v.storage_type != SUBDIR_HEADER) return -P8_INVALID_STORAGE_TYPE;
|
||||
|
||||
|
||||
if (dir) *dir = v;
|
||||
|
||||
if (!files) return 1;
|
||||
|
||||
if (v.file_count)
|
||||
{
|
||||
files->reserve(v.file_count);
|
||||
//files->resize(v.file_count);
|
||||
|
||||
//unsigned count = 0;
|
||||
unsigned index = 1; // skip the header.
|
||||
for(;;)
|
||||
{
|
||||
//
|
||||
if ( (buffer[0x04 + v.entry_length * index] >> 4) != DELETED_FILE)
|
||||
{
|
||||
unsigned offset = v.entry_length * index + 0x4;
|
||||
FileEntry f;
|
||||
f.Load(buffer + offset);
|
||||
f.address = (block << 9) + offset;
|
||||
|
||||
files->push_back(f);
|
||||
|
||||
//if (++count == v.file_count) break;
|
||||
}
|
||||
index++;
|
||||
if (index >= v.entries_per_block)
|
||||
{
|
||||
if (!next) break; // all done!
|
||||
|
||||
|
||||
if (blocks.insert(next).second == false)
|
||||
{
|
||||
return -P8_CYCLICAL_BLOCK;
|
||||
}
|
||||
|
||||
ok = Read(next, buffer);
|
||||
if (ok < 0) return ok;
|
||||
block = next;
|
||||
|
||||
|
||||
prev = Read16(&buffer[0x00]);
|
||||
next = Read16(&buffer[0x02]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
84
ProDOS/Disk.h
Normal file
84
ProDOS/Disk.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Disk.h
|
||||
* ProFUSE
|
||||
*
|
||||
* Created by Kelvin Sherlock on 12/18/08.
|
||||
*
|
||||
*/
|
||||
#ifndef __DISK_H__
|
||||
#define __DISK_H__
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <ProDOS/File.h>
|
||||
#include <Device/BlockDevice.h>
|
||||
|
||||
#include <memory>
|
||||
#include <Common/smart_pointers.h>
|
||||
|
||||
|
||||
enum {
|
||||
P8_OK = 0,
|
||||
P8_INTERNAL_ERROR,
|
||||
P8_INVALID_FORK,
|
||||
P8_INVALID_BLOCK,
|
||||
P8_INVALID_STORAGE_TYPE,
|
||||
P8_CYCLICAL_BLOCK
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
P8_DATA_FORK = 0,
|
||||
P8_RESOURCE_FORK = 1
|
||||
};
|
||||
|
||||
|
||||
/* flags */
|
||||
enum {
|
||||
P8_DOS_ORDER = 1,
|
||||
P8_2MG = 2,
|
||||
P8_DC42 = 4
|
||||
|
||||
};
|
||||
|
||||
class Disk;
|
||||
typedef SHARED_PTR(Disk) DiskPointer;
|
||||
|
||||
class Disk {
|
||||
|
||||
public:
|
||||
~Disk();
|
||||
|
||||
//static Disk *Open2MG(const char *file);
|
||||
static DiskPointer OpenFile(Device::BlockDevicePointer device);
|
||||
|
||||
|
||||
int Normalize(FileEntry &f, unsigned fork, ExtendedEntry *ee = NULL);
|
||||
|
||||
int Read(unsigned block, void *buffer);
|
||||
int ReadIndex(unsigned block, void *buffer, unsigned level, off_t offset, unsigned blocks);
|
||||
|
||||
int ReadFile(const FileEntry &f, void *buffer);
|
||||
|
||||
void *ReadFile(const FileEntry &f, unsigned fork, uint32_t *size, int * error);
|
||||
|
||||
|
||||
int ReadVolume(VolumeEntry *volume, std::vector<FileEntry> *files);
|
||||
int ReadDirectory(unsigned block, SubdirEntry *dir, std::vector<FileEntry> *files);
|
||||
|
||||
private:
|
||||
Disk();
|
||||
Disk(Device::BlockDevicePointer device);
|
||||
|
||||
unsigned _blocks;
|
||||
|
||||
Device::BlockDevicePointer _device;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,32 +1,14 @@
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <stdio.h>
|
||||
#include "Exception.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
using namespace ProFUSE;
|
||||
namespace ProDOS {
|
||||
|
||||
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())
|
||||
{
|
||||
@@ -145,4 +127,6 @@ const char *ProDOSException::errorString()
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
#ifndef __EXCEPTION_H__
|
||||
#define __EXCEPTION_H__
|
||||
#ifndef __PRODOS_EXCEPTION_H__
|
||||
#define __PRODOS_EXCEPTION_H__
|
||||
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
namespace ProFUSE {
|
||||
namespace ProDOS {
|
||||
|
||||
|
||||
// ProDOS Errors
|
||||
@@ -67,87 +66,27 @@ enum
|
||||
resAddErr = 0x71
|
||||
};
|
||||
|
||||
class Exception : public std::exception
|
||||
{
|
||||
|
||||
class Exception : public ::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();
|
||||
|
||||
private:
|
||||
typedef ::Exception super;
|
||||
};
|
||||
|
||||
inline Exception::Exception(const char *cp):
|
||||
_error(0),
|
||||
_string(cp)
|
||||
|
||||
|
||||
inline Exception::Exception(const char *cp, int error) :
|
||||
super(cp, error)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
inline Exception::Exception(const std::string& string, int error) :
|
||||
super(string, error)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -155,4 +94,4 @@ inline ProDOSException::ProDOSException(const std::string& string, int error) :
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
231
ProDOS/File.cpp
Normal file
231
ProDOS/File.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* File.cpp
|
||||
* ProFUSE
|
||||
*
|
||||
* Created by Kelvin Sherlock on 12/18/08.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProDOS/File.h>
|
||||
#include <ProDOS/DateTime.h>
|
||||
#include <Endian/Endian.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
using namespace LittleEndian;
|
||||
|
||||
|
||||
bool FileEntry::Load(const void *data)
|
||||
{
|
||||
const uint8_t *cp = (const uint8_t *)data;
|
||||
|
||||
address = 0;
|
||||
|
||||
storage_type = cp[0x00] >> 4;
|
||||
name_length = cp[0x00] & 0x0f;
|
||||
|
||||
memcpy(file_name, &cp[0x01], name_length);
|
||||
file_name[name_length] = 0;
|
||||
|
||||
file_type = cp[0x10];
|
||||
|
||||
key_pointer = Read16(&cp[0x11]);
|
||||
|
||||
blocks_used = Read16(&cp[0x13]);
|
||||
|
||||
eof = Read24(&cp[0x15]);
|
||||
|
||||
creation = ProDOS::DateTime(Read16(&cp[0x18]), Read16(&cp[0x1a]));
|
||||
|
||||
//version = cp[0x1c];
|
||||
//min_version = cp[0x1d];
|
||||
|
||||
unsigned xcase = Read16(&cp[0x1c]);
|
||||
if (xcase & 0x8000)
|
||||
{
|
||||
// gsos technote #8
|
||||
unsigned mask = 0x4000;
|
||||
for (unsigned i = 0; i < name_length; i++)
|
||||
{
|
||||
if (xcase & mask) file_name[i] = tolower(file_name[i]);
|
||||
mask = mask >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
access = cp[0x1e];
|
||||
|
||||
|
||||
aux_type = Read16(&cp[0x1f]);
|
||||
|
||||
last_mod = ProDOS::DateTime(Read16(&cp[0x21]), Read16(&cp[0x23]));
|
||||
|
||||
header_pointer = Read16(&cp[0x25]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool ExtendedEntry::Load(const void *data)
|
||||
{
|
||||
const uint8_t *cp = (const uint8_t *)data;
|
||||
|
||||
//prodos technote #25.
|
||||
// offset 0 - mini entry for data fork
|
||||
|
||||
dataFork.storage_type = cp[0x00] & 0x0f;
|
||||
dataFork.key_block = Read16(&cp[0x01]);
|
||||
dataFork.blocks_used = Read16(&cp[0x03]);
|
||||
dataFork.eof = Read24(&cp[0x05]);
|
||||
|
||||
// offset 256 - mini entry for resource fork.
|
||||
|
||||
resourceFork.storage_type = cp[256 + 0x00] & 0x0f;
|
||||
resourceFork.key_block = Read16(&cp[256 + 0x01]);
|
||||
resourceFork.blocks_used = Read16(&cp[256 + 0x03]);
|
||||
resourceFork.eof = Read24(&cp[256 + 0x05]);
|
||||
|
||||
// xFInfo may be missing.
|
||||
bzero(FInfo, sizeof(FInfo));
|
||||
bzero(xFInfo, sizeof(xFInfo));
|
||||
|
||||
// size must be 18.
|
||||
unsigned size;
|
||||
unsigned entry;
|
||||
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
unsigned ptr = i == 0 ? 8 : 26;
|
||||
size = cp[ptr];
|
||||
if (size != 18) continue;
|
||||
entry = cp[ptr + 1];
|
||||
switch(entry)
|
||||
{
|
||||
case 1:
|
||||
memcpy(FInfo, &cp[ptr + 2], 16);
|
||||
break;
|
||||
case 2:
|
||||
memcpy(xFInfo, &cp[ptr + 2], 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool VolumeEntry::Load(const void *data)
|
||||
{
|
||||
const uint8_t *cp = (const uint8_t *)data;
|
||||
|
||||
//prev_block = load16(&cp[0x00]);
|
||||
//next_block = load16(&cp[0x02]);
|
||||
|
||||
storage_type = cp[0x00] >> 4;
|
||||
name_length = cp[0x00] & 0x0f;
|
||||
|
||||
memcpy(volume_name, &cp[0x01], name_length);
|
||||
volume_name[name_length] = 0;
|
||||
|
||||
// 0x14--0x1b reserved
|
||||
|
||||
creation = ProDOS::DateTime(Read16(&cp[0x18]), Read16(&cp[0x1a]));
|
||||
last_mod = ProDOS::DateTime(Read16(&cp[0x12]), Read16(&cp[0x14]));
|
||||
|
||||
if (last_mod == 0) last_mod = creation;
|
||||
|
||||
//version = cp[0x1c];
|
||||
//min_version = cp[0x1d];
|
||||
|
||||
unsigned xcase = Read16(&cp[0x16]);
|
||||
if (xcase & 0x8000)
|
||||
{
|
||||
// gsos technote #8
|
||||
unsigned mask = 0x4000;
|
||||
for (unsigned i = 0; i < name_length; i++)
|
||||
{
|
||||
if (xcase & mask) volume_name[i] = tolower(volume_name[i]);
|
||||
mask = mask >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
access = cp[0x1e];
|
||||
|
||||
entry_length = cp[0x1f];
|
||||
|
||||
entries_per_block = cp[0x20];
|
||||
|
||||
file_count = Read16(&cp[0x21]);
|
||||
|
||||
bit_map_pointer = Read16(&cp[0x23]);
|
||||
|
||||
total_blocks = Read16(&cp[0x25]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool SubdirEntry::Load(const void *data)
|
||||
{
|
||||
const uint8_t *cp = (const uint8_t *)data;
|
||||
|
||||
|
||||
//prev_block = load16(&cp[0x00]);
|
||||
//next_block = load16(&cp[0x02]);
|
||||
|
||||
storage_type = cp[0x00] >> 4;
|
||||
name_length = cp[0x00] & 0x0f;
|
||||
|
||||
memcpy(subdir_name, &cp[0x01], name_length);
|
||||
subdir_name[name_length] = 0;
|
||||
|
||||
// 0x14 should be $14.
|
||||
|
||||
// 0x145-0x1b reserved
|
||||
|
||||
creation = ProDOS::DateTime(Read16(&cp[0x18]), Read16(&cp[0x1a]));
|
||||
|
||||
//version = cp[0x1c];
|
||||
//min_version = cp[0x1d];
|
||||
/*
|
||||
unsigned xcase = load16(&cp[0x1c]);
|
||||
if (xcase & 0x8000)
|
||||
{
|
||||
// gsos technote #8
|
||||
unsigned mask = 0x4000;
|
||||
for (unsigned i = 0; i < name_length; i++)
|
||||
{
|
||||
if (xcase & mask) subdir_name[i] = tolower(subdir_name[i]);
|
||||
mask = mask >> 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
access = cp[0x1e];
|
||||
|
||||
entry_length = cp[0x1f];
|
||||
|
||||
entries_per_block = cp[0x20];
|
||||
|
||||
file_count = Read16(&cp[0x21]);
|
||||
|
||||
parent_pointer = Read16(&cp[0x23]);
|
||||
|
||||
parent_entry = cp[0x25];
|
||||
|
||||
parent_entry_length = cp[0x26];
|
||||
|
||||
return true;
|
||||
}
|
||||
133
ProDOS/File.h
Normal file
133
ProDOS/File.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* File.h
|
||||
* ProFUSE
|
||||
*
|
||||
* Created by Kelvin Sherlock on 12/18/08.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PRODOS_FILE_H__
|
||||
#define __PRODOS_FILE_H__
|
||||
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
DELETED_FILE = 0,
|
||||
SEEDLING_FILE = 1,
|
||||
SAPLING_FILE = 2,
|
||||
TREE_FILE = 3,
|
||||
PASCAL_FILE = 4,
|
||||
EXTENDED_FILE = 5,
|
||||
DIRECTORY_FILE = 0x0d,
|
||||
SUBDIR_HEADER = 0x0e,
|
||||
VOLUME_HEADER = 0x0f
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
FILE_ENTRY_SIZE = 0x27,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
ACCESS_DESTROY = 0x80,
|
||||
ACCESS_RENAME = 0x40,
|
||||
ACCESS_MODIFIED = 0x20,
|
||||
ACCESS_WRITE = 0x02,
|
||||
ACCRESS_READ = 0x01
|
||||
};
|
||||
|
||||
|
||||
class FileEntry {
|
||||
public:
|
||||
|
||||
bool Load(const void *data);
|
||||
|
||||
unsigned storage_type;
|
||||
unsigned name_length;
|
||||
char file_name[15 + 1];
|
||||
unsigned file_type;
|
||||
unsigned key_pointer;
|
||||
unsigned blocks_used;
|
||||
uint32_t eof;
|
||||
time_t creation;
|
||||
//unsigned version;
|
||||
//unsigned min_version;
|
||||
unsigned access;
|
||||
unsigned aux_type;
|
||||
time_t last_mod;
|
||||
unsigned header_pointer;
|
||||
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct MiniEntry {
|
||||
|
||||
unsigned storage_type;
|
||||
unsigned key_block;
|
||||
unsigned blocks_used;
|
||||
uint32_t eof;
|
||||
|
||||
};
|
||||
|
||||
class ExtendedEntry {
|
||||
public:
|
||||
|
||||
bool Load(const void *data);
|
||||
|
||||
MiniEntry dataFork;
|
||||
MiniEntry resourceFork;
|
||||
|
||||
uint8_t FInfo[16];
|
||||
uint8_t xFInfo[16];
|
||||
};
|
||||
|
||||
|
||||
class VolumeEntry {
|
||||
public:
|
||||
|
||||
bool Load(const void *data);
|
||||
|
||||
unsigned storage_type;
|
||||
unsigned name_length;
|
||||
char volume_name[15+1];
|
||||
time_t creation;
|
||||
time_t last_mod;
|
||||
//unsigned version;
|
||||
//unsigned min_version;
|
||||
unsigned access;
|
||||
unsigned entry_length;
|
||||
unsigned entries_per_block;
|
||||
unsigned file_count;
|
||||
unsigned bit_map_pointer;
|
||||
unsigned total_blocks;
|
||||
|
||||
friend class DirIter;
|
||||
|
||||
};
|
||||
|
||||
class SubdirEntry {
|
||||
public:
|
||||
|
||||
bool Load(const void *data);
|
||||
|
||||
unsigned storage_type;
|
||||
unsigned name_length;
|
||||
char subdir_name[15+1];
|
||||
time_t creation;
|
||||
//unsigned version;
|
||||
//unsigned min_version;
|
||||
unsigned access;
|
||||
unsigned entry_length;
|
||||
unsigned entries_per_block;
|
||||
unsigned file_count;
|
||||
unsigned parent_pointer;
|
||||
unsigned parent_entry;
|
||||
unsigned parent_entry_length;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
CC = g++
|
||||
CPPFLAGS += -g -Wall -I../
|
||||
|
||||
|
||||
all : DateTime.o
|
||||
|
||||
DateTime.o : DateTime.cpp DateTime.h
|
||||
18
ProDOS/common.h
Normal file
18
ProDOS/common.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* common.h
|
||||
* ProFUSE
|
||||
*
|
||||
* Created by Kelvin Sherlock on 12/20/08.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define BLOCK_SIZE 512
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
activeBuildConfigurationName = Debug;
|
||||
activeExecutable = B6F3682611B431AC0045E114 /* newfs_prodos */;
|
||||
activeTarget = B6F3682411B431AC0045E114 /* newfs_prodos */;
|
||||
activeBuildConfigurationName = "Debug Universal";
|
||||
activeExecutable = B6F3648111AB36260045E114 /* xattr */;
|
||||
activeTarget = B6F3647F11AB36260045E114 /* xattr */;
|
||||
addToTargets = (
|
||||
B6F3682411B431AC0045E114 /* newfs_prodos */,
|
||||
);
|
||||
breakpoints = (
|
||||
B6F3642F11AA1E150045E114 /* NibbleTest.cpp:76 */,
|
||||
@@ -104,26 +103,21 @@
|
||||
PBXFileDataSource_Warnings_ColumnID,
|
||||
);
|
||||
};
|
||||
PBXPerProjectTemplateStateSaveDate = 299215102;
|
||||
PBXWorkspaceStateSaveDate = 299215102;
|
||||
PBXPerProjectTemplateStateSaveDate = 320626757;
|
||||
PBXWorkspaceStateSaveDate = 320626757;
|
||||
};
|
||||
perUserProjectItems = {
|
||||
B6272A9811D5AC5E0073C73A /* PBXTextBookmark */ = B6272A9811D5AC5E0073C73A /* PBXTextBookmark */;
|
||||
B6272A9911D5AC5E0073C73A /* PBXTextBookmark */ = B6272A9911D5AC5E0073C73A /* PBXTextBookmark */;
|
||||
B6272A9A11D5AC5E0073C73A /* PBXTextBookmark */ = B6272A9A11D5AC5E0073C73A /* PBXTextBookmark */;
|
||||
B6272A9B11D5AC5E0073C73A /* PBXTextBookmark */ = B6272A9B11D5AC5E0073C73A /* PBXTextBookmark */;
|
||||
B6272A9C11D5AC5E0073C73A /* PBXTextBookmark */ = B6272A9C11D5AC5E0073C73A /* PBXTextBookmark */;
|
||||
B6272B0D11D691320073C73A /* PBXTextBookmark */ = B6272B0D11D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B0E11D691320073C73A /* PBXTextBookmark */ = B6272B0E11D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B0F11D691320073C73A /* PBXTextBookmark */ = B6272B0F11D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B1011D691320073C73A /* PBXTextBookmark */ = B6272B1011D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B1111D691320073C73A /* XCBuildMessageTextBookmark */ = B6272B1111D691320073C73A /* XCBuildMessageTextBookmark */;
|
||||
B6272B1111D691320073C73A /* PBXTextBookmark */ = B6272B1111D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B1311D691320073C73A /* PBXTextBookmark */ = B6272B1311D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B1411D691320073C73A /* PBXTextBookmark */ = B6272B1411D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B1511D691320073C73A /* PBXTextBookmark */ = B6272B1511D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B1611D691320073C73A /* PBXTextBookmark */ = B6272B1611D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B1711D691320073C73A /* PBXTextBookmark */ = B6272B1711D691320073C73A /* PBXTextBookmark */;
|
||||
B6272B7711D6A3C30073C73A /* PBXTextBookmark */ = B6272B7711D6A3C30073C73A /* PBXTextBookmark */;
|
||||
B63EFC2611A2D5A400C90DCE /* PBXTextBookmark */ = B63EFC2611A2D5A400C90DCE /* PBXTextBookmark */;
|
||||
B63EFC3211A2D5A400C90DCE /* PBXTextBookmark */ = B63EFC3211A2D5A400C90DCE /* PBXTextBookmark */;
|
||||
B63EFDA011A4488200C90DCE /* PBXTextBookmark */ = B63EFDA011A4488200C90DCE /* PBXTextBookmark */;
|
||||
@@ -139,10 +133,15 @@
|
||||
B63EFEA011A488C200C90DCE /* PBXTextBookmark */ = B63EFEA011A488C200C90DCE /* PBXTextBookmark */;
|
||||
B63EFEA111A488C200C90DCE /* PBXTextBookmark */ = B63EFEA111A488C200C90DCE /* PBXTextBookmark */;
|
||||
B63EFEA811A488C200C90DCE /* PBXTextBookmark */ = B63EFEA811A488C200C90DCE /* PBXTextBookmark */;
|
||||
B656AE2411A84FA400AB578A /* PBXTextBookmark */ = B656AE2411A84FA400AB578A /* PBXTextBookmark */;
|
||||
B656AE2611A84FA400AB578A /* PBXTextBookmark */ = B656AE2611A84FA400AB578A /* PBXTextBookmark */;
|
||||
B65CFB6911B495790024A2D9 /* PBXTextBookmark */ = B65CFB6911B495790024A2D9 /* PBXTextBookmark */;
|
||||
B65CFB6A11B495790024A2D9 /* PBXTextBookmark */ = B65CFB6A11B495790024A2D9 /* PBXTextBookmark */;
|
||||
B6A53B8E1319DDFC00C9070F /* PBXTextBookmark */ = B6A53B8E1319DDFC00C9070F /* PBXTextBookmark */;
|
||||
B6A53BC7131B400800C9070F /* PBXTextBookmark */ = B6A53BC7131B400800C9070F /* PBXTextBookmark */;
|
||||
B6A53BC8131B400800C9070F /* PBXTextBookmark */ = B6A53BC8131B400800C9070F /* PBXTextBookmark */;
|
||||
B6A53C34131B4CF800C9070F /* PBXTextBookmark */ = B6A53C34131B4CF800C9070F /* PBXTextBookmark */;
|
||||
B6AA3AB21318D063007D4BA1 /* PBXTextBookmark */ = B6AA3AB21318D063007D4BA1 /* PBXTextBookmark */;
|
||||
B6AA3AB31318D063007D4BA1 /* PBXTextBookmark */ = B6AA3AB31318D063007D4BA1 /* PBXTextBookmark */;
|
||||
B6AA3AB41318D063007D4BA1 /* PBXTextBookmark */ = B6AA3AB41318D063007D4BA1 /* PBXTextBookmark */;
|
||||
B6E5F0DD11A60726000AD141 /* PBXTextBookmark */ = B6E5F0DD11A60726000AD141 /* PBXTextBookmark */;
|
||||
B6E5F0F211A73144000AD141 /* PBXTextBookmark */ = B6E5F0F211A73144000AD141 /* PBXTextBookmark */;
|
||||
B6E5F11211A73340000AD141 /* PBXTextBookmark */ = B6E5F11211A73340000AD141 /* PBXTextBookmark */;
|
||||
@@ -156,7 +155,6 @@
|
||||
B6F3657E11AE255B0045E114 /* PBXTextBookmark */ = B6F3657E11AE255B0045E114 /* PBXTextBookmark */;
|
||||
B6F3665411B190370045E114 /* PBXTextBookmark */ = B6F3665411B190370045E114 /* PBXTextBookmark */;
|
||||
B6F3665C11B194AC0045E114 /* PBXTextBookmark */ = B6F3665C11B194AC0045E114 /* PBXTextBookmark */;
|
||||
B6F366C211B1A28C0045E114 /* PBXTextBookmark */ = B6F366C211B1A28C0045E114 /* PBXTextBookmark */;
|
||||
B6F366C411B1A28C0045E114 /* PBXTextBookmark */ = B6F366C411B1A28C0045E114 /* PBXTextBookmark */;
|
||||
B6F366C611B1A28C0045E114 /* PBXTextBookmark */ = B6F366C611B1A28C0045E114 /* PBXTextBookmark */;
|
||||
B6F366C711B1A28C0045E114 /* PBXTextBookmark */ = B6F366C711B1A28C0045E114 /* PBXTextBookmark */;
|
||||
@@ -164,18 +162,13 @@
|
||||
B6F366C911B1A28C0045E114 /* PBXTextBookmark */ = B6F366C911B1A28C0045E114 /* PBXTextBookmark */;
|
||||
B6F366CA11B1A28C0045E114 /* PBXTextBookmark */ = B6F366CA11B1A28C0045E114 /* PBXTextBookmark */;
|
||||
B6F366CB11B1A28C0045E114 /* PBXTextBookmark */ = B6F366CB11B1A28C0045E114 /* PBXTextBookmark */;
|
||||
B6F366CC11B1A28C0045E114 /* PBXTextBookmark */ = B6F366CC11B1A28C0045E114 /* PBXTextBookmark */;
|
||||
B6F366D911B1A7A70045E114 /* PBXTextBookmark */ = B6F366D911B1A7A70045E114 /* PBXTextBookmark */;
|
||||
B6F3675411B316D10045E114 /* PBXTextBookmark */ = B6F3675411B316D10045E114 /* PBXTextBookmark */;
|
||||
B6F3677C11B326580045E114 /* PBXTextBookmark */ = B6F3677C11B326580045E114 /* PBXTextBookmark */;
|
||||
B6F3677D11B326580045E114 /* PBXTextBookmark */ = B6F3677D11B326580045E114 /* PBXTextBookmark */;
|
||||
B6F3677E11B326580045E114 /* PBXTextBookmark */ = B6F3677E11B326580045E114 /* PBXTextBookmark */;
|
||||
B6F3677F11B326580045E114 /* PBXTextBookmark */ = B6F3677F11B326580045E114 /* PBXTextBookmark */;
|
||||
B6F367A011B330D10045E114 /* PBXTextBookmark */ = B6F367A011B330D10045E114 /* PBXTextBookmark */;
|
||||
B6F367AE11B337A70045E114 /* PBXTextBookmark */ = B6F367AE11B337A70045E114 /* PBXTextBookmark */;
|
||||
B6F3684911B44D090045E114 /* PBXTextBookmark */ = B6F3684911B44D090045E114 /* PBXTextBookmark */;
|
||||
B6F3684A11B44D090045E114 /* PBXTextBookmark */ = B6F3684A11B44D090045E114 /* PBXTextBookmark */;
|
||||
B6F3684B11B44D090045E114 /* PBXTextBookmark */ = B6F3684B11B44D090045E114 /* PBXTextBookmark */;
|
||||
B6F8D4AD131CB30300461B54 /* PBXTextBookmark */ = B6F8D4AD131CB30300461B54 /* PBXTextBookmark */;
|
||||
};
|
||||
sourceControlManager = B63EFA6711A093C200C90DCE /* Source Control */;
|
||||
userBuildSettings = {
|
||||
@@ -190,16 +183,16 @@
|
||||
};
|
||||
B6272A8F11D5AC3C0073C73A /* fuse_pascal.cpp */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 4095}}";
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 4069}}";
|
||||
sepNavSelRange = "{0, 0}";
|
||||
sepNavVisRange = "{0, 724}";
|
||||
sepNavVisRange = "{0, 672}";
|
||||
};
|
||||
};
|
||||
B6272A9011D5AC3C0073C73A /* fuse_pascal_ops.cpp */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 6396}}";
|
||||
sepNavSelRange = "{0, 0}";
|
||||
sepNavVisRange = "{0, 643}";
|
||||
sepNavIntBoundsRect = "{{0, 0}, {1245, 7124}}";
|
||||
sepNavSelRange = "{1531, 0}";
|
||||
sepNavVisRange = "{367, 1775}";
|
||||
};
|
||||
};
|
||||
B6272A9111D5AC3C0073C73A /* newfs_pascal.cpp */ = {
|
||||
@@ -216,16 +209,6 @@
|
||||
sepNavVisRange = "{0, 936}";
|
||||
};
|
||||
};
|
||||
B6272A9811D5AC5E0073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFBF111A244EE00C90DCE /* VolumeEntry.cpp */;
|
||||
name = "VolumeEntry.cpp: 618";
|
||||
rLen = 6;
|
||||
rLoc = 13761;
|
||||
rType = 0;
|
||||
vrLen = 1289;
|
||||
vrLoc = 13115;
|
||||
};
|
||||
B6272A9911D5AC5E0073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6272A8E11D5AC3C0073C73A /* apfm.cpp */;
|
||||
@@ -236,16 +219,6 @@
|
||||
vrLen = 562;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6272A9A11D5AC5E0073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6272A8F11D5AC3C0073C73A /* fuse_pascal.cpp */;
|
||||
name = "fuse_pascal.cpp: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 724;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6272A9B11D5AC5E0073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6272A9011D5AC3C0073C73A /* fuse_pascal_ops.cpp */;
|
||||
@@ -334,17 +307,17 @@
|
||||
vrLen = 679;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6272B1111D691320073C73A /* XCBuildMessageTextBookmark */ = {
|
||||
B6272B1111D691320073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
comments = "'Device' has not been declared";
|
||||
fRef = B6272B1211D691320073C73A /* Bitmap.h */;
|
||||
fallbackIsa = XCBuildMessageTextBookmark;
|
||||
rLen = 1;
|
||||
rLoc = 21;
|
||||
rType = 1;
|
||||
};
|
||||
B6272B1211D691320073C73A /* Bitmap.h */ = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
name = Bitmap.h;
|
||||
path = ./ProDOS/Bitmap.h;
|
||||
sourceTree = "<group>";
|
||||
@@ -369,16 +342,6 @@
|
||||
vrLen = 740;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6272B1511D691320073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6272AA611D5AE0C0073C73A /* Bitmap.h */;
|
||||
name = "Bitmap.h: 21";
|
||||
rLen = 77;
|
||||
rLoc = 226;
|
||||
rType = 0;
|
||||
vrLen = 735;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6272B1611D691320073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFAB611A098C400C90DCE /* BlockCache.cpp */;
|
||||
@@ -389,26 +352,6 @@
|
||||
vrLen = 718;
|
||||
vrLoc = 403;
|
||||
};
|
||||
B6272B1711D691320073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFAB711A098C400C90DCE /* BlockCache.h */;
|
||||
name = "BlockCache.h: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 909;
|
||||
vrLoc = 148;
|
||||
};
|
||||
B6272B7711D6A3C30073C73A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFAB711A098C400C90DCE /* BlockCache.h */;
|
||||
name = "BlockCache.h: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 928;
|
||||
vrLoc = 129;
|
||||
};
|
||||
B63EFA6711A093C200C90DCE /* Source Control */ = {
|
||||
isa = PBXSourceControlManager;
|
||||
fallbackIsa = XCSourceControlManager;
|
||||
@@ -427,7 +370,7 @@
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 1339}}";
|
||||
sepNavSelRange = "{0, 0}";
|
||||
sepNavVisRange = "{0, 868}";
|
||||
sepNavVisRange = "{0, 819}";
|
||||
};
|
||||
};
|
||||
B63EFA7611A0948500C90DCE /* Endian.h */ = {
|
||||
@@ -544,9 +487,9 @@
|
||||
};
|
||||
B63EFAB711A098C400C90DCE /* BlockCache.h */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 754}}";
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 767}}";
|
||||
sepNavSelRange = "{0, 0}";
|
||||
sepNavVisRange = "{129, 928}";
|
||||
sepNavVisRange = "{118, 910}";
|
||||
};
|
||||
};
|
||||
B63EFAB811A098C400C90DCE /* ConcreteBlockCache.cpp */ = {
|
||||
@@ -677,16 +620,16 @@
|
||||
};
|
||||
B63EFBEC11A244EE00C90DCE /* FileEntry.cpp */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {1009, 8775}}";
|
||||
sepNavSelRange = "{5793, 0}";
|
||||
sepNavVisRange = "{4945, 1395}";
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 9581}}";
|
||||
sepNavSelRange = "{628, 36}";
|
||||
sepNavVisRange = "{335, 746}";
|
||||
};
|
||||
};
|
||||
B63EFBF111A244EE00C90DCE /* VolumeEntry.cpp */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 13208}}";
|
||||
sepNavSelRange = "{13761, 6}";
|
||||
sepNavVisRange = "{13115, 1289}";
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 13026}}";
|
||||
sepNavSelRange = "{13717, 0}";
|
||||
sepNavVisRange = "{13228, 1176}";
|
||||
};
|
||||
};
|
||||
B63EFC2611A2D5A400C90DCE /* PBXTextBookmark */ = {
|
||||
@@ -716,58 +659,6 @@
|
||||
sepNavVisRange = "{687, 1732}";
|
||||
};
|
||||
};
|
||||
B63EFC9911A35F7200C90DCE /* fuse_pascal.cpp */ = {
|
||||
isa = PBXFileReference;
|
||||
fileEncoding = 4;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
name = fuse_pascal.cpp;
|
||||
path = /Users/kelvin/Projects/PROFuseX/fuse_pascal.cpp;
|
||||
sourceTree = "<absolute>";
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 4082}}";
|
||||
sepNavSelRange = "{4414, 0}";
|
||||
sepNavVisRange = "{3977, 1077}";
|
||||
};
|
||||
};
|
||||
B63EFC9B11A35F7B00C90DCE /* newfs_pascal.cpp */ = {
|
||||
isa = PBXFileReference;
|
||||
fileEncoding = 4;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
name = newfs_pascal.cpp;
|
||||
path = /Users/kelvin/Projects/PROFuseX/newfs_pascal.cpp;
|
||||
sourceTree = "<absolute>";
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {1009, 4381}}";
|
||||
sepNavSelRange = "{4492, 0}";
|
||||
sepNavVisRange = "{2844, 1735}";
|
||||
};
|
||||
};
|
||||
B63EFC9D11A35F8200C90DCE /* fuse_pascal_ops.cpp */ = {
|
||||
isa = PBXFileReference;
|
||||
fileEncoding = 4;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
name = fuse_pascal_ops.cpp;
|
||||
path = /Users/kelvin/Projects/PROFuseX/fuse_pascal_ops.cpp;
|
||||
sourceTree = "<absolute>";
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {701, 6448}}";
|
||||
sepNavSelRange = "{855, 6}";
|
||||
sepNavVisRange = "{18, 1415}";
|
||||
};
|
||||
};
|
||||
B63EFC9F11A35F8F00C90DCE /* apfm.cpp */ = {
|
||||
isa = PBXFileReference;
|
||||
fileEncoding = 4;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
name = apfm.cpp;
|
||||
path = /Users/kelvin/Projects/PROFuseX/apfm.cpp;
|
||||
sourceTree = "<absolute>";
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {1009, 14040}}";
|
||||
sepNavSelRange = "{13109, 0}";
|
||||
sepNavVisRange = "{11908, 1651}";
|
||||
};
|
||||
};
|
||||
B63EFCC811A366C800C90DCE /* MappedFile.h */ = {
|
||||
isa = PBXFileReference;
|
||||
lastKnownFileType = sourcecode.c.h;
|
||||
@@ -789,9 +680,9 @@
|
||||
YES,
|
||||
);
|
||||
argumentStrings = (
|
||||
/Users/kelvin/Projects/PROFuseX/pascaltest.DSK,
|
||||
rm,
|
||||
LINEFEED.CODE,
|
||||
/Users/kelvin/Projects/PROFuseX/bleh.po,
|
||||
cat,
|
||||
XATTR.CPP,
|
||||
);
|
||||
autoAttachOnCrash = 1;
|
||||
breakpointsEnabled = 1;
|
||||
@@ -1080,16 +971,6 @@
|
||||
sourceDirectories = (
|
||||
);
|
||||
};
|
||||
B656AE2411A84FA400AB578A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFC9D11A35F8200C90DCE /* fuse_pascal_ops.cpp */;
|
||||
name = "fuse_pascal_ops.cpp: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 813;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B656AE2611A84FA400AB578A /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFAA211A094E000C90DCE /* RawDevice.h */;
|
||||
@@ -1163,15 +1044,82 @@
|
||||
vrLen = 800;
|
||||
vrLoc = 2262;
|
||||
};
|
||||
B65CFB6A11B495790024A2D9 /* PBXTextBookmark */ = {
|
||||
B6A53B851319DA3D00C9070F /* smart_pointers.h */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 475}}";
|
||||
sepNavSelRange = "{0, 0}";
|
||||
sepNavVisRange = "{0, 903}";
|
||||
};
|
||||
};
|
||||
B6A53B8E1319DDFC00C9070F /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6F3647B11AB361D0045E114 /* xattr.cpp */;
|
||||
name = "xattr.cpp: 330";
|
||||
rLen = 6;
|
||||
rLoc = 6657;
|
||||
fRef = B6A53B851319DA3D00C9070F /* smart_pointers.h */;
|
||||
name = "smart_pointers.h: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 829;
|
||||
vrLoc = 5931;
|
||||
vrLen = 903;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6A53BC7131B400800C9070F /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6F3651B11ADD0280045E114 /* FileEntry.h */;
|
||||
name = "FileEntry.h: 20";
|
||||
rLen = 23;
|
||||
rLoc = 292;
|
||||
rType = 0;
|
||||
vrLen = 797;
|
||||
vrLoc = 62;
|
||||
};
|
||||
B6A53BC8131B400800C9070F /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFBEC11A244EE00C90DCE /* FileEntry.cpp */;
|
||||
name = "FileEntry.cpp: 40";
|
||||
rLen = 36;
|
||||
rLoc = 628;
|
||||
rType = 0;
|
||||
vrLen = 746;
|
||||
vrLoc = 335;
|
||||
};
|
||||
B6A53C34131B4CF800C9070F /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFBF111A244EE00C90DCE /* VolumeEntry.cpp */;
|
||||
name = "VolumeEntry.cpp: 616";
|
||||
rLen = 0;
|
||||
rLoc = 13717;
|
||||
rType = 0;
|
||||
vrLen = 1185;
|
||||
vrLoc = 13219;
|
||||
};
|
||||
B6AA3AB21318D063007D4BA1 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFAB711A098C400C90DCE /* BlockCache.h */;
|
||||
name = "BlockCache.h: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 910;
|
||||
vrLoc = 118;
|
||||
};
|
||||
B6AA3AB31318D063007D4BA1 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFA7511A0948500C90DCE /* Endian.cpp */;
|
||||
name = "Endian.cpp: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 819;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6AA3AB41318D063007D4BA1 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6272A8F11D5AC3C0073C73A /* fuse_pascal.cpp */;
|
||||
name = "fuse_pascal.cpp: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 672;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6E5F0DD11A60726000AD141 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
@@ -1250,19 +1198,6 @@
|
||||
vrLen = 1126;
|
||||
vrLoc = 442;
|
||||
};
|
||||
B6F3647B11AB361D0045E114 /* xattr.cpp */ = {
|
||||
isa = PBXFileReference;
|
||||
fileEncoding = 4;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
name = xattr.cpp;
|
||||
path = /Users/kelvin/Projects/PROFuseX/xattr.cpp;
|
||||
sourceTree = "<absolute>";
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 5512}}";
|
||||
sepNavSelRange = "{6657, 6}";
|
||||
sepNavVisRange = "{5931, 829}";
|
||||
};
|
||||
};
|
||||
B6F3647F11AB36260045E114 /* xattr */ = {
|
||||
activeExec = 0;
|
||||
executables = (
|
||||
@@ -1325,9 +1260,9 @@
|
||||
};
|
||||
B6F3651B11ADD0280045E114 /* FileEntry.h */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {1009, 1326}}";
|
||||
sepNavSelRange = "{1407, 0}";
|
||||
sepNavVisRange = "{0, 1668}";
|
||||
sepNavIntBoundsRect = "{{0, 0}, {838, 1430}}";
|
||||
sepNavSelRange = "{292, 23}";
|
||||
sepNavVisRange = "{62, 797}";
|
||||
};
|
||||
};
|
||||
B6F3651C11ADD0280045E114 /* Entry.h */ = {
|
||||
@@ -1372,7 +1307,7 @@
|
||||
continueAfterActions = 0;
|
||||
countType = 0;
|
||||
delayBeforeContinue = 0;
|
||||
fileReference = B63EFC9F11A35F8F00C90DCE /* apfm.cpp */;
|
||||
fileReference = B6272A8E11D5AC3C0073C73A /* apfm.cpp */;
|
||||
functionName = "action_rm(int argc, char **argv, Pascal::VolumeEntry *volume)";
|
||||
hitCount = 0;
|
||||
ignoreCount = 0;
|
||||
@@ -1435,16 +1370,6 @@
|
||||
vrLen = 951;
|
||||
vrLoc = 1203;
|
||||
};
|
||||
B6F366C211B1A28C0045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFC9B11A35F7B00C90DCE /* newfs_pascal.cpp */;
|
||||
name = "newfs_pascal.cpp: 227";
|
||||
rLen = 0;
|
||||
rLoc = 5474;
|
||||
rType = 0;
|
||||
vrLen = 1282;
|
||||
vrLoc = 4530;
|
||||
};
|
||||
B6F366C411B1A28C0045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFACB11A09DAA00C90DCE /* MappedFile.cpp */;
|
||||
@@ -1515,36 +1440,6 @@
|
||||
vrLen = 613;
|
||||
vrLoc = 128;
|
||||
};
|
||||
B6F366CC11B1A28C0045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFC9F11A35F8F00C90DCE /* apfm.cpp */;
|
||||
name = "apfm.cpp: 755";
|
||||
rLen = 0;
|
||||
rLoc = 22959;
|
||||
rType = 0;
|
||||
vrLen = 884;
|
||||
vrLoc = 15404;
|
||||
};
|
||||
B6F366D911B1A7A70045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFC9911A35F7200C90DCE /* fuse_pascal.cpp */;
|
||||
name = "fuse_pascal.cpp: 195";
|
||||
rLen = 0;
|
||||
rLoc = 4414;
|
||||
rType = 0;
|
||||
vrLen = 1077;
|
||||
vrLoc = 3977;
|
||||
};
|
||||
B6F3675411B316D10045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFBEC11A244EE00C90DCE /* FileEntry.cpp */;
|
||||
name = "FileEntry.cpp: 113";
|
||||
rLen = 0;
|
||||
rLoc = 2383;
|
||||
rType = 0;
|
||||
vrLen = 767;
|
||||
vrLoc = 1707;
|
||||
};
|
||||
B6F3676311B323680045E114 /* TextWriter.h */ = {
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {1009, 958}}";
|
||||
@@ -1589,16 +1484,6 @@
|
||||
vrLen = 532;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6F3677F11B326580045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6F3651B11ADD0280045E114 /* FileEntry.h */;
|
||||
name = "FileEntry.h: 41";
|
||||
rLen = 0;
|
||||
rLoc = 1069;
|
||||
rType = 0;
|
||||
vrLen = 933;
|
||||
vrLoc = 1184;
|
||||
};
|
||||
B6F367A011B330D10045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFACA11A09DAA00C90DCE /* File.h */;
|
||||
@@ -1619,19 +1504,6 @@
|
||||
vrLen = 874;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6F3682111B430870045E114 /* newfs_prodos.cpp */ = {
|
||||
isa = PBXFileReference;
|
||||
fileEncoding = 4;
|
||||
lastKnownFileType = sourcecode.cpp.cpp;
|
||||
name = newfs_prodos.cpp;
|
||||
path = /Users/kelvin/Projects/PROFuseX/newfs_prodos.cpp;
|
||||
sourceTree = "<absolute>";
|
||||
uiCtxt = {
|
||||
sepNavIntBoundsRect = "{{0, 0}, {1009, 3185}}";
|
||||
sepNavSelRange = "{266, 0}";
|
||||
sepNavVisRange = "{0, 1849}";
|
||||
};
|
||||
};
|
||||
B6F3682411B431AC0045E114 /* newfs_prodos */ = {
|
||||
activeExec = 0;
|
||||
executables = (
|
||||
@@ -1665,16 +1537,6 @@
|
||||
sourceDirectories = (
|
||||
);
|
||||
};
|
||||
B6F3684911B44D090045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B63EFA7511A0948500C90DCE /* Endian.cpp */;
|
||||
name = "Endian.cpp: 1";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rType = 0;
|
||||
vrLen = 868;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6F3684A11B44D090045E114 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6F3676411B323680045E114 /* TextWriter.cpp */;
|
||||
@@ -1685,14 +1547,14 @@
|
||||
vrLen = 803;
|
||||
vrLoc = 0;
|
||||
};
|
||||
B6F3684B11B44D090045E114 /* PBXTextBookmark */ = {
|
||||
B6F8D4AD131CB30300461B54 /* PBXTextBookmark */ = {
|
||||
isa = PBXTextBookmark;
|
||||
fRef = B6F3682111B430870045E114 /* newfs_prodos.cpp */;
|
||||
name = "newfs_prodos.cpp: 1";
|
||||
fRef = B63EFBF111A244EE00C90DCE /* VolumeEntry.cpp */;
|
||||
name = "VolumeEntry.cpp: 616";
|
||||
rLen = 0;
|
||||
rLoc = 0;
|
||||
rLoc = 13717;
|
||||
rType = 0;
|
||||
vrLen = 1184;
|
||||
vrLoc = 0;
|
||||
vrLen = 1176;
|
||||
vrLoc = 13228;
|
||||
};
|
||||
}
|
||||
@@ -269,6 +269,8 @@
|
||||
<string>08FB7794FE84155DC02AAC07</string>
|
||||
<string>B6272A8D11D5AC3C0073C73A</string>
|
||||
<string>B6272AA411D5AE0C0073C73A</string>
|
||||
<string>B63EFBE711A244EE00C90DCE</string>
|
||||
<string>B63EFACF11A09DB500C90DCE</string>
|
||||
<string>B63EFAB511A098C400C90DCE</string>
|
||||
<string>B63EFA9411A094E000C90DCE</string>
|
||||
<string>B656ADED11A84D3200AB578A</string>
|
||||
@@ -278,9 +280,8 @@
|
||||
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
|
||||
<array>
|
||||
<array>
|
||||
<integer>19</integer>
|
||||
<integer>17</integer>
|
||||
<integer>0</integer>
|
||||
<integer>63</integer>
|
||||
<integer>62</integer>
|
||||
</array>
|
||||
</array>
|
||||
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
|
||||
@@ -301,7 +302,7 @@
|
||||
<real>318</real>
|
||||
</array>
|
||||
<key>RubberWindowFrame</key>
|
||||
<string>182 101 1239 1000 0 0 1920 1178 </string>
|
||||
<string>413 92 1239 1000 0 0 1920 1178 </string>
|
||||
</dict>
|
||||
<key>Module</key>
|
||||
<string>PBXSmartGroupTreeModule</string>
|
||||
@@ -317,7 +318,7 @@
|
||||
<key>PBXProjectModuleGUID</key>
|
||||
<string>B63EFA6111A093C200C90DCE</string>
|
||||
<key>PBXProjectModuleLabel</key>
|
||||
<string>BlockCache.h</string>
|
||||
<string>VolumeEntry.cpp</string>
|
||||
<key>PBXSplitModuleInNavigatorKey</key>
|
||||
<dict>
|
||||
<key>Split0</key>
|
||||
@@ -325,11 +326,11 @@
|
||||
<key>PBXProjectModuleGUID</key>
|
||||
<string>B63EFA6211A093C200C90DCE</string>
|
||||
<key>PBXProjectModuleLabel</key>
|
||||
<string>BlockCache.h</string>
|
||||
<string>VolumeEntry.cpp</string>
|
||||
<key>_historyCapacity</key>
|
||||
<integer>0</integer>
|
||||
<key>bookmark</key>
|
||||
<string>B6272B7711D6A3C30073C73A</string>
|
||||
<string>B6F8D4AD131CB30300461B54</string>
|
||||
<key>history</key>
|
||||
<array>
|
||||
<string>B63EFC2611A2D5A400C90DCE</string>
|
||||
@@ -352,7 +353,6 @@
|
||||
<string>B6E5F11211A73340000AD141</string>
|
||||
<string>B6E5F13A11A74F2B000AD141</string>
|
||||
<string>B6E5F18211A76B74000AD141</string>
|
||||
<string>B656AE2411A84FA400AB578A</string>
|
||||
<string>B656AE2611A84FA400AB578A</string>
|
||||
<string>B6F3647111AB35FE0045E114</string>
|
||||
<string>B6F3649E11AB59190045E114</string>
|
||||
@@ -362,7 +362,6 @@
|
||||
<string>B6F3657E11AE255B0045E114</string>
|
||||
<string>B6F3665411B190370045E114</string>
|
||||
<string>B6F3665C11B194AC0045E114</string>
|
||||
<string>B6F366C211B1A28C0045E114</string>
|
||||
<string>B6F366C411B1A28C0045E114</string>
|
||||
<string>B6F366C611B1A28C0045E114</string>
|
||||
<string>B6F366C711B1A28C0045E114</string>
|
||||
@@ -370,23 +369,14 @@
|
||||
<string>B6F366C911B1A28C0045E114</string>
|
||||
<string>B6F366CA11B1A28C0045E114</string>
|
||||
<string>B6F366CB11B1A28C0045E114</string>
|
||||
<string>B6F366CC11B1A28C0045E114</string>
|
||||
<string>B6F366D911B1A7A70045E114</string>
|
||||
<string>B6F3675411B316D10045E114</string>
|
||||
<string>B6F3677C11B326580045E114</string>
|
||||
<string>B6F3677D11B326580045E114</string>
|
||||
<string>B6F3677E11B326580045E114</string>
|
||||
<string>B6F3677F11B326580045E114</string>
|
||||
<string>B6F367A011B330D10045E114</string>
|
||||
<string>B6F367AE11B337A70045E114</string>
|
||||
<string>B6F3684911B44D090045E114</string>
|
||||
<string>B6F3684A11B44D090045E114</string>
|
||||
<string>B6F3684B11B44D090045E114</string>
|
||||
<string>B65CFB6911B495790024A2D9</string>
|
||||
<string>B65CFB6A11B495790024A2D9</string>
|
||||
<string>B6272A9811D5AC5E0073C73A</string>
|
||||
<string>B6272A9911D5AC5E0073C73A</string>
|
||||
<string>B6272A9A11D5AC5E0073C73A</string>
|
||||
<string>B6272A9B11D5AC5E0073C73A</string>
|
||||
<string>B6272A9C11D5AC5E0073C73A</string>
|
||||
<string>B6272B0D11D691320073C73A</string>
|
||||
@@ -396,9 +386,14 @@
|
||||
<string>B6272B1111D691320073C73A</string>
|
||||
<string>B6272B1311D691320073C73A</string>
|
||||
<string>B6272B1411D691320073C73A</string>
|
||||
<string>B6272B1511D691320073C73A</string>
|
||||
<string>B6272B1611D691320073C73A</string>
|
||||
<string>B6272B1711D691320073C73A</string>
|
||||
<string>B6AA3AB21318D063007D4BA1</string>
|
||||
<string>B6AA3AB31318D063007D4BA1</string>
|
||||
<string>B6AA3AB41318D063007D4BA1</string>
|
||||
<string>B6A53B8E1319DDFC00C9070F</string>
|
||||
<string>B6A53BC7131B400800C9070F</string>
|
||||
<string>B6A53BC8131B400800C9070F</string>
|
||||
<string>B6A53C34131B4CF800C9070F</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>SplitCount</key>
|
||||
@@ -412,21 +407,23 @@
|
||||
<key>GeometryConfiguration</key>
|
||||
<dict>
|
||||
<key>Frame</key>
|
||||
<string>{{0, 0}, {899, 535}}</string>
|
||||
<string>{{0, 0}, {899, 497}}</string>
|
||||
<key>RubberWindowFrame</key>
|
||||
<string>182 101 1239 1000 0 0 1920 1178 </string>
|
||||
<string>413 92 1239 1000 0 0 1920 1178 </string>
|
||||
</dict>
|
||||
<key>Module</key>
|
||||
<string>PBXNavigatorGroup</string>
|
||||
<key>Proportion</key>
|
||||
<string>535pt</string>
|
||||
<string>497pt</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Proportion</key>
|
||||
<string>419pt</string>
|
||||
<string>457pt</string>
|
||||
<key>Tabs</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>BecomeActive</key>
|
||||
<true/>
|
||||
<key>ContentConfiguration</key>
|
||||
<dict>
|
||||
<key>PBXProjectModuleGUID</key>
|
||||
@@ -437,7 +434,9 @@
|
||||
<key>GeometryConfiguration</key>
|
||||
<dict>
|
||||
<key>Frame</key>
|
||||
<string>{{10, 27}, {899, 392}}</string>
|
||||
<string>{{10, 27}, {899, 430}}</string>
|
||||
<key>RubberWindowFrame</key>
|
||||
<string>413 92 1239 1000 0 0 1920 1178 </string>
|
||||
</dict>
|
||||
<key>Module</key>
|
||||
<string>XCDetailModule</string>
|
||||
@@ -491,9 +490,7 @@
|
||||
<key>GeometryConfiguration</key>
|
||||
<dict>
|
||||
<key>Frame</key>
|
||||
<string>{{10, 27}, {899, 392}}</string>
|
||||
<key>RubberWindowFrame</key>
|
||||
<string>182 101 1239 1000 0 0 1920 1178 </string>
|
||||
<string>{{10, 27}, {899, 420}}</string>
|
||||
</dict>
|
||||
<key>Module</key>
|
||||
<string>PBXBuildResultsModule</string>
|
||||
@@ -521,11 +518,11 @@
|
||||
</array>
|
||||
<key>TableOfContents</key>
|
||||
<array>
|
||||
<string>B6272A9F11D5AC5E0073C73A</string>
|
||||
<string>B6F8D48A131C605200461B54</string>
|
||||
<string>1CA23ED40692098700951B8B</string>
|
||||
<string>B6272AA011D5AC5E0073C73A</string>
|
||||
<string>B6F8D48B131C605200461B54</string>
|
||||
<string>B63EFA6111A093C200C90DCE</string>
|
||||
<string>B6272AA111D5AC5E0073C73A</string>
|
||||
<string>B6F8D48C131C605200461B54</string>
|
||||
<string>1CA23EDF0692099D00951B8B</string>
|
||||
<string>1CA23EE00692099D00951B8B</string>
|
||||
<string>1CA23EE10692099D00951B8B</string>
|
||||
@@ -674,14 +671,14 @@
|
||||
</array>
|
||||
<key>TableOfContents</key>
|
||||
<array>
|
||||
<string>B6F3647611AB35FE0045E114</string>
|
||||
<string>B6A53BCB131B400800C9070F</string>
|
||||
<string>1CCC7628064C1048000F2A68</string>
|
||||
<string>1CCC7629064C1048000F2A68</string>
|
||||
<string>B6F3647711AB35FE0045E114</string>
|
||||
<string>B6F3647811AB35FE0045E114</string>
|
||||
<string>B6F3647911AB35FE0045E114</string>
|
||||
<string>B6F3647A11AB35FE0045E114</string>
|
||||
<string>B63EFA6111A093C200C90DCE</string>
|
||||
<string>B6A53BCC131B400800C9070F</string>
|
||||
<string>B6A53BCD131B400800C9070F</string>
|
||||
<string>B6A53BCE131B400800C9070F</string>
|
||||
<string>B6A53BCF131B400800C9070F</string>
|
||||
<string>B6A53BD0131B400800C9070F</string>
|
||||
</array>
|
||||
<key>ToolbarConfigUserDefaultsMinorVersion</key>
|
||||
<string>2</string>
|
||||
@@ -715,11 +712,10 @@
|
||||
<integer>5</integer>
|
||||
<key>WindowOrderList</key>
|
||||
<array>
|
||||
<string>B6272B1911D691320073C73A</string>
|
||||
<string>/Users/kelvin/Projects/PROFuseX/PROFuseX.xcodeproj</string>
|
||||
</array>
|
||||
<key>WindowString</key>
|
||||
<string>182 101 1239 1000 0 0 1920 1178 </string>
|
||||
<string>413 92 1239 1000 0 0 1920 1178 </string>
|
||||
<key>WindowToolsV3</key>
|
||||
<array>
|
||||
<dict>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
CC = g++
|
||||
CPPFLAGS += -g -Wall -I../
|
||||
|
||||
|
||||
all : Exception.o Lock.o
|
||||
|
||||
Exception.o : Exception.cpp Exception.h
|
||||
|
||||
Lock.o : Lock.cpp Lock.h
|
||||
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# profuse
|
||||
ProDOS file system for FUSE
|
||||
|
||||
## End of Life Notice
|
||||
|
||||
This software, while usable, is EOL. No further updates are expected.
|
||||
|
||||
ProFUSE 2.0, featuring read/write support for ProDOS and HFS, is available as part of
|
||||
[Golden Gate](http://golden-gate.ksherlock.com)
|
||||
|
||||
See the Wiki for details about the ProDOS file system.
|
||||
74
bin/apfm.cpp
74
bin/apfm.cpp
@@ -5,7 +5,6 @@
|
||||
* E -
|
||||
*/
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
@@ -23,6 +22,7 @@
|
||||
#include <Pascal/Date.h>
|
||||
#include <Pascal/TextWriter.h>
|
||||
|
||||
#include <Device/Device.h>
|
||||
#include <Device/BlockDevice.h>
|
||||
|
||||
#include <File/File.h>
|
||||
@@ -44,25 +44,31 @@ enum commands {
|
||||
void usage()
|
||||
{
|
||||
std::fputs(
|
||||
"Pascal File Manager v 0.0\n\n"
|
||||
"Usage: apfm [-h] [-f format] diskimage action ...\n"
|
||||
"Options:\n"
|
||||
" -h Show usage information.\n"
|
||||
" -f format Specify disk format. Valid values are:\n"
|
||||
" po: ProDOS order disk image\n"
|
||||
" do: DOS Order disk image\n"
|
||||
"\n"
|
||||
"Actions:\n"
|
||||
" cat\n"
|
||||
" krunch\n"
|
||||
" ls\n"
|
||||
" cp\n"
|
||||
" mv\n"
|
||||
" rm\n"
|
||||
" get\n"
|
||||
" put\n",
|
||||
stdout
|
||||
);
|
||||
"Pascal File Manager v 0.0\n\n"
|
||||
"Usage: apfm [-h] [-f format] diskimage action ...\n"
|
||||
"Options:\n"
|
||||
" -h Show usage information.\n"
|
||||
" -f format Specify disk format. Valid values are:\n"
|
||||
" dc42 DiskCopy 4.2 Image\n"
|
||||
" davex Davex Disk Image\n"
|
||||
" 2img Universal Disk Image\n"
|
||||
#ifdef HAVE_NUFX
|
||||
" sdk ShrinkIt Disk Image\n"
|
||||
#endif
|
||||
" do DOS Order Disk Image\n"
|
||||
" po ProDOS Order Disk Image (default)\n"
|
||||
"\n"
|
||||
"Actions:\n"
|
||||
" cat\n"
|
||||
" krunch\n"
|
||||
" ls\n"
|
||||
" cp\n"
|
||||
" mv\n"
|
||||
" rm\n"
|
||||
" get\n"
|
||||
" put\n",
|
||||
stdout
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -263,7 +269,7 @@ void printUnusedEntry(unsigned block, unsigned size)
|
||||
std::printf("< UNUSED > %4u %4u\n", size, block);
|
||||
}
|
||||
|
||||
void printFileEntry(Pascal::FileEntry *e, bool extended)
|
||||
void printFileEntry(Pascal::FileEntryPointer e, bool extended)
|
||||
{
|
||||
Pascal::Date dt = e->modification();
|
||||
|
||||
@@ -329,7 +335,7 @@ int action_ls(int argc, char **argv, Pascal::VolumeEntry *volume)
|
||||
|
||||
for (unsigned i = 0; i < fileCount; ++i)
|
||||
{
|
||||
Pascal::FileEntry *e = volume->fileAtIndex(i);
|
||||
Pascal::FileEntryPointer e = volume->fileAtIndex(i);
|
||||
if (!e) continue;
|
||||
|
||||
|
||||
@@ -409,7 +415,7 @@ int action_cat(unsigned argc, char **argv, Pascal::VolumeEntry *volume)
|
||||
unsigned fileSize;
|
||||
unsigned offset;
|
||||
uint8_t buffer[512];
|
||||
Pascal::FileEntry *e = NULL;
|
||||
Pascal::FileEntryPointer e;
|
||||
// find it...
|
||||
|
||||
e = volume->fileByName(argv[i]);
|
||||
@@ -588,7 +594,7 @@ int action_rm(int argc, char **argv, Pascal::VolumeEntry *volume)
|
||||
// TODO -- catch errors ?
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
Pascal::FileEntry *e = volume->fileByName(argv[i]);
|
||||
Pascal::FileEntryPointer e = volume->fileByName(argv[i]);
|
||||
|
||||
if (!e)
|
||||
{
|
||||
@@ -691,7 +697,7 @@ int action_get(int argc, char **argv, Pascal::VolumeEntry *volume)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
Pascal::FileEntry *entry;
|
||||
Pascal::FileEntryPointer entry;
|
||||
|
||||
switch(argc)
|
||||
{
|
||||
@@ -736,7 +742,7 @@ int action_get(int argc, char **argv, Pascal::VolumeEntry *volume)
|
||||
|
||||
|
||||
|
||||
File::File file(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
File file(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
|
||||
unsigned fileSize = entry->fileSize();
|
||||
unsigned offset = 0;
|
||||
@@ -910,7 +916,7 @@ int action_put(int argc, char **argv, Pascal::VolumeEntry *volume)
|
||||
|
||||
blocks = text.blocks();
|
||||
|
||||
Pascal::FileEntry *entry = volume->create(outfile, blocks);
|
||||
Pascal::FileEntryPointer entry = volume->create(outfile, blocks);
|
||||
if (!entry)
|
||||
{
|
||||
perror(NULL);
|
||||
@@ -923,7 +929,7 @@ int action_put(int argc, char **argv, Pascal::VolumeEntry *volume)
|
||||
}
|
||||
else
|
||||
{
|
||||
Pascal::FileEntry *entry = volume->create(outfile, blocks);
|
||||
Pascal::FileEntryPointer entry = volume->create(outfile, blocks);
|
||||
if (!entry)
|
||||
{
|
||||
perror(NULL);
|
||||
@@ -962,8 +968,8 @@ int action_put(int argc, char **argv, Pascal::VolumeEntry *volume)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::auto_ptr<Pascal::VolumeEntry> volume;
|
||||
std::auto_ptr<Device::BlockDevice> device;
|
||||
Pascal::VolumeEntryPointer volume;
|
||||
Device::BlockDevicePointer device;
|
||||
|
||||
unsigned fmt = 0;
|
||||
|
||||
@@ -1025,10 +1031,10 @@ int main(int argc, char **argv)
|
||||
|
||||
unsigned actionCode = command(action);
|
||||
|
||||
device.reset( Device::BlockDevice::Open(file, commandFlags(actionCode), fmt) );
|
||||
device = Device::BlockDevice::Open(file, commandFlags(actionCode), fmt);
|
||||
|
||||
volume.reset( new Pascal::VolumeEntry(device.get()));
|
||||
device.release();
|
||||
volume = Pascal::VolumeEntry::Open(device);
|
||||
device.reset();
|
||||
|
||||
switch (actionCode)
|
||||
{
|
||||
@@ -1061,7 +1067,7 @@ int main(int argc, char **argv)
|
||||
usage();
|
||||
return 3;
|
||||
}
|
||||
catch (ProFUSE::Exception& e)
|
||||
catch (Exception& e)
|
||||
{
|
||||
std::fprintf(stderr, "%s\n", e.what());
|
||||
std::fprintf(stderr, "%s\n", e.errorString());
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <cstddef>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -9,25 +10,24 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define __FreeBSD__ 10
|
||||
#define __DARWIN_64_BIT_INO_T 1
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#define FUSE_USE_VERSION 27
|
||||
|
||||
#include <fuse/fuse_opt.h>
|
||||
#include <fuse/fuse_lowlevel.h>
|
||||
|
||||
#include <fuse_opt.h>
|
||||
#include <fuse_lowlevel.h>
|
||||
|
||||
#include <Pascal/Pascal.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
|
||||
#include <Device/BlockDevice.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
#include <File/File.h>
|
||||
|
||||
#include <Device/Device.h>
|
||||
#include <Device/BlockDevice.h>
|
||||
|
||||
std::string fDiskImage;
|
||||
|
||||
|
||||
|
||||
void usage()
|
||||
{
|
||||
std::printf("profuse_pascal 0.1\n\n");
|
||||
@@ -43,6 +43,9 @@ void usage()
|
||||
" dc42 DiskCopy 4.2 Image\n"
|
||||
" davex Davex Disk Image\n"
|
||||
" 2img Universal Disk Image\n"
|
||||
#ifdef HAVE_NUFX
|
||||
" sdk ShrinkIt Disk Image\n"
|
||||
#endif
|
||||
" do DOS Order Disk Image\n"
|
||||
" po ProDOS Order Disk Image (default)\n"
|
||||
" -o opt1,opt2... other mount parameters.\n"
|
||||
@@ -168,7 +171,7 @@ int main(int argc, char **argv)
|
||||
int multithread = false;
|
||||
|
||||
|
||||
std::auto_ptr<Pascal::VolumeEntry> volume;
|
||||
Pascal::VolumeEntryPointer volume;
|
||||
|
||||
|
||||
init_ops(&pascal_ops);
|
||||
@@ -194,11 +197,10 @@ int main(int argc, char **argv)
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
Device::BlockDevicePointer device;
|
||||
|
||||
std::auto_ptr<Device::BlockDevice> device;
|
||||
|
||||
device.reset( Device::BlockDevice::Open(fDiskImage.c_str(), File::ReadOnly, format) );
|
||||
device = Device::BlockDevice::Open(fDiskImage.c_str(), File::ReadOnly, format);
|
||||
|
||||
|
||||
if (!device.get())
|
||||
@@ -207,20 +209,15 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
volume.reset( new Pascal::VolumeEntry(device.get()) );
|
||||
device.release();
|
||||
volume = Pascal::VolumeEntry::Open(device);
|
||||
}
|
||||
catch (ProFUSE::POSIXException &e)
|
||||
catch (::Exception &e)
|
||||
{
|
||||
std::fprintf(stderr, "%s\n", e.what());
|
||||
std::fprintf(stderr, "%s\n", std::strerror(e.error()));
|
||||
return -1;
|
||||
}
|
||||
catch (ProFUSE::Exception &e)
|
||||
{
|
||||
std::fprintf(stderr, "%s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define __FreeBSD__ 10
|
||||
#define __DARWIN_64_BIT_INO_T 1
|
||||
#endif
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define FUSE_USE_VERSION 27
|
||||
|
||||
#include <string>
|
||||
@@ -13,18 +7,22 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
|
||||
#include <fuse/fuse_opt.h>
|
||||
#include <fuse/fuse_lowlevel.h>
|
||||
|
||||
|
||||
#include <fuse_opt.h>
|
||||
#include <fuse_lowlevel.h>
|
||||
|
||||
|
||||
|
||||
#include <Pascal/Pascal.h>
|
||||
#include <ProFUSE/auto.h>
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/auto.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <POSIX/Exception.h>
|
||||
|
||||
#define NO_ATTR() \
|
||||
{ \
|
||||
@@ -56,20 +54,30 @@
|
||||
using namespace Pascal;
|
||||
|
||||
|
||||
static FileEntry *findChild(VolumeEntry *volume, unsigned inode)
|
||||
// fd_table is files which have been open.
|
||||
// fd_table_available is a list of indexes in fd_table which are not currently used.
|
||||
static std::vector<FileEntryPointer> fd_table;
|
||||
static std::vector<unsigned> fd_table_available;
|
||||
|
||||
static FileEntryPointer findChild(VolumeEntry *volume, unsigned inode)
|
||||
{
|
||||
|
||||
for (unsigned i = 0, l = volume->fileCount(); i < l; ++i)
|
||||
{
|
||||
FileEntry *child = volume->fileAtIndex(i);
|
||||
FileEntryPointer child = volume->fileAtIndex(i);
|
||||
if (!child) continue;
|
||||
|
||||
if (inode == child->inode()) return child;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return FileEntryPointer();
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark fs
|
||||
|
||||
|
||||
static void pascal_init(void *userdata, struct fuse_conn_info *conn)
|
||||
{
|
||||
DEBUGNAME()
|
||||
@@ -82,7 +90,7 @@ static void pascal_init(void *userdata, struct fuse_conn_info *conn)
|
||||
|
||||
for (unsigned i = 0, l = volume->fileCount(); i < l; ++i)
|
||||
{
|
||||
FileEntry *child = volume->fileAtIndex(i);
|
||||
FileEntryPointer child = volume->fileAtIndex(i);
|
||||
child->fileSize();
|
||||
}
|
||||
|
||||
@@ -96,6 +104,34 @@ static void pascal_destroy(void *userdata)
|
||||
}
|
||||
|
||||
|
||||
static void pascal_statfs(fuse_req_t req, fuse_ino_t ino)
|
||||
{
|
||||
DEBUGNAME()
|
||||
|
||||
struct statvfs vst;
|
||||
VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req);
|
||||
|
||||
ERROR(!volume, EIO)
|
||||
|
||||
// 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->volumeBlocks();
|
||||
vst.f_bfree = volume->freeBlocks(true); // free blocks
|
||||
vst.f_bavail = volume->freeBlocks(false); // free blocks (non-root)
|
||||
vst.f_files = volume->fileCount();
|
||||
vst.f_ffree = -1; // free inodes.
|
||||
vst.f_favail = -1; // free inodes (non-root)
|
||||
vst.f_fsid = 0; // file system id?
|
||||
vst.f_flag = volume->readOnly() ? ST_RDONLY | ST_NOSUID : ST_NOSUID;
|
||||
vst.f_namemax = 15;
|
||||
|
||||
fuse_reply_statfs(req, &vst);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark xattr
|
||||
@@ -105,7 +141,7 @@ static void pascal_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
|
||||
DEBUGNAME()
|
||||
|
||||
VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req);
|
||||
FileEntry *file;
|
||||
FileEntryPointer file;
|
||||
std::string attr;
|
||||
unsigned attrSize;
|
||||
|
||||
@@ -149,7 +185,7 @@ static void pascal_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, si
|
||||
|
||||
|
||||
VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req);
|
||||
FileEntry *file;
|
||||
FileEntryPointer file;
|
||||
std::string attr(name);
|
||||
|
||||
ERROR(ino == 1, ENOATTR)
|
||||
@@ -223,7 +259,7 @@ static void pascal_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t of
|
||||
DEBUGNAME()
|
||||
|
||||
VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req);
|
||||
ProFUSE::auto_array<uint8_t> buffer(new uint8_t[size]);
|
||||
::auto_array<uint8_t> buffer(new uint8_t[size]);
|
||||
unsigned count = volume->fileCount();
|
||||
|
||||
|
||||
@@ -269,7 +305,7 @@ static void pascal_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t of
|
||||
{
|
||||
unsigned tmp;
|
||||
|
||||
FileEntry *file = volume->fileAtIndex(i);
|
||||
FileEntryPointer file = volume->fileAtIndex(i);
|
||||
if (file == NULL) break; //?
|
||||
|
||||
// only these fields are used.
|
||||
@@ -352,7 +388,7 @@ static void pascal_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
|
||||
for (unsigned i = 0, l = volume->fileCount(); i < l; ++i)
|
||||
{
|
||||
FileEntry *file = volume->fileAtIndex(i);
|
||||
FileEntryPointer file = volume->fileAtIndex(i);
|
||||
if (file == NULL) break;
|
||||
|
||||
if (::strcasecmp(file->name(), name)) continue;
|
||||
@@ -363,7 +399,7 @@ static void pascal_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
entry.entry_timeout = 0.0;
|
||||
entry.ino = file->inode();
|
||||
|
||||
stat(file, &entry.attr);
|
||||
stat(file.get(), &entry.attr);
|
||||
fuse_reply_entry(req, &entry);
|
||||
return;
|
||||
}
|
||||
@@ -378,7 +414,7 @@ static void pascal_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info
|
||||
|
||||
struct stat st;
|
||||
VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req);
|
||||
FileEntry *file;
|
||||
FileEntryPointer file;
|
||||
|
||||
if (ino == 1)
|
||||
{
|
||||
@@ -392,7 +428,7 @@ static void pascal_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info
|
||||
ERROR(file == NULL, ENOENT)
|
||||
//printf("\t%s\n", file->name());
|
||||
|
||||
stat(file, &st);
|
||||
stat(file.get(), &st);
|
||||
fuse_reply_attr(req, &st, 0.0);
|
||||
}
|
||||
|
||||
@@ -402,10 +438,11 @@ static void pascal_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info
|
||||
|
||||
static void pascal_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
|
||||
{
|
||||
unsigned index;
|
||||
DEBUGNAME()
|
||||
|
||||
VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req);
|
||||
FileEntry *file;
|
||||
FileEntryPointer file;
|
||||
|
||||
ERROR(ino == 1, EISDIR)
|
||||
|
||||
@@ -415,7 +452,20 @@ static void pascal_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f
|
||||
|
||||
ERROR((fi->flags & O_ACCMODE) != O_RDONLY, EACCES)
|
||||
|
||||
fi->fh = (uint64_t)file;
|
||||
// insert the FileEntryPointer into fd_table.
|
||||
if (fd_table_available.size())
|
||||
{
|
||||
index = fd_table_available.back();
|
||||
fd_table_available.pop_back();
|
||||
fd_table[index] = file;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = fd_table.size();
|
||||
fd_table.push_back(file);
|
||||
}
|
||||
|
||||
fi->fh = index;
|
||||
|
||||
fuse_reply_open(req, fi);
|
||||
}
|
||||
@@ -423,31 +473,38 @@ static void pascal_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f
|
||||
|
||||
static void pascal_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
|
||||
{
|
||||
unsigned index = fi->fh;
|
||||
DEBUGNAME()
|
||||
|
||||
fd_table[index].reset();
|
||||
fd_table_available.push_back(index);
|
||||
|
||||
fuse_reply_err(req, 0);
|
||||
}
|
||||
|
||||
|
||||
static void pascal_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
|
||||
{
|
||||
unsigned index = fi->fh;
|
||||
|
||||
DEBUGNAME()
|
||||
|
||||
|
||||
//VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req);
|
||||
FileEntry *file = (FileEntry *)fi->fh;
|
||||
FileEntryPointer file = fd_table[index];
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
ProFUSE::auto_array<uint8_t> buffer(new uint8_t[size]);
|
||||
::auto_array<uint8_t> buffer(new uint8_t[size]);
|
||||
unsigned rsize = file->read(buffer.get(), size, off);
|
||||
|
||||
fuse_reply_buf(req, (char *)(buffer.get()), rsize);
|
||||
return;
|
||||
}
|
||||
catch (ProFUSE::POSIXException &e)
|
||||
|
||||
catch (POSIX::Exception &e)
|
||||
{
|
||||
printf("posix error...\n");
|
||||
ERROR(true, e.error());
|
||||
@@ -460,7 +517,6 @@ static void pascal_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
|
||||
|
||||
}
|
||||
|
||||
|
||||
void init_ops(fuse_lowlevel_ops *ops)
|
||||
{
|
||||
DEBUGNAME()
|
||||
@@ -469,6 +525,7 @@ void init_ops(fuse_lowlevel_ops *ops)
|
||||
|
||||
ops->init = pascal_init;
|
||||
ops->destroy = pascal_destroy;
|
||||
ops->statfs = pascal_statfs;
|
||||
|
||||
// returns pascal.filekind, text encoding.
|
||||
ops->listxattr = pascal_listxattr;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <Device/RawDevice.h>
|
||||
|
||||
|
||||
#include <ProFUSE/Exception.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
#include <Pascal/Pascal.h>
|
||||
|
||||
@@ -212,10 +212,10 @@ int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
struct stat st;
|
||||
bool rawDevice;
|
||||
bool rawDevice = false;
|
||||
|
||||
std::auto_ptr<BlockDevice> device;
|
||||
std::auto_ptr<VolumeEntry> volume;
|
||||
BlockDevicePointer device;
|
||||
VolumeEntryPointer volume;
|
||||
|
||||
// Check for block device. if so, verify.
|
||||
// if file exists, verify before overwrite.
|
||||
@@ -228,7 +228,7 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "`%s' is a raw device. Are you sure you want to initialize it? ", fname);
|
||||
if (!yes_or_no()) return -1;
|
||||
|
||||
device.reset( RawDevice::Open(fname, File::ReadWrite) );
|
||||
device = RawDevice::Open(fname, File::ReadWrite);
|
||||
blocks = device->blocks();
|
||||
rawDevice = true;
|
||||
|
||||
@@ -260,7 +260,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (!rawDevice)
|
||||
device.reset( BlockDevice::Create(fname, volumeName.c_str(), blocks, format));
|
||||
device = BlockDevice::Create(fname, volumeName.c_str(), blocks, format);
|
||||
|
||||
if (!device.get())
|
||||
{
|
||||
@@ -271,7 +271,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (!bootFile.empty())
|
||||
{
|
||||
MappedFile bf(bootFile.c_str(), File::ReadOnly , std::nothrow);
|
||||
MappedFile bf(bootFile.c_str(), File::ReadOnly, std::nothrow);
|
||||
|
||||
if (!bf.isValid())
|
||||
{
|
||||
@@ -298,24 +298,17 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
volume.reset(
|
||||
new VolumeEntry(volumeName.c_str(), device.get())
|
||||
);
|
||||
device.release();
|
||||
volume = VolumeEntry::Create(device, volumeName.c_str());
|
||||
|
||||
|
||||
}
|
||||
catch (ProFUSE::POSIXException& e)
|
||||
catch (::Exception& e)
|
||||
{
|
||||
std::fprintf(stderr, "%s\n", e.what());
|
||||
std::fprintf(stderr, "%s\n", ::strerror(e.error()));
|
||||
return -2;
|
||||
}
|
||||
catch (ProFUSE::Exception& e)
|
||||
{
|
||||
std::fprintf(stderr, "%s\n", e.what());
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#define NEWFS_VERSION "0.1"
|
||||
|
||||
using namespace ProFUSE;
|
||||
using namespace Device;
|
||||
|
||||
void usage()
|
||||
{
|
||||
|
||||
374
bin/profuse.cpp
Normal file
374
bin/profuse.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* main.cpp
|
||||
* ProFUSE
|
||||
*
|
||||
* Created by Kelvin Sherlock on 12/24/08.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
|
||||
#define __FreeBSD__ 10
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define __DARWIN_64_BIT_INO_T 1
|
||||
#define _REENTRANT
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <cstddef>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <Device/BlockDevice.h>
|
||||
|
||||
|
||||
#include "profuse.h"
|
||||
|
||||
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
|
||||
/*
|
||||
* globals variables.
|
||||
*
|
||||
*/
|
||||
|
||||
std::string fDiskImage;
|
||||
|
||||
|
||||
DiskPointer disk;
|
||||
VolumeEntry volume;
|
||||
|
||||
bool validProdosName(const char *name)
|
||||
{
|
||||
// OS X looks for hidden files that don't exist (and aren't legal prodos names)
|
||||
// most are not legal prodos names, so this filters them out easily.
|
||||
|
||||
// [A-Za-z][0-9A-Za-z.]{0,14}
|
||||
|
||||
if (!isalpha(*name)) return false;
|
||||
|
||||
unsigned i;
|
||||
for(i = 1; name[i]; i++)
|
||||
{
|
||||
char c = name[i];
|
||||
if (c == '.' || isalnum(c)) continue;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return i < 16;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static struct fuse_lowlevel_ops prodos_oper;
|
||||
|
||||
enum {
|
||||
PRODOS_OPT_HELP,
|
||||
PRODOS_OPT_VERSION,
|
||||
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[] = {
|
||||
FUSE_OPT_KEY("-h", PRODOS_OPT_HELP),
|
||||
FUSE_OPT_KEY("--help", PRODOS_OPT_HELP),
|
||||
|
||||
FUSE_OPT_KEY("-V", PRODOS_OPT_VERSION),
|
||||
FUSE_OPT_KEY("--version", PRODOS_OPT_VERSION),
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
static void usage()
|
||||
{
|
||||
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"
|
||||
#ifdef HAVE_NUFX
|
||||
" sdk ShrinkIt Disk Image\n"
|
||||
#endif
|
||||
" 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)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case PRODOS_OPT_HELP:
|
||||
usage();
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case PRODOS_OPT_VERSION:
|
||||
// TODO
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
case FUSE_OPT_KEY_NONOPT:
|
||||
// first arg is the disk image.
|
||||
if (fDiskImage.empty())
|
||||
{
|
||||
fDiskImage = arg;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
// create a dir in /Volumes/diskname.
|
||||
bool make_mount_dir(string name, string &path)
|
||||
{
|
||||
path = "";
|
||||
|
||||
if (name.find('/') != string::npos) return false;
|
||||
if (name.find('\\') != string::npos) return false;
|
||||
if (name.find(':') != string::npos) return false;
|
||||
|
||||
path = "";
|
||||
path = "/Volumes/" + name;
|
||||
rmdir(path.c_str());
|
||||
if (mkdir(path.c_str(), 0777) == 0) return true;
|
||||
|
||||
for (unsigned i = 0; i < 26; i++)
|
||||
{
|
||||
path = "/Volumes/" + name + " " + (char)('a' + i);
|
||||
|
||||
rmdir(path.c_str());
|
||||
if (mkdir(path.c_str(), 0777) == 0) return true;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
path = "";
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
struct fuse_chan *ch;
|
||||
char *mountpoint = NULL;
|
||||
int err = -1;
|
||||
struct options options;
|
||||
|
||||
unsigned format = 0;
|
||||
|
||||
int foreground = false;
|
||||
int multithread = false;
|
||||
|
||||
|
||||
#if __APPLE__
|
||||
string mountpath;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
std::memset(&prodos_oper, 0, sizeof(prodos_oper));
|
||||
|
||||
std::memset(&options, 0, sizeof(options));
|
||||
|
||||
|
||||
prodos_oper.listxattr = prodos_listxattr;
|
||||
prodos_oper.getxattr = prodos_getxattr;
|
||||
|
||||
prodos_oper.opendir = prodos_opendir;
|
||||
prodos_oper.releasedir = prodos_releasedir;
|
||||
prodos_oper.readdir = prodos_readdir;
|
||||
|
||||
prodos_oper.lookup = prodos_lookup;
|
||||
prodos_oper.getattr = prodos_getattr;
|
||||
|
||||
prodos_oper.open = prodos_open;
|
||||
prodos_oper.release = prodos_release;
|
||||
prodos_oper.read = prodos_read;
|
||||
|
||||
prodos_oper.statfs = prodos_statfs;
|
||||
|
||||
|
||||
// scan the argument list, looking for the name of the disk image.
|
||||
if (fuse_opt_parse(&args, &options , prodos_opts, prodos_opt_proc) == -1)
|
||||
exit(1);
|
||||
|
||||
if (fDiskImage.empty())
|
||||
{
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// default prodos-order disk image.
|
||||
if (options.format)
|
||||
{
|
||||
format = Device::BlockDevice::ImageType(options.format);
|
||||
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 (::Exception &e)
|
||||
{
|
||||
std::fprintf(stderr, "%s\n", e.what());
|
||||
std::fprintf(stderr, "%s\n", e.errorString());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
disk->ReadVolume(&volume, NULL);
|
||||
|
||||
#ifdef __APPLE__
|
||||
{
|
||||
// Macfuse supports custom volume names (displayed in Finder)
|
||||
string str="-ovolname=";
|
||||
str += volume.volume_name;
|
||||
fuse_opt_add_arg(&args, str.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// use 512byte blocks.
|
||||
#if __APPLE__
|
||||
fuse_opt_add_arg(&args, "-oiosize=512");
|
||||
#endif
|
||||
|
||||
do {
|
||||
|
||||
if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) == -1) break;
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
if (mountpoint == NULL || *mountpoint == 0)
|
||||
{
|
||||
if (make_mount_dir(volume.volume_name, mountpath))
|
||||
mountpoint = (char *)mountpath.c_str();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
foreground = options.debug;
|
||||
|
||||
|
||||
if (mountpoint == NULL || *mountpoint == 0)
|
||||
{
|
||||
fprintf(stderr, "no mount point\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( (ch = fuse_mount(mountpoint, &args)) != NULL)
|
||||
{
|
||||
struct fuse_session *se;
|
||||
|
||||
se = fuse_lowlevel_new(&args, &prodos_oper, sizeof(prodos_oper), NULL);
|
||||
if (se != NULL) do {
|
||||
|
||||
err = fuse_daemonize(foreground);
|
||||
if (err < 0 ) break;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
fuse_opt_free_args(&args);
|
||||
|
||||
disk.reset();
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (mountpath.size()) rmdir(mountpath.c_str());
|
||||
#endif
|
||||
|
||||
return err ? 1 : 0;
|
||||
}
|
||||
56
bin/profuse.h
Normal file
56
bin/profuse.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* profuse.h
|
||||
* profuse
|
||||
*
|
||||
* Created by Kelvin Sherlock on 1/23/2009.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PROFUSE_H__
|
||||
#define __PROFUSE_H__
|
||||
|
||||
#include <ProDOS/File.h>
|
||||
#include <ProDOS/Disk.h>
|
||||
#include <ProDOS/common.h>
|
||||
|
||||
|
||||
#define FUSE_USE_VERSION 27
|
||||
|
||||
#include <fuse_opt.h>
|
||||
#include <fuse_lowlevel.h>
|
||||
|
||||
|
||||
#undef ERROR
|
||||
#define ERROR(cond,errno) if ( (cond) ){ fuse_reply_err(req, errno); return; }
|
||||
|
||||
|
||||
extern DiskPointer disk;
|
||||
|
||||
bool validProdosName(const char *name);
|
||||
|
||||
// xattr
|
||||
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);
|
||||
void prodos_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size);
|
||||
|
||||
//dirent
|
||||
void prodos_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
|
||||
void prodos_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
|
||||
void prodos_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi);
|
||||
|
||||
// stat
|
||||
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_statfs(fuse_req_t req, fuse_ino_t ino);
|
||||
|
||||
|
||||
// file io.
|
||||
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_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
132
bin/profuse_dirent.cpp
Normal file
132
bin/profuse_dirent.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* profuse_dirent.cpp
|
||||
* profuse
|
||||
*
|
||||
* Created by Kelvin Sherlock on 1/23/2009.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "profuse.h"
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#pragma mark Directory Functions
|
||||
|
||||
/*
|
||||
* when the directory is opened, we load the volume/directory and store the FileEntry vector into
|
||||
* fi->fh.
|
||||
*
|
||||
*/
|
||||
void prodos_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
|
||||
{
|
||||
fprintf(stderr, "opendir: %u\n", (unsigned)ino);
|
||||
// verify it's a directory/volume here?
|
||||
|
||||
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
vector<FileEntry> files;
|
||||
bool ok;
|
||||
|
||||
|
||||
ok = disk->Read(ino == 1 ? 2 : ino >> 9, buffer);
|
||||
ERROR(ok < 0, EIO)
|
||||
|
||||
|
||||
if (ino == 1)
|
||||
{
|
||||
VolumeEntry v;
|
||||
v.Load(buffer + 0x04);
|
||||
|
||||
ok = disk->ReadVolume(&v, &files);
|
||||
|
||||
ERROR(ok < 0, EIO)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
FileEntry e;
|
||||
e.Load(buffer + (ino & 0x1ff));
|
||||
|
||||
ERROR(e.storage_type != DIRECTORY_FILE, ENOTDIR)
|
||||
|
||||
ok = disk->ReadDirectory(e.key_pointer, NULL, &files);
|
||||
|
||||
ERROR(ok < 0, EIO);
|
||||
}
|
||||
|
||||
// copy the vector contents to a vector *.
|
||||
vector<FileEntry> *fp = new vector<FileEntry>();
|
||||
files.swap(*fp);
|
||||
|
||||
fi->fh = (uint64_t)fp;
|
||||
fuse_reply_open(req, fi);
|
||||
}
|
||||
|
||||
void prodos_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
|
||||
{
|
||||
fprintf(stderr,"releasedir: %u\n", (unsigned)ino);
|
||||
vector<FileEntry> *files = (vector<FileEntry> *)fi->fh;
|
||||
|
||||
if (files) delete files;
|
||||
|
||||
fuse_reply_err(req, 0);
|
||||
}
|
||||
|
||||
void prodos_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
|
||||
{
|
||||
vector<FileEntry> *files = (vector<FileEntry> *)fi->fh;
|
||||
struct stat st;
|
||||
|
||||
fprintf(stderr, "readdir %u %u %u\n", (unsigned)ino, (unsigned)size, (unsigned)off);
|
||||
|
||||
// TODO -- add "." and ".." entries...
|
||||
|
||||
|
||||
// if the offset >= number of entries, get out.
|
||||
if (!files || files->size() <= off)
|
||||
{
|
||||
fprintf(stderr, "fuse_reply_buf(req, NULL, 0)\n");
|
||||
fuse_reply_buf(req, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// now some dirent info...
|
||||
|
||||
bzero(&st, sizeof(st));
|
||||
// only mode and ino are used.
|
||||
|
||||
char *buffer = new char[size];
|
||||
|
||||
unsigned count = files->size();
|
||||
unsigned current_size = 0;
|
||||
for (unsigned i = off; i < count; ++i)
|
||||
{
|
||||
FileEntry &f = (*files)[i];
|
||||
|
||||
st.st_mode = f.storage_type == DIRECTORY_FILE ? S_IFDIR | 0555 : S_IFREG | 0444;
|
||||
st.st_ino = f.address;
|
||||
|
||||
unsigned entry_size = fuse_add_direntry(req, NULL, 0, f.file_name, NULL, 0);
|
||||
if (entry_size + current_size >= size) break;
|
||||
|
||||
|
||||
fuse_add_direntry(req, (char *)buffer + current_size, size, f.file_name, &st, i + 1);
|
||||
current_size += entry_size;
|
||||
|
||||
}
|
||||
|
||||
fuse_reply_buf(req, buffer, current_size);
|
||||
delete []buffer;
|
||||
}
|
||||
|
||||
136
bin/profuse_file.cpp
Normal file
136
bin/profuse_file.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* profuse_file.cpp
|
||||
* profuse
|
||||
*
|
||||
* Created by Kelvin Sherlock on 1/23/2009.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "profuse.h"
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
#pragma mark Read Functions
|
||||
|
||||
void prodos_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
|
||||
{
|
||||
fprintf(stderr, "open: %u\n", (unsigned)ino);
|
||||
|
||||
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
int ok;
|
||||
|
||||
FileEntry *e = NULL;
|
||||
|
||||
ERROR(ino == 1, EISDIR)
|
||||
|
||||
ok = disk->Read(ino >> 9, buffer);
|
||||
ERROR(ok < 0, EIO)
|
||||
|
||||
e = new FileEntry();
|
||||
e->Load(buffer + (ino & 0x1ff));
|
||||
|
||||
if (e->storage_type == EXTENDED_FILE)
|
||||
{
|
||||
ok = disk->Normalize(*e, 0);
|
||||
|
||||
if (ok < 0)
|
||||
{
|
||||
delete e;
|
||||
ERROR(true, EIO)
|
||||
}
|
||||
}
|
||||
|
||||
// EXTENDED_FILE already handled (it would be an error here.)
|
||||
switch(e->storage_type)
|
||||
{
|
||||
case SEEDLING_FILE:
|
||||
case SAPLING_FILE:
|
||||
case TREE_FILE:
|
||||
break;
|
||||
//case PASCAL_FILE: //?
|
||||
case DIRECTORY_FILE:
|
||||
delete e;
|
||||
ERROR(true, EISDIR)
|
||||
break;
|
||||
default:
|
||||
ERROR(true, EIO)
|
||||
}
|
||||
|
||||
if ( (fi->flags & O_ACCMODE) != O_RDONLY)
|
||||
{
|
||||
delete e;
|
||||
ERROR(true, EACCES);
|
||||
}
|
||||
fi->fh = (uint64_t)e;
|
||||
|
||||
fuse_reply_open(req, fi);
|
||||
}
|
||||
|
||||
void prodos_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
|
||||
{
|
||||
fprintf(stderr, "release: %u\n", (unsigned)ino);
|
||||
|
||||
FileEntry *e = (FileEntry *)fi->fh;
|
||||
|
||||
if (e) delete e;
|
||||
|
||||
fuse_reply_err(req, 0);
|
||||
|
||||
}
|
||||
|
||||
void prodos_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
|
||||
{
|
||||
fprintf(stderr, "read: %u %u %u\n", (unsigned)ino, (unsigned)size, (unsigned)off);
|
||||
|
||||
FileEntry *e = (FileEntry *)fi->fh;
|
||||
|
||||
ERROR(e == NULL, EIO)
|
||||
|
||||
if (off >= e->eof)
|
||||
{
|
||||
fuse_reply_buf(req, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
unsigned level = 0;
|
||||
switch(e->storage_type)
|
||||
{
|
||||
case TREE_FILE:
|
||||
level = 2;
|
||||
break;
|
||||
case SAPLING_FILE:
|
||||
level = 1;
|
||||
break;
|
||||
case SEEDLING_FILE:
|
||||
level = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// currently, reading is done on a block basis.
|
||||
// experimentally, fuse reads the entire file
|
||||
// this may not hold for larger files.
|
||||
|
||||
|
||||
// TODO -- error if size + off > eof.
|
||||
|
||||
unsigned blocks = (size + (off & 0x1ff) + BLOCK_SIZE - 1) >> 9;
|
||||
int ok;
|
||||
uint8_t *buffer = new uint8_t[blocks << 9];
|
||||
|
||||
fprintf(stderr, "ReadIndex(%x, buffer, %x, %x, %x)\n", e->key_pointer, level, (int)off, (int)blocks);
|
||||
|
||||
ok = disk->ReadIndex(e->key_pointer, buffer, level, off, blocks);
|
||||
if (ok < 0)
|
||||
{
|
||||
fuse_reply_err(req, EIO);
|
||||
}
|
||||
else
|
||||
{
|
||||
fuse_reply_buf(req, (const char *)buffer + (off & 0x1ff), size);
|
||||
}
|
||||
|
||||
delete []buffer;
|
||||
}
|
||||
253
bin/profuse_stat.cpp
Normal file
253
bin/profuse_stat.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* prodos_stat.cpp
|
||||
* profuse
|
||||
*
|
||||
* Created by Kelvin Sherlock on 1/23/2009.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma mark Stat Functions
|
||||
|
||||
#include "profuse.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
using std::vector;
|
||||
|
||||
int prodos_stat(FileEntry& e, struct stat *st)
|
||||
{
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
int ok;
|
||||
|
||||
|
||||
if (e.storage_type == EXTENDED_FILE)
|
||||
{
|
||||
ok = disk->Normalize(e, 0);
|
||||
if (ok < 0) return ok;
|
||||
}
|
||||
|
||||
st->st_blksize = BLOCK_SIZE;
|
||||
|
||||
st->st_ctime = e.creation;
|
||||
#ifdef HAVE_STAT_BIRTHTIME
|
||||
st->st_birthtime = e.creation;
|
||||
#endif
|
||||
|
||||
st->st_mtime = e.last_mod;
|
||||
st->st_atime = e.last_mod;
|
||||
|
||||
|
||||
st->st_nlink = 1;
|
||||
st->st_mode = 0444 | S_IFREG;
|
||||
st->st_size = e.eof;
|
||||
|
||||
|
||||
if (e.storage_type == DIRECTORY_FILE)
|
||||
{
|
||||
ok = disk->Read(e.key_pointer, buffer);
|
||||
if (ok < 0) return -1;
|
||||
|
||||
SubdirEntry se;
|
||||
se.Load(buffer + 0x04);
|
||||
|
||||
if (se.storage_type != SUBDIR_HEADER) return -1;
|
||||
|
||||
st->st_mode = S_IFDIR | 0555;
|
||||
st->st_size = BLOCK_SIZE;
|
||||
st->st_nlink = se.file_count + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
switch(e.storage_type)
|
||||
{
|
||||
case SEEDLING_FILE:
|
||||
case SAPLING_FILE:
|
||||
case TREE_FILE:
|
||||
//case PASCAL_FILE:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prodos_stat(const VolumeEntry &v, struct stat *st)
|
||||
{
|
||||
|
||||
if (v.storage_type != VOLUME_HEADER) return -1;
|
||||
|
||||
st->st_mode = S_IFDIR | 0555;
|
||||
st->st_ctime = v.creation;
|
||||
|
||||
#ifdef HAVE_STAT_BIRTHTIME
|
||||
st->st_birthtime = v.creation;
|
||||
#endif
|
||||
st->st_mtime = v.last_mod;
|
||||
st->st_atime = v.last_mod;
|
||||
|
||||
st->st_nlink = v.file_count + 1;
|
||||
st->st_size = BLOCK_SIZE;
|
||||
st->st_blksize = BLOCK_SIZE;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void prodos_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
|
||||
{
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
struct stat st;
|
||||
int ok;
|
||||
|
||||
fprintf(stderr, "get_attr %u\n", (unsigned)ino);
|
||||
|
||||
bzero(&st, sizeof(st));
|
||||
|
||||
/*
|
||||
* ino 1 is the volume header. Others are pointers.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
ok = disk->Read(ino == 1 ? 2 : ino >> 9, buffer);
|
||||
ERROR(ok < 0, EIO)
|
||||
|
||||
// ino 1 is the volume header.
|
||||
if (ino == 1)
|
||||
{
|
||||
VolumeEntry v;
|
||||
v.Load(buffer + 0x04);
|
||||
ok = prodos_stat(v, &st);
|
||||
ERROR(ok < 0, EIO);
|
||||
|
||||
st.st_ino = ino;
|
||||
|
||||
fuse_reply_attr(req, &st, 0.0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
FileEntry e;
|
||||
e.Load(buffer + (ino & 0x1ff));
|
||||
ok = prodos_stat(e, &st);
|
||||
|
||||
ERROR(ok < 0, EIO);
|
||||
|
||||
st.st_ino = ino;
|
||||
|
||||
fuse_reply_attr(req, &st, 0.0); //
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO -- add Disk::Lookup support so we don't have to parse the entire dir header.
|
||||
// TODO -- add caching.
|
||||
void prodos_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
{
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
struct fuse_entry_param entry;
|
||||
int ok;
|
||||
vector<FileEntry> files;
|
||||
|
||||
|
||||
fprintf(stderr, "lookup: %u %s\n", (unsigned)parent, name);
|
||||
|
||||
ERROR(!validProdosName(name), ENOENT)
|
||||
|
||||
ok = disk->Read(parent == 1 ? 2 : parent >> 9, buffer);
|
||||
ERROR(ok < 0, EIO)
|
||||
|
||||
bzero(&entry, sizeof(entry));
|
||||
|
||||
entry.attr_timeout = 0.0;
|
||||
entry.entry_timeout = 0.0;
|
||||
|
||||
// get the file list
|
||||
// TODO -- Disk::look-up-one-file
|
||||
if (parent == 1)
|
||||
{
|
||||
VolumeEntry v;
|
||||
ok = disk->ReadVolume(&v, &files);
|
||||
ERROR(ok < 0, EIO)
|
||||
}
|
||||
else
|
||||
{
|
||||
FileEntry e;
|
||||
e.Load(buffer + (parent & 0x1ff));
|
||||
ERROR(e.storage_type != DIRECTORY_FILE, ENOENT);
|
||||
|
||||
ok = disk->ReadDirectory(e.key_pointer, NULL, &files);
|
||||
ERROR(ok < 0, EIO)
|
||||
}
|
||||
// ok, now go through the file list and look for a (case insensitive) match.
|
||||
|
||||
|
||||
ok = -1;
|
||||
unsigned name_length = strlen(name);
|
||||
|
||||
for(vector<FileEntry>::iterator iter = files.begin(); iter != files.end(); ++iter)
|
||||
{
|
||||
FileEntry& f = *iter;
|
||||
if ( (f.name_length == name_length) && (strcasecmp(name, f.file_name) == 0))
|
||||
{
|
||||
ok = prodos_stat(f, &entry.attr);
|
||||
fprintf(stderr, "stat %s %x (%x %x) %d\n", f.file_name, f.address, f.address >> 9, f.address & 0x1ff, ok);
|
||||
entry.ino = f.address;
|
||||
entry.attr.st_ino = f.address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ERROR(ok < 0, ENOENT);
|
||||
|
||||
fprintf(stderr, "file found!\n");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
575
bin/profuse_xattr.cpp
Normal file
575
bin/profuse_xattr.cpp
Normal file
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
* profuse_xattr.cpp
|
||||
* profuse
|
||||
*
|
||||
* Created by Kelvin Sherlock on 1/23/2009.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "profuse.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define NO_ATTRIBUTE ENOATTR
|
||||
#else
|
||||
#define NO_ATTRIBUTE EOPNOTSUPP
|
||||
#endif
|
||||
|
||||
static bool isTextFile(unsigned ftype, unsigned auxtype)
|
||||
{
|
||||
if (ftype == 0x04) return true; // ascii text
|
||||
if (ftype == 0xb0) return true; // source code.
|
||||
if (ftype == 0x50 && auxtype == 0x5445) return true; // teach text
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static const char *mimeType(unsigned ftype, unsigned auxtype)
|
||||
{
|
||||
switch(ftype)
|
||||
{
|
||||
case 0x04:
|
||||
if (auxtype == 0) return "text/plain";
|
||||
break;
|
||||
case 0xb0:
|
||||
return "text/plain";
|
||||
break;
|
||||
case 0x50:
|
||||
if (auxtype == 0x5445) return "text/plain";
|
||||
break;
|
||||
case 0xc0:
|
||||
if (auxtype == 0x8006) return "image/gif";
|
||||
break;
|
||||
case 0xe0:
|
||||
if (auxtype == 0x8000) return "application/x-BinaryII";
|
||||
if (auxtype == 0x8002) return "application/x-Shrinkit";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void setCreator(uint8_t *finfo, unsigned ftype, unsigned auxtype)
|
||||
{
|
||||
|
||||
/*
|
||||
|
||||
tech note PT515
|
||||
ProDOS -> Macintosh conversion
|
||||
|
||||
ProDOS Macintosh
|
||||
Filetype Auxtype Creator Filetype
|
||||
$00 $0000 'pdos' 'BINA'
|
||||
$B0 (SRC) (any) 'pdos' 'TEXT'
|
||||
$04 (TXT) $0000 'pdos' 'TEXT'
|
||||
$FF (SYS) (any) 'pdos' 'PSYS'
|
||||
$B3 (S16) (any) 'pdos' 'PS16'
|
||||
$uv $wxyz 'pdos' 'p' $uv $wx $yz
|
||||
|
||||
Programmer's Reference for System 6.0:
|
||||
|
||||
ProDOS Macintosh
|
||||
File Type Auxiliary Type Creator Type File Type
|
||||
$00 $0000 “pdos” “BINA”
|
||||
$04 (TXT) $0000 “pdos” “TEXT”
|
||||
$FF (SYS) (any) “pdos” “PSYS”
|
||||
$B3 (S16) $DByz “pdos” “p” $B3 $DB $yz
|
||||
$B3 (S16) (any) “pdos” “PS16”
|
||||
$D7 $0000 “pdos” “MIDI”
|
||||
$D8 $0000 “pdos” “AIFF”
|
||||
$D8 $0001 “pdos” “AIFC”
|
||||
$E0 $0005 “dCpy” “dImg”
|
||||
$FF (SYS) (any) “pdos” “PSYS”
|
||||
$uv $wxyz “pdos” “p” $uv $wx $yz
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
finfo[0] = 'p';
|
||||
finfo[1] = ftype;
|
||||
finfo[2] = auxtype >> 8;
|
||||
finfo[3] = auxtype;
|
||||
|
||||
memcpy(finfo + 4, "pdos", 4);
|
||||
|
||||
switch (ftype)
|
||||
{
|
||||
case 0x00:
|
||||
if (auxtype == 0) memcpy(finfo, "BINA", 4);
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
if (auxtype == 0) memcpy(finfo, "TEXT", 4);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
if (auxtype == 0x5445) memcpy(finfo, "TEXT", 4);
|
||||
break;
|
||||
|
||||
case 0xb0:
|
||||
memcpy(finfo, "TEXT", 4);
|
||||
break;
|
||||
|
||||
case 0xb3:
|
||||
if ((auxtype >> 8) != 0xdb) memcpy(finfo, "PS16", 4);
|
||||
break;
|
||||
|
||||
case 0xd7:
|
||||
if (auxtype == 0) memcpy(finfo, "MIDI", 4);
|
||||
break;
|
||||
|
||||
case 0xd8:
|
||||
if (auxtype == 0) memcpy(finfo, "AIFF", 4);
|
||||
if (auxtype == 1) memcpy(finfo, "AIFC", 4);
|
||||
break;
|
||||
|
||||
case 0xe0:
|
||||
if (auxtype == 5) memcpy(finfo, "dImgdCpy", 8);
|
||||
break;
|
||||
|
||||
case 0xff:
|
||||
memcpy(finfo, "PSYS", 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark XAttribute Functions
|
||||
|
||||
|
||||
static void xattr_filetype(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
||||
{
|
||||
uint8_t attr = e.file_type;
|
||||
unsigned attr_size = 1;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR (size < attr_size, ERANGE)
|
||||
|
||||
// consider position here?
|
||||
fuse_reply_buf(req, (char *)&attr, attr_size);
|
||||
}
|
||||
|
||||
|
||||
static void xattr_auxtype(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
||||
{
|
||||
uint8_t attr[2];
|
||||
unsigned attr_size = 2;
|
||||
|
||||
attr[0] = e.aux_type & 0xff;
|
||||
attr[1] = (e.aux_type >> 8) & 0xff;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR (size < attr_size, ERANGE)
|
||||
|
||||
// consider position here?
|
||||
fuse_reply_buf(req, (char *)&attr, attr_size);
|
||||
}
|
||||
|
||||
// user.charset
|
||||
static void xattr_charset(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
||||
{
|
||||
const char attr[] = "macintosh";
|
||||
unsigned attr_size = sizeof(attr) - 1;
|
||||
|
||||
ERROR(!isTextFile(e.file_type, e.aux_type), NO_ATTRIBUTE)
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR (size < attr_size, ERANGE)
|
||||
|
||||
fuse_reply_buf(req, (char *)&attr, attr_size);
|
||||
}
|
||||
|
||||
//apple.TextEncoding
|
||||
static void xattr_textencoding(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
||||
{
|
||||
const char attr[] = "MACINTOSH;0";
|
||||
unsigned attr_size = sizeof(attr) - 1;
|
||||
|
||||
ERROR(!isTextFile(e.file_type, e.aux_type), NO_ATTRIBUTE)
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR (size < attr_size, ERANGE)
|
||||
|
||||
fuse_reply_buf(req, (char *)&attr, attr_size);
|
||||
}
|
||||
|
||||
static void xattr_rfork(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
||||
{
|
||||
int ok;
|
||||
unsigned level;
|
||||
|
||||
ERROR (e.storage_type != EXTENDED_FILE, NO_ATTRIBUTE)
|
||||
|
||||
ok = disk->Normalize(e, 1);
|
||||
ERROR(ok < 0, EIO)
|
||||
|
||||
|
||||
switch(e.storage_type)
|
||||
{
|
||||
case SEEDLING_FILE:
|
||||
level = 0;
|
||||
break;
|
||||
case SAPLING_FILE:
|
||||
level = 1;
|
||||
break;
|
||||
case TREE_FILE:
|
||||
level = 2;
|
||||
break;
|
||||
default:
|
||||
ERROR(true, EIO)
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, e.eof);
|
||||
return;
|
||||
}
|
||||
|
||||
size = std::min((uint32_t)(size + off), e.eof);
|
||||
|
||||
unsigned blocks = (size + (off & 0x1ff) + BLOCK_SIZE - 1) >> 9;
|
||||
uint8_t *buffer = new uint8_t[blocks << 9];
|
||||
|
||||
fprintf(stderr, "ReadIndex(%x, buffer, %x, %x, %x)\n", e.key_pointer, level, (int)off, (int)blocks);
|
||||
|
||||
ok = disk->ReadIndex(e.key_pointer, buffer, level, off, blocks);
|
||||
|
||||
if (ok < 0)
|
||||
{
|
||||
fuse_reply_err(req, EIO);
|
||||
}
|
||||
else
|
||||
{
|
||||
fuse_reply_buf(req, (char *)buffer + (off & 0x1ff), size);
|
||||
}
|
||||
delete []buffer;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Finder info.
|
||||
static void xattr_finfo(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
||||
{
|
||||
int ok;
|
||||
ExtendedEntry ee;
|
||||
|
||||
uint8_t attr[32];
|
||||
unsigned attr_size = 32;
|
||||
|
||||
//ERROR (e.storage_type != EXTENDED_FILE, ENOENT)
|
||||
|
||||
switch (e.storage_type)
|
||||
{
|
||||
case SEEDLING_FILE:
|
||||
case SAPLING_FILE:
|
||||
case TREE_FILE:
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
bzero(attr, attr_size);
|
||||
setCreator(attr, e.file_type, e.aux_type);
|
||||
fuse_reply_buf(req, (char *)attr, attr_size);
|
||||
return;
|
||||
|
||||
case EXTENDED_FILE:
|
||||
// handled below.
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR(true, NO_ATTRIBUTE);
|
||||
}
|
||||
|
||||
|
||||
ok = disk->Normalize(e, 1, &ee);
|
||||
ERROR(ok < 0, EIO)
|
||||
|
||||
// sanity check
|
||||
switch(e.storage_type)
|
||||
{
|
||||
case SEEDLING_FILE:
|
||||
case SAPLING_FILE:
|
||||
case TREE_FILE:
|
||||
break;
|
||||
default:
|
||||
ERROR(true, EIO)
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR (size < attr_size, ERANGE)
|
||||
|
||||
memcpy(attr, ee.FInfo, 16);
|
||||
memcpy(attr + 16, ee.xFInfo, 16);
|
||||
|
||||
// if no creator, create one.
|
||||
if (memcmp(attr, "\0\0\0\0\0\0\0\0", 8) == 0)
|
||||
setCreator(attr, e.file_type, e.aux_type);
|
||||
|
||||
fuse_reply_buf(req, (char *)attr, attr_size);
|
||||
}
|
||||
|
||||
|
||||
static void xattr_mimetype(FileEntry& e, fuse_req_t req, size_t size, off_t off)
|
||||
{
|
||||
unsigned attr_size;
|
||||
const char *mime = mimeType(e.file_type, e.aux_type);
|
||||
ERROR(!mime, NO_ATTRIBUTE);
|
||||
|
||||
attr_size = strlen(mime);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR (size < attr_size, ERANGE)
|
||||
|
||||
fuse_reply_buf(req, mime, attr_size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void prodos_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
|
||||
{
|
||||
// list of supported attributes.
|
||||
//
|
||||
#define NO_ATTR() \
|
||||
{ \
|
||||
if (size) fuse_reply_buf(req, NULL, 0); \
|
||||
else fuse_reply_xattr(req, 0); \
|
||||
return; \
|
||||
}
|
||||
|
||||
fprintf(stderr, "listxattr %u\n", (unsigned)ino);
|
||||
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
int ok;
|
||||
unsigned attr_size;
|
||||
string attr;
|
||||
|
||||
|
||||
|
||||
if(ino == 1)
|
||||
NO_ATTR()
|
||||
|
||||
ok = disk->Read(ino >> 9, buffer);
|
||||
|
||||
ERROR(ok < 0, EIO)
|
||||
|
||||
|
||||
FileEntry e;
|
||||
e.Load(buffer + (ino & 0x1ff));
|
||||
|
||||
|
||||
attr += "prodos.FileType";
|
||||
attr.append(1, 0);
|
||||
|
||||
attr += "prodos.AuxType";
|
||||
attr.append(1, 0);
|
||||
|
||||
switch(e.storage_type)
|
||||
{
|
||||
case EXTENDED_FILE:
|
||||
{
|
||||
// TODO -- pretend there's no resource fork if resource fork eof == 0 ?
|
||||
//
|
||||
//ok = disk->Normalize(e, 1);
|
||||
//ERROR(ok < 0, EIO)
|
||||
|
||||
attr += "prodos.ResourceFork";
|
||||
attr.append(1, 0);
|
||||
|
||||
attr += "com.apple.FinderInfo";
|
||||
attr.append(1, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case SEEDLING_FILE:
|
||||
case SAPLING_FILE:
|
||||
case TREE_FILE:
|
||||
// generate HFS creator codes.
|
||||
attr += "com.apple.FinderInfo";
|
||||
attr.append(1, 0);
|
||||
break;
|
||||
|
||||
case DIRECTORY_FILE:
|
||||
NO_ATTR()
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
NO_ATTR()
|
||||
break;
|
||||
}
|
||||
|
||||
if (isTextFile(e.file_type, e.aux_type))
|
||||
{
|
||||
attr += "com.apple.TextEncoding";
|
||||
attr.append(1, 0);
|
||||
|
||||
attr += "user.charset";
|
||||
attr.append(1, 0);
|
||||
}
|
||||
|
||||
if (mimeType(e.file_type, e.aux_type))
|
||||
{
|
||||
attr += "user.mime_type";
|
||||
attr.append(1, 0);
|
||||
}
|
||||
|
||||
attr_size = attr.length();
|
||||
|
||||
fprintf(stderr, "%d %s\n", attr_size, attr.c_str());
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_xattr(req, attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size < attr_size)
|
||||
{
|
||||
fuse_reply_err(req, ERANGE);
|
||||
return;
|
||||
}
|
||||
|
||||
fuse_reply_buf(req, attr.data(), attr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* offset is only valid in OS X for the resource fork.
|
||||
*
|
||||
*/
|
||||
void prodos_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size, uint32_t off)
|
||||
{
|
||||
|
||||
|
||||
fprintf(stderr, "getxattr: %u %s %u %u \n", (unsigned)ino, name, (unsigned)size, (unsigned)off);
|
||||
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
|
||||
|
||||
ERROR(ino == 1, NO_ATTRIBUTE) // finder can't handle EISDIR.
|
||||
|
||||
|
||||
int ok = disk->Read(ino >> 9, buffer);
|
||||
|
||||
ERROR(ok < 0, EIO)
|
||||
|
||||
|
||||
FileEntry e;
|
||||
e.Load(buffer + (ino & 0x1ff));
|
||||
|
||||
switch(e.storage_type)
|
||||
{
|
||||
case SEEDLING_FILE:
|
||||
case SAPLING_FILE:
|
||||
case TREE_FILE:
|
||||
case EXTENDED_FILE:
|
||||
break;
|
||||
case DIRECTORY_FILE:
|
||||
ERROR(true, NO_ATTRIBUTE) // Finder can't handle EISDIR.
|
||||
default:
|
||||
ERROR(true, NO_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (strcmp("prodos.FileType", name) == 0)
|
||||
{
|
||||
xattr_filetype(e, req, size, off);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp("prodos.AuxType", name) == 0)
|
||||
{
|
||||
xattr_auxtype(e, req, size, off);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp("com.apple.TextEncoding", name) == 0)
|
||||
{
|
||||
xattr_textencoding(e, req, size, off);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (e.storage_type == EXTENDED_FILE) && (strcmp("prodos.ResourceFork", name) == 0))
|
||||
{
|
||||
xattr_rfork(e, req, size, off);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( strcmp("com.apple.FinderInfo", name) == 0)
|
||||
{
|
||||
xattr_finfo(e, req, size, off);
|
||||
return;
|
||||
}
|
||||
|
||||
// linux standard
|
||||
if (strcmp("user.mime_type", name) == 0)
|
||||
{
|
||||
xattr_mimetype(e, req, size, off);
|
||||
return;
|
||||
}
|
||||
|
||||
// linux standard
|
||||
if (strcmp("user.charset", name) == 0)
|
||||
{
|
||||
xattr_charset(e, req, size, off);
|
||||
return;
|
||||
}
|
||||
|
||||
fuse_reply_err(req, NO_ATTRIBUTE);
|
||||
|
||||
}
|
||||
/*
|
||||
* Linux, et alia do not have an offset parameter.
|
||||
*/
|
||||
void prodos_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
|
||||
{
|
||||
prodos_getxattr(req, ino, name, size, 0);
|
||||
}
|
||||
|
||||
284
bin/xattr.cpp
284
bin/xattr.cpp
@@ -13,10 +13,27 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <err.h>
|
||||
|
||||
|
||||
typedef std::vector<std::string>::iterator vsiter;
|
||||
|
||||
// prototypes to shut up clang.
|
||||
|
||||
void hexdump(const uint8_t *data, ssize_t size);
|
||||
ssize_t get_attr_list(const char * fname, std::vector<std::string> &out);
|
||||
void dumpxattr(const char *file, const char *attr);
|
||||
int op_list(int argc, char **argv);
|
||||
int op_dump(int argc, char **argv);
|
||||
int op_read(int argc, char **argv);
|
||||
int op_rm(int argc, char **argv);
|
||||
int op_mv(int argc, char **argv);
|
||||
int op_cp(int argc, char **argv);
|
||||
ssize_t read_all(int fd, std::vector<uint8_t> &out);
|
||||
int op_write(int argc, char **argv);
|
||||
void usage(const char *name);
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
// apple has additional parameter for position and options.
|
||||
|
||||
@@ -36,6 +53,11 @@ inline int setxattr(const char *path, const char *name, void *value, size_t size
|
||||
{
|
||||
return setxattr(path, name, value, size, 0, flags);
|
||||
}
|
||||
|
||||
inline int removexattr(const char *path, const char *name) {
|
||||
return removexattr(path, name, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void hexdump(const uint8_t *data, ssize_t size)
|
||||
@@ -124,40 +146,48 @@ ssize_t get_attr_list(const char * fname, std::vector<std::string> &out)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* safely read the entire xattr into buffer.
|
||||
*
|
||||
*/
|
||||
int read_xattr(const char *fname, const char *attr_name, std::vector<uint8_t> &buffer) {
|
||||
|
||||
|
||||
|
||||
for(;;) {
|
||||
|
||||
ssize_t asize = getxattr(fname, attr_name, NULL, 0);
|
||||
if (asize < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer.resize(asize);
|
||||
asize = getxattr(fname, attr_name, buffer.data(), asize);
|
||||
if (asize < 0) {
|
||||
// ERANGE -- buffer is not large enough.
|
||||
if (errno == EINTR || errno == ERANGE) continue;
|
||||
return -1;
|
||||
}
|
||||
buffer.resize(asize);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hexdump an individual attribute.
|
||||
*/
|
||||
void dumpxattr(const char *file, const char *attr)
|
||||
void dumpxattr(const char *fname, const char *attr_name)
|
||||
{
|
||||
ssize_t asize;
|
||||
char *buffer;
|
||||
std::vector<uint8_t> buffer;
|
||||
if (read_xattr(fname, attr_name, buffer) < 0) {
|
||||
warn("getxattr(\"%s\", \"%s\")", fname, attr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
asize = getxattr(file, attr, NULL, 0);
|
||||
if (asize < 0)
|
||||
{
|
||||
std::perror(attr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::printf("%s: %u\n", attr, (unsigned)asize);
|
||||
|
||||
buffer = new char[asize];
|
||||
//if (!buffer) return;
|
||||
|
||||
asize = getxattr(file, attr, buffer, asize);
|
||||
if (asize >= 0)
|
||||
{
|
||||
hexdump((uint8_t *)buffer, asize);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::perror(attr);
|
||||
}
|
||||
|
||||
delete []buffer;
|
||||
std::printf("%s: %u\n", attr_name, (unsigned)buffer.size());
|
||||
hexdump(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +195,7 @@ char *buffer;
|
||||
* list a file's attributes (and size)
|
||||
*
|
||||
*/
|
||||
int list(int argc, char **argv)
|
||||
int op_list(int argc, char **argv)
|
||||
{
|
||||
|
||||
const char *fname = *argv;
|
||||
@@ -205,7 +235,7 @@ int list(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::perror(attr_name);
|
||||
warn("getxattr(\"%s\", \"%s\")", fname, attr_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +247,7 @@ int list(int argc, char **argv)
|
||||
* hexdump a file's attributes.
|
||||
*
|
||||
*/
|
||||
int dump(int argc, char **argv)
|
||||
int op_dump(int argc, char **argv)
|
||||
{
|
||||
|
||||
const char *fname = *argv;
|
||||
@@ -250,7 +280,7 @@ int dump(int argc, char **argv)
|
||||
|
||||
|
||||
// must specify the xattr name.
|
||||
int read(int argc, char **argv)
|
||||
int op_read(int argc, char **argv)
|
||||
{
|
||||
|
||||
if (argc != 2)
|
||||
@@ -261,37 +291,22 @@ int read(int argc, char **argv)
|
||||
|
||||
const char *fname = argv[0];
|
||||
const char *attr_name = argv[1];
|
||||
|
||||
// get the attribute size and read it in.
|
||||
ssize_t asize = getxattr(fname, attr_name, NULL, 0);
|
||||
if (asize < 0)
|
||||
{
|
||||
std::perror(attr_name);
|
||||
return -1;
|
||||
}
|
||||
if (asize == 0) return 0;
|
||||
|
||||
uint8_t *buffer = new uint8_t[asize];
|
||||
asize = getxattr(fname, attr_name, buffer, asize);
|
||||
|
||||
if (asize < 0)
|
||||
{
|
||||
std::perror(attr_name);
|
||||
return -1;
|
||||
std::vector<uint8_t> buffer;
|
||||
if (read_xattr(fname, attr_name, buffer) < 0 ) {
|
||||
warn("getxattr(\"%s\", \"%s\")", fname, attr_name);
|
||||
return -1;
|
||||
}
|
||||
if (buffer.size() == 0) return 0;
|
||||
|
||||
if (::write(STDOUT_FILENO, buffer, asize) != asize)
|
||||
if (::write(STDOUT_FILENO, buffer.data(), buffer.size()) < 0)
|
||||
{
|
||||
perror(NULL);
|
||||
delete []buffer;
|
||||
warn("write");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
delete []buffer;
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -303,51 +318,50 @@ ssize_t read_all(int fd, std::vector<uint8_t> &out)
|
||||
// stdin could be a file, a pipe, or a tty.
|
||||
if (fstat(fd, &st) < 0)
|
||||
{
|
||||
std::perror("stdin");
|
||||
warn("fstat stdin");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bsize = std::max(st.st_blksize, (blksize_t)512);
|
||||
out.reserve(std::max(st.st_size, (off_t)512));
|
||||
|
||||
uint8_t *buffer = new uint8_t[bsize];
|
||||
std::vector<uint8_t> buffer;
|
||||
buffer.resize(bsize);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
ssize_t size = ::read(fd, buffer, bsize);
|
||||
ssize_t size = ::read(fd, buffer.data(), bsize);
|
||||
|
||||
if (size == 0) break;
|
||||
if (size == -1)
|
||||
{
|
||||
if (errno == EINTR) continue;
|
||||
delete[] buffer;
|
||||
std::perror(NULL);
|
||||
warn("read");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// force reserve?
|
||||
out.insert(out.end(), buffer, buffer + size);
|
||||
out.insert(out.end(), buffer.data(), buffer.data() + size);
|
||||
}
|
||||
|
||||
|
||||
delete []buffer;
|
||||
|
||||
return out.size();
|
||||
}
|
||||
|
||||
|
||||
// xattr write filename attrname
|
||||
// stdin -> filename:attrname
|
||||
int write(int argc, char **argv)
|
||||
int op_write(int argc, char **argv)
|
||||
{
|
||||
|
||||
std::vector<uint8_t> buffer;
|
||||
int flags = 0;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
std::fprintf(stderr, "Must specify attribute to be read.\n");
|
||||
std::fprintf(stderr, "Must specify attribute to be written.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -365,15 +379,11 @@ int write(int argc, char **argv)
|
||||
// if neither of the above is specified, will create and replace.
|
||||
// XATTR_NOFOLLOW : do not follow symbolic links (Apple only)
|
||||
|
||||
#ifdef __APPLE__
|
||||
flags = XATTR_NOFOLLOW;
|
||||
#endif
|
||||
|
||||
ssize_t asize = setxattr(fname, attr_name, &buffer[0], buffer.size(), flags);
|
||||
ssize_t asize = setxattr(fname, attr_name, buffer.data(), buffer.size(), 0);
|
||||
|
||||
if (asize < 0)
|
||||
{
|
||||
std::perror(attr_name);
|
||||
warn("setxattr(\"%s\", \"%s\")", fname, attr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -381,6 +391,126 @@ int write(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* remove an attribute
|
||||
*
|
||||
*/
|
||||
int op_rm(int argc, char **argv)
|
||||
{
|
||||
int rv = 0;
|
||||
const char *fname = *argv;
|
||||
|
||||
std::vector<std::string>attr;
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
std::fprintf(stderr, "Must specify attribute to be removed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
attr.push_back(argv[i]);
|
||||
}
|
||||
|
||||
|
||||
for (vsiter i = attr.begin(); i != attr.end() ; ++i)
|
||||
{
|
||||
const char *attr_name = i->c_str();
|
||||
int ok = removexattr(fname, attr_name);
|
||||
|
||||
if (ok < 0) {
|
||||
warn("removexattr(\"%s\", \"%s\")", fname, attr_name);
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy an attribute
|
||||
*
|
||||
*/
|
||||
|
||||
int op_cp(int argc, char **argv)
|
||||
{
|
||||
const char *fname = *argv;
|
||||
|
||||
std::vector<std::string>attr;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
std::fprintf(stderr, "Must specify source and destination.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *src_attr_name = argv[1];
|
||||
const char *dest_attr_name = argv[2];
|
||||
|
||||
std::vector<uint8_t> buffer;
|
||||
if (read_xattr(fname, src_attr_name, buffer) < 0) {
|
||||
warn("getxattr(\"%s\", \"%s\")", fname, src_attr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t asize = setxattr(fname, dest_attr_name, buffer.data(), buffer.size(), 0);
|
||||
|
||||
if (asize < 0)
|
||||
{
|
||||
warn("setxattr(\"%s\", \"%s\")", fname, dest_attr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* move an attribute
|
||||
*
|
||||
*/
|
||||
|
||||
int op_mv(int argc, char **argv)
|
||||
{
|
||||
const char *fname = *argv;
|
||||
|
||||
std::vector<std::string>attr;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
std::fprintf(stderr, "Must specify source and destination.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *src_attr_name = argv[1];
|
||||
const char *dest_attr_name = argv[2];
|
||||
|
||||
std::vector<uint8_t> buffer;
|
||||
if (read_xattr(fname, src_attr_name, buffer) < 0) {
|
||||
warn("getxattr(\"%s\", \"%s\")", fname, src_attr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t asize = setxattr(fname, dest_attr_name, buffer.data(), buffer.size(), 0);
|
||||
|
||||
if (asize < 0)
|
||||
{
|
||||
warn("setxattr(\"%s\", \"%s\")", fname, dest_attr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ok = removexattr(fname, src_attr_name);
|
||||
if (ok < 0) {
|
||||
warn("removexattr(\"%s\", \"%s\")", fname, dest_attr_name);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void usage(const char *name)
|
||||
{
|
||||
std::printf("usage:\n");
|
||||
@@ -401,12 +531,20 @@ int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) usage(*argv);
|
||||
|
||||
if (std::strcmp(argv[1], "list") == 0) return list(argc - 2, argv + 2);
|
||||
if (std::strcmp(argv[1], "dump") == 0) return dump(argc - 2, argv + 2);
|
||||
if (std::strcmp(argv[1], "list") == 0 || std::strcmp(argv[1], "ls") == 0)
|
||||
return op_list(argc - 2, argv + 2);
|
||||
|
||||
if (std::strcmp(argv[1], "dump") == 0 || std::strcmp(argv[1], "hd") == 0)
|
||||
return op_dump(argc - 2, argv + 2);
|
||||
|
||||
if (std::strcmp(argv[1], "read") == 0) return read(argc - 2, argv + 2);
|
||||
if (std::strcmp(argv[1], "write") == 0) return write(argc - 2, argv + 2);
|
||||
if (std::strcmp(argv[1], "read") == 0) return op_read(argc - 2, argv + 2);
|
||||
if (std::strcmp(argv[1], "write") == 0) return op_write(argc - 2, argv + 2);
|
||||
|
||||
|
||||
if (std::strcmp(argv[1], "rm") == 0) return op_rm(argc - 2, argv + 2);
|
||||
if (std::strcmp(argv[1], "mv") == 0) return op_mv(argc - 2, argv + 2);
|
||||
if (std::strcmp(argv[1], "cp") == 0) return op_cp(argc - 2, argv + 2);
|
||||
|
||||
|
||||
usage(*argv);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user