initial checkin

git-svn-id: https://profuse.googlecode.com/svn/trunk@4 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
ksherlock 2009-01-01 03:23:02 +00:00
parent 90bf49881f
commit bc7c5d73bb
10 changed files with 4355 additions and 0 deletions

546
Disk.cpp Normal file
View File

@ -0,0 +1,546 @@
/*
* Disk.cpp
* ProFUSE
*
* Created by Kelvin Sherlock on 12/18/08.
*
*/
#include "Disk.h"
#include "common.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdio.h>
#include <algorithm>
#include <set>
#include <vector>
struct ucmp
{
bool operator()(unsigned a, unsigned b) const
{
return a < b;
}
};
using std::set;
using std::vector;
typedef set<unsigned, ucmp> uset;
Disk::Disk()
{
_data = (uint8_t *)-1;
_blocks = 0;
_offset = 0;
_size = 0;
}
Disk::~Disk()
{
if (_data != (uint8_t *)-1)
munmap(_data, _size);
}
Disk *Disk::OpenFile(const char *file)
{
int fd;
struct stat st;
size_t size;
unsigned blocks;
unsigned offset;
void *map;
Disk *d = NULL;
fd = open(file, O_RDONLY);
if (fd >= 0)
{
if (fstat(fd, &st) == 0)
{
size = st.st_size;
// raw disk images must be a blocksize multiple and <= 32 Meg.
if ( (size & 0x1ff) == 0
&& size > 0
&& size <= 32 * 1024 * 1024
)
{
blocks = size >> 9;
offset = 0;
}
else {
// check for disk copy 4.2:
// 800k disk, but there's a 84-byte header
// and possible tag data (???)
// +80 = 0x01 (800K Disk)
// +81 = 0x24 (800K ProDOS disk)
// +82 = 0x01
// +83 = 0x00
uint8_t buffer[1024];
if (read(fd, buffer, 1024) != 1024)
{
close(fd);
return NULL;
}
if (size == 819284
&& buffer[80] == 0x01
&& buffer[81] == 0x24
&& buffer[82] == 0x01
&& buffer[83] == 0x00)
{
// Disk Copy.
// currently ignoring the checksum.
blocks = 819284 >> 9;
offset = 84;
}
// check 2mg.
else if (buffer[0] == '2'
&& buffer[1] == 'I'
&& buffer[2] == 'M'
&& buffer[3] == 'G'
&& buffer[0x0c] == 0x01 // ProDOS order
)
{
//
blocks = load32(&buffer[0x14]);
offset = load32(&buffer[0x18]);
}
else
{
close(fd);
return NULL;
}
lseek(fd, 0, SEEK_SET);
}
map = mmap(NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
if (map != (void *)-1)
{
d = new Disk();
d->_size = size;
d->_data = (uint8_t *)map;
d->_blocks = blocks;
d->_offset = offset;
}
}
close(fd);
}
return d;
}
// 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(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;
memcpy(buffer, _data + _offset + (block << 9), BLOCK_SIZE);
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 != DATA_FORK && fork != 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 != 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(buffer);
if (fork == 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;
}
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)
{
// does not yet handle sparse files (completely).
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];
ok = Read(block, key);
if (ok < 0 ) return ok;
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 = load16(&buffer[0x00]);
next = load16(&buffer[0x02]);
VolumeEntry v(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(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 = load16(&buffer[0x00]);
next = load16(&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 = load16(&buffer[0x00]);
next = load16(&buffer[0x02]);
SubdirEntry v(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(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 = load16(&buffer[0x00]);
next = load16(&buffer[0x02]);
index = 0;
}
}
}
return 1;
}

66
Disk.h Normal file
View File

@ -0,0 +1,66 @@
/*
* 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 "File.h"
enum {
P8_OK = 0,
P8_INTERNAL_ERROR,
P8_INVALID_FORK,
P8_INVALID_BLOCK,
P8_INVALID_STORAGE_TYPE,
P8_CYCLICAL_BLOCK
};
enum {
DATA_FORK = 0,
RESOURCE_FORK = 1
};
class Disk {
public:
~Disk();
//static Disk *Open2MG(const char *file);
static Disk *OpenFile(const char *file);
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();
uint8_t *_data;
unsigned _offset;
unsigned _blocks;
size_t _size;
};
#endif

275
File.cpp Normal file
View File

@ -0,0 +1,275 @@
/*
* File.cpp
* ProFUSE
*
* Created by Kelvin Sherlock on 12/18/08.
*
*/
#include "File.h"
#include "common.h"
#include <strings.h>
#include <stdint.h>
#include <ctype.h>
/*
* ProDOS technote 28
*
* The following definition allows the same range of years that the Apple IIgs
* Control Panel CDA currently does:
*
* o A seven-bit ProDOS year value is in the range 0 to 99
* (100 through 127 are invalid)
* o Year values from 40 to 99 represent 1940 through 1999
* o Year values from 0 to 39 represent 2000 through 2039
*/
inline time_t timeToUnix(unsigned yymmdd, unsigned hhmm)
{
if (yymmdd == 0) return 0;
tm t;
bzero(&t, sizeof(tm));
t.tm_min = hhmm & 0x3f;
t.tm_hour = (hhmm >> 8) & 0x1f;
t.tm_mday = yymmdd & 0x1f;
t.tm_mon = ((yymmdd >> 5) & 0x0f) - 1;
t.tm_year = (yymmdd) >> 9;
if (t.tm_year <= 39) t.tm_year += 100;
return mktime(&t);
}
FileEntry::FileEntry()
{
bzero(this, sizeof(FileEntry));
}
FileEntry::FileEntry(const FileEntry& f)
{
*this = f;
}
FileEntry::FileEntry(const FileEntry *f)
{
if (f) *this = *f;
else bzero(this, sizeof(FileEntry));
}
FileEntry::FileEntry(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 = load16(&cp[0x11]);
blocks_used = load16(&cp[0x13]);
eof = load24(&cp[0x15]);
creation = timeToUnix(load16(&cp[0x18]), load16(&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) file_name[i] = tolower(file_name[i]);
mask = mask >> 1;
}
}
access = cp[0x1e];
aux_type = load16(&cp[0x1f]);
last_mod = timeToUnix(load16(&cp[0x21]), load16(&cp[0x23]));
header_pointer = load16(&cp[0x25]);
}
ExtendedEntry::ExtendedEntry()
{
bzero(this, sizeof(ExtendedEntry));
}
ExtendedEntry::ExtendedEntry(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 = load16(&cp[0x01]);
dataFork.blocks_used = load16(&cp[0x03]);
dataFork.eof = load24(&cp[0x05]);
// offset 256 - mini entry for resource fork.
resourceFork.storage_type = cp[256 + 0x00] & 0x0f;
resourceFork.key_block = load16(&cp[256 + 0x01]);
resourceFork.blocks_used = load16(&cp[256 + 0x03]);
resourceFork.eof = load24(&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;
}
}
//
}
VolumeEntry::VolumeEntry()
{
bzero(this, sizeof(VolumeEntry));
}
VolumeEntry::VolumeEntry(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 = timeToUnix(load16(&cp[0x18]), load16(&cp[0x1a]));
//version = cp[0x1c];
//min_version = cp[0x1d];
unsigned xcase = load16(&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 = load16(&cp[0x21]);
bit_map_pointer = load16(&cp[0x23]);
total_blocks = load16(&cp[0x25]);
}
SubdirEntry::SubdirEntry()
{
bzero(this, sizeof(SubdirEntry));
}
SubdirEntry::SubdirEntry(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 = timeToUnix(load16(&cp[0x18]), load16(&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 = load16(&cp[0x21]);
parent_pointer = load16(&cp[0x23]);
parent_entry = cp[0x25];
parent_entry_length = cp[0x26];
}

144
File.h Normal file
View File

@ -0,0 +1,144 @@
/*
* File.h
* ProFUSE
*
* Created by Kelvin Sherlock on 12/18/08.
*
*/
#ifndef __FILE_H__
#define __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:
FileEntry();
FileEntry(const FileEntry& f);
FileEntry(const FileEntry *f);
FileEntry(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;
};
#if 0
class BlockList {
public:
unsigned prev_block;
unsigned next_block;
};
#endif
struct MiniEntry {
unsigned storage_type;
unsigned key_block;
unsigned blocks_used;
uint32_t eof;
};
class ExtendedEntry {
public:
ExtendedEntry();
ExtendedEntry(const void *data);
MiniEntry dataFork;
MiniEntry resourceFork;
uint8_t FInfo[16];
uint8_t xFInfo[16];
};
class VolumeEntry {
public:
VolumeEntry();
VolumeEntry(const void *data);
unsigned storage_type;
unsigned name_length;
char volume_name[15+1];
time_t creation;
//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:
SubdirEntry();
SubdirEntry(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

33
common.h Normal file
View File

@ -0,0 +1,33 @@
/*
* common.h
* ProFUSE
*
* Created by Kelvin Sherlock on 12/20/08.
*
*/
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdint.h>
#define BLOCK_SIZE 512
inline unsigned load16(const uint8_t *cp)
{
return (cp[1] << 8 ) | cp[0];
}
inline unsigned load24(const uint8_t *cp)
{
return (cp[2] << 16 ) | (cp[1] << 8) | (cp[0]);
}
inline unsigned load32(const uint8_t *cp)
{
return (cp[3] << 24) | (cp[2] << 16 ) | (cp[1] << 8) | (cp[0]);
}
#endif

967
main.cpp Normal file
View File

@ -0,0 +1,967 @@
/*
* 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
*/
#define FUSE_USE_VERSION 26
#include <fuse_lowlevel.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <ctype.h>
#include <vector>
#include <string>
#include <algorithm>
#include "common.h"
#include "Disk.h"
#include "File.h"
using std::vector;
using std::string;
Disk *disk = NULL;
char *dfile = NULL;
#undef ERROR
#define ERROR(cond,errno) if ( (cond) ){ fuse_reply_err(req, errno); return; }
static 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;
}
#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);
}
static void xattr_textencoding(FileEntry& e, fuse_req_t req, size_t size, off_t off)
{
// TODO -- ascii text encoding for ascii files?
const char attr[] = "MACINTOSH;0";
unsigned attr_size = sizeof(attr) - 1;
// currently only valid for Teach Files.
if (e.file_type != 0x50 || e.aux_type != 0x5445)
{
ERROR(true, ENOENT)
}
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_rfork(FileEntry& e, fuse_req_t req, size_t size, off_t off)
{
int ok;
unsigned level;
ERROR (e.storage_type != EXTENDED_FILE, ENOENT)
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)
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);
fuse_reply_buf(req, (char *)attr, attr_size);
}
static 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", 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(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:
break;
case DIRECTORY_FILE:
NO_ATTR()
break;
default:
NO_ATTR()
break;
}
if (e.file_type == 0x50 && e.aux_type == 0x5445) // teach text
{
attr += "com.apple.TextEncoding";
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;
}
// position not needed/valid for linux.
// position ignored, for now.
static 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", ino, name, (int)size, (int)off);
uint8_t buffer[BLOCK_SIZE];
ERROR(ino == 1, ENOENT) // finder can't handle EISDIR.
int ok = disk->Read(ino >> 9, buffer);
ERROR(ok < 0, EIO)
FileEntry e(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, ENOENT) // Finder can't handle EISDIR.
default:
ERROR(true, ENOENT);
}
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 ( (e.storage_type == EXTENDED_FILE) && (strcmp("com.apple.FinderInfo", name) == 0))
{
xattr_finfo(e, req, size, off);
return;
}
fuse_reply_err(req, ENOENT);
}
#pragma mark Directory Functions
/*
* when the directory is opened, we load the volume/directory and store the FileEntry vector into
* fi->fh.
*
*/
static void prodos_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
fprintf(stderr, "opendir: %u\n", 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(buffer + 0x04);
ok = disk->ReadVolume(&v, &files);
ERROR(ok < 0, EIO)
}
else
{
FileEntry e(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);
}
static void prodos_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
fprintf(stderr,"releasedir: %d\n", ino);
vector<FileEntry> *files = (vector<FileEntry> *)fi->fh;
if (files) delete files;
fuse_reply_err(req, 0);
}
static 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", ino, size, 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;
}
#pragma mark Stat Functions
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 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(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;
//st->st_birthtime = v.creation;
st->st_mtime = v.creation;
st->st_atime = v.creation;
st->st_nlink = v.file_count + 1;
st->st_size = BLOCK_SIZE;
st->st_blksize = BLOCK_SIZE;
return 1;
}
static 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", 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(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(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.
static 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: %d %s\n", 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(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);
}
#pragma mark Read Functions
static void prodos_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
fprintf(stderr, "open: %u\n", 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(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_RDONLY)
{
delete e;
ERROR(true, EACCES);
}
fi->fh = (uint64_t)e;
fuse_reply_open(req, fi);
}
static void prodos_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
fprintf(stderr, "release: %d\n", ino);
FileEntry *e = (FileEntry *)fi->fh;
if (e) delete e;
fuse_reply_err(req, 0);
}
static 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", ino, size, 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;
}
static struct fuse_lowlevel_ops prodos_oper;
enum {
PRODOS_OPT_HELP,
PRODOS_OPT_VERSION
};
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),
{0, 0, 0}
};
static void usage()
{
fprintf(stderr, "profuse [options] disk_image mountpoint\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:
if (dfile == NULL)
{
dfile = strdup(arg);
return 0;
}
return 1;
}
return 1;
}
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;
disk = NULL;
bzero(&prodos_oper, sizeof(prodos_oper));
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;
// scan the argument list, looking for the name of the disk image.
if (fuse_opt_parse(&args, NULL , prodos_opts, prodos_opt_proc) == -1)
exit(1);
if (dfile == NULL || *dfile == 0)
{
usage();
exit(0);
}
// TODO -- check file size, volume header
// check for 2mg or disk copy 4.2 header.
disk = Disk::OpenFile(dfile);
if (!disk)
{
fprintf(stderr, "Unable to mount disk %s\n", dfile);
exit(1);
}
// tODO -- add blocksize, volume name
do {
if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) == -1) break;
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)
{
if (fuse_set_signal_handlers(se) != -1)
{
fuse_session_add_chan(se, ch);
err = fuse_session_loop(se);
fuse_remove_signal_handlers(se);
fuse_session_remove_chan(ch);
}
fuse_session_destroy(se);
}
fuse_unmount(mountpoint, ch);
}
} while (false);
fuse_opt_free_args(&args);
if (disk)
{
delete disk;
disk = NULL;
}
if (dfile) free(dfile);
return err ? 1 : 0;
}

