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,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>;

View File

@ -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;
}
};
}

View File

@ -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;
}

View File

@ -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");