splitting up functions

git-svn-id: https://profuse.googlecode.com/svn/trunk@23 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
ksherlock 2009-01-23 20:35:09 +00:00
parent a83fc6df28
commit e971546b2a
10 changed files with 1319 additions and 1220 deletions

785
main.cpp
View File

@ -13,31 +13,18 @@
#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"
#include "profuse.h"
using std::vector;
using std::string;
@ -47,12 +34,8 @@ char *dfile = NULL;
VolumeEntry volume;
#undef ERROR
#define ERROR(cond,errno) if ( (cond) ){ fuse_reply_err(req, errno); return; }
static bool validProdosName(const char *name)
bool validProdosName(const char *name)
{
// OS X looks for hidden files that don't exist (and aren't legal prodos names)
// most are not legal prodos names, so this filters them out easily.
@ -75,770 +58,9 @@ static bool validProdosName(const char *name)
}
#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, "ASCII" Text
if (e.file_type == 0x04 || (e.file_type == 0x50 && e.aux_type == 0x5445))
/* do nothing */ ;
else
{
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 == 0x04
|| (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;
}
// TODO -- more consistent position support.
static void prodos_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size, uint32_t off)
{
#ifdef __APPLE__
#define NO_ATTRIBUTE ENOENT
#else
#define NO_ATTRIBUTE EOPNOTSUPP
#endif
fprintf(stderr, "getxattr: %u %s %u %u \n", ino, name, (int)size, (int)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(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 ( (e.storage_type == EXTENDED_FILE) && (strcmp("com.apple.FinderInfo", name) == 0))
{
xattr_finfo(e, req, size, off);
return;
}
fuse_reply_err(req, NO_ATTRIBUTE);
}
/*
* Linux, et alia do not have an offset parameter.
*/
static void prodos_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
{
prodos_getxattr(req, ino, name, size, 0);
}
#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 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(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.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_ACCMODE) != 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;
@ -897,6 +119,7 @@ bool make_mount_dir(string name, string &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;
@ -905,7 +128,7 @@ bool make_mount_dir(string name, string &path)
for (unsigned i = 0; i < 26; i++)
{
path = "/Volumes/" + name + "_" + (char)('a' + i);
path = "/Volumes/" + name + " " + (char)('a' + i);
rmdir(path.c_str());
if (mkdir(path.c_str(), 0777) == 0) return true;

View File

@ -2,7 +2,7 @@
CC=g++
CFLAGS=-c $(shell pkg-config fuse --cflags)
LDFLAGS=$(shell pkg-config fuse --libs)
SOURCES=main.cpp File.cpp Disk.cpp DiskCopy42.cpp UniversalDiskImage.cpp
SOURCES=main.cpp File.cpp Disk.cpp DiskCopy42.cpp UniversalDiskImage.cpp profuse_dirent.cpp profuse_file.cpp profuse_stat.cpp profuse_xattr.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=profuse
@ -22,4 +22,12 @@ File.o: File.cpp File.h
Disk.o: Disk.cpp Disk.h File.h DiskCopy42.h UniversalDiskImage.h
main.o: main.cpp Disk.h File.h
main.o: main.cpp Disk.h File.h profuse.h
profuse_dirent.o: profuse_dirent.cpp profuse.h
profuse_file.o: profuse_file.cpp profuse.h
profuse_stat.o: profuse_stat.cpp profuse.h
profuse_xattr.o: profuse_xattr.cpp profuse.h

50
profuse.h Normal file
View File

@ -0,0 +1,50 @@
/*
* profuse.h
* profuse
*
* Created by Kelvin Sherlock on 1/23/2009.
*
*/
#ifndef __PROFUSE_H__
#define __PROFUSE_H__
#include "File.h"
#include "Disk.h"
#include "common.h"
#define FUSE_USE_VERSION 26
#include <fuse_lowlevel.h>
#undef ERROR
#define ERROR(cond,errno) if ( (cond) ){ fuse_reply_err(req, errno); return; }
extern Disk *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);
// 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

View File

@ -197,94 +197,7 @@
<key>Notifications</key>
<array/>
<key>OpenEditors</key>
<array>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>B61B78650F16CB1000C3E140</string>
<key>PBXProjectModuleLabel</key>
<string>main.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>B61B78660F16CB1000C3E140</string>
<key>PBXProjectModuleLabel</key>
<string>main.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>B61B78980F16DE8200C3E140</string>
<key>history</key>
<array>
<string>B61B78610F16CB0D00C3E140</string>
</array>
</dict>
<key>SplitCount</key>
<string>1</string>
</dict>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {1412, 827}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>428 146 1412 868 0 0 1920 1178 </string>
</dict>
</dict>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>B61B78720F16CE3800C3E140</string>
<key>PBXProjectModuleLabel</key>
<string>Disk.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>B61B78730F16CE3800C3E140</string>
<key>PBXProjectModuleLabel</key>
<string>Disk.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>B61B78990F16DE8200C3E140</string>
<key>history</key>
<array>
<string>B61B78740F16CE3800C3E140</string>
<string>B61B78750F16CE3800C3E140</string>
</array>
<key>prevStack</key>
<array>
<string>B61B78760F16CE3800C3E140</string>
<string>B61B78770F16CE3800C3E140</string>
</array>
</dict>
<key>SplitCount</key>
<string>1</string>
</dict>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {692, 1074}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>943 50 692 1115 0 0 1920 1178 </string>
</dict>
</dict>
</array>
<array/>
<key>PerspectiveWidths</key>
<array>
<integer>-1</integer>
@ -369,8 +282,7 @@
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
<array>
<integer>6</integer>
<integer>1</integer>
<integer>17</integer>
<integer>0</integer>
</array>
</array>
@ -412,7 +324,7 @@
<key>PBXProjectModuleGUID</key>
<string>1CE0B20306471E060097A5F4</string>
<key>PBXProjectModuleLabel</key>
<string>Disk.cpp</string>
<string>DiskCopy42.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
@ -420,23 +332,27 @@
<key>PBXProjectModuleGUID</key>
<string>1CE0B20406471E060097A5F4</string>
<key>PBXProjectModuleLabel</key>
<string>Disk.cpp</string>
<string>DiskCopy42.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>B61B78970F16DE8200C3E140</string>
<string>B6C786F40F2A612600053681</string>
<key>history</key>
<array>
<string>B6614B050EFF5F280073C4E7</string>
<string>B679E4B60F02EFA200FB3F0C</string>
<string>B6DBB4F10F0C6CD800F385F2</string>
<string>B6B767C80F0FFA3900D819C9</string>
<string>B6B17F940F1136550060F7AA</string>
<string>B642F1530F133632001F7696</string>
<string>B642F1540F133632001F7696</string>
<string>B642F16A0F1341D4001F7696</string>
<string>B61B78A20F16EA8700C3E140</string>
<string>B6C786E50F2A5FF300053681</string>
<string>B6C786E60F2A5FF300053681</string>
<string>B6C786E70F2A5FF300053681</string>
<string>B6C786EE0F2A612600053681</string>
<string>B6C786EF0F2A612600053681</string>
<string>B6C786F00F2A612600053681</string>
<string>B6B7A85F0F140BBB001024D2</string>
<string>B6B7A87E0F144D05001024D2</string>
</array>
<key>prevStack</key>
<array>
@ -450,6 +366,12 @@
<string>B6B17F950F1136550060F7AA</string>
<string>B6B17FA80F1140160060F7AA</string>
<string>B6B7A8600F140BBB001024D2</string>
<string>B6C786E80F2A5FF300053681</string>
<string>B6C786E90F2A5FF300053681</string>
<string>B6C786EA0F2A5FF300053681</string>
<string>B6C786F10F2A612600053681</string>
<string>B6C786F20F2A612600053681</string>
<string>B6C786F30F2A612600053681</string>
</array>
</dict>
<key>SplitCount</key>
@ -507,9 +429,9 @@
</array>
<key>TableOfContents</key>
<array>
<string>B61B78630F16CB1000C3E140</string>
<string>B6C786AB0F2A598F00053681</string>
<string>1CE0B1FE06471DED0097A5F4</string>
<string>B61B78640F16CB1000C3E140</string>
<string>B6C786AC0F2A598F00053681</string>
<string>1CE0B20306471E060097A5F4</string>
<string>1CE0B20506471E060097A5F4</string>
</array>
@ -644,9 +566,8 @@
<key>WindowOrderList</key>
<array>
<string>B60E918C0EFD7E1E000E4348</string>
<string>B61B78720F16CE3800C3E140</string>
<string>1CD10A99069EF8BA00B06720</string>
<string>/Users/kelvin/Projects/profuse/profuse.xcodeproj</string>
<string>B61B78650F16CB1000C3E140</string>
</array>
<key>WindowString</key>
<string>189 537 1212 568 0 0 1920 1178 </string>
@ -665,12 +586,14 @@
<key>Dock</key>
<array>
<dict>
<key>BecomeActive</key>
<true/>
<key>ContentConfiguration</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>1CD0528F0623707200166675</string>
<key>PBXProjectModuleLabel</key>
<string></string>
<string>profuse_xattr.cpp</string>
<key>StatusBarVisibility</key>
<true/>
</dict>
@ -728,7 +651,7 @@
<key>TableOfContents</key>
<array>
<string>B60E918C0EFD7E1E000E4348</string>
<string>B61B78790F16CE3800C3E140</string>
<string>B6C786CB0F2A5E8000053681</string>
<string>1CD0528F0623707200166675</string>
<string>XCMainBuildResultsModuleGUID</string>
</array>
@ -848,13 +771,13 @@
<key>TableOfContents</key>
<array>
<string>1CD10A99069EF8BA00B06720</string>
<string>B6B7A8730F140D48001024D2</string>
<string>B6C786AD0F2A598F00053681</string>
<string>1C162984064C10D400B95A72</string>
<string>B6B7A8740F140D48001024D2</string>
<string>B6B7A8750F140D48001024D2</string>
<string>B6B7A8760F140D48001024D2</string>
<string>B6B7A8770F140D48001024D2</string>
<string>B6B7A8780F140D48001024D2</string>
<string>B6C786AE0F2A598F00053681</string>
<string>B6C786AF0F2A598F00053681</string>
<string>B6C786B00F2A598F00053681</string>
<string>B6C786B10F2A598F00053681</string>
<string>B6C786B20F2A598F00053681</string>
</array>
<key>ToolbarConfiguration</key>
<string>xcode.toolbar.config.debugV3</string>
@ -1080,7 +1003,7 @@
<key>PBXProjectModuleGUID</key>
<string>1C78EAB2065D492600B07095</string>
<key>PBXProjectModuleLabel</key>
<string>Disk.cpp</string>
<string>main.cpp</string>
<key>StatusBarVisibility</key>
<true/>
</dict>
@ -1157,7 +1080,7 @@
<key>TableOfContents</key>
<array>
<string>B60E929F0EFDA500000E4348</string>
<string>B6B7A85B0F140B41001024D2</string>
<string>B61B78A60F16EA8700C3E140</string>
<string>1C78EAB2065D492600B07095</string>
<string>1CD052920623707200166675</string>
</array>
@ -1168,7 +1091,7 @@
<key>WindowToolGUID</key>
<string>B60E929F0EFDA500000E4348</string>
<key>WindowToolIsVisible</key>
<false/>
<true/>
</dict>
<dict>
<key>Identifier</key>

View File

@ -12,13 +12,41 @@
B60E91C10EFD8049000E4348 /* xmain.cpp:129 */,
B60E92720EFDA086000E4348 /* File.cpp:88 */,
B6D81E5B0EFDE859000219B7 /* xmain.cpp:163 */,
B6AE1CFF0F0335FC00D36ADB /* main.cpp:30 */,
B6AE1CFF0F0335FC00D36ADB /* main.cpp:20 */,
);
codeSenseManager = B60E91510EFB3628000E4348 /* Code sense */;
executables = (
B60E914A0EFB3612000E4348 /* profuse */,
);
perUserDictionary = {
PBXConfiguration.PBXFileTableDataSource3.PBXErrorsWarningsDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
PBXFileTableDataSourceColumnSortingKey = PBXErrorsWarningsDataSource_LocationID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
300,
595,
);
PBXFileTableDataSourceColumnsKey = (
PBXErrorsWarningsDataSource_TypeID,
PBXErrorsWarningsDataSource_MessageID,
PBXErrorsWarningsDataSource_LocationID,
);
};
PBXConfiguration.PBXFileTableDataSource3.PBXExecutablesDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
PBXFileTableDataSourceColumnSortingKey = PBXExecutablesDataSource_NameID;
PBXFileTableDataSourceColumnWidthsKey = (
22,
300,
593,
);
PBXFileTableDataSourceColumnsKey = (
PBXExecutablesDataSource_ActiveFlagID,
PBXExecutablesDataSource_NameID,
PBXExecutablesDataSource_CommentsID,
);
};
PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
PBXFileTableDataSourceColumnSortingDirectionKey = 1;
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
@ -87,8 +115,8 @@
PBXFileDataSource_Warnings_ColumnID,
);
};
PBXPerProjectTemplateStateSaveDate = 253152006;
PBXWorkspaceStateSaveDate = 253152006;
PBXPerProjectTemplateStateSaveDate = 254433671;
PBXWorkspaceStateSaveDate = 254433671;
};
perUserProjectItems = {
B60E917F0EFD7E1E000E4348 = B60E917F0EFD7E1E000E4348 /* PBXTextBookmark */;
@ -96,37 +124,11 @@
B60E91810EFD7E1E000E4348 = B60E91810EFD7E1E000E4348 /* PBXTextBookmark */;
B60E922B0EFD94CA000E4348 = B60E922B0EFD94CA000E4348 /* PBXTextBookmark */;
B60E929C0EFDA500000E4348 = B60E929C0EFDA500000E4348 /* PBXTextBookmark */;
B61B78610F16CB0D00C3E140 /* PBXBookmark */ = B61B78610F16CB0D00C3E140 /* PBXBookmark */;
B61B78620F16CB1000C3E140 /* PBXTextBookmark */ = B61B78620F16CB1000C3E140 /* PBXTextBookmark */;
B61B78670F16CB1000C3E140 /* PBXTextBookmark */ = B61B78670F16CB1000C3E140 /* PBXTextBookmark */;
B61B78700F16CE3800C3E140 /* PBXTextBookmark */ = B61B78700F16CE3800C3E140 /* PBXTextBookmark */;
B61B78710F16CE3800C3E140 /* PBXTextBookmark */ = B61B78710F16CE3800C3E140 /* PBXTextBookmark */;
B61B78740F16CE3800C3E140 /* PBXTextBookmark */ = B61B78740F16CE3800C3E140 /* PBXTextBookmark */;
B61B78750F16CE3800C3E140 /* PBXTextBookmark */ = B61B78750F16CE3800C3E140 /* PBXTextBookmark */;
B61B78760F16CE3800C3E140 /* PBXTextBookmark */ = B61B78760F16CE3800C3E140 /* PBXTextBookmark */;
B61B78770F16CE3800C3E140 /* PBXTextBookmark */ = B61B78770F16CE3800C3E140 /* PBXTextBookmark */;
B61B78780F16CE3800C3E140 /* PBXTextBookmark */ = B61B78780F16CE3800C3E140 /* PBXTextBookmark */;
B61B787B0F16CE8800C3E140 /* PBXTextBookmark */ = B61B787B0F16CE8800C3E140 /* PBXTextBookmark */;
B61B787C0F16CE8800C3E140 /* PBXTextBookmark */ = B61B787C0F16CE8800C3E140 /* PBXTextBookmark */;
B61B787D0F16CE8800C3E140 /* PBXTextBookmark */ = B61B787D0F16CE8800C3E140 /* PBXTextBookmark */;
B61B787E0F16CF8D00C3E140 /* PBXTextBookmark */ = B61B787E0F16CF8D00C3E140 /* PBXTextBookmark */;
B61B787F0F16CF8D00C3E140 /* PBXTextBookmark */ = B61B787F0F16CF8D00C3E140 /* PBXTextBookmark */;
B61B78800F16CF8D00C3E140 /* PBXTextBookmark */ = B61B78800F16CF8D00C3E140 /* PBXTextBookmark */;
B61B78830F16D04E00C3E140 /* PBXTextBookmark */ = B61B78830F16D04E00C3E140 /* PBXTextBookmark */;
B61B78840F16D04E00C3E140 /* PBXTextBookmark */ = B61B78840F16D04E00C3E140 /* PBXTextBookmark */;
B61B78850F16D04E00C3E140 /* PBXTextBookmark */ = B61B78850F16D04E00C3E140 /* PBXTextBookmark */;
B61B788A0F16D9F000C3E140 /* PBXTextBookmark */ = B61B788A0F16D9F000C3E140 /* PBXTextBookmark */;
B61B788B0F16D9F000C3E140 /* PBXTextBookmark */ = B61B788B0F16D9F000C3E140 /* PBXTextBookmark */;
B61B788C0F16D9F000C3E140 /* PBXTextBookmark */ = B61B788C0F16D9F000C3E140 /* PBXTextBookmark */;
B61B78930F16DE1400C3E140 /* PBXTextBookmark */ = B61B78930F16DE1400C3E140 /* PBXTextBookmark */;
B61B78940F16DE1400C3E140 /* PBXTextBookmark */ = B61B78940F16DE1400C3E140 /* PBXTextBookmark */;
B61B78950F16DE1400C3E140 /* PBXTextBookmark */ = B61B78950F16DE1400C3E140 /* PBXTextBookmark */;
B61B78970F16DE8200C3E140 /* PBXTextBookmark */ = B61B78970F16DE8200C3E140 /* PBXTextBookmark */;
B61B78980F16DE8200C3E140 /* PBXTextBookmark */ = B61B78980F16DE8200C3E140 /* PBXTextBookmark */;
B61B78990F16DE8200C3E140 /* PBXTextBookmark */ = B61B78990F16DE8200C3E140 /* PBXTextBookmark */;
B61B78A20F16EA8700C3E140 = B61B78A20F16EA8700C3E140 /* PBXTextBookmark */;
B61B78A40F16EA8700C3E140 = B61B78A40F16EA8700C3E140 /* PBXTextBookmark */;
B6340C7B0F22C271008931E1 = B6340C7B0F22C271008931E1 /* PBXTextBookmark */;
B642F1530F133632001F7696 = B642F1530F133632001F7696 /* PBXTextBookmark */;
B642F1540F133632001F7696 = B642F1540F133632001F7696 /* PBXTextBookmark */;
B642F1550F133632001F7696 = B642F1550F133632001F7696 /* PBXTextBookmark */;
B642F16A0F1341D4001F7696 = B642F16A0F1341D4001F7696 /* PBXTextBookmark */;
B6614B050EFF5F280073C4E7 = B6614B050EFF5F280073C4E7 /* PBXTextBookmark */;
B679E4B60F02EFA200FB3F0C = B679E4B60F02EFA200FB3F0C /* PBXTextBookmark */;
@ -138,8 +140,31 @@
B6B767CB0F0FFA3900D819C9 = B6B767CB0F0FFA3900D819C9 /* PBXTextBookmark */;
B6B7A85F0F140BBB001024D2 = B6B7A85F0F140BBB001024D2 /* PBXTextBookmark */;
B6B7A8600F140BBB001024D2 = B6B7A8600F140BBB001024D2 /* PBXTextBookmark */;
B6B7A87E0F144D05001024D2 = B6B7A87E0F144D05001024D2 /* PBXTextBookmark */;
B6DBB4F10F0C6CD800F385F2 = B6DBB4F10F0C6CD800F385F2 /* PBXTextBookmark */;
B6C786AA0F2A598F00053681 /* PBXTextBookmark */ = B6C786AA0F2A598F00053681 /* PBXTextBookmark */;
B6C786C90F2A5E8000053681 /* PBXTextBookmark */ = B6C786C90F2A5E8000053681 /* PBXTextBookmark */;
B6C786CA0F2A5E8000053681 /* PBXTextBookmark */ = B6C786CA0F2A5E8000053681 /* PBXTextBookmark */;
B6C786DD0F2A5FED00053681 /* PBXTextBookmark */ = B6C786DD0F2A5FED00053681 /* PBXTextBookmark */;
B6C786DE0F2A5FED00053681 /* PBXTextBookmark */ = B6C786DE0F2A5FED00053681 /* PBXTextBookmark */;
B6C786DF0F2A5FED00053681 /* PBXTextBookmark */ = B6C786DF0F2A5FED00053681 /* PBXTextBookmark */;
B6C786E00F2A5FED00053681 /* PBXTextBookmark */ = B6C786E00F2A5FED00053681 /* PBXTextBookmark */;
B6C786E10F2A5FED00053681 /* PBXTextBookmark */ = B6C786E10F2A5FED00053681 /* PBXTextBookmark */;
B6C786E20F2A5FED00053681 /* PBXTextBookmark */ = B6C786E20F2A5FED00053681 /* PBXTextBookmark */;
B6C786E30F2A5FED00053681 /* PBXTextBookmark */ = B6C786E30F2A5FED00053681 /* PBXTextBookmark */;
B6C786E40F2A5FED00053681 /* PBXTextBookmark */ = B6C786E40F2A5FED00053681 /* PBXTextBookmark */;
B6C786E50F2A5FF300053681 /* PBXTextBookmark */ = B6C786E50F2A5FF300053681 /* PBXTextBookmark */;
B6C786E60F2A5FF300053681 /* PBXTextBookmark */ = B6C786E60F2A5FF300053681 /* PBXTextBookmark */;
B6C786E70F2A5FF300053681 /* PBXTextBookmark */ = B6C786E70F2A5FF300053681 /* PBXTextBookmark */;
B6C786E80F2A5FF300053681 /* PBXTextBookmark */ = B6C786E80F2A5FF300053681 /* PBXTextBookmark */;
B6C786E90F2A5FF300053681 /* PBXTextBookmark */ = B6C786E90F2A5FF300053681 /* PBXTextBookmark */;
B6C786EA0F2A5FF300053681 /* PBXTextBookmark */ = B6C786EA0F2A5FF300053681 /* PBXTextBookmark */;
B6C786EB0F2A5FF300053681 /* PBXTextBookmark */ = B6C786EB0F2A5FF300053681 /* PBXTextBookmark */;
B6C786EE0F2A612600053681 /* PBXTextBookmark */ = B6C786EE0F2A612600053681 /* PBXTextBookmark */;
B6C786EF0F2A612600053681 /* PBXTextBookmark */ = B6C786EF0F2A612600053681 /* PBXTextBookmark */;
B6C786F00F2A612600053681 /* PBXTextBookmark */ = B6C786F00F2A612600053681 /* PBXTextBookmark */;
B6C786F10F2A612600053681 /* PBXTextBookmark */ = B6C786F10F2A612600053681 /* PBXTextBookmark */;
B6C786F20F2A612600053681 /* PBXTextBookmark */ = B6C786F20F2A612600053681 /* PBXTextBookmark */;
B6C786F30F2A612600053681 /* PBXTextBookmark */ = B6C786F30F2A612600053681 /* PBXTextBookmark */;
B6C786F40F2A612600053681 /* PBXTextBookmark */ = B6C786F40F2A612600053681 /* PBXTextBookmark */;
};
sourceControlManager = B60E91500EFB3628000E4348 /* Source Control */;
userBuildSettings = {
@ -228,10 +253,10 @@
};
B60E91540EFB51FE000E4348 /* Disk.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {633, 8064}}";
sepNavIntBoundsRect = "{{0, 0}, {633, 7826}}";
sepNavSelRange = "{9022, 68}";
sepNavVisRange = "{8353, 1853}";
sepNavWindowFrame = "{{511, 7}, {692, 1171}}";
sepNavWindowFrame = "{{943, -6}, {692, 1171}}";
};
};
B60E91580EFD77E3000E4348 /* common.h */ = {
@ -326,11 +351,7 @@
vrLen = 345;
vrLoc = 1359;
};
B61B78610F16CB0D00C3E140 /* PBXBookmark */ = {
isa = PBXBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
};
B61B78620F16CB1000C3E140 /* PBXTextBookmark */ = {
B61B78A20F16EA8700C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
@ -340,265 +361,25 @@
vrLen = 351;
vrLoc = 31;
};
B61B78670F16CB1000C3E140 /* PBXTextBookmark */ = {
B61B78A40F16EA8700C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 832";
name = "main.cpp: 33";
rLen = 0;
rLoc = 18035;
rLoc = 323;
rType = 0;
vrLen = 1165;
vrLoc = 17670;
vrLen = 330;
vrLoc = 441;
};
B61B78700F16CE3800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 351;
vrLoc = 31;
};
B61B78710F16CE3800C3E140 /* PBXTextBookmark */ = {
B6340C7B0F22C271008931E1 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 920";
rLen = 16;
rLoc = 20849;
rType = 0;
vrLen = 1338;
vrLoc = 18850;
};
B61B78740F16CE3800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91530EFB51FE000E4348 /* Disk.h */;
name = "Disk.h: 3";
name = "main.cpp: 33";
rLen = 0;
rLoc = 25;
rLoc = 323;
rType = 0;
vrLen = 1184;
vrLoc = 0;
};
B61B78750F16CE3800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 1220;
vrLoc = 78;
};
B61B78760F16CE3800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 1220;
vrLoc = 78;
};
B61B78770F16CE3800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91530EFB51FE000E4348 /* Disk.h */;
name = "Disk.h: 3";
rLen = 0;
rLoc = 25;
rType = 0;
vrLen = 1184;
vrLoc = 0;
};
B61B78780F16CE3800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 402";
rLen = 68;
rLoc = 9022;
rType = 0;
vrLen = 1853;
vrLoc = 8353;
};
B61B787B0F16CE8800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 351;
vrLoc = 31;
};
B61B787C0F16CE8800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 922";
rLen = 0;
rLoc = 20932;
rType = 0;
vrLen = 1338;
vrLoc = 18850;
};
B61B787D0F16CE8800C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 402";
rLen = 68;
rLoc = 9022;
rType = 0;
vrLen = 1853;
vrLoc = 8353;
};
B61B787E0F16CF8D00C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 351;
vrLoc = 31;
};
B61B787F0F16CF8D00C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 924";
rLen = 0;
rLoc = 20884;
rType = 0;
vrLen = 1386;
vrLoc = 18944;
};
B61B78800F16CF8D00C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 402";
rLen = 68;
rLoc = 9022;
rType = 0;
vrLen = 1853;
vrLoc = 8353;
};
B61B78830F16D04E00C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 351;
vrLoc = 31;
};
B61B78840F16D04E00C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 924";
rLen = 0;
rLoc = 20840;
rType = 0;
vrLen = 1346;
vrLoc = 18944;
};
B61B78850F16D04E00C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 402";
rLen = 68;
rLoc = 9022;
rType = 0;
vrLen = 1853;
vrLoc = 8353;
};
B61B788A0F16D9F000C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 351;
vrLoc = 31;
};
B61B788B0F16D9F000C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 892";
rLen = 0;
rLoc = 19330;
rType = 0;
vrLen = 1100;
vrLoc = 18397;
};
B61B788C0F16D9F000C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 402";
rLen = 68;
rLoc = 9022;
rType = 0;
vrLen = 1853;
vrLoc = 8353;
};
B61B78930F16DE1400C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 351;
vrLoc = 31;
};
B61B78940F16DE1400C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 1025";
rLen = 0;
rLoc = 22371;
rType = 0;
vrLen = 1338;
vrLoc = 21056;
};
B61B78950F16DE1400C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 402";
rLen = 68;
rLoc = 9022;
rType = 0;
vrLen = 1853;
vrLoc = 8353;
};
B61B78970F16DE8200C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 351;
vrLoc = 31;
};
B61B78980F16DE8200C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 970";
rLen = 0;
rLoc = 20932;
rType = 0;
vrLen = 1333;
vrLoc = 19977;
};
B61B78990F16DE8200C3E140 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 402";
rLen = 68;
rLoc = 9022;
rType = 0;
vrLen = 1853;
vrLoc = 8353;
vrLen = 330;
vrLoc = 441;
};
B642F1290F132FA3001F7696 /* UniversalDiskImage.h */ = {
uiCtxt = {
@ -610,9 +391,9 @@
};
B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1353, 796}}";
sepNavIntBoundsRect = "{{0, 0}, {883, 728}}";
sepNavSelRange = "{820, 0}";
sepNavVisRange = "{0, 964}";
sepNavVisRange = "{500, 463}";
sepNavWindowFrame = "{{668, 219}, {1412, 924}}";
};
};
@ -636,16 +417,6 @@
vrLen = 355;
vrLoc = 0;
};
B642F1550F133632001F7696 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 364";
rLen = 0;
rLoc = 7422;
rType = 0;
vrLen = 325;
vrLoc = 28;
};
B642F16A0F1341D4001F7696 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91580EFD77E3000E4348 /* common.h */;
@ -668,10 +439,10 @@
};
B679E4A70F02E79300FB3F0C /* main.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1353, 14546}}";
sepNavSelRange = "{20932, 0}";
sepNavVisRange = "{19977, 1333}";
sepNavWindowFrame = "{{263, 144}, {1412, 924}}";
sepNavIntBoundsRect = "{{0, 0}, {1250, 3864}}";
sepNavSelRange = "{284, 0}";
sepNavVisRange = "{0, 950}";
sepNavWindowFrame = "{{342, 156}, {1412, 924}}";
};
};
B679E4B60F02EFA200FB3F0C /* PBXTextBookmark */ = {
@ -694,7 +465,7 @@
vrLen = 356;
vrLoc = 0;
};
B6AE1CFF0F0335FC00D36ADB /* main.cpp:30 */ = {
B6AE1CFF0F0335FC00D36ADB /* main.cpp:20 */ = {
isa = PBXFileBreakpoint;
actions = (
);
@ -706,7 +477,7 @@
functionName = "prodos_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)";
hitCount = 0;
ignoreCount = 0;
lineNumber = 30;
lineNumber = 20;
location = "ProDOS-Fuse";
modificationTime = 251949619.113812;
state = 2;
@ -717,6 +488,11 @@
name = fuse_common.h;
path = /usr/local/include/fuse/fuse_common.h;
sourceTree = "<absolute>";
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {883, 4032}}";
sepNavSelRange = "{6850, 63}";
sepNavVisRange = "{5837, 708}";
};
};
B6B17F940F1136550060F7AA /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
@ -748,7 +524,7 @@
};
B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {883, 588}}";
sepNavIntBoundsRect = "{{0, 0}, {883, 616}}";
sepNavSelRange = "{150, 0}";
sepNavVisRange = "{0, 333}";
sepNavWindowFrame = "{{299, 31}, {1412, 924}}";
@ -804,15 +580,286 @@
vrLen = 333;
vrLoc = 0;
};
B6B7A87E0F144D05001024D2 /* PBXTextBookmark */ = {
B6C786AA0F2A598F00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B60E91540EFB51FE000E4348 /* Disk.cpp */;
name = "Disk.cpp: 328";
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 33";
rLen = 0;
rLoc = 7422;
rLoc = 323;
rType = 0;
vrLen = 351;
vrLoc = 31;
vrLen = 330;
vrLoc = 441;
};
B6C786B30F2A59AF00053681 /* profuse.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1250, 831}}";
sepNavSelRange = "{185, 0}";
sepNavVisRange = "{0, 1380}";
};
};
B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {796, 5194}}";
sepNavSelRange = "{2396, 68}";
sepNavVisRange = "{0, 546}";
};
};
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1250, 1806}}";
sepNavSelRange = "{193, 0}";
sepNavVisRange = "{0, 1150}";
};
};
B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1250, 3010}}";
sepNavSelRange = "{181, 0}";
sepNavVisRange = "{0, 1136}";
};
};
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {883, 1974}}";
sepNavSelRange = "{132, 0}";
sepNavVisRange = "{0, 365}";
};
};
B6C786C90F2A5E8000053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
comments = "error: #error On FreeBSD API version 25 or greater must be used";
fRef = B6B17F820F103AA70060F7AA /* fuse_common.h */;
rLen = 1;
rLoc = 265;
rType = 1;
};
B6C786CA0F2A5E8000053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6B17F820F103AA70060F7AA /* fuse_common.h */;
name = "fuse_common.h: 266";
rLen = 63;
rLoc = 6850;
rType = 0;
vrLen = 1208;
vrLoc = 6380;
};
B6C786DD0F2A5FED00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6B17F820F103AA70060F7AA /* fuse_common.h */;
name = "fuse_common.h: 266";
rLen = 63;
rLoc = 6850;
rType = 0;
vrLen = 1208;
vrLoc = 6380;
};
B6C786DE0F2A5FED00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
name = "profuse_xattr.cpp: 120";
rLen = 68;
rLoc = 2396;
rType = 0;
vrLen = 546;
vrLoc = 0;
};
B6C786DF0F2A5FED00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */;
name = "profuse_dirent.cpp: 12";
rLen = 0;
rLoc = 135;
rType = 0;
vrLen = 610;
vrLoc = 38;
};
B6C786E00F2A5FED00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
comments = "error: 'EISDIR' was not declared in this scope";
fRef = B6C786C30F2A5DCE00053681 /* profuse_file.cpp */;
rLen = 1;
rLoc = 24;
rType = 1;
};
B6C786E10F2A5FED00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6B17F820F103AA70060F7AA /* fuse_common.h */;
name = "fuse_common.h: 266";
rLen = 63;
rLoc = 6850;
rType = 0;
vrLen = 1208;
vrLoc = 6380;
};
B6C786E20F2A5FED00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
name = "profuse_xattr.cpp: 120";
rLen = 68;
rLoc = 2396;
rType = 0;
vrLen = 546;
vrLoc = 0;
};
B6C786E30F2A5FED00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */;
name = "profuse_dirent.cpp: 12";
rLen = 0;
rLoc = 135;
rType = 0;
vrLen = 610;
vrLoc = 38;
};
B6C786E40F2A5FED00053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786C30F2A5DCE00053681 /* profuse_file.cpp */;
name = "profuse_file.cpp: 11";
rLen = 0;
rLoc = 132;
rType = 0;
vrLen = 607;
vrLoc = 0;
};
B6C786E50F2A5FF300053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 33";
rLen = 0;
rLoc = 323;
rType = 0;
vrLen = 330;
vrLoc = 441;
};
B6C786E60F2A5FF300053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786B30F2A59AF00053681 /* profuse.h */;
name = "profuse.h: 15";
rLen = 0;
rLoc = 592;
rType = 0;
vrLen = 176;
vrLoc = 0;
};
B6C786E70F2A5FF300053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
name = "profuse_xattr.cpp: 1";
rLen = 0;
rLoc = 0;
rType = 0;
vrLen = 360;
vrLoc = 0;
};
B6C786E80F2A5FF300053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B679E4A70F02E79300FB3F0C /* main.cpp */;
name = "main.cpp: 33";
rLen = 0;
rLoc = 323;
rType = 0;
vrLen = 330;
vrLoc = 441;
};
B6C786E90F2A5FF300053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786B30F2A59AF00053681 /* profuse.h */;
name = "profuse.h: 15";
rLen = 0;
rLoc = 592;
rType = 0;
vrLen = 176;
vrLoc = 0;
};
B6C786EA0F2A5FF300053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */;
name = "profuse_xattr.cpp: 1";
rLen = 0;
rLoc = 0;
rType = 0;
vrLen = 360;
vrLoc = 0;
};
B6C786EB0F2A5FF300053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6B17F820F103AA70060F7AA /* fuse_common.h */;
name = "fuse_common.h: 266";
rLen = 63;
rLoc = 6850;
rType = 0;
vrLen = 789;
vrLoc = 6545;
};
B6C786EE0F2A612600053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6B17F820F103AA70060F7AA /* fuse_common.h */;
name = "fuse_common.h: 266";
rLen = 63;
rLoc = 6850;
rType = 0;
vrLen = 708;
vrLoc = 5837;
};
B6C786EF0F2A612600053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */;
name = "UniversalDiskImage.cpp: 42";
rLen = 0;
rLoc = 820;
rType = 0;
vrLen = 463;
vrLoc = 500;
};
B6C786F00F2A612600053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786C30F2A5DCE00053681 /* profuse_file.cpp */;
name = "profuse_file.cpp: 11";
rLen = 0;
rLoc = 132;
rType = 0;
vrLen = 365;
vrLoc = 0;
};
B6C786F10F2A612600053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6B17F820F103AA70060F7AA /* fuse_common.h */;
name = "fuse_common.h: 266";
rLen = 63;
rLoc = 6850;
rType = 0;
vrLen = 708;
vrLoc = 5837;
};
B6C786F20F2A612600053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */;
name = "UniversalDiskImage.cpp: 42";
rLen = 0;
rLoc = 820;
rType = 0;
vrLen = 463;
vrLoc = 500;
};
B6C786F30F2A612600053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6C786C30F2A5DCE00053681 /* profuse_file.cpp */;
name = "profuse_file.cpp: 11";
rLen = 0;
rLoc = 132;
rType = 0;
vrLen = 365;
vrLoc = 0;
};
B6C786F40F2A612600053681 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */;
name = "DiskCopy42.cpp: 11";
rLen = 0;
rLoc = 150;
rType = 0;
vrLen = 333;
vrLoc = 0;
};
B6D81E5B0EFDE859000219B7 /* xmain.cpp:163 */ = {
isa = PBXFileBreakpoint;
@ -839,14 +886,4 @@
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;
};
}

