Add write to new FileStore
This commit is contained in:
parent
4d86f0e3d9
commit
efe8bf3e46
184
deps/ox/src/ox/fs/filestore/filestoretemplate.hpp
vendored
184
deps/ox/src/ox/fs/filestore/filestoretemplate.hpp
vendored
@ -15,12 +15,12 @@ namespace ox::fs {
|
||||
|
||||
template<typename size_t>
|
||||
struct __attribute__((packed)) FileStoreItem: public Item<size_t> {
|
||||
private:
|
||||
ox::LittleEndian<size_t> id = 0;
|
||||
ox::LittleEndian<size_t> fileType = 0;
|
||||
ox::LittleEndian<size_t> links = 0;
|
||||
ox::LittleEndian<size_t> left = 0;
|
||||
ox::LittleEndian<size_t> right = 0;
|
||||
|
||||
public:
|
||||
explicit FileStoreItem(size_t size): Item<size_t>(size) {
|
||||
}
|
||||
|
||||
@ -33,6 +33,8 @@ template<typename size_t>
|
||||
class FileStoreTemplate: public FileStore {
|
||||
|
||||
private:
|
||||
using ItemPtr = typename ox::fs::NodeBuffer<size_t, FileStoreItem<uint32_t>>::ItemPtr;
|
||||
|
||||
struct __attribute__((packed)) FileStoreData {
|
||||
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 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<typename size_t>
|
||||
@ -82,40 +112,64 @@ FileStoreTemplate<size_t>::FileStoreTemplate(void *buff, size_t buffSize) {
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::format() {
|
||||
Error err = 0;
|
||||
new (m_buffer) NodeBuffer<size_t, FileStoreItem<uint32_t>>(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<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::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<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::write(InodeId_t id, void *data, InodeId_t dataLen, uint8_t fileType) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::incLinks(InodeId_t id) {
|
||||
auto item = find(id);
|
||||
if (item.valid()) {
|
||||
item->links++;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
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;
|
||||
}
|
||||
|
||||
@ -141,17 +195,107 @@ InodeId_t FileStoreTemplate<size_t>::spaceNeeded(InodeId_t size) {
|
||||
|
||||
template<typename size_t>
|
||||
InodeId_t FileStoreTemplate<size_t>::size() {
|
||||
return 1;
|
||||
return m_buffer->size();
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
InodeId_t FileStoreTemplate<size_t>::available() {
|
||||
return 1;
|
||||
return m_buffer->available();
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
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>;
|
||||
|
40
deps/ox/src/ox/fs/filestore/nodebuffer.hpp
vendored
40
deps/ox/src/ox/fs/filestore/nodebuffer.hpp
vendored
@ -15,7 +15,7 @@ namespace ox::fs {
|
||||
template<typename size_t, typename Item>
|
||||
class __attribute__((packed)) NodeBuffer {
|
||||
|
||||
private:
|
||||
public:
|
||||
struct __attribute__((packed)) Header {
|
||||
ox::LittleEndian<size_t> size = 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)> {
|
||||
inline ItemPtr() = default;
|
||||
|
||||
inline ItemPtr(std::nullptr_t) {
|
||||
}
|
||||
|
||||
inline ItemPtr(void *dataStart, size_t dataSize, size_t itemOffset, size_t 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);
|
||||
if (itemOffset >= sizeof(Header) and
|
||||
itemSpace >= static_cast<size_t>(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<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::lastItem()
|
||||
if (first.valid()) {
|
||||
return prev(first);
|
||||
}
|
||||
return ItemPtr();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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 ItemPtr();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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>
|
||||
bool NodeBuffer<size_t, Item>::valid(size_t maxSize) {
|
||||
return m_header.size <= maxSize;
|
||||
@ -184,11 +198,16 @@ size_t NodeBuffer<size_t, Item>::available() {
|
||||
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>
|
||||
void NodeBuffer<size_t, Item>::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<size_t, Item>::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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
31
deps/ox/src/ox/fs/filestore/ptr.hpp
vendored
31
deps/ox/src/ox/fs/filestore/ptr.hpp
vendored
@ -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<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>
|
||||
inline Ptr<T, size_t, minOffset>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t 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>
|
||||
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>
|
||||
@ -72,8 +84,16 @@ inline size_t Ptr<T, size_t, minOffset>::end() {
|
||||
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>
|
||||
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->())");
|
||||
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>
|
||||
inline Ptr<T, size_t, minOffset>::operator size_t() const {
|
||||
if (valid()) {
|
||||
if (m_dataStart and m_itemOffset) {
|
||||
return m_itemOffset;
|
||||
}
|
||||
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>
|
||||
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*())");
|
||||
return *static_cast<T>(this);
|
||||
}
|
||||
|
||||
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
|
||||
m_dataStart = static_cast<uint8_t*>(dataStart);
|
||||
if (itemSize >= sizeof(T) and
|
||||
dataStart and
|
||||
itemStart >= minOffset and
|
||||
itemStart + itemSize <= dataSize) {
|
||||
m_dataStart = static_cast<uint8_t*>(dataStart);
|
||||
m_itemOffset = itemStart;
|
||||
m_itemSize = itemSize;
|
||||
}
|
||||
|
6
deps/ox/src/ox/std/types.hpp
vendored
6
deps/ox/src/ox/std/types.hpp
vendored
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user