79
profuse.1 Normal file
View File

@ -0,0 +1,79 @@
.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
.\"See Also:
.\"man mdoc.samples for a complete listing of options
.\"man mdoc for the short list of editing options
.\"/usr/share/misc/mdoc.template
.Dd 12/18/08 \" DATE
.Dt profuse 1 \" Program name and manual section number
.Os Darwin
.Sh NAME \" Section Header - required - don't modify
.Nm ProFUSE,
.\" The following lines are read in generating the apropos(man -k) database. Use only key
.\" words here as the database is built based on the words here and in the .ND line.
.Nm Other_name_for_same_program(),
.Nm Yet another name for the same program.
.\" Use .Nm macro to designate other names for the documented program.
.Nd This line parsed for whatis database.
.Sh SYNOPSIS \" Section Header - required - don't modify
.Nm
.Op Fl abcd \" [-abcd]
.Op Fl a Ar path \" [-a path]
.Op Ar file \" [file]
.Op Ar \" [file ...]
.Ar arg0 \" Underlined argument - use .Ar anywhere to underline
arg2 ... \" Arguments
.Sh DESCRIPTION \" Section Header - required - don't modify
Use the .Nm macro to refer to your program throughout the man page like such:
.Nm
Underlining is accomplished with the .Ar macro like this:
.Ar underlined text .
.Pp \" Inserts a space
A list of items with descriptions:
.Bl -tag -width -indent \" Begins a tagged list
.It item a \" Each item preceded by .It macro
Description of item a
.It item b
Description of item b
.El \" Ends the list
.Pp
A list of flags and their descriptions:
.Bl -tag -width -indent \" Differs from above in tag removed
.It Fl a \"-a flag as a list item
Description of -a flag
.It Fl b
Description of -b flag
.El \" Ends the list
.Pp
.\" .Sh ENVIRONMENT \" May not be needed
.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
.\" .It Ev ENV_VAR_1
.\" Description of ENV_VAR_1
.\" .It Ev ENV_VAR_2
.\" Description of ENV_VAR_2
.\" .El
.Sh FILES \" File used or created by the topic of the man page
.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
.It Pa /usr/share/file_name
FILE_1 description
.It Pa /Users/joeuser/Library/really_long_file_name
FILE_2 description
.El \" Ends the list
.\" .Sh DIAGNOSTICS \" May not be needed
.\" .Bl -diag
.\" .It Diagnostic Tag
.\" Diagnostic informtion here.
.\" .It Diagnostic Tag
.\" Diagnostic informtion here.
.\" .El
.Sh SEE ALSO
.\" List links in ascending order by section, alphabetically within a section.
.\" Please do not reference files that do not exist without filing a bug report
.Xr a 1 ,
.Xr b 1 ,
.Xr c 1 ,
.Xr a 2 ,
.Xr b 2 ,
.Xr a 3 ,
.Xr b 3
.\" .Sh BUGS \" Document known, unremedied bugs
.\" .Sh HISTORY \" Document history if command behaves in a unique manner

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,540 @@
// !$*UTF8*$!
{
08FB7793FE84155DC02AAC07 /* Project object */ = {
activeArchitecturePreference = i386;
activeBuildConfigurationName = "Debug Universal";
activeExecutable = B60E914A0EFB3612000E4348 /* profuse */;
activeTarget = 8DD76F620486A84900D96B5E /* profuse */;
addToTargets = (
8DD76F620486A84900D96B5E /* profuse */,
);
breakpoints = (
B60E91C10EFD8049000E4348 /* xmain.cpp:129 */,
B60E92720EFDA086000E4348 /* File.cpp:88 */,
B6D81E5B0EFDE859000219B7 /* xmain.cpp:163 */,
B6AE1CFF0F0335FC00D36ADB /* main.cpp:30 */,
);
codeSenseManager = B60E91510EFB3628000E4348 /* Code sense */;
executables = (
B60E914A0EFB3612000E4348 /* profuse */,
);
perUserDictionary = {
PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = 1;
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
705,
20,
48,
43,
43,
20,
);
PBXFileTableDataSourceColumnsKey = (
PBXFileDataSource_FiletypeID,
PBXFileDataSource_Filename_ColumnID,
PBXFileDataSource_Built_ColumnID,
PBXFileDataSource_ObjectSize_ColumnID,
PBXFileDataSource_Errors_ColumnID,
PBXFileDataSource_Warnings_ColumnID,
PBXFileDataSource_Target_ColumnID,
);
};
PBXConfiguration.PBXFileTableDataSource3.XCSCMDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
20,
681,
20,
48,
43,
43,
20,
);
PBXFileTableDataSourceColumnsKey = (
PBXFileDataSource_SCM_ColumnID,
PBXFileDataSource_FiletypeID,
PBXFileDataSource_Filename_ColumnID,
PBXFileDataSource_Built_ColumnID,
PBXFileDataSource_ObjectSize_ColumnID,
PBXFileDataSource_Errors_ColumnID,
PBXFileDataSource_Warnings_ColumnID,
PBXFileDataSource_Target_ColumnID,
);
};
PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
665,
60,
20,
48,
43,
43,
);
PBXFileTableDataSourceColumnsKey = (
PBXFileDataSource_FiletypeID,
PBXFileDataSource_Filename_ColumnID,
PBXTargetDataSource_PrimaryAttribute,
PBXFileDataSource_Built_ColumnID,
PBXFileDataSource_ObjectSize_ColumnID,
PBXFileDataSource_Errors_ColumnID,
PBXFileDataSource_Warnings_ColumnID,
);
};
PBXPerProjectTemplateStateSaveDate = 252472219;
PBXWorkspaceStateSaveDate = 252472219;
};
perUserProjectItems = {
B60E917F0EFD7E1E000E4348 = B60E917F0EFD7E1E000E4348 /* PBXTextBookmark */;
B60E91800EFD7E1E000E4348 = B60E91800EFD7E1E000E4348 /* PBXTextBookmark */;
B60E91810EFD7E1E000E4348 = B60E91810EFD7E1E000E4348 /* PBXTextBookmark */;
B60E922B0EFD94CA000E4348 = B60E922B0EFD94CA000E4348 /* PBXTextBookmark */;
B60E929C0EFDA500000E4348 = B60E929C0EFDA500000E4348 /* PBXTextBookmark */;
B61846170F0AF6B40045CCF7 = B61846170F0AF6B40045CCF7 /* PBXBookmark */;
B61846570F0B02820045CCF7 = B61846570F0B02820045CCF7 /* PBXTextBookmark */;
B61846580F0B02820045CCF7 = B61846580F0B02820045CCF7 /* PBXTextBookmark */;
B61846590F0B02820045CCF7 = B61846590F0B02820045CCF7 /* PBXTextBookmark */;
B634B4FA0F09BFB100D9D93E = B634B4FA0F09BFB100D9D93E /* PBXTextBookmark */;
B6614B050EFF5F280073C4E7 = B6614B050EFF5F280073C4E7 /* PBXTextBookmark */;
B6643BF00F0708B400630102 = B6643BF00F0708B400630102 /* PBXTextBookmark */;
B679E4A20F02E77700FB3F0C = B679E4A20F02E77700FB3F0C /* PBXTextBookmark */;
B679E4B60F02EFA200FB3F0C = B679E4B60F02EFA200FB3F0C /* PBXTextBookmark */;
B679E4BB0F02EFA200FB3F0C = B679E4BB0F02EFA200FB3F0C /* PBXTextBookmark */;
B6A271C50F040B8E00646F02 = B6A271C50F040B8E00646F02 /* PBXTextBookmark */;
B6A271C70F040B8E00646F02 = B6A271C70F040B8E00646F02 /* PBXTextBookmark */;
B6DBB4DE0F0C6BB400F385F2 /* PBXTextBookmark */ = B6DBB4DE0F0C6BB400F385F2 /* PBXTextBookmark */;
B6DBB4F10F0C6CD800F385F2 /* PBXTextBookmark */ = B6DBB4F10F0C6CD800F385F2 /* PBXTextBookmark */;
B6DBB4F20F0C6CD800F385F2 /* PBXBookmark */ = B6DBB4F20F0C6CD800F385F2 /* PBXBookmark */;
B6DBB4F30F0C6CD800F385F2 /* PBXTextBookmark */ = B6DBB4F30F0C6CD800F385F2 /* PBXTextBookmark */;
B6DBB4F40F0C6CD800F385F2 /* PBXTextBookmark */ = B6DBB4F40F0C6CD800F385F2 /* PBXTextBookmark */;
B6DBB4F90F0C6DA600F385F2 /* PBXTextBookmark */ = B6DBB4F90F0C6DA600F385F2 /* PBXTextBookmark */;
B6DBB4FC0F0C6DE600F385F2 /* PBXTextBookmark */ = B6DBB4FC0F0C6DE600F385F2 /* PBXTextBookmark */;
};
sourceControlManager = B60E91500EFB3628000E4348 /* Source Control */;
userBuildSettings = {
};
};
08FB7796FE84155DC02AAC07 /* xmain.cpp */ = {
isa = PBXFileReference;
fileEncoding = 4;
lastKnownFileType = sourcecode.cpp.cpp;
name = xmain.cpp;
path = "/Users/kelvin/Projects/ProDOS-Fuse/xmain.cpp";
sourceTree = "<absolute>";
};
8DD76F620486A84900D96B5E /* profuse */ = {
activeExec = 0;
executables = (
B60E914A0EFB3612000E4348 /* profuse */,
);
};
B60E914A0EFB3612000E4348 /* profuse */ = {
isa = PBXExecutable;
activeArgIndices = (
);
argumentStrings = (
);
autoAttachOnCrash = 1;
breakpointsEnabled = 0;
configStateDict = {
};
customDataFormattersEnabled = 1;
debuggerPlugin = GDBDebugging;
disassemblyDisplayState = 0;
dylibVariantSuffix = "";
enableDebugStr = 1;
environmentEntries = (
);
executableSystemSymbolLevel = 0;
executableUserSymbolLevel = 0;
libgmallocEnabled = 0;
name = profuse;
savedGlobals = {
};
sourceDirectories = (
);
variableFormatDictionary = {
"_data-char *-Disk::Read" = 1;
"entry_length-unsigned int-Disk::ReadDirectory" = 1;
"xcase-unsigned int-FileEntry::FileEntry" = 3;
};
};
B60E914D0EFB3627000E4348 /* File.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {496, 2072}}";
sepNavSelRange = "{25, 0}";
sepNavVisRange = "{0, 1187}";
sepNavWindowFrame = "{{95, -86}, {555, 1173}}";
};
};
B60E914E0EFB3628000E4348 /* File.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {496, 3892}}";
sepNavSelRange = "{27, 0}";
sepNavVisRange = "{0, 1472}";
sepNavWindowFrame = "{{667, -9}, {555, 1173}}";
};
};
B60E91500EFB3628000E4348 /* Source Control */ = {
isa = PBXSourceControlManager;
fallbackIsa = XCSourceControlManager;
isSCMEnabled = 0;
scmConfiguration = {
repositoryName = "";
};
};
B60E91510EFB3628000E4348 /* Code sense */ = {
isa = PBXCodeSenseManager;
indexTemplatePath = "";
};
B60E91530EFB51FE000E4348 /* Disk.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {633, 1043}}";
sepNavSelRange = "{25, 0}";
sepNavVisRange = "{0, 1182}";
sepNavWindowFrame = "{{77, 7}, {692, 1171}}";
};
};
B60E91540EFB51FE000E4348 /* Disk.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {633, 7910}}";
sepNavSelRange = "{27, 0}";
sepNavVisRange = "{0, 1149}";
sepNavWindowFrame = "{{511, 7}, {692, 1171}}";
};
};
B60E91580EFD77E3000E4348 /* common.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {633, 1043}}";
sepNavSelRange = "{27, 0}";
sepNavVisRange = "{0, 474}";
sepNavWindowFrame = "{{15, 2}, {692, 1171}}";
};
};
B60E917F0EFD7E1E000E4348 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E914D0EFB3627000E4348 /* File.h */;
name = "File.h: 1";
rLen = 0;
rLoc = 0;
rType = 0;
vrLen = 350;
vrLoc = 0;
};
B60E91800EFD7E1E000E4348 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91530EFB51FE000E4348 /* Disk.h */;
name = "Disk.h: 1";
rLen = 0;
rLoc = 0;
rType = 0;
vrLen = 159;
vrLoc = 0;
};
B60E91810EFD7E1E000E4348 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 1";
rLen = 0;
rLoc = 0;
rType = 0;
vrLen = 292;
vrLoc = 0;
};
B60E91C10EFD8049000E4348 /* xmain.cpp:129 */ = {
isa = PBXFileBreakpoint;
actions = (
);
breakpointStyle = 0;
continueAfterActions = 0;
countType = 0;
delayBeforeContinue = 0;
fileReference = 08FB7796FE84155DC02AAC07 /* xmain.cpp */;
functionName = "main (int argc, char * const argv[])";
hitCount = 0;
ignoreCount = 0;
lineNumber = 129;
location = "ProDOS-Fuse";
modificationTime = 251949619.113675;
state = 2;
};
B60E922B0EFD94CA000E4348 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91580EFD77E3000E4348 /* common.h */;
name = "common.h: 14";
rLen = 0;
rLoc = 146;
rType = 0;
vrLen = 327;
vrLoc = 0;
};
B60E92720EFDA086000E4348 /* File.cpp:88 */ = {
isa = PBXFileBreakpoint;
actions = (
);
breakpointStyle = 0;
continueAfterActions = 0;
countType = 0;
delayBeforeContinue = 0;
fileReference = B60E914E0EFB3628000E4348 /* File.cpp */;
functionName = "FileEntry::FileEntry(const void *data)";
hitCount = 0;
ignoreCount = 0;
lineNumber = 88;
location = "ProDOS-Fuse";
modificationTime = 251949619.113693;
state = 2;
};
B60E929C0EFDA500000E4348 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E914E0EFB3628000E4348 /* File.cpp */;
name = "File.cpp: 106";
rLen = 0;
rLoc = 3668;
rType = 0;
vrLen = 345;
vrLoc = 1359;
};
B61846170F0AF6B40045CCF7 /* PBXBookmark */ = {
isa = PBXBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
};
B61846570F0B02820045CCF7 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 34";
rLen = 0;
rLoc = 480;
rType = 0;
vrLen = 295;
vrLoc = 441;
};
B61846580F0B02820045CCF7 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 34";
rLen = 0;
rLoc = 480;
rType = 0;
vrLen = 316;
vrLoc = 420;
};
B61846590F0B02820045CCF7 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 324";
rLen = 0;
rLoc = 7441;
rType = 0;
vrLen = 1213;
vrLoc = 0;
};
B634B4FA0F09BFB100D9D93E /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 324";
rLen = 0;
rLoc = 7441;
rType = 0;
vrLen = 351;
vrLoc = 0;
};
B6614B050EFF5F280073C4E7 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E914D0EFB3627000E4348 /* File.h */;
name = "File.h: 31";
rLen = 0;
rLoc = 414;
rType = 0;
vrLen = 330;
vrLoc = 1231;
};
B6643BF00F0708B400630102 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E914E0EFB3628000E4348 /* File.cpp */;
name = "File.cpp: 176";
rLen = 0;
rLoc = 3668;
rType = 0;
vrLen = 505;
vrLoc = 1290;
};
B679E4A20F02E77700FB3F0C /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91580EFD77E3000E4348 /* common.h */;
name = "common.h: 14";
rLen = 0;
rLoc = 146;
rType = 0;
vrLen = 374;
vrLoc = 0;
};
B679E4A70F02E79300FB3F0C /* main.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1353, 13692}}";
sepNavSelRange = "{17984, 0}";
sepNavVisRange = "{17670, 1165}";
sepNavWindowFrame = "{{263, 144}, {1412, 924}}";
};
};
B679E4B60F02EFA200FB3F0C /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91530EFB51FE000E4348 /* Disk.h */;
name = "Disk.h: 1";
rLen = 0;
rLoc = 0;
rType = 0;
vrLen = 342;
vrLoc = 0;
};
B679E4BB0F02EFA200FB3F0C /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 1";
rLen = 0;
rLoc = 0;
rType = 0;
vrLen = 356;
vrLoc = 0;
};
B6A271C50F040B8E00646F02 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6AE1DAD0F03529000D36ADB /* pool.h */;
name = "pool.h: 25";
rLen = 0;
rLoc = 456;
rType = 0;
vrLen = 571;
vrLoc = 210;
};
B6A271C70F040B8E00646F02 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6AE1DAD0F03529000D36ADB /* pool.h */;
name = "pool.h: 25";
rLen = 0;
rLoc = 456;
rType = 0;
vrLen = 571;
vrLoc = 210;
};
B6AE1CFF0F0335FC00D36ADB /* main.cpp:30 */ = {
isa = PBXFileBreakpoint;
actions = (
);
breakpointStyle = 0;
continueAfterActions = 0;
countType = 0;
delayBeforeContinue = 0;
fileReference = B679E4A70F02E79300FB3F0C /* main.cpp */;
functionName = "prodos_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)";
hitCount = 0;
ignoreCount = 0;
lineNumber = 30;
location = "ProDOS-Fuse";
modificationTime = 251949619.113812;
state = 2;
};
B6AE1DAD0F03529000D36ADB /* pool.h */ = {
isa = PBXFileReference;
fileEncoding = 4;
lastKnownFileType = sourcecode.c.h;
name = pool.h;
path = "/Users/kelvin/Projects/ProDOS-Fuse/pool.h";
sourceTree = "<absolute>";
};
B6D81E5B0EFDE859000219B7 /* xmain.cpp:163 */ = {
isa = PBXFileBreakpoint;
actions = (
);
breakpointStyle = 0;
continueAfterActions = 0;
countType = 0;
delayBeforeContinue = 0;
fileReference = 08FB7796FE84155DC02AAC07 /* xmain.cpp */;
functionName = "main (int argc, char * const argv[])";
hitCount = 0;
ignoreCount = 0;
lineNumber = 163;
location = "ProDOS-Fuse";
modificationTime = 251949619.113805;
state = 2;
};
B6DBB4DE0F0C6BB400F385F2 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 34";
rLen = 0;
rLoc = 480;
rType = 0;
vrLen = 315;
vrLoc = 420;
};
B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {883, 1190}}";
sepNavSelRange = "{429, 0}";
sepNavVisRange = "{2400, 722}";
sepNavWindowFrame = "{{15, 249}, {1412, 924}}";
};
};
B6DBB4F10F0C6CD800F385F2 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 34";
rLen = 0;
rLoc = 480;
rType = 0;
vrLen = 315;
vrLoc = 420;
};
B6DBB4F20F0C6CD800F385F2 /* PBXBookmark */ = {
isa = PBXBookmark;
fRef = B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */;
};
B6DBB4F30F0C6CD800F385F2 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 34";
rLen = 0;
rLoc = 480;
rType = 0;
vrLen = 315;
vrLoc = 420;
};
B6DBB4F40F0C6CD800F385F2 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */;
name = "profuse.1: 10";
rLen = 0;
rLoc = 429;
rType = 0;
vrLen = 722;
vrLoc = 2400;
};
B6DBB4F90F0C6DA600F385F2 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */;
name = "profuse.1: 10";
rLen = 0;
rLoc = 429;
rType = 0;
vrLen = 722;
vrLoc = 2400;
};
B6DBB4FC0F0C6DE600F385F2 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */;
name = "profuse.1: 10";
rLen = 0;
rLoc = 429;
rType = 0;
vrLen = 722;
vrLoc = 2400;
};
}

