diff --git a/Pascal/File.h b/Pascal/File.h index 5a3e389..8d34eca 100644 --- a/Pascal/File.h +++ b/Pascal/File.h @@ -5,7 +5,7 @@ #include -namespace ProFUSE { +namespace Device { class BlockDevice; class AbstractBlockCache; } diff --git a/ProFUSE/Makefile b/ProFUSE/Makefile new file mode 100644 index 0000000..657e89d --- /dev/null +++ b/ProFUSE/Makefile @@ -0,0 +1,9 @@ +CC = g++ +CPPFLAGS += -g -Wall -I../ + + +all : Exception.o Lock.o + +Exception.o : Exception.cpp Exception.h + +Lock.o : Lock.cpp Lock.h \ No newline at end of file diff --git a/apfm.cpp b/apfm.cpp index f603df2..8e1c984 100644 --- a/apfm.cpp +++ b/apfm.cpp @@ -23,7 +23,6 @@ - const char *MonthName(unsigned m) { static const char *months[] = { @@ -102,16 +101,35 @@ void printFileEntry(Pascal::FileEntry *e, bool extended) } -int list(Pascal::VolumeEntry *volume, bool extended) +int action_ls(int argc, char **argv, Pascal::VolumeEntry *volume) { + //TODO -- check for -l flag. + + bool extended = false; unsigned fileCount = volume->fileCount(); unsigned used = volume->blocks(); unsigned max = 0; unsigned volumeSize = volume->volumeBlocks(); unsigned lastBlock = volume->lastBlock(); + int ch; std::fprintf(stdout, "%s:\n", volume->name()); + argv[0] = "afpm ls"; + + while ((ch = ::getopt(argc, argv, "l")) != -1) + { + switch(ch) + { + case 'l': + extended = true; + break; + } + } + + argc -= optind; + argv += optind; + for (unsigned i = 0; i < fileCount; ++i) { Pascal::FileEntry *e = volume->fileAtIndex(i); @@ -158,20 +176,95 @@ int list(Pascal::VolumeEntry *volume, bool extended) } +int action_cat(unsigned argc, char **argv, Pascal::VolumeEntry *volume) +{ + // cat file1, file2... + argv[0] = "afpm cat"; + + if (argc < 2) + { + std::fprintf(stderr, "apfm cat: Please specify one or more files."); + return 1; + } + + for (unsigned i = 0; i < argc; ++i) + { + const char *fname = argv[i]; + unsigned fileSize; + unsigned offset; + uint8_t buffer[512]; + Pascal::FileEntry *e = NULL; + // find it... + + for (unsigned i = 0, l = volume->fileCount(); i < l; ++i) + { + e = volume->fileAtIndex(i); + if (::strcasecmp(e->name(), fname) == 0) break; + e = NULL; + } + + if (!e) + { + std::fprintf(stderr, "apfm cat: %s: no such file.\n", fname); + continue; + } + + fileSize = e->fileSize(); + offset = 0; + while (offset < fileSize) + { + unsigned count = std::min(512u, fileSize - offset); + e->read(buffer, count, offset); + + std::fwrite(buffer, count, 1, stdout); + offset += count; + } + } + + return 0; +} + +int action_cp(int argc, char **argv, Pascal::VolumeEntry *volume) +{ + return 0; +} + +int action_mv(int argc, char **argv, Pascal::VolumeEntry *volume) +{ + return 0; +} + +int action_rm(int argc, char **argv, Pascal::VolumeEntry *volume) +{ + return 0; +} + +int action_krunch(int argc, char **argv, Pascal::VolumeEntry *volume) +{ + return 0; +} + + + + void usage() { std::printf( "Pascal File Manager v 0.0\n\n" - "Usage: fileman [-h] [-f format] action diskimage\n" + "Usage: fileman [-h] [-f format] diskimage action ...\n" "Options:\n" " -h Show usage information.\n" " -f format Specify disk format. Valid values are:\n" - " po: ProDOS order disk image\n" - " do: DOS Order disk image\n" + " po: ProDOS order disk image\n" + " do: DOS Order disk image\n" "\n" "Actions:\n" - " L List files\n" - " E List files (extended)\n" + " cat\n" + " cp\n" + " krunch\n" + " ls\n" + " mv\n" + " rm\n" ); } @@ -179,14 +272,14 @@ void usage() int main(int argc, char **argv) { std::auto_ptr volume; - std::auto_ptr device; + std::auto_ptr device; unsigned fmt = 0; int c; - - + + // getop stops at first non '-' arg so it will not affect action flags. while ((c = ::getopt(argc, argv, "f:h")) != -1) { std::printf("%c\n", c); @@ -203,24 +296,27 @@ int main(int argc, char **argv) case 'h': case '?': + case ':': usage(); - std::exit(0); + return c == 'h' ? 0 : 1; } } argc -= optind; argv += optind; + optreset = 1; + optind = 1; if (argc != 2) { usage(); - std::exit(1); + return 0; } - const char *file = argv[1]; - const char *action = argv[0]; + const char *file = argv[0]; + const char *action = argv[1]; if (!fmt) fmt = Device::DiskImage::ImageType(optarg, 'PO__'); @@ -230,28 +326,35 @@ int main(int argc, char **argv) switch(fmt) { case 'DO__': - device.reset( new ProFUSE::DOSOrderDiskImage(file, true) ); + device.reset( new Device::DOSOrderDiskImage(file, true) ); break; case 'PO__': - device.reset( new ProFUSE::ProDOSOrderDiskImage(file, true) ); + device.reset( new Device::ProDOSOrderDiskImage(file, true) ); break; case 'DC42': - device.reset( new ProFUSE::DiskCopy42Image(file, true) ); + device.reset( new Device::DiskCopy42Image(file, true) ); break; default: std::fprintf(stderr, "Unable to determine format. Please use -f flag.\n"); - exit(2); + return 2; } volume.reset( new Pascal::VolumeEntry(device.get())); device.release(); - - if (!::strcasecmp("E", action)) return list(volume.get(), true); - if (!::strcasecmp("L", action)) return list(volume.get(), false); - + + + if (!::strcasecmp("cat", action)) return action_cat(argc - 1, argv + 1, volume.get()); + if (!::strcasecmp("cp", action)) return action_cp(argc - 1, argv + 1, volume.get()); + if (!::strcasecmp("krunch", action)) return action_krunch(argc - 1, argv + 1, volume.get()); + if (!::strcasecmp("ls", action)) return action_ls(argc - 1, argv + 1, volume.get()); + if (!::strcasecmp("mv", action)) return action_mv(argc - 1, argv + 1, volume.get()); + if (!::strcasecmp("rm", action)) return action_rm(argc - 1, argv + 1, volume.get()); + + usage(); + return 3; } catch (ProFUSE::Exception& e) { @@ -259,5 +362,5 @@ int main(int argc, char **argv) std::fprintf(stderr, "%s\n", strerror(e.error())); } - + return 0; } \ No newline at end of file diff --git a/fuse_pascal.cpp b/fuse_pascal.cpp index 1aed2ac..fa8a973 100644 --- a/fuse_pascal.cpp +++ b/fuse_pascal.cpp @@ -18,11 +18,12 @@ #include -#include "File.h" -#include "../BlockDevice.h" -#include "../Exception.h" -#include "../MappedFile.h" -#include "../DiskCopy42Image.h" +#include +#include + +#include +#include +#include Pascal::VolumeEntry *fVolume = NULL; std::string fDiskImage; @@ -102,6 +103,7 @@ static int pascal_option_proc(void *data, const char *arg, int key, struct fuse_ case FUSE_OPT_KEY_NONOPT: + // first arg is the disk image. if (fDiskImage.empty()) { fDiskImage = arg; @@ -120,9 +122,12 @@ bool make_mount_dir(std::string name, std::string &path) { path = ""; - if (name.find('/') != std::string::npos) return false; - if (name.find('\\') != std::string::npos) return false; - if (name.find(':') != std::string::npos) return false; + if (name.find('/') != std::string::npos + || name.find('\\') != std::string::npos + || name.find(':') != std::string::npos ) + { + name = "Pascal Volume"; + } path = ""; path = "/Volumes/" + name; @@ -134,10 +139,7 @@ bool make_mount_dir(std::string name, std::string &path) path = "/Volumes/" + name + " " + (char)('a' + i); rmdir(path.c_str()); - if (mkdir(path.c_str(), 0777) == 0) return true; - - - + if (mkdir(path.c_str(), 0777) == 0) return true; } path = ""; @@ -178,31 +180,31 @@ int main(int argc, char **argv) // default prodos-order disk image. if (options.format) { - format = ProFUSE::DiskImage::ImageType(options.format); + format = Device::DiskImage::ImageType(options.format); if (!format) std::fprintf(stderr, "Warning: Unknown image type ``%s''\n", options.format); } if (!format) - format = ProFUSE::DiskImage::ImageType(fDiskImage.c_str(), 'PO__'); + format = Device::DiskImage::ImageType(fDiskImage.c_str(), 'PO__'); bool readOnly = true; try { - std::auto_ptr device; + std::auto_ptr device; switch(format) { case 'DC42': - device.reset(new ProFUSE::DiskCopy42Image(fDiskImage.c_str(), readOnly)); + device.reset(new Device::DiskCopy42Image(fDiskImage.c_str(), readOnly)); break; case 'PO__': - device.reset(new ProFUSE::ProDOSOrderDiskImage(fDiskImage.c_str(), readOnly)); + device.reset(new Device::ProDOSOrderDiskImage(fDiskImage.c_str(), readOnly)); break; case 'DO__': - device.reset(new ProFUSE::DOSOrderDiskImage(fDiskImage.c_str(), readOnly)); + device.reset(new Device::DOSOrderDiskImage(fDiskImage.c_str(), readOnly)); break; @@ -278,8 +280,8 @@ int main(int argc, char **argv) se = fuse_lowlevel_new(&args, &pascal_ops, sizeof(pascal_ops), fVolume); if (se) do { - foreground = 1; - multithread = 0; + //foreground = 1; + //multithread = 0; err = fuse_daemonize(foreground); // todo if (err < 0 ) break; diff --git a/fuse_pascal_ops.cpp b/fuse_pascal_ops.cpp index 7ead116..d2d272d 100644 --- a/fuse_pascal_ops.cpp +++ b/fuse_pascal_ops.cpp @@ -8,11 +8,11 @@ #include #include -/* + #define __FreeBSD__ 10 #define __DARWIN_64_BIT_INO_T 1 #define _FILE_OFFSET_BITS 64 -*/ + #define FUSE_USE_VERSION 27 #include @@ -20,10 +20,9 @@ - -#include "File.h" -#include "../auto.h" -#include "../Exception.h" +#include +#include +#include #define NO_ATTR() \ { \ @@ -64,11 +63,21 @@ static void pascal_init(void *userdata, struct fuse_conn_info *conn) { std::printf("pascal_init\n"); // nop + + // text files have a non-thread safe index. + // which is initialized via read() or fileSize() + VolumeEntry *volume = (VolumeEntry *)userdata; + for (unsigned i = 0, l = volume->fileCount(); i < l; ++i) + { + volume->fileAtIndex(i)->fileSize(); + } + } static void pascal_destroy(void *userdata) { std::printf("pascal_destroy\n"); + // nop } @@ -199,7 +208,7 @@ static void pascal_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t of std::printf("pascal_readdir %u, %u, %u\n", (unsigned)ino, (unsigned)size, (unsigned)off); VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req); - auto_array buffer(new uint8_t[size]); + ProFUSE::auto_array buffer(new uint8_t[size]); unsigned count = volume->fileCount(); @@ -208,7 +217,7 @@ static void pascal_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t of std::memset(&st, 0, sizeof(st)); - // . && .. entries. + // . and .. need to be added in here but are handled by the fs elsewhere. do { if (off == 0) @@ -408,9 +417,11 @@ static void pascal_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, //VolumeEntry *volume = (VolumeEntry *)fuse_req_userdata(req); FileEntry *file = (FileEntry *)fi->fh; + + try { - auto_array buffer(new uint8_t[size]); + ProFUSE::auto_array buffer(new uint8_t[size]); unsigned rsize = file->read(buffer.get(), size, off); fuse_reply_buf(req, (char *)(buffer.get()), rsize);