diff --git a/main.cpp b/main.cpp index 641b51c..ec7cc83 100644 --- a/main.cpp +++ b/main.cpp @@ -13,31 +13,18 @@ #define _REENTRANT #define _POSIX_C_SOURCE 200112L */ -#define FUSE_USE_VERSION 26 - - -#include #include #include #include -#include -#include -#include -#include -#include - #include #include #include -#include -#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 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 *fp = new vector(); - 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 *files = (vector *)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 *files = (vector *)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 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::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; diff --git a/makefile.linux b/makefile.linux index 8856fae..a2fcb11 100755 --- a/makefile.linux +++ b/makefile.linux @@ -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 diff --git a/profuse.h b/profuse.h new file mode 100644 index 0000000..1982aab --- /dev/null +++ b/profuse.h @@ -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 + + +#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 \ No newline at end of file diff --git a/profuse.xcodeproj/kelvin.mode1v3 b/profuse.xcodeproj/kelvin.mode1v3 index 1788151..ccbbfdf 100644 --- a/profuse.xcodeproj/kelvin.mode1v3 +++ b/profuse.xcodeproj/kelvin.mode1v3 @@ -197,94 +197,7 @@ Notifications OpenEditors - - - Content - - PBXProjectModuleGUID - B61B78650F16CB1000C3E140 - PBXProjectModuleLabel - main.cpp - PBXSplitModuleInNavigatorKey - - Split0 - - PBXProjectModuleGUID - B61B78660F16CB1000C3E140 - PBXProjectModuleLabel - main.cpp - _historyCapacity - 0 - bookmark - B61B78980F16DE8200C3E140 - history - - B61B78610F16CB0D00C3E140 - - - SplitCount - 1 - - StatusBarVisibility - - - Geometry - - Frame - {{0, 20}, {1412, 827}} - PBXModuleWindowStatusBarHidden2 - - RubberWindowFrame - 428 146 1412 868 0 0 1920 1178 - - - - Content - - PBXProjectModuleGUID - B61B78720F16CE3800C3E140 - PBXProjectModuleLabel - Disk.cpp - PBXSplitModuleInNavigatorKey - - Split0 - - PBXProjectModuleGUID - B61B78730F16CE3800C3E140 - PBXProjectModuleLabel - Disk.cpp - _historyCapacity - 0 - bookmark - B61B78990F16DE8200C3E140 - history - - B61B78740F16CE3800C3E140 - B61B78750F16CE3800C3E140 - - prevStack - - B61B78760F16CE3800C3E140 - B61B78770F16CE3800C3E140 - - - SplitCount - 1 - - StatusBarVisibility - - - Geometry - - Frame - {{0, 20}, {692, 1074}} - PBXModuleWindowStatusBarHidden2 - - RubberWindowFrame - 943 50 692 1115 0 0 1920 1178 - - - + PerspectiveWidths -1 @@ -369,8 +282,7 @@ PBXSmartGroupTreeModuleOutlineStateSelectionKey - 6 - 1 + 17 0 @@ -412,7 +324,7 @@ PBXProjectModuleGUID 1CE0B20306471E060097A5F4 PBXProjectModuleLabel - Disk.cpp + DiskCopy42.cpp PBXSplitModuleInNavigatorKey Split0 @@ -420,23 +332,27 @@ PBXProjectModuleGUID 1CE0B20406471E060097A5F4 PBXProjectModuleLabel - Disk.cpp + DiskCopy42.cpp _historyCapacity 0 bookmark - B61B78970F16DE8200C3E140 + B6C786F40F2A612600053681 history B6614B050EFF5F280073C4E7 B679E4B60F02EFA200FB3F0C - B6DBB4F10F0C6CD800F385F2 B6B767C80F0FFA3900D819C9 - B6B17F940F1136550060F7AA B642F1530F133632001F7696 B642F1540F133632001F7696 B642F16A0F1341D4001F7696 + B61B78A20F16EA8700C3E140 + B6C786E50F2A5FF300053681 + B6C786E60F2A5FF300053681 + B6C786E70F2A5FF300053681 + B6C786EE0F2A612600053681 + B6C786EF0F2A612600053681 + B6C786F00F2A612600053681 B6B7A85F0F140BBB001024D2 - B6B7A87E0F144D05001024D2 prevStack @@ -450,6 +366,12 @@ B6B17F950F1136550060F7AA B6B17FA80F1140160060F7AA B6B7A8600F140BBB001024D2 + B6C786E80F2A5FF300053681 + B6C786E90F2A5FF300053681 + B6C786EA0F2A5FF300053681 + B6C786F10F2A612600053681 + B6C786F20F2A612600053681 + B6C786F30F2A612600053681 SplitCount @@ -507,9 +429,9 @@ TableOfContents - B61B78630F16CB1000C3E140 + B6C786AB0F2A598F00053681 1CE0B1FE06471DED0097A5F4 - B61B78640F16CB1000C3E140 + B6C786AC0F2A598F00053681 1CE0B20306471E060097A5F4 1CE0B20506471E060097A5F4 @@ -644,9 +566,8 @@ WindowOrderList B60E918C0EFD7E1E000E4348 - B61B78720F16CE3800C3E140 + 1CD10A99069EF8BA00B06720 /Users/kelvin/Projects/profuse/profuse.xcodeproj - B61B78650F16CB1000C3E140 WindowString 189 537 1212 568 0 0 1920 1178 @@ -665,12 +586,14 @@ Dock + BecomeActive + ContentConfiguration PBXProjectModuleGUID 1CD0528F0623707200166675 PBXProjectModuleLabel - + profuse_xattr.cpp StatusBarVisibility @@ -728,7 +651,7 @@ TableOfContents B60E918C0EFD7E1E000E4348 - B61B78790F16CE3800C3E140 + B6C786CB0F2A5E8000053681 1CD0528F0623707200166675 XCMainBuildResultsModuleGUID @@ -848,13 +771,13 @@ TableOfContents 1CD10A99069EF8BA00B06720 - B6B7A8730F140D48001024D2 + B6C786AD0F2A598F00053681 1C162984064C10D400B95A72 - B6B7A8740F140D48001024D2 - B6B7A8750F140D48001024D2 - B6B7A8760F140D48001024D2 - B6B7A8770F140D48001024D2 - B6B7A8780F140D48001024D2 + B6C786AE0F2A598F00053681 + B6C786AF0F2A598F00053681 + B6C786B00F2A598F00053681 + B6C786B10F2A598F00053681 + B6C786B20F2A598F00053681 ToolbarConfiguration xcode.toolbar.config.debugV3 @@ -1080,7 +1003,7 @@ PBXProjectModuleGUID 1C78EAB2065D492600B07095 PBXProjectModuleLabel - Disk.cpp + main.cpp StatusBarVisibility @@ -1157,7 +1080,7 @@ TableOfContents B60E929F0EFDA500000E4348 - B6B7A85B0F140B41001024D2 + B61B78A60F16EA8700C3E140 1C78EAB2065D492600B07095 1CD052920623707200166675 @@ -1168,7 +1091,7 @@ WindowToolGUID B60E929F0EFDA500000E4348 WindowToolIsVisible - + Identifier diff --git a/profuse.xcodeproj/kelvin.pbxuser b/profuse.xcodeproj/kelvin.pbxuser index a1c0bc6..3a8f97e 100644 --- a/profuse.xcodeproj/kelvin.pbxuser +++ b/profuse.xcodeproj/kelvin.pbxuser @@ -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 = ""; + 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; - }; } diff --git a/profuse.xcodeproj/project.pbxproj b/profuse.xcodeproj/project.pbxproj index 0e1f200..33e9c92 100644 --- a/profuse.xcodeproj/project.pbxproj +++ b/profuse.xcodeproj/project.pbxproj @@ -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 = ""; }; B6B17FA00F1138830060F7AA /* DiskCopy42.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskCopy42.h; sourceTree = ""; }; B6B17FA10F1138830060F7AA /* DiskCopy42.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskCopy42.cpp; sourceTree = ""; }; + B6C786B30F2A59AF00053681 /* profuse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = profuse.h; sourceTree = ""; }; + B6C786B40F2A59FE00053681 /* profuse_xattr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_xattr.cpp; sourceTree = ""; }; + B6C786BB0F2A5C0800053681 /* profuse_dirent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_dirent.cpp; sourceTree = ""; }; + B6C786BF0F2A5CC000053681 /* profuse_stat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_stat.cpp; sourceTree = ""; }; + B6C786C30F2A5DCE00053681 /* profuse_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profuse_file.cpp; sourceTree = ""; }; B6DBB4E70F0C6BBD00F385F2 /* profuse.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = profuse.1; sourceTree = ""; }; /* 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 = ""; @@ -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; }; diff --git a/profuse_dirent.cpp b/profuse_dirent.cpp new file mode 100644 index 0000000..5571ab3 --- /dev/null +++ b/profuse_dirent.cpp @@ -0,0 +1,127 @@ +/* + * profuse_dirent.cpp + * profuse + * + * Created by Kelvin Sherlock on 1/23/2009. + * + */ + +#include "profuse.h" + +#include + +#include +#include +#include + +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 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 *fp = new vector(); + 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 *files = (vector *)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 *files = (vector *)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; +} + diff --git a/profuse_file.cpp b/profuse_file.cpp new file mode 100644 index 0000000..73d22d5 --- /dev/null +++ b/profuse_file.cpp @@ -0,0 +1,134 @@ +/* + * profuse_file.cpp + * profuse + * + * Created by Kelvin Sherlock on 1/23/2009. + * + */ + +#include "profuse.h" +#include + + +#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; +} diff --git a/profuse_stat.cpp b/profuse_stat.cpp new file mode 100644 index 0000000..6a82521 --- /dev/null +++ b/profuse_stat.cpp @@ -0,0 +1,214 @@ +/* + * prodos_stat.cpp + * profuse + * + * Created by Kelvin Sherlock on 1/23/2009. + * + */ + + +#pragma mark Stat Functions + +#include "profuse.h" +#include +#include + +#include + + +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 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::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); +} + diff --git a/profuse_xattr.cpp b/profuse_xattr.cpp new file mode 100644 index 0000000..ce79d6a --- /dev/null +++ b/profuse_xattr.cpp @@ -0,0 +1,365 @@ +/* + * profuse_xattr.cpp + * profuse + * + * Created by Kelvin Sherlock on 1/23/2009. + * + */ + + +#include "profuse.h" + +#include +#include +#include + +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); +} +