nostalgia/src/ox/fs/oxfstool.cpp
Gary Talent f92c8ab577 Squashed 'deps/ox/' changes from a5166e0..68c144f
68c144f Add ls to file system
1ce2797 Flatten out namespaces to only ox
e0063a7 Cleanup oxfstool format output
a2dfb41 Fix FS read by type to read byte by byte

git-subtree-dir: deps/ox
git-subtree-split: 68c144fe755e1f1a6cebb841b6c37b618a35fa43
2017-05-12 00:26:58 -05:00

366 lines
8.1 KiB
C++

/*
* Copyright 2015 - 2017 gtalent2@gmail.com
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ox/std/strops.hpp>
#include <ox/fs/filesystem.hpp>
// suppress warnings about using fopen
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif
using namespace ox;
using namespace std;
const static auto oxfstoolVersion = "1.3.0";
const static auto usage = "usage:\n"
"\toxfs format [16,32,64] <size> <path>\n"
"\toxfs read <FS file> <inode>\n"
"\toxfs write <FS file> <inode> <insertion file>\n"
"\toxfs write-expand <FS file> <inode> <insertion file>\n"
"\toxfs rm <FS file> <inode>\n"
"\toxfs compact <FS file>\n"
"\toxfs version\n";
char *loadFileBuff(FILE *file, ::size_t *sizeOut = nullptr) {
if (file) {
fseek(file, 0, SEEK_END);
const auto size = ftell(file);
rewind(file);
auto buff = new char[size];
auto itemsRead = fread(buff, size, 1, file);
fclose(file);
if (sizeOut) {
*sizeOut = itemsRead ? size : 0;
}
return buff;
} else {
return nullptr;
}
}
char *loadFileBuff(const char *path, ::size_t *sizeOut = nullptr) {
return loadFileBuff(fopen(path, "rb"), sizeOut);
}
size_t bytes(const char *str) {
auto size = ::ox_strlen(str);
const auto lastChar = str[size-1];
auto multiplier = 1;
char copy[size + 1];
ox_memcpy(copy, str, size + 1);
// parse size unit
if (lastChar < '0' || lastChar > '9') {
copy[size-1] = 0;
switch (lastChar) {
case 'k':
case 'K':
multiplier = 1024;
break;
case 'm':
case 'M':
multiplier = 1024 * 1024;
break;
case 'g':
case 'G':
multiplier = 1024 * 1024 * 1024;
break;
default:
multiplier = -1;
}
}
return ox_atoi(copy) * multiplier;
}
int format(int argc, char **args) {
printf("Creating file system...\n");
auto err = 0;
if (argc >= 5) {
auto type = ox_atoi(args[2]);
auto size = bytes(args[3]);
auto path = args[4];
auto buff = new uint8_t[size];
if (size < sizeof(FileStore64)) {
err = 1;
cerr << "File system size " << size << " too small, must be at least " << sizeof(FileStore64) << endl;
}
if (!err) {
// format
switch (type) {
case 16:
FileSystem16::format(buff, (FileStore16::FsSize_t) size, true);
break;
case 32:
FileSystem32::format(buff, (FileStore32::FsSize_t) size, true);
break;
case 64:
FileSystem64::format(buff, size, true);
break;
default:
err = 1;
}
if (!err) {
auto file = fopen(path, "wb");
if (file) {
err = fwrite(buff, size, 1, file) != 1;
err |= fclose(file);
if (err) {
fprintf(stderr, "Could not write to file: %s.\n", path);
}
} else {
fprintf(stderr, "Could not open file: %s.\n", path);
}
}
}
delete []buff;
if (err == 0) {
cerr << "Created file system " << path << endl;
cerr << " type " << type << endl;
cerr << " wrote " << size << " bytes\n";
}
} else {
fprintf(stderr, "Insufficient arguments\n");
}
return err;
}
int read(int argc, char **args) {
auto err = 1;
if (argc >= 4) {
auto fsPath = args[2];
auto inode = ox_atoi(args[3]);
size_t fsSize;
size_t fileSize;
auto fsBuff = loadFileBuff(fsPath, &fsSize);
if (fsBuff) {
auto fs = createFileSystem(fsBuff, fsSize);
if (fs) {
auto output = fs->read(inode, &fileSize);
if (output) {
fwrite(output, fileSize, 1, stdout);
delete []output;
err = 0;
}
delete fs;
delete []fsBuff;
} else {
fprintf(stderr, "Invalid file system type: %d.\n", *(uint32_t*) fsBuff);
}
} else {
fprintf(stderr, "Could not open file: %s\n", fsPath);
}
} else {
fprintf(stderr, "Insufficient arguments\n");
}
return err;
}
int write(int argc, char **args, bool expand) {
auto err = 0;
if (argc >= 5) {
auto fsPath = args[2];
auto inode = ox_atoi(args[3]);
auto srcPath = args[4];
size_t srcSize;
auto fsFile = fopen(fsPath, "rb");
if (fsFile) {
fseek(fsFile, 0, SEEK_END);
auto fsSize = (size_t) ftell(fsFile);
rewind(fsFile);
auto fsBuff = new uint8_t[fsSize];
auto itemsRead = fread(fsBuff, fsSize, 1, fsFile);
fclose(fsFile);
if (itemsRead) {
auto srcBuff = loadFileBuff(srcPath, &srcSize);
if (srcBuff) {
auto expanded = false;
auto fs = createFileSystem(fsBuff, fsSize);
if (fs) {
if (expand && fs->available() <= srcSize) {
auto needed = fs->size() + fs->spaceNeeded(srcSize);
fsSize = needed;
fs = expandCopyCleanup(fs, needed);
fsBuff = fs->buff();
}
err |= fs->write(inode, srcBuff, srcSize);
// compact the file system if it was expanded
if (expanded) {
fs->resize();
}
if (err) {
fprintf(stderr, "Could not write to file system.\n");
}
delete fs;
} else {
fprintf(stderr, "Invalid file system type: %d.\n", *(uint32_t*) fsBuff);
err = 1;
}
if (!err) {
fsFile = fopen(fsPath, "wb");
if (fsFile) {
err = fwrite(fsBuff, fsSize, 1, fsFile) != 1;
err |= fclose(fsFile);
if (err) {
fprintf(stderr, "Could not write to file system file.\n");
}
} else {
err = 1;
}
}
delete []srcBuff;
} else {
err = 1;
fprintf(stderr, "Could not load source file: %s.\n", srcPath);
}
}
delete []fsBuff;
} else {
fprintf(stderr, "Could not open file system\n");
}
} else {
fprintf(stderr, "Insufficient arguments\n");
}
return err;
}
int compact(int argc, char **args) {
auto err = 1;
if (argc >= 2) {
auto fsPath = args[2];
size_t fsSize;
auto fsBuff = loadFileBuff(fsPath, &fsSize);
if (fsBuff) {
auto fs = createFileSystem(fsBuff, fsSize);
if (fs) {
fs->resize();
} else {
fprintf(stderr, "Invalid file system.\n");
}
// write back to file
auto fsFile = fopen(fsPath, "wb");
if (fsFile) {
err = fwrite(fsBuff, fs->size(), 1, fsFile) != 1;
err |= fclose(fsFile);
if (err) {
fprintf(stderr, "Could not write to file system file.\n");
}
} else {
err = 1;
}
delete fs;
delete []fsBuff;
} else {
fprintf(stderr, "Could not open file: %s\n", fsPath);
}
} else {
fprintf(stderr, "Insufficient arguments\n");
}
return err;
}
int remove(int argc, char **args) {
auto err = 1;
if (argc >= 4) {
auto fsPath = args[2];
auto inode = ox_atoi(args[3]);
size_t fsSize;
auto fsBuff = loadFileBuff(fsPath, &fsSize);
if (fsBuff) {
auto fs = createFileSystem(fsBuff, fsSize);
if (fs) {
err = fs->remove(inode);
} else {
fprintf(stderr, "Invalid file system.\n");
}
if (err) {
fprintf(stderr, "Could not write to file system.\n");
} else {
auto fsFile = fopen(fsPath, "wb");
if (fsFile) {
err = fwrite(fsBuff, fsSize, 1, fsFile) != 1;
err |= fclose(fsFile);
if (err) {
fprintf(stderr, "Could not write to file system file.\n");
}
} else {
err = 1;
}
}
delete fs;
delete []fsBuff;
} else {
fprintf(stderr, "Could not open file: %s\n", fsPath);
}
} else {
fprintf(stderr, "Insufficient arguments\n");
}
return err;
}
int main(int argc, char **args) {
auto err = 0;
if (argc > 1) {
auto cmd = args[1];
if (ox_strcmp(cmd, "format") == 0) {
err = format(argc, args);
} else if (ox_strcmp(cmd, "read") == 0) {
err = read(argc, args);
} else if (ox_strcmp(cmd, "write") == 0) {
err = write(argc, args, false);
} else if (ox_strcmp(cmd, "write-expand") == 0) {
err = write(argc, args, true);
} else if (ox_strcmp(cmd, "compact") == 0) {
err = compact(argc, args);
} else if (ox_strcmp(cmd, "rm") == 0) {
err = remove(argc, args);
} else if (ox_strcmp(cmd, "help") == 0) {
printf("%s\n", usage);
} else if (ox_strcmp(cmd, "version") == 0) {
printf("oxfstool version %s\n", oxfstoolVersion);
printf("oxfs format version %d\n", FileStore16::VERSION);
} else {
printf("Command '%s' not recognized.\n", cmd);
err = 1;
}
} else {
printf("%s\n", usage);
}
return err;
}