diff --git a/CMakeLists.txt b/CMakeLists.txt index b8822dba9..9904b0932 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8.8) -project(Memphis) +project(WombatFS) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) include(address_sanitizer) @@ -24,4 +24,5 @@ include_directories("src") add_subdirectory(src) add_subdirectory(test) -add_test("MemFs" test/MemFsTest) +add_test("Format" test/Format) +add_test("FsStore" test/FsStore) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e108b850..cdf6bc8c7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8.8) add_library( - Memphis + WFS filestore.cpp _memops.cpp ) @@ -11,5 +11,5 @@ install( filestore.hpp _memops.hpp DESTINATION - include/Memphis + include/WFS ) diff --git a/src/filestore.cpp b/src/filestore.cpp index 40677efa0..aad8eb401 100644 --- a/src/filestore.cpp +++ b/src/filestore.cpp @@ -10,156 +10,5 @@ namespace wombat { namespace fs { - -uint32_t FileStore::version = 0; - -uint8_t *initFs(uint8_t *buffer, size_t size, bool hasDirectories) { - auto fs = (MemFsHeader*) buffer; - fs->version = FileStore::version; - return (uint8_t*) fs; -} - -MemFsPtr FileStore::Record::size() { - return offsetof(FileStore::Record, m_id) + dataLen; -} - -void FileStore::Record::setId(RecordId id) { - this->m_id = id; -} - -void FileStore::Record::setData(uint8_t *data, int size) { - memcpy(this + m_data, data, size); - m_data = size; -} - - -// FileStore - -FileStore::FileStore(uint8_t *begin, uint8_t *end, Error *error): m_version(*((uint32_t*) begin)), m_lastRec(*(MemFsPtr*) (begin + sizeof(m_version))) { - if (version != m_version) { - // version mismatch - if (error) { - *error = 1; - } - } else { - // ok - m_begin = begin; - m_end = end; - m_root = (Record*) (begin + sizeof(MemFsPtr)); - if (error) { - *error = 0; - } - } -} - -void FileStore::init() { - memset(m_begin, 0, m_end - m_begin); - m_version = version; -} - -void FileStore::write(RecordId id, uint8_t *data, MemFsPtr dataLen) { - const MemFsPtr size = offsetof(FileStore::Record, m_id) + dataLen; - auto rec = (Record*) alloc(size); - rec->dataLen = dataLen; - insert(m_root, rec); -} - -int FileStore::read(RecordId id, uint8_t *data, MemFsPtr *size) { - auto rec = getRecord(m_root, id); - int retval = 1; - if (rec) { - *size = rec->dataLen; - memcpy(data, ptr(rec->m_data), *size); - retval = 0; - } - return retval; -} - -FileStore::Record *FileStore::getRecord(FileStore::Record *root, RecordId id) { - auto cmp = root->m_id > id; - MemFsPtr recPt; - if (cmp) { - recPt = root->left; - } else if (!cmp) { - recPt = root->right; - } else { - recPt = ptr(root); - } - if (recPt) { - return getRecord(ptr(recPt), id); - } else { - return ptr(recPt); - } -} - -void *FileStore::alloc(MemFsPtr size) { - const auto iterator = this->iterator(); - if ((iterator + size) > (uint64_t) m_end) { - compress(); - if ((iterator + size) > (uint64_t) m_end) { - return nullptr; - } - } - ptr(m_lastRec)->next = iterator; - - auto rec = ptr(iterator); - memset(rec, 0, size); - ptr(iterator)->prev = m_lastRec; - m_lastRec = iterator; - return rec; -} - -void FileStore::compress() { - auto current = m_root; - while (current->next) { - auto prevEnd = current + current->size(); - current = ptr(current->next); - if (prevEnd != current) { - memcpy(prevEnd, current, current->size()); - current = prevEnd; - } - } -} - -bool FileStore::insert(Record *root, Record *insertValue, MemFsPtr *rootParentPtr) { - auto cmp = root->m_id > insertValue->m_id; - if (cmp) { - if (root->left) { - return insert(ptr(root->left), insertValue, &root->left); - } else { - root->left = ((uint8_t*) insertValue) - m_begin; - return true; - } - } else if (!cmp) { - if (root->right) { - return insert(ptr(root->right), insertValue, &root->right); - } else { - root->right = ((uint8_t*) insertValue) - m_begin; - return true; - } - } else { - auto ivAddr = ((uint8_t*) insertValue) - m_begin; - if (root->prev) { - ptr(root->prev)->next = ivAddr; - } - if (root->next) { - ptr(root->next)->prev = ivAddr; - } - if (rootParentPtr) { - *rootParentPtr = ivAddr; - } - return true; - } - return false; -} - -MemFsPtr FileStore::iterator() { - return m_lastRec + ((Record*) m_begin + m_lastRec)->size(); -} - -MemFsPtr FileStore::ptr(void *ptr) { - return ((uint8_t*) ptr) - m_begin; -} - } } diff --git a/src/filestore.hpp b/src/filestore.hpp index b99bcbfe5..2665a1a7f 100644 --- a/src/filestore.hpp +++ b/src/filestore.hpp @@ -8,42 +8,42 @@ #ifndef WOMBAT_FS_FILESTORE_HPP #define WOMBAT_FS_FILESTORE_HPP +#include "_memops.hpp" #include "_types.hpp" namespace wombat { namespace fs { -typedef uint32_t MemFsPtr; -typedef uint32_t RecordId; - -struct MemFsHeader { - uint32_t version; - MemFsPtr rootDir = -1; -}; - -class DirectoryHeader { - /** - * Count of the number of files listed in this directory. - */ - MemFsPtr files; - - const char* operator[](int i); -}; - +template class FileStore { + public: - static uint32_t version; + struct FsHeader { + uint32_t version; + FsSize_t rootDir = -1; + }; + + struct Inode { + enum class Type: uint8_t { + FILE, + DIRECTORY + } type; + FsSize_t size; + }; + + typedef FsSize_t RecordId; + private: struct Record { // the next Record in memory - MemFsPtr prev, next; - MemFsPtr left, right; - MemFsPtr dataLen; + FsSize_t prev, next; + FsSize_t left, right; + FsSize_t dataLen; // offsets from Record this - MemFsPtr m_id; - MemFsPtr m_data; + FsSize_t m_id; + FsSize_t m_data; - MemFsPtr size(); + FsSize_t size(); void setId(RecordId); void setData(uint8_t *data, int size); }; @@ -51,7 +51,7 @@ class FileStore { uint8_t *m_begin, *m_end; uint32_t &m_version; // the last Record in the FileStore's memory chunk - MemFsPtr &m_lastRec; + FsSize_t &m_lastRec; Record *m_root; public: @@ -75,7 +75,7 @@ class FileStore { * @param data the contents of the file * @param dataLen the number of bytes data points to */ - void write(RecordId id, uint8_t *data, MemFsPtr dataLen); + void write(RecordId id, uint8_t *data, FsSize_t dataLen); /** * Reads the "file" at the given id. You are responsible for freeing @@ -85,7 +85,11 @@ class FileStore { * @param size pointer to a value that will be assigned the size of data * @return 0 if read is a success */ - int read(RecordId id, uint8_t *data, MemFsPtr *size); + int read(RecordId id, uint8_t *data, FsSize_t *size); + + static uint8_t version(); + + static uint8_t *format(uint8_t *buffer, size_t size, bool hasDirectories); private: /** @@ -95,13 +99,13 @@ class FileStore { * @param pathLen number of characters in pathLen * @return the requested Record, if available */ - Record *getRecord(Record *root, RecordId id); + Record *getRecord(FileStore::Record *root, RecordId id); /** * Gets an address for a new Record. * @param size the size of the Record */ - void *alloc(MemFsPtr size); + void *alloc(FsSize_t size); /** * Compresses all of the records into a contiguous space, starting at m_root. @@ -113,32 +117,200 @@ class FileStore { * If the record already exists, it replaces the old on deletes it. * @return true if the record was inserted */ - bool insert(Record *root, Record *insertValue, MemFsPtr *rootParentPtr = 0); + bool insert(Record *root, Record *insertValue, FsSize_t *rootParentPtr = 0); /** - * Gets the MemFsPtr associated with the next Record to be allocated. - * @retrun the MemFsPtr associated with the next Record to be allocated + * Gets the FsSize_t associated with the next Record to be allocated. + * @retrun the FsSize_t associated with the next Record to be allocated */ - MemFsPtr iterator(); + FsSize_t iterator(); /** - * Converts an actual pointer to a MemFsPtr. + * Converts an actual pointer to a FsSize_t. */ - MemFsPtr ptr(void *ptr); + FsSize_t ptr(void *ptr); /** - * Converts a MemFsPtr to an actual pointer. + * Converts a FsSize_t to an actual pointer. */ template - T ptr(MemFsPtr ptr); + T ptr(FsSize_t ptr) { + return (T) m_begin + ptr; + }; }; -template -T FileStore::ptr(MemFsPtr ptr) { - return (T) m_begin + ptr; +template +FsSize_t FileStore::Record::size() { + return offsetof(FileStore::Record, m_id) + dataLen; } -uint8_t *initFs(uint8_t *buffer, size_t size, bool hasDirectories); +template +void FileStore::Record::setId(RecordId id) { + this->m_id = id; +} + +template +void FileStore::Record::setData(uint8_t *data, int size) { + memcpy(this + m_data, data, size); + m_data = size; +} + + +// FileStore + +template +FileStore::FileStore(uint8_t *begin, uint8_t *end, Error *error): m_version(*((uint32_t*) begin)), m_lastRec(*(FsSize_t*) (begin + sizeof(m_version))) { + if (version() != m_version) { + // version mismatch + if (error) { + *error = 1; + } + } else { + // ok + m_begin = begin; + m_end = end; + m_root = (Record*) (begin + sizeof(FsSize_t)); + if (error) { + *error = 0; + } + } +} + +template +void FileStore::init() { + memset(m_begin, 0, m_end - m_begin); + m_version = version; +} + +template +void FileStore::write(RecordId id, uint8_t *data, FsSize_t dataLen) { + const FsSize_t size = offsetof(FileStore::Record, m_id) + dataLen; + auto rec = (Record*) alloc(size); + rec->dataLen = dataLen; + insert(m_root, rec); +} + +template +int FileStore::read(RecordId id, uint8_t *data, FsSize_t *size) { + auto rec = getRecord(m_root, id); + int retval = 1; + if (rec) { + if (size) { + *size = rec->dataLen; + } + memcpy(data, ptr(rec->m_data), rec->dataLen); + retval = 0; + } + return retval; +} + +template +typename FileStore::Record *FileStore::getRecord(FileStore::Record *root, RecordId id) { + auto cmp = root->m_id > id; + FsSize_t recPt; + if (cmp) { + recPt = root->left; + } else if (!cmp) { + recPt = root->right; + } else { + recPt = ptr(root); + } + if (recPt) { + return getRecord(ptr(recPt), id); + } else { + return ptr(recPt); + } +} + +template +void *FileStore::alloc(FsSize_t size) { + const auto iterator = this->iterator(); + if ((iterator + size) > (uint64_t) m_end) { + compress(); + if ((iterator + size) > (uint64_t) m_end) { + return nullptr; + } + } + ptr(m_lastRec)->next = iterator; + + auto rec = ptr(iterator); + memset(rec, 0, size); + ptr(iterator)->prev = m_lastRec; + m_lastRec = iterator; + return rec; +} + +template +void FileStore::compress() { + auto current = m_root; + while (current->next) { + auto prevEnd = current + current->size(); + current = ptr(current->next); + if (prevEnd != current) { + memcpy(prevEnd, current, current->size()); + current = prevEnd; + } + } +} + +template +bool FileStore::insert(Record *root, Record *insertValue, FsSize_t *rootParentPtr) { + auto cmp = root->m_id > insertValue->m_id; + if (cmp) { + if (root->left) { + return insert(ptr(root->left), insertValue, &root->left); + } else { + root->left = ((uint8_t*) insertValue) - m_begin; + return true; + } + } else if (!cmp) { + if (root->right) { + return insert(ptr(root->right), insertValue, &root->right); + } else { + root->right = ((uint8_t*) insertValue) - m_begin; + return true; + } + } else { + auto ivAddr = ((uint8_t*) insertValue) - m_begin; + if (root->prev) { + ptr(root->prev)->next = ivAddr; + } + if (root->next) { + ptr(root->next)->prev = ivAddr; + } + if (rootParentPtr) { + *rootParentPtr = ivAddr; + } + return true; + } + return false; +} + +template +FsSize_t FileStore::iterator() { + return m_lastRec + ((Record*) m_begin + m_lastRec)->size(); +} + +template +FsSize_t FileStore::ptr(void *ptr) { + return ((uint8_t*) ptr) - m_begin; +} + +template +uint8_t FileStore::version() { + return 0; +}; + +template +uint8_t *FileStore::format(uint8_t *buffer, size_t size, bool hasDirectories) { + auto retval = (typename FileStore::FsHeader*) buffer; + retval->version = FileStore::version(); + return (uint8_t*) retval; +} + +typedef FileStore FileStore16; +typedef FileStore FileStore32; +typedef FileStore FileStore64; } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 48bcfb4e6..b08972ccd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,8 +1,14 @@ cmake_minimum_required(VERSION 2.8.8) add_executable( - MemFsTest - test.cpp + Format + format.cpp ) -target_link_libraries(MemFsTest Memphis) +add_executable( + FsStore + fsstore.cpp +) + +target_link_libraries(Format WFS) +target_link_libraries(FsStore WFS) diff --git a/test/test.cpp b/test/format.cpp similarity index 82% rename from test/test.cpp rename to test/format.cpp index 7eb4e41a6..afef2e242 100644 --- a/test/test.cpp +++ b/test/format.cpp @@ -13,7 +13,7 @@ int main() { const auto size = 1 << 16; uint8_t volume[size]; uint32_t err; - initFs(volume, size, false); - FileStore(volume, volume + size, &err); + FileStore32::format(volume, size, false); + FileStore32(volume, volume + size, &err); return err; } diff --git a/test/fsstore.cpp b/test/fsstore.cpp new file mode 100644 index 000000000..82394265d --- /dev/null +++ b/test/fsstore.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 2015 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 + +using namespace wombat::fs; + +int main() { + const auto size = 1 << 16; + uint8_t volume[size]; + char out[6]; + uint32_t err; + FileStore32 fs(volume, volume + size, &err); + fs.write(42, (uint8_t*) "Hello", 6); + err = fs.read(42, (uint8_t*) out, nullptr); + return err; +}