From efe8bf3e46be63247fb97bc1011933f5a8775b9f Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sat, 10 Mar 2018 23:31:21 -0600 Subject: [PATCH] Add write to new FileStore --- .../src/ox/fs/filestore/filestoretemplate.hpp | 200 +++++++++++++++--- deps/ox/src/ox/fs/filestore/nodebuffer.hpp | 40 +++- deps/ox/src/ox/fs/filestore/ptr.hpp | 37 +++- deps/ox/src/ox/std/types.hpp | 6 + 4 files changed, 240 insertions(+), 43 deletions(-) diff --git a/deps/ox/src/ox/fs/filestore/filestoretemplate.hpp b/deps/ox/src/ox/fs/filestore/filestoretemplate.hpp index e3009adc..863ff316 100644 --- a/deps/ox/src/ox/fs/filestore/filestoretemplate.hpp +++ b/deps/ox/src/ox/fs/filestore/filestoretemplate.hpp @@ -15,24 +15,26 @@ namespace ox::fs { template struct __attribute__((packed)) FileStoreItem: public Item { - private: - ox::LittleEndian id = 0; - ox::LittleEndian left = 0; - ox::LittleEndian right = 0; + ox::LittleEndian id = 0; + ox::LittleEndian fileType = 0; + ox::LittleEndian links = 0; + ox::LittleEndian left = 0; + ox::LittleEndian right = 0; - public: - explicit FileStoreItem(size_t size): Item(size) { - } + explicit FileStoreItem(size_t size): Item(size) { + } - ox::fs::Ptr data() { - return Ptr(this, this->size(), sizeof(*this), this->size() - sizeof(*this)); - } + ox::fs::Ptr data() { + return Ptr(this, this->size(), sizeof(*this), this->size() - sizeof(*this)); + } }; template class FileStoreTemplate: public FileStore { private: + using ItemPtr = typename ox::fs::NodeBuffer>::ItemPtr; + struct __attribute__((packed)) FileStoreData { ox::LittleEndian rootNode = sizeof(NodeBuffer>); }; @@ -47,12 +49,12 @@ class FileStoreTemplate: public FileStore { Error setSize(InodeId_t buffSize); - Error write(InodeId_t id, void *data, InodeId_t dataLen, uint8_t fileType = 0); - Error incLinks(InodeId_t id); Error decLinks(InodeId_t id); + Error write(InodeId_t id, void *data, InodeId_t dataLen, uint8_t fileType = 0); + Error read(InodeId_t id, void *data, InodeId_t *size); Error read(InodeId_t id, InodeId_t readStart, InodeId_t readSize, void *data, InodeId_t *size); @@ -68,6 +70,34 @@ class FileStoreTemplate: public FileStore { private: FileStoreData &fileStoreData(); + /** + * Places the given Item at the given ID. If it already exists, the + * existing value will be overwritten. + */ + void placeItem(ItemPtr root, ItemPtr item); + + /** + * Finds the parent an inode by its ID. + */ + ItemPtr findParent(ItemPtr ptr, size_t id); + + /** + * Finds an inode by its ID. + */ + ItemPtr find(ItemPtr ptr, size_t id); + + /** + * Finds an inode by its ID. + */ + ItemPtr find(size_t id); + + /** + * Gets the root inode. + */ + ItemPtr rootInode(); + + bool canWrite(InodeId_t id, size_t size); + }; template @@ -82,40 +112,64 @@ FileStoreTemplate::FileStoreTemplate(void *buff, size_t buffSize) { template Error FileStoreTemplate::format() { - Error err = 0; new (m_buffer) NodeBuffer>(m_buffSize); auto data = m_buffer->malloc(sizeof(FileStoreData)); if (data.valid()) { new (data->data()) FileStoreData; - } else { - err = 1; + return 0; } - return err; + return 1; } template Error FileStoreTemplate::setSize(InodeId_t size) { - Error err = 0; if (m_buffSize >= size) { - err |= m_buffer->setSize(size); - } else { - err = 1; + return m_buffer->setSize(size); } - return err; -} - -template -Error FileStoreTemplate::write(InodeId_t id, void *data, InodeId_t dataLen, uint8_t fileType) { return 1; } template Error FileStoreTemplate::incLinks(InodeId_t id) { + auto item = find(id); + if (item.valid()) { + item->links++; + return 0; + } return 1; } template Error FileStoreTemplate::decLinks(InodeId_t id) { + auto item = find(id); + if (item.valid()) { + item->links--; + return 0; + } + return 1; +} + +template +Error FileStoreTemplate::write(InodeId_t id, void *data, InodeId_t dataSize, uint8_t fileType) { + // TODO: delete the old node if it exists + if (canWrite(id, dataSize)) { + auto dest = m_buffer->malloc(dataSize); + // if first malloc failed, compact and try again + dest = m_buffer->malloc(dataSize); + if (dest.valid()) { + new (dest) FileStoreItem(dataSize); + dest->id = id; + dest->fileType = fileType; + ox_memcpy(dest->data(), data, dest->size()); + auto root = rootInode(); + if (root.valid()) { + placeItem(root, dest); + } else { + fileStoreData().rootNode = root; + } + return 0; + } + } return 1; } @@ -141,17 +195,107 @@ InodeId_t FileStoreTemplate::spaceNeeded(InodeId_t size) { template InodeId_t FileStoreTemplate::size() { - return 1; + return m_buffer->size(); } template InodeId_t FileStoreTemplate::available() { - return 1; + return m_buffer->available(); } template typename FileStoreTemplate::FileStoreData &FileStoreTemplate::fileStoreData() { - return *reinterpret_cast(m_buffer->firstItem()); + return *reinterpret_cast(m_buffer->firstItem()->data().get()); +} + +template +void FileStoreTemplate::placeItem(ItemPtr root, ItemPtr item) { + if (item->id > root->id) { + auto right = m_buffer->ptr(root->right); + if (right.valid()) { + placeItem(right, item); + } else { + root->right = root; + } + } else if (item->id < root->id) { + auto left = m_buffer->ptr(root->left); + if (left.valid()) { + placeItem(left, item); + } else { + root->left = root; + } + } +} + +template +typename FileStoreTemplate::ItemPtr FileStoreTemplate::findParent(ItemPtr item, size_t id) { + if (id > item->id) { + auto right = m_buffer->ptr(item->right); + if (right.valid()) { + if (right->id == id) { + return item; + } else { + return findParent(right, id); + } + } + } else if (id < item->id) { + auto left = m_buffer->ptr(item->left); + if (left.valid()) { + if (left->id == id) { + return item; + } else { + return findParent(left, id); + } + } + } + return nullptr; +} + +template +typename FileStoreTemplate::ItemPtr FileStoreTemplate::find(ItemPtr item, size_t id) { + if (item.valid()) { + if (id > item->id) { + return find(m_buffer->ptr(item->right), id); + } else if (id < item->id) { + return find(m_buffer->ptr(item->left), id); + } else { + return item; + } + } + return nullptr; +} + +template +typename FileStoreTemplate::ItemPtr FileStoreTemplate::find(size_t id) { + auto root = m_buffer->ptr(fileStoreData().rootNode); + if (root.valid()) { + auto item = find(root, id); + return item; + } + return nullptr; +} + +/** + * Gets the root inode. + */ +template +typename FileStoreTemplate::ItemPtr FileStoreTemplate::rootInode() { + return m_buffer->ptr(fileStoreData().rootNode); +} + +template +bool FileStoreTemplate::canWrite(InodeId_t id, size_t size) { + if (m_buffer->spaceNeeded(size) >= m_buffer->available()) { + return true; + } else { + auto existing = find(id); + if (existing.valid()) { + if (m_buffer->spaceNeeded(size) >= existing.size()) { + return true; + } + } + } + return false; } using FileStore16 = FileStoreTemplate; diff --git a/deps/ox/src/ox/fs/filestore/nodebuffer.hpp b/deps/ox/src/ox/fs/filestore/nodebuffer.hpp index 2080cc85..d1f333aa 100644 --- a/deps/ox/src/ox/fs/filestore/nodebuffer.hpp +++ b/deps/ox/src/ox/fs/filestore/nodebuffer.hpp @@ -15,7 +15,7 @@ namespace ox::fs { template class __attribute__((packed)) NodeBuffer { - private: + public: struct __attribute__((packed)) Header { ox::LittleEndian size = sizeof(Header); ox::LittleEndian bytesUsed = sizeof(Header); @@ -25,6 +25,9 @@ class __attribute__((packed)) NodeBuffer { struct ItemPtr: public ox::fs::Ptr { inline ItemPtr() = default; + inline ItemPtr(std::nullptr_t) { + } + inline ItemPtr(void *dataStart, size_t dataSize, size_t itemOffset, size_t size): Ptr(dataStart, dataSize, itemOffset, size) { } @@ -35,8 +38,8 @@ class __attribute__((packed)) NodeBuffer { auto item = reinterpret_cast(static_cast(dataStart) + itemOffset); if (itemOffset >= sizeof(Header) and itemSpace >= static_cast(sizeof(Item)) and - itemSpace >= item->size()) { - this->init(dataStart, dataSize, itemOffset, item->size()); + itemSpace >= item->fullSize()) { + this->init(dataStart, dataSize, itemOffset, sizeof(item) + item->fullSize()); } else { this->init(dataStart, dataSize, 0, 0); } @@ -77,6 +80,12 @@ class __attribute__((packed)) NodeBuffer { */ size_t available(); + /** + * @return the actual number a bytes need to store the given number of + * bytes + */ + size_t spaceNeeded(size_t size); + private: void compact(void (*cb)(ItemPtr itemMoved)); @@ -100,7 +109,7 @@ typename NodeBuffer::ItemPtr NodeBuffer::lastItem() if (first.valid()) { return prev(first); } - return ItemPtr(); + return nullptr; } template @@ -147,7 +156,7 @@ typename NodeBuffer::ItemPtr NodeBuffer::malloc(size } return out; } - return ItemPtr(); + return nullptr; } template @@ -174,6 +183,11 @@ Error NodeBuffer::setSize(size_t size) { } } +template +size_t NodeBuffer::size() { + return m_header.size; +} + template bool NodeBuffer::valid(size_t maxSize) { return m_header.size <= maxSize; @@ -184,11 +198,16 @@ size_t NodeBuffer::available() { return m_header.size - m_header.bytesUsed; } +template +size_t NodeBuffer::spaceNeeded(size_t size) { + return sizeof(Item) + size; +} + template void NodeBuffer::compact(void (*cb)(ItemPtr)) { auto src = firstItem(); auto dest = data(); - while (src.valid()) { + while (src.valid() && dest.valid()) { // move node ox_memcpy(dest, src, src.size()); if (cb) { @@ -205,7 +224,7 @@ void NodeBuffer::compact(void (*cb)(ItemPtr)) { } // update iterators src = ptr(dest->next); - dest += ptr(dest)->size; + dest += ptr(dest).size(); } } @@ -232,6 +251,13 @@ struct __attribute__((packed)) Item { size_t size() const { return m_size; } + + /** + * @return the size of the data + the size of the Item type + */ + size_t fullSize() const { + return sizeof(*this) + m_size; + } }; } diff --git a/deps/ox/src/ox/fs/filestore/ptr.hpp b/deps/ox/src/ox/fs/filestore/ptr.hpp index 43b31550..7ecb7a2e 100644 --- a/deps/ox/src/ox/fs/filestore/ptr.hpp +++ b/deps/ox/src/ox/fs/filestore/ptr.hpp @@ -20,10 +20,15 @@ class Ptr { uint8_t *m_dataStart = nullptr; size_t m_itemOffset = 0; size_t m_itemSize = 0; + // this should be removed later on, but the excessive validation is + // desirable during during heavy development + mutable uint8_t m_validated = false; public: inline Ptr() = default; + inline Ptr(std::nullptr_t); + inline Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T)); inline bool valid() const; @@ -34,6 +39,8 @@ class Ptr { inline size_t end(); + inline T *get() const; + inline T *operator->() const; inline operator T*() const; @@ -43,10 +50,14 @@ class Ptr { inline T &operator*() const; protected: - void init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize); + inline void init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize); }; +template +inline Ptr::Ptr(std::nullptr_t) { +} + template inline Ptr::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) { init(dataStart, dataSize, itemStart, itemSize); @@ -54,7 +65,8 @@ inline Ptr::Ptr(void *dataStart, size_t dataSize, size_t i template inline bool Ptr::valid() const { - return m_dataStart and m_itemOffset; + m_validated = m_dataStart != nullptr; + return m_validated; } template @@ -72,8 +84,16 @@ inline size_t Ptr::end() { return m_itemOffset + m_itemSize; } +template +inline T *Ptr::get() const { + ox_assert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::get())"); + ox_assert(valid(), "Invalid pointer access. (ox::fs::Ptr::get())"); + return reinterpret_cast(m_dataStart + m_itemOffset); +} + template inline T *Ptr::operator->() const { + ox_assert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator->())"); ox_assert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())"); return reinterpret_cast(m_dataStart + m_itemOffset); } @@ -85,7 +105,7 @@ inline Ptr::operator T*() const { template inline Ptr::operator size_t() const { - if (valid()) { + if (m_dataStart and m_itemOffset) { return m_itemOffset; } return 0; @@ -93,18 +113,19 @@ inline Ptr::operator size_t() const { template inline T &Ptr::operator*() const { + ox_assert(m_validated, "Unvalidated pointer dereference. (ox::fs::Ptr::operator*())"); ox_assert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())"); return *static_cast(this); } template -void Ptr::init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) { +inline void Ptr::init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) { // do some sanity checks before assuming this is valid - m_dataStart = static_cast(dataStart); if (itemSize >= sizeof(T) and - dataStart and - itemStart >= minOffset and - itemStart + itemSize <= dataSize) { + dataStart and + itemStart >= minOffset and + itemStart + itemSize <= dataSize) { + m_dataStart = static_cast(dataStart); m_itemOffset = itemStart; m_itemSize = itemSize; } diff --git a/deps/ox/src/ox/std/types.hpp b/deps/ox/src/ox/std/types.hpp index 2412d231..5db46d45 100644 --- a/deps/ox/src/ox/std/types.hpp +++ b/deps/ox/src/ox/std/types.hpp @@ -51,6 +51,12 @@ typedef uint32_t uintptr_t; #error size_t, intptr_t, and uintptr_t undefined #endif +namespace std { + +typedef decltype(nullptr) nullptr_t; + +} + static_assert(sizeof(int8_t) == 1, "int8_t is wrong size"); static_assert(sizeof(int16_t) == 2, "int16_t is wrong size"); static_assert(sizeof(int32_t) == 4, "int32_t is wrong size");