View File

@ -12,6 +12,10 @@
B642F12B0F132FA3001F7696 /* UniversalDiskImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B642F12A0F132FA3001F7696 /* UniversalDiskImage.cpp */; };
B679E4A80F02E79300FB3F0C /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B679E4A70F02E79300FB3F0C /* main.cpp */; };
B6B17FA20F1138830060F7AA /* DiskCopy42.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */; };
B6C786B50F2A59FF00053681 /* profuse_xattr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */; };
B6C786BC0F2A5C0800053681 /* profuse_dirent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */; };
B6C786C00F2A5CC000053681 /* profuse_stat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */; };
B6C786C40F2A5DCE00053681 /* profuse_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C786C30F2A5DCE00053681 /* profuse_file.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -38,6 +42,11 @@
B679E4A70F02E79300FB3F0C /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
B6B17FA00F1138830060F7AA /* DiskCopy42.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskCopy42.h; sourceTree = "<group>"; };
B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskCopy42.cpp; sourceTree = "<group>"; };
B6C786B30F2A59AF00053681 /* profuse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = profuse.h; sourceTree = "<group>"; };
B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_xattr.cpp; sourceTree = "<group>"; };
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_dirent.cpp; sourceTree = "<group>"; };
B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_stat.cpp; sourceTree = "<group>"; };
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_file.cpp; sourceTree = "<group>"; };
B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = profuse.1; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -76,6 +85,11 @@
B679E4A70F02E79300FB3F0C /* main.cpp */,
B6B17FA00F1138830060F7AA /* DiskCopy42.h */,
B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */,
B6C786B30F2A59AF00053681 /* profuse.h */,
B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */,
B6C786C30F2A5DCE00053681 /* profuse_file.cpp */,
B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */,
B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */,
);
name = Source;
sourceTree = "<group>";
@ -151,6 +165,10 @@
B679E4A80F02E79300FB3F0C /* main.cpp in Sources */,
B6B17FA20F1138830060F7AA /* DiskCopy42.cpp in Sources */,
B642F12B0F132FA3001F7696 /* UniversalDiskImage.cpp in Sources */,
B6C786B50F2A59FF00053681 /* profuse_xattr.cpp in Sources */,
B6C786BC0F2A5C0800053681 /* profuse_dirent.cpp in Sources */,
B6C786C00F2A5CC000053681 /* profuse_stat.cpp in Sources */,
B6C786C40F2A5DCE00053681 /* profuse_file.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

127
profuse_dirent.cpp Normal file
View File

@ -0,0 +1,127 @@
/*
* profuse_dirent.cpp
* profuse
*
* Created by Kelvin Sherlock on 1/23/2009.
*
*/
#include "profuse.h"
#include <errno.h>
#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", 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);
}
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);
}
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;
}