View File

@ -0,0 +1,283 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 45;
objects = {
/* Begin PBXBuildFile section */
B60E914F0EFB3628000E4348 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B60E914E0EFB3628000E4348 /* File.cpp */; };
B60E91550EFB51FE000E4348 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B60E91540EFB51FE000E4348 /* Disk.cpp */; };
B679E49B0F02E71400FB3F0C /* libfuse_ino64.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B679E49A0F02E71400FB3F0C /* libfuse_ino64.2.dylib */; };
B679E4A80F02E79300FB3F0C /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B679E4A70F02E79300FB3F0C /* main.cpp */; };
B6AE1D530F033B5E00D36ADB /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6AE1D520F033B5E00D36ADB /* CoreFoundation.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
8DD76F690486A84900D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
8DD76F6C0486A84900D96B5E /* profuse */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = profuse; sourceTree = BUILT_PRODUCTS_DIR; };
B60E914D0EFB3627000E4348 /* File.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = File.h; sourceTree = "<group>"; };
B60E914E0EFB3628000E4348 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = File.cpp; sourceTree = "<group>"; };
B60E91530EFB51FE000E4348 /* Disk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Disk.h; sourceTree = "<group>"; };
B60E91540EFB51FE000E4348 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Disk.cpp; sourceTree = "<group>"; };
B60E91580EFD77E3000E4348 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
B679E49A0F02E71400FB3F0C /* libfuse_ino64.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libfuse_ino64.2.dylib; path = /usr/local/lib/libfuse_ino64.2.dylib; sourceTree = "<absolute>"; };
B679E4A70F02E79300FB3F0C /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
B6AE1D520F033B5E00D36ADB /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = profuse.1; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8DD76F660486A84900D96B5E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B679E49B0F02E71400FB3F0C /* libfuse_ino64.2.dylib in Frameworks */,
B6AE1D530F033B5E00D36ADB /* CoreFoundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* ProDOS-Fuse */ = {
isa = PBXGroup;
children = (
08FB7795FE84155DC02AAC07 /* Source */,
C6859E8C029090F304C91782 /* Documentation */,
1AB674ADFE9D54B511CA2CBB /* Products */,
B679E49D0F02E71D00FB3F0C /* Libraries */,
);
name = "ProDOS-Fuse";
sourceTree = "<group>";
};
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
B60E91580EFD77E3000E4348 /* common.h */,
B60E91530EFB51FE000E4348 /* Disk.h */,
B60E91540EFB51FE000E4348 /* Disk.cpp */,
B60E914D0EFB3627000E4348 /* File.h */,
B60E914E0EFB3628000E4348 /* File.cpp */,
B679E4A70F02E79300FB3F0C /* main.cpp */,
);
name = Source;
sourceTree = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8DD76F6C0486A84900D96B5E /* profuse */,
);
name = Products;
sourceTree = "<group>";
};
B679E49D0F02E71D00FB3F0C /* Libraries */ = {
isa = PBXGroup;
children = (
B6AE1D520F033B5E00D36ADB /* CoreFoundation.framework */,
B679E49A0F02E71400FB3F0C /* libfuse_ino64.2.dylib */,
);
name = Libraries;
sourceTree = "<group>";
};
C6859E8C029090F304C91782 /* Documentation */ = {
isa = PBXGroup;
children = (
B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */,
);
name = Documentation;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8DD76F620486A84900D96B5E /* profuse */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "profuse" */;
buildPhases = (
8DD76F640486A84900D96B5E /* Sources */,
8DD76F660486A84900D96B5E /* Frameworks */,
8DD76F690486A84900D96B5E /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = profuse;
productInstallPath = "$(HOME)/bin";
productName = "ProDOS-Fuse";
productReference = 8DD76F6C0486A84900D96B5E /* profuse */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "profuse" */;
compatibilityVersion = "Xcode 3.1";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* ProDOS-Fuse */;
projectDirPath = "";
projectRoot = "";
targets = (
8DD76F620486A84900D96B5E /* profuse */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
8DD76F640486A84900D96B5E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B60E914F0EFB3628000E4348 /* File.cpp in Sources */,
B60E91550EFB51FE000E4348 /* Disk.cpp in Sources */,
B679E4A80F02E79300FB3F0C /* main.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
1DEB923208733DC60010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"_GLIBCXX_DEBUG=1",
"_GLIBCXX_DEBUG_PEDANTIC=1",
);
INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = "ProDOS-Fuse";
};
name = Debug;
};
1DEB923308733DC60010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_MODEL_TUNING = G5;
INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = "ProDOS-Fuse";
};
name = Release;
};
1DEB923608733DC60010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "";
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = /usr/local/include/fuse;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = (
"-D__FreeBSD__=10",
"-D_FILE_OFFSET_BITS=64",
"-D__DARWIN_64_BIT_INO_T=1",
);
PREBINDING = NO;
SDKROOT = macosx10.5;
};
name = Debug;
};
1DEB923708733DC60010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
SDKROOT = macosx10.5;
};
name = Release;
};
B618461A0F0AF6CC0045CCF7 /* Debug Universal */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "";
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = /usr/local/include/fuse;
ONLY_ACTIVE_ARCH = NO;
OTHER_CFLAGS = (
"-D__FreeBSD__=10",
"-D_FILE_OFFSET_BITS=64",
"-D__DARWIN_64_BIT_INO_T=1",
);
PREBINDING = NO;
SDKROOT = macosx10.5;
};
name = "Debug Universal";
};
B618461B0F0AF6CC0045CCF7 /* Debug Universal */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"_GLIBCXX_DEBUG=1",
"_GLIBCXX_DEBUG_PEDANTIC=1",
);
INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = profuse;
};
name = "Debug Universal";
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "profuse" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB923208733DC60010E9CD /* Debug */,
B618461B0F0AF6CC0045CCF7 /* Debug Universal */,
1DEB923308733DC60010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "profuse" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB923608733DC60010E9CD /* Debug */,
B618461A0F0AF6CC0045CCF7 /* Debug Universal */,
1DEB923708733DC60010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}