diff --git a/src/ox/fs/filestore.hpp b/src/ox/fs/filestore.hpp index a6882f560..dd82a4f0c 100644 --- a/src/ox/fs/filestore.hpp +++ b/src/ox/fs/filestore.hpp @@ -18,6 +18,7 @@ class FileStore { public: typedef uint16_t InodeId_t; typedef FsT FsSize_t; + const static auto VERSION = 2; struct StatInfo { InodeId_t inodeId; @@ -41,16 +42,25 @@ class FileStore { void *data(); }; - uint32_t m_fsType; + uint16_t m_version; + uint16_t m_fsType; FsSize_t m_size; + FsSize_t m_memUsed; FsSize_t m_rootInode; public: + /** + * Dumps this file store's inodes to the given file store. + */ + int dumpTo(FileStore *dest); + /** * Compacts and resizes the file store to the minimum possible size for * the contents. + * + * NOTE: This does NOT resize the buffer that this file store refers to! */ - void resize(); + void resize(FsSize_t size = 0); /** * Writes the given data to a "file" with the given id. @@ -90,9 +100,17 @@ class FileStore { */ FsSize_t size(); - static uint8_t version(); + /** + * Returns the space currently available in this file store. + * @return the space currently available in this file store. + */ + FsSize_t available(); + + uint16_t fsType(); + + uint16_t version(); - static uint8_t *format(uint8_t *buffer, FsSize_t size, uint32_t fsType = 0); + static uint8_t *format(uint8_t *buffer, FsSize_t size, uint16_t fsType = 0); private: /** @@ -124,7 +142,7 @@ class FileStore { * Removes the given node from the linked list. * @param node node to remove */ - void unlink(Inode *node); + void dealloc(Inode *node); /** * Gets the address of the next available inode, assuming there is a next @@ -214,25 +232,49 @@ void *FileStore::Inode::data() { // FileStore template -void FileStore::resize() { - compact(); - auto last = lastInode(); - m_size = ptr(last) + last->size(); +int FileStore::dumpTo(FileStore *dest) { + if (dest->size() >= size()) { + auto i = ptr(firstInode()); + do { + dest->write(i->id, i->data(), i->dataLen, i->fileType); + i = ptr(i->next); + } while (ptr(i) != firstInode()); + return 0; + } else { + return -1; + } +} + +template +void FileStore::resize(FsSize_t size) { + if (size < m_size) { + // shrink file store + if (m_memUsed > size) { + size = m_memUsed; + } + compact(); + m_size = size; + } else if (size > m_size) { + // grow file store + m_size = size; + } } template int FileStore::write(InodeId_t id, void *data, FsSize_t dataLen, uint8_t fileType) { auto retval = 1; const FsSize_t size = sizeof(Inode) + dataLen; - auto inode = (Inode*) alloc(size); - if (inode) { - remove(id); - inode->id = id; - inode->fileType = fileType; - inode->setData(data, dataLen); - auto root = ptr(m_rootInode); - if (insert(root, inode) || root == inode) { - retval = 0; + if (size <= (m_size - m_memUsed)) { + auto inode = (Inode*) alloc(size); + if (inode) { + remove(id); + inode->id = id; + inode->fileType = fileType; + inode->setData(data, dataLen); + auto root = ptr(m_rootInode); + if (insert(root, inode) || root == inode) { + retval = 0; + } } } return retval; @@ -260,7 +302,7 @@ int FileStore::remove(Inode *root, InodeId_t id) { if (node->left) { insert(root, ptr(node->left)); } - unlink(node); + dealloc(node); node->id = 0; node->left = 0; node->right = 0; @@ -280,7 +322,7 @@ int FileStore::remove(Inode *root, InodeId_t id) { if (node->left) { insert(root, ptr(node->left)); } - unlink(node); + dealloc(node); node->id = 0; node->left = 0; node->right = 0; @@ -292,7 +334,7 @@ int FileStore::remove(Inode *root, InodeId_t id) { if (root->left) { insert(ptr(m_rootInode), ptr(root->left)); } - unlink(root); + dealloc(root); root->id = 0; root->left = 0; root->right = 0; @@ -303,15 +345,15 @@ int FileStore::remove(Inode *root, InodeId_t id) { } template -void FileStore::unlink(Inode *inode) { +void FileStore::dealloc(Inode *inode) { auto next = ptr(inode->next); auto prev = ptr(inode->prev); prev->next = ptr(next); next->prev = ptr(prev); + m_memUsed -= inode->size(); + ox_memset(inode, 0, inode->size()); - inode->prev = firstInode(); - inode->next = firstInode(); } template @@ -359,6 +401,11 @@ FsSize_t FileStore::size() { return m_size; } +template +FsSize_t FileStore::available() { + return m_size - m_memUsed; +} + template typename FileStore::Inode *FileStore::getInode(Inode *root, InodeId_t id) { Inode *retval = nullptr; @@ -425,6 +472,7 @@ void *FileStore::alloc(FsSize_t size) { ox_memset(inode, 0, size); inode->prev = ptr(firstInode())->prev; inode->next = retval + size; + m_memUsed += size; ptr(firstInode())->prev = retval; return inode; } @@ -498,19 +546,26 @@ typename FileStore::Inode *FileStore::lastInode() { } template -uint8_t FileStore::version() { - return 1; +uint16_t FileStore::fsType() { + return m_fsType; }; template -uint8_t *FileStore::format(uint8_t *buffer, FsSize_t size, uint32_t fsType) { +uint16_t FileStore::version() { + return m_version; +}; + +template +uint8_t *FileStore::format(uint8_t *buffer, FsSize_t size, uint16_t fsType) { ox_memset(buffer, 0, size); auto *fs = (FileStore*) buffer; fs->m_fsType = fsType; + fs->m_version = VERSION; fs->m_size = size; + fs->m_memUsed = sizeof(FileStore) + sizeof(Inode); fs->m_rootInode = sizeof(FileStore); - ((Inode*) (fs + 1))->prev = fs->firstInode(); + ((Inode*) (fs + 1))->prev = sizeof(FileStore); fs->lastInode()->next = sizeof(FileStore); return (uint8_t*) buffer; diff --git a/src/ox/fs/filesystem.cpp b/src/ox/fs/filesystem.cpp index 103ea0ece..23040f868 100644 --- a/src/ox/fs/filesystem.cpp +++ b/src/ox/fs/filesystem.cpp @@ -11,7 +11,7 @@ namespace ox { namespace fs { FileSystem *createFileSystem(void *buff) { - auto type = *((uint32_t*) buff); + auto type = ((FileStore16*) buff)->fsType(); FileSystem *fs = nullptr; switch (type) { diff --git a/src/ox/fs/filesystem.hpp b/src/ox/fs/filesystem.hpp index 376d03768..2f676a708 100644 --- a/src/ox/fs/filesystem.hpp +++ b/src/ox/fs/filesystem.hpp @@ -13,8 +13,6 @@ namespace ox { namespace fs { -using namespace std; - enum FsType { OxFS_16 = 1, OxFS_32 = 2, @@ -42,12 +40,14 @@ class FileSystem { virtual int remove(uint64_t inode) = 0; - virtual void resize() = 0; + virtual void resize(uint64_t size = 0) = 0; virtual int write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = NormalFile) = 0; virtual FileStat stat(uint64_t inode) = 0; + virtual uint64_t available() = 0; + virtual uint64_t size() = 0; }; @@ -99,7 +99,7 @@ class FileSystemTemplate: public FileSystem { int read(uint64_t inode, void *buffer, size_t size) override; - void resize() override; + void resize(uint64_t size = 0) override; int remove(uint64_t inode) override; @@ -109,6 +109,8 @@ class FileSystemTemplate: public FileSystem { FileStat stat(uint64_t inode) override; + uint64_t available() override; + uint64_t size() override; static uint8_t *format(void *buffer, typename FileStore::FsSize_t size, bool useDirectories); @@ -208,8 +210,13 @@ int FileSystemTemplate::write(uint64_t inode, void *buffer, #endif template -void FileSystemTemplate::resize() { - return store->resize(); +void FileSystemTemplate::resize(uint64_t size) { + return store->resize(size); +} + +template +uint64_t FileSystemTemplate::available() { + return store->available(); } template @@ -222,7 +229,7 @@ uint64_t FileSystemTemplate::size() { #endif template uint8_t *FileSystemTemplate::format(void *buffer, typename FileStore::FsSize_t size, bool useDirectories) { - buffer = FileStore::format((uint8_t*) buffer, size, (uint32_t) FS_TYPE); + buffer = FileStore::format((uint8_t*) buffer, size, (uint16_t) FS_TYPE); FileSystemTemplate fs(buffer); if (buffer && useDirectories) { diff --git a/src/ox/fs/oxfstool.cpp b/src/ox/fs/oxfstool.cpp index d65baef62..e533f7df3 100644 --- a/src/ox/fs/oxfstool.cpp +++ b/src/ox/fs/oxfstool.cpp @@ -24,9 +24,10 @@ const static auto oxfstoolVersion = "1.1.0"; const static auto usage = "usage:\n" "\toxfs format [16,32,64] \n" "\toxfs read \n" -"\toxfs write " -"\toxfs compact " +"\toxfs write \n" +"\toxfs write-expand \n" "\toxfs rm \n" +"\toxfs compact \n" "\toxfs version\n"; char *loadFileBuff(const char *path, ::size_t *sizeOut = nullptr) { @@ -155,6 +156,7 @@ int read(int argc, char **args) { if (output) { fwrite(output, fileSize, 1, stdout); + delete []output; err = 0; } @@ -172,7 +174,7 @@ int read(int argc, char **args) { return err; } -int write(int argc, char **args) { +int write(int argc, char **args, bool expand) { auto err = 0; if (argc >= 5) { auto fsPath = args[2]; @@ -184,9 +186,9 @@ int write(int argc, char **args) { if (fsFile) { fseek(fsFile, 0, SEEK_END); - const auto fsSize = (size_t) ftell(fsFile); + auto fsSize = (size_t) ftell(fsFile); rewind(fsFile); - auto fsBuff = (char*) malloc(fsSize); + auto fsBuff = new uint8_t[fsSize]; auto itemsRead = fread(fsBuff, fsSize, 1, fsFile); fclose(fsFile); @@ -195,10 +197,24 @@ int write(int argc, char **args) { if (srcBuff) { auto fs = createFileSystem(fsBuff); if (fs) { + if (expand && fs->available() <= srcSize) { + auto needed = (fs->size() - fs->available()) + fsSize; + auto cloneBuff = new uint8_t[needed]; + ox_memcpy(cloneBuff, fsBuff, fsSize); + + delete fs; + delete []fsBuff; + + fsBuff = cloneBuff; + fs = createFileSystem(fsBuff); + fsSize = needed; + fs->resize(fsSize); + } err |= fs->write(inode, srcBuff, srcSize); 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; @@ -224,7 +240,7 @@ int write(int argc, char **args) { } } - free(fsBuff); + delete []fsBuff; } else { fprintf(stderr, "Could not open file system\n"); } @@ -234,7 +250,7 @@ int write(int argc, char **args) { return err; } -int resize(int argc, char **args) { +int compact(int argc, char **args) { auto err = 1; if (argc >= 2) { auto fsPath = args[2]; @@ -325,16 +341,18 @@ int main(int argc, char **args) { } else if (ox_strcmp(cmd, "read") == 0) { err = read(argc, args); } else if (ox_strcmp(cmd, "write") == 0) { - err = write(argc, args); - } else if (ox_strcmp(cmd, "resize") == 0) { - err = resize(argc, args); + 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()); + printf("oxfs format version %d\n", FileStore16::VERSION); } else { printf("Command '%s' not recognized.\n", cmd); err = 1;