134
profuse_file.cpp Normal file
View File

@ -0,0 +1,134 @@
/*
* profuse_file.cpp
* profuse
*
* Created by Kelvin Sherlock on 1/23/2009.
*
*/
#include "profuse.h"
#include <errno.h>
#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", 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_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: %d\n", 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", 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;
}

214
profuse_stat.cpp Normal file
View File

@ -0,0 +1,214 @@
/*
* prodos_stat.cpp
* profuse
*
* Created by Kelvin Sherlock on 1/23/2009.
*
*/
#pragma mark Stat Functions
#include "profuse.h"
#include <errno.h>
#include <string.h>
#include <vector>
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(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.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;
}
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.
// 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: %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);
}

365
profuse_xattr.cpp Normal file
View File

@ -0,0 +1,365 @@
/*
* profuse_xattr.cpp
* profuse
*
* Created by Kelvin Sherlock on 1/23/2009.
*
*/
#include "profuse.h"
#include <algorithm>
#include <string>
#include <errno.h>
using std::string;
#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, "ASCII" Text
if (e.file_type == 0x04 || (e.file_type == 0x50 && e.aux_type == 0x5445))
/* do nothing */ ;
else
{
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 bool isTextFile(unsigned ftype, unsigned auxtype)
{
if (ftype == 0x04) return true; // ascii text
if (ftype == 0x50 && auxtype == 0x5445) return true; // teach text
return false;
}
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 (isTextFile(e.file_type, e.aux_type))
{
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;
}
/*
* 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)
{
#ifdef __APPLE__
#define NO_ATTRIBUTE ENOENT
#else
#define NO_ATTRIBUTE EOPNOTSUPP
#endif
fprintf(stderr, "getxattr: %u %s %u %u \n", ino, name, (int)size, (int)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(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 ( (e.storage_type == EXTENDED_FILE) && (strcmp("com.apple.FinderInfo", name) == 0))
{
xattr_finfo(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);
}