Add write to new FileStore

This commit is contained in:
Gary Talent 2018-03-10 23:31:21 -06:00
parent 4d86f0e3d9
commit efe8bf3e46
4 changed files with 240 additions and 43 deletions

View File

@ -15,24 +15,26 @@ namespace ox::fs {
template<typename size_t> template<typename size_t>
struct __attribute__((packed)) FileStoreItem: public Item<size_t> { struct __attribute__((packed)) FileStoreItem: public Item<size_t> {
private: ox::LittleEndian<size_t> id = 0;
ox::LittleEndian<size_t> id = 0; ox::LittleEndian<size_t> fileType = 0;
ox::LittleEndian<size_t> left = 0; ox::LittleEndian<size_t> links = 0;
ox::LittleEndian<size_t> right = 0; ox::LittleEndian<size_t> left = 0;
ox::LittleEndian<size_t> right = 0;
public: explicit FileStoreItem(size_t size): Item<size_t>(size) {
explicit FileStoreItem(size_t size): Item<size_t>(size) { }
}
ox::fs::Ptr<uint8_t, size_t> data() { ox::fs::Ptr<uint8_t, size_t> data() {
return Ptr<uint8_t, size_t>(this, this->size(), sizeof(*this), this->size() - sizeof(*this)); return Ptr<uint8_t, size_t>(this, this->size(), sizeof(*this), this->size() - sizeof(*this));
} }
}; };
template<typename size_t> template<typename size_t>
class FileStoreTemplate: public FileStore { class FileStoreTemplate: public FileStore {
private: private:
using ItemPtr = typename ox::fs::NodeBuffer<size_t, FileStoreItem<uint32_t>>::ItemPtr;
struct __attribute__((packed)) FileStoreData { struct __attribute__((packed)) FileStoreData {
ox::LittleEndian<size_t> rootNode = sizeof(NodeBuffer<size_t, FileStoreItem<uint32_t>>); ox::LittleEndian<size_t> rootNode = sizeof(NodeBuffer<size_t, FileStoreItem<uint32_t>>);
}; };
@ -47,12 +49,12 @@ class FileStoreTemplate: public FileStore {
Error setSize(InodeId_t buffSize); 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 incLinks(InodeId_t id);
Error decLinks(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, void *data, InodeId_t *size);
Error read(InodeId_t id, InodeId_t readStart, InodeId_t readSize, 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: private:
FileStoreData &fileStoreData(); 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<typename size_t> template<typename size_t>
@ -82,40 +112,64 @@ FileStoreTemplate<size_t>::FileStoreTemplate(void *buff, size_t buffSize) {
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::format() { Error FileStoreTemplate<size_t>::format() {
Error err = 0;
new (m_buffer) NodeBuffer<size_t, FileStoreItem<uint32_t>>(m_buffSize); new (m_buffer) NodeBuffer<size_t, FileStoreItem<uint32_t>>(m_buffSize);
auto data = m_buffer->malloc(sizeof(FileStoreData)); auto data = m_buffer->malloc(sizeof(FileStoreData));
if (data.valid()) { if (data.valid()) {
new (data->data()) FileStoreData; new (data->data()) FileStoreData;
} else { return 0;
err = 1;
} }
return err; return 1;
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::setSize(InodeId_t size) { Error FileStoreTemplate<size_t>::setSize(InodeId_t size) {
Error err = 0;
if (m_buffSize >= size) { if (m_buffSize >= size) {
err |= m_buffer->setSize(size); return m_buffer->setSize(size);
} else {
err = 1;
} }
return err;
}
template<typename size_t>
Error FileStoreTemplate<size_t>::write(InodeId_t id, void *data, InodeId_t dataLen, uint8_t fileType) {
return 1; return 1;
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::incLinks(InodeId_t id) { Error FileStoreTemplate<size_t>::incLinks(InodeId_t id) {
auto item = find(id);
if (item.valid()) {
item->links++;
return 0;
}
return 1; return 1;
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::decLinks(InodeId_t id) { Error FileStoreTemplate<size_t>::decLinks(InodeId_t id) {
auto item = find(id);
if (item.valid()) {
item->links--;
return 0;
}
return 1;
}
template<typename size_t>
Error FileStoreTemplate<size_t>::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; return 1;
} }
@ -141,17 +195,107 @@ InodeId_t FileStoreTemplate<size_t>::spaceNeeded(InodeId_t size) {
template<typename size_t> template<typename size_t>
InodeId_t FileStoreTemplate<size_t>::size() { InodeId_t FileStoreTemplate<size_t>::size() {
return 1; return m_buffer->size();
} }
template<typename size_t> template<typename size_t>
InodeId_t FileStoreTemplate<size_t>::available() { InodeId_t FileStoreTemplate<size_t>::available() {
return 1; return m_buffer->available();
} }
template<typename size_t> template<typename size_t>
typename FileStoreTemplate<size_t>::FileStoreData &FileStoreTemplate<size_t>::fileStoreData() { typename FileStoreTemplate<size_t>::FileStoreData &FileStoreTemplate<size_t>::fileStoreData() {
return *reinterpret_cast<FileStoreData*>(m_buffer->firstItem()); return *reinterpret_cast<FileStoreData*>(m_buffer->firstItem()->data().get());
}
template<typename size_t>
void FileStoreTemplate<size_t>::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 size_t>
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::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 size_t>
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::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 size_t>
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::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 size_t>
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::rootInode() {
return m_buffer->ptr(fileStoreData().rootNode);
}
template<typename size_t>
bool FileStoreTemplate<size_t>::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<uint16_t>; using FileStore16 = FileStoreTemplate<uint16_t>;

View File

@ -15,7 +15,7 @@ namespace ox::fs {
template<typename size_t, typename Item> template<typename size_t, typename Item>
class __attribute__((packed)) NodeBuffer { class __attribute__((packed)) NodeBuffer {
private: public:
struct __attribute__((packed)) Header { struct __attribute__((packed)) Header {
ox::LittleEndian<size_t> size = sizeof(Header); ox::LittleEndian<size_t> size = sizeof(Header);
ox::LittleEndian<size_t> bytesUsed = sizeof(Header); ox::LittleEndian<size_t> bytesUsed = sizeof(Header);
@ -25,6 +25,9 @@ class __attribute__((packed)) NodeBuffer {
struct ItemPtr: public ox::fs::Ptr<Item, size_t, sizeof(Header)> { struct ItemPtr: public ox::fs::Ptr<Item, size_t, sizeof(Header)> {
inline ItemPtr() = default; inline ItemPtr() = default;
inline ItemPtr(std::nullptr_t) {
}
inline ItemPtr(void *dataStart, size_t dataSize, size_t itemOffset, size_t size): inline ItemPtr(void *dataStart, size_t dataSize, size_t itemOffset, size_t size):
Ptr<Item, size_t, sizeof(Header)>(dataStart, dataSize, itemOffset, size) { Ptr<Item, size_t, sizeof(Header)>(dataStart, dataSize, itemOffset, size) {
} }
@ -35,8 +38,8 @@ class __attribute__((packed)) NodeBuffer {
auto item = reinterpret_cast<Item*>(static_cast<uint8_t*>(dataStart) + itemOffset); auto item = reinterpret_cast<Item*>(static_cast<uint8_t*>(dataStart) + itemOffset);
if (itemOffset >= sizeof(Header) and if (itemOffset >= sizeof(Header) and
itemSpace >= static_cast<size_t>(sizeof(Item)) and itemSpace >= static_cast<size_t>(sizeof(Item)) and
itemSpace >= item->size()) { itemSpace >= item->fullSize()) {
this->init(dataStart, dataSize, itemOffset, item->size()); this->init(dataStart, dataSize, itemOffset, sizeof(item) + item->fullSize());
} else { } else {
this->init(dataStart, dataSize, 0, 0); this->init(dataStart, dataSize, 0, 0);
} }
@ -77,6 +80,12 @@ class __attribute__((packed)) NodeBuffer {
*/ */
size_t available(); size_t available();
/**
* @return the actual number a bytes need to store the given number of
* bytes
*/
size_t spaceNeeded(size_t size);
private: private:
void compact(void (*cb)(ItemPtr itemMoved)); void compact(void (*cb)(ItemPtr itemMoved));
@ -100,7 +109,7 @@ typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::lastItem()
if (first.valid()) { if (first.valid()) {
return prev(first); return prev(first);
} }
return ItemPtr(); return nullptr;
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>
@ -147,7 +156,7 @@ typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::malloc(size
} }
return out; return out;
} }
return ItemPtr(); return nullptr;
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>
@ -174,6 +183,11 @@ Error NodeBuffer<size_t, Item>::setSize(size_t size) {
} }
} }
template<typename size_t, typename Item>
size_t NodeBuffer<size_t, Item>::size() {
return m_header.size;
}
template<typename size_t, typename Item> template<typename size_t, typename Item>
bool NodeBuffer<size_t, Item>::valid(size_t maxSize) { bool NodeBuffer<size_t, Item>::valid(size_t maxSize) {
return m_header.size <= maxSize; return m_header.size <= maxSize;
@ -184,11 +198,16 @@ size_t NodeBuffer<size_t, Item>::available() {
return m_header.size - m_header.bytesUsed; return m_header.size - m_header.bytesUsed;
} }
template<typename size_t, typename Item>
size_t NodeBuffer<size_t, Item>::spaceNeeded(size_t size) {
return sizeof(Item) + size;
}
template<typename size_t, typename Item> template<typename size_t, typename Item>
void NodeBuffer<size_t, Item>::compact(void (*cb)(ItemPtr)) { void NodeBuffer<size_t, Item>::compact(void (*cb)(ItemPtr)) {
auto src = firstItem(); auto src = firstItem();
auto dest = data(); auto dest = data();
while (src.valid()) { while (src.valid() && dest.valid()) {
// move node // move node
ox_memcpy(dest, src, src.size()); ox_memcpy(dest, src, src.size());
if (cb) { if (cb) {
@ -205,7 +224,7 @@ void NodeBuffer<size_t, Item>::compact(void (*cb)(ItemPtr)) {
} }
// update iterators // update iterators
src = ptr(dest->next); src = ptr(dest->next);
dest += ptr(dest)->size; dest += ptr(dest).size();
} }
} }
@ -232,6 +251,13 @@ struct __attribute__((packed)) Item {
size_t size() const { size_t size() const {
return m_size; return m_size;
} }
/**
* @return the size of the data + the size of the Item type
*/
size_t fullSize() const {
return sizeof(*this) + m_size;
}
}; };
} }

View File

@ -20,10 +20,15 @@ class Ptr {
uint8_t *m_dataStart = nullptr; uint8_t *m_dataStart = nullptr;
size_t m_itemOffset = 0; size_t m_itemOffset = 0;
size_t m_itemSize = 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: public:
inline Ptr() = default; inline Ptr() = default;
inline Ptr(std::nullptr_t);
inline Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T)); inline Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T));
inline bool valid() const; inline bool valid() const;
@ -34,6 +39,8 @@ class Ptr {
inline size_t end(); inline size_t end();
inline T *get() const;
inline T *operator->() const; inline T *operator->() const;
inline operator T*() const; inline operator T*() const;
@ -43,10 +50,14 @@ class Ptr {
inline T &operator*() const; inline T &operator*() const;
protected: 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<typename T, typename size_t, size_t minOffset>
inline Ptr<T, size_t, minOffset>::Ptr(std::nullptr_t) {
}
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
inline Ptr<T, size_t, minOffset>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) { inline Ptr<T, size_t, minOffset>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) {
init(dataStart, dataSize, itemStart, itemSize); init(dataStart, dataSize, itemStart, itemSize);
@ -54,7 +65,8 @@ inline Ptr<T, size_t, minOffset>::Ptr(void *dataStart, size_t dataSize, size_t i
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
inline bool Ptr<T, size_t, minOffset>::valid() const { inline bool Ptr<T, size_t, minOffset>::valid() const {
return m_dataStart and m_itemOffset; m_validated = m_dataStart != nullptr;
return m_validated;
} }
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
@ -72,8 +84,16 @@ inline size_t Ptr<T, size_t, minOffset>::end() {
return m_itemOffset + m_itemSize; return m_itemOffset + m_itemSize;
} }
template<typename T, typename size_t, size_t minOffset>
inline T *Ptr<T, size_t, minOffset>::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<T*>(m_dataStart + m_itemOffset);
}
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
inline T *Ptr<T, size_t, minOffset>::operator->() const { inline T *Ptr<T, size_t, minOffset>::operator->() const {
ox_assert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator->())");
ox_assert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())"); ox_assert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())");
return reinterpret_cast<T*>(m_dataStart + m_itemOffset); return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
} }
@ -85,7 +105,7 @@ inline Ptr<T, size_t, minOffset>::operator T*() const {
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
inline Ptr<T, size_t, minOffset>::operator size_t() const { inline Ptr<T, size_t, minOffset>::operator size_t() const {
if (valid()) { if (m_dataStart and m_itemOffset) {
return m_itemOffset; return m_itemOffset;
} }
return 0; return 0;
@ -93,18 +113,19 @@ inline Ptr<T, size_t, minOffset>::operator size_t() const {
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
inline T &Ptr<T, size_t, minOffset>::operator*() const { inline T &Ptr<T, size_t, minOffset>::operator*() const {
ox_assert(m_validated, "Unvalidated pointer dereference. (ox::fs::Ptr::operator*())");
ox_assert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())"); ox_assert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())");
return *static_cast<T>(this); return *static_cast<T>(this);
} }
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
void Ptr<T, size_t, minOffset>::init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) { inline void Ptr<T, size_t, minOffset>::init(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize) {
// do some sanity checks before assuming this is valid // do some sanity checks before assuming this is valid
m_dataStart = static_cast<uint8_t*>(dataStart);
if (itemSize >= sizeof(T) and if (itemSize >= sizeof(T) and
dataStart and dataStart and
itemStart >= minOffset and itemStart >= minOffset and
itemStart + itemSize <= dataSize) { itemStart + itemSize <= dataSize) {
m_dataStart = static_cast<uint8_t*>(dataStart);
m_itemOffset = itemStart; m_itemOffset = itemStart;
m_itemSize = itemSize; m_itemSize = itemSize;
} }

View File

@ -51,6 +51,12 @@ typedef uint32_t uintptr_t;
#error size_t, intptr_t, and uintptr_t undefined #error size_t, intptr_t, and uintptr_t undefined
#endif #endif
namespace std {
typedef decltype(nullptr) nullptr_t;
}
static_assert(sizeof(int8_t) == 1, "int8_t is wrong size"); 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(int16_t) == 2, "int16_t is wrong size");
static_assert(sizeof(int32_t) == 4, "int32_t is wrong size"); static_assert(sizeof(int32_t) == 4, "int32_t is wrong size");