diff options
Diffstat (limited to 'src/tools/floptool.cpp')
| -rw-r--r-- | src/tools/floptool.cpp | 294 |
1 files changed, 274 insertions, 20 deletions
diff --git a/src/tools/floptool.cpp b/src/tools/floptool.cpp index de97045b7f8..c4f5196acd1 100644 --- a/src/tools/floptool.cpp +++ b/src/tools/floptool.cpp @@ -11,6 +11,7 @@ #include "formats/fsblk.h" #include "corestr.h" +#include "hashing.h" #include "ioprocs.h" #include "path.h" #include "strformat.h" @@ -38,9 +39,12 @@ static void display_usage(const char *first_argument) fprintf(stderr, " %s flopconvert [input_format|auto] output_format <inputfile> <outputfile> -- Convert a floppy image\n", exe_name.c_str()); fprintf(stderr, " %s flopcreate output_format filesystem <outputfile> -- Create a preformatted floppy image\n", exe_name.c_str()); fprintf(stderr, " %s flopdir input_format filesystem <image> -- List the contents of a floppy image\n", exe_name.c_str()); + fprintf(stderr, " %s flophashes input_format filesystem <image> -- List hashes for each file on a floppy image\n", exe_name.c_str()); fprintf(stderr, " %s flopread input_format filesystem <image> <path> <outputfile> -- Extract a file from a floppy image\n", exe_name.c_str()); fprintf(stderr, " %s flopwrite input_format filesystem <image> <inputfile> <path> -- Write a file into a floppy image\n", exe_name.c_str()); + fprintf(stderr, " %s flopchmeta format filesystem <image> [<path>] [-<name> <value> ...] -- Change metadata for a file or volume on a floppy image\n", exe_name.c_str()); fprintf(stderr, " %s hddir filesystem <image> -- List the contents of a hard disk image\n", exe_name.c_str()); + fprintf(stderr, " %s hdhashes filesystem <image> -- List hashes for each file on a hard disk image\n", exe_name.c_str()); fprintf(stderr, " %s hdread filesystem <image> <path> <outputfile> -- Extract a file from a hard disk image\n", exe_name.c_str()); fprintf(stderr, " %s hdwrite filesystem <image> <inputfile> <path> -- Write a file into a hard disk image\n", exe_name.c_str()); fprintf(stderr, " %s version -- Display the current version of floptool\n", exe_name.c_str()); @@ -342,6 +346,25 @@ static void dir_scan(fs::filesystem_t *fs, u32 depth, const std::vector<std::str } } +static void dir_report(const std::vector<std::vector<std::string>> &entries, size_t nc) +{ + std::vector<u32> sizes(nc); + + for(const auto &e : entries) + for(unsigned int i=0; i != nc; i++) + sizes[i] = std::max<u32>(sizes[i], e[i].size()); + + for(const auto &e : entries) { + std::string l; + for(unsigned int i=0; i != nc; i++) { + if(i) + l += ' '; + l += util::string_format("%-*s", sizes[i], e[i]); + } + printf("%s\n", l.c_str()); + } +} + static int generic_dir(image_handler &ih) { auto [fsm, fs] = ih.get_fs(); @@ -378,21 +401,7 @@ static int generic_dir(image_handler &ih) dir_scan(fs, 0, std::vector<std::string>(), entries, nmap, names.size(), dmetad, fmetad); - std::vector<u32> sizes(names.size()); - - for(const auto &e : entries) - for(unsigned int i=0; i != names.size(); i++) - sizes[i] = std::max<u32>(sizes[i], e[i].size()); - - for(const auto &e : entries) { - std::string l; - for(unsigned int i=0; i != names.size(); i++) { - if(i) - l += ' '; - l += util::string_format("%-*s", sizes[i], e[i]); - } - printf("%s\n", l.c_str()); - } + dir_report(entries, names.size()); return 0; } @@ -467,6 +476,154 @@ static int hddir(int argc, char *argv[]) } +static std::error_condition dir_scan_hashes(fs::filesystem_t *fs, u32 depth, const std::vector<std::string> &path, std::vector<std::vector<std::string>> &entries) +{ + std::string head; + for(u32 i = 0; i != depth; i++) + head += " "; + auto [err, contents] = fs->directory_contents(path); + if(err) + return err; + for(const auto &c : contents) { + size_t id = entries.size(); + entries.resize(id+1); + entries[id].resize(entries[0].size()); + auto npath = path; + npath.push_back(c.m_name); + switch(c.m_type) { + case fs::dir_entry_type::dir: { + entries[id][0] = head + "dir " + c.m_name; + if(std::error_condition err = dir_scan_hashes(fs, depth+1, npath, entries)) + entries[id][3] = err.message(); + break; + } + case fs::dir_entry_type::file: { + entries[id][0] = head + "file " + c.m_name; + { + auto [err, dfork] = fs->file_read(npath); + if(err) + entries[id][3] = err.message(); + else { + entries[id][1] = std::to_string(dfork.size()); + entries[id][2] = util::crc32_creator::simple(dfork.data(), dfork.size()).as_string(); + entries[id][3] = util::sha1_creator::simple(dfork.data(), dfork.size()).as_string(); + } + } + if(entries[id].size() > 4) { + auto [err2, rfork] = fs->file_rsrc_read(npath); + if(err2) + entries[id][6] = err2.message(); + else if(!rfork.empty()) { + entries[id][4] = std::to_string(rfork.size()); + entries[id][5] = util::crc32_creator::simple(rfork.data(), rfork.size()).as_string(); + entries[id][6] = util::sha1_creator::simple(rfork.data(), rfork.size()).as_string(); + } + } + break; + } + } + } + return std::error_condition(); +} + +static int generic_hashes(image_handler &ih) +{ + auto [fsm, fs] = ih.get_fs(); + + std::vector<std::vector<std::string>> entries; + + entries.resize(1); + entries[0].push_back("name"); + entries[0].push_back("length"); + entries[0].push_back("crc32"); + entries[0].push_back("sha1"); + if(fsm->has_rsrc()) { + entries[0].push_back("rsrc_length"); + entries[0].push_back("rsrc_crc32"); + entries[0].push_back("rsrc_sha1"); + } + + std::error_condition err = dir_scan_hashes(fs, 0, std::vector<std::string>(), entries); + if(err) { + fprintf(stderr, "Error scanning directory: %s\n", err.message().c_str()); + return 1; + } + + dir_report(entries, entries[0].size()); + + return 0; +} + +static int flophashes(int argc, char *argv[]) +{ + if(argc!=5) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); + return 1; + } + + image_handler ih; + ih.set_on_disk_path(argv[4]); + + const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih); + if(!source_format) + return 1; + + auto fs = formats.find_filesystem_format_by_key(argv[3]); + if(!fs) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[3]); + return 1; + } + + if(!fs->m_manager || !fs->m_manager->can_read()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[3]); + return 1; + } + + if(ih.floppy_load(*source_format)) { + fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name()); + return 1; + } + + if(ih.floppy_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); + return 1; + } + + return generic_hashes(ih); +} + +static int hdhashes(int argc, char *argv[]) +{ + if(argc!=4) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); + return 1; + } + + image_handler ih; + ih.set_on_disk_path(argv[3]); + + auto fs = formats.find_filesystem_format_by_key(argv[2]); + if(!fs) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]); + return 1; + } + + if(!fs->m_manager || !fs->m_manager->can_read()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]); + return 1; + } + + if(ih.hd_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); + return 1; + } + + return generic_hashes(ih); +} + + static int generic_read(image_handler &ih, const char *srcpath, const char *dstpath) { auto [fsm, fs] = ih.get_fs(); @@ -625,8 +782,8 @@ static int flopwrite(int argc, char *argv[]) return 1; } - if(!fs->m_manager || !fs->m_manager->can_read()) { - fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[3]); + if(!fs->m_manager || !fs->m_manager->can_write()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement writing\n", argv[3]); return 1; } @@ -659,7 +816,6 @@ static int hdwrite(int argc, char *argv[]) return 1; } - image_handler ih; ih.set_on_disk_path(argv[3]); @@ -669,8 +825,8 @@ static int hdwrite(int argc, char *argv[]) return 1; } - if(!fs->m_manager || !fs->m_manager->can_read()) { - fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]); + if(!fs->m_manager || !fs->m_manager->can_write()) { + fprintf(stderr, "Error: Filesystem '%s' does not implement writing\n", argv[2]); return 1; } @@ -679,9 +835,101 @@ static int hdwrite(int argc, char *argv[]) return 1; } + // FIXME: this doesn't actually save anything return generic_write(ih, argv[4], argv[5]); } + +static int generic_chmeta(image_handler &ih, fs::meta_data &&meta, bool isfile, const char *srcpath) +{ + auto [fsm, fs] = ih.get_fs(); + + const auto metad = isfile ? fsm->file_meta_description() : fsm->volume_meta_description(); + for(const auto &nv : meta.meta) { + auto it = std::find_if(metad.begin(), metad.end(), [&nv] (const fs::meta_description &desc) { return desc.m_name == nv.first; }); + if(it == metad.end()) { + fprintf(stderr, "Error: Filesystem '%s' does not provide %s metadata for %s\n", + fsm->name(), + fs::meta_data::entry_name(nv.first), + isfile ? "files" : "volumes"); + return 1; + } + if(it->m_ro) { + fprintf(stderr, "Error: Filesystem '%s' does not permit changing %s metadata on a %s\n", + fsm->name(), + fs::meta_data::entry_name(nv.first), + isfile ? "file" : "volume"); + return 1; + } + if(it->m_validator && !it->m_validator(nv.second)) { + fprintf(stderr, "Error: Filesystem '%s' does not recognize '%s' as valid %s metadata (%s)\n", + fsm->name(), + nv.second.as_string().c_str(), + fs::meta_data::entry_name(nv.first), + it->m_tooltip); + return 1; + } + } + + std::error_condition err; + if(isfile) { + std::vector<std::string> path = ih.path_split(srcpath); + err = fs->metadata_change(path, meta); + } else + err = fs->volume_metadata_change(meta); + + if(err) { + fprintf(stderr, "%s metadata change failed: %s\n", isfile ? "File" : "Volume", err.message().c_str()); + return 1; + } + + return 0; +} + +static int flopchmeta(int argc, char *argv[]) +{ + fs::meta_data meta = extract_meta_data(argc, argv); + + if(argc!=5 && argc!=6) { + fprintf(stderr, "Incorrect number of arguments.\n\n"); + display_usage(argv[0]); + return 1; + } + + image_handler ih; + ih.set_on_disk_path(argv[4]); + + const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih); + if(!source_format) + return 1; + + auto fs = formats.find_filesystem_format_by_key(argv[3]); + if(!fs || !fs->m_manager) { + fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[3]); + return 1; + } + + if(ih.floppy_load(*source_format)) { + fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name()); + return 1; + } + + if(ih.floppy_mount_fs(*fs)) { + fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name()); + return 1; + } + + int err = generic_chmeta(ih, std::move(meta), argc==6, argc==6 ? argv[5] : ""); + if(err) + return err; + + ih.fs_to_floppy(); + if(ih.floppy_save(*source_format)) + return 1; + + return 0; +} + static int version(int argc, char *argv[]) { extern const char build_version[]; @@ -707,12 +955,18 @@ int CLIB_DECL main(int argc, char *argv[]) return flopcreate(argc, argv); else if(!core_stricmp("flopdir", argv[1])) return flopdir(argc, argv); + else if(!core_stricmp("flophashes", argv[1])) + return flophashes(argc, argv); else if(!core_stricmp("flopread", argv[1])) return flopread(argc, argv); else if(!core_stricmp("flopwrite", argv[1])) return flopwrite(argc, argv); + else if(!core_stricmp("flopchmeta", argv[1])) + return flopchmeta(argc, argv); else if(!core_stricmp("hddir", argv[1])) return hddir(argc, argv); + else if(!core_stricmp("hdhashes", argv[1])) + return hdhashes(argc, argv); else if(!core_stricmp("hdread", argv[1])) return hdread(argc, argv); else if(!core_stricmp("hdwrite", argv[1])) |
