diff --git a/deps/ox/src/ox/fs/filestore/filestoretemplate.hpp b/deps/ox/src/ox/fs/filestore/filestoretemplate.hpp index c3afc3ba..d8aafc8b 100644 --- a/deps/ox/src/ox/fs/filestore/filestoretemplate.hpp +++ b/deps/ox/src/ox/fs/filestore/filestoretemplate.hpp @@ -87,7 +87,7 @@ class FileStoreTemplate: public FileStore { * @return 0 if read is a success */ template - int read(InodeId_t id, FsSize_t readStart, + Error read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, T *data, FsSize_t *size); @@ -104,12 +104,24 @@ class FileStoreTemplate: public FileStore { FileStoreData *fileStoreData(); + /** + * Places the given Item at the given ID. If it already exists, the + * existing value will be overwritten. + */ + Error placeItem(ItemPtr item); + /** * Places the given Item at the given ID. If it already exists, the * existing value will be overwritten. */ Error placeItem(ItemPtr root, ItemPtr item, int depth = 0); + /** + * Removes the given Item at the given ID. If it already exists, the + * existing value will be overwritten. + */ + Error unplaceItem(ItemPtr root, ItemPtr item, int depth = 0); + /** * Finds the parent an inode by its ID. */ @@ -152,12 +164,12 @@ Error FileStoreTemplate::format() { auto data = m_buffer->template dataOf(fsData); if (data.valid()) { new (data) FileStoreData; - return 0; + return OxError(0); } else { oxTrace("ox::fs::FileStoreTemplate::format::fail") << "Could not read data section of FileStoreData"; } } - return 1; + return OxError(1); } template @@ -165,7 +177,7 @@ Error FileStoreTemplate::setSize(InodeId_t size) { if (m_buffSize >= size) { return m_buffer->setSize(size); } - return 1; + return OxError(1); } template @@ -173,9 +185,9 @@ Error FileStoreTemplate::incLinks(InodeId_t id) { auto item = find(id); if (item.valid()) { item->links++; - return 0; + return OxError(0); } - return 1; + return OxError(1); } template @@ -183,9 +195,9 @@ Error FileStoreTemplate::decLinks(InodeId_t id) { auto item = find(id); if (item.valid()) { item->links--; - return 0; + return OxError(0); } - return 1; + return OxError(1); } template @@ -222,12 +234,12 @@ Error FileStoreTemplate::write(InodeId_t id, void *data, FsSize_t dataSi auto root = m_buffer->ptr(fsData->rootNode); if (root.valid()) { oxTrace("ox::fs::FileStoreTemplate::write") << "Placing" << dest->id << "on" << root->id << "at" << destData.offset(); - return placeItem(root, dest); + return placeItem(dest); } else { - oxTrace("ox::fs::FileStoreTemplate::write") << "Initializing root inode with offset of" << dest.offset() - << "and data size of" << destData.size(); + oxTrace("ox::fs::FileStoreTemplate::write") << "Initializing root inode ( offset:" << dest.offset() + << ", data size:" << destData.size() << ")"; fsData->rootNode = dest.offset(); - return 0; + return OxError(0); } } else { oxTrace("ox::fs::FileStoreTemplate::write::fail") << "Could not place item due to absence of FileStore header."; @@ -236,7 +248,7 @@ Error FileStoreTemplate::write(InodeId_t id, void *data, FsSize_t dataSi } m_buffer->free(dest); } - return 1; + return OxError(1); } template @@ -254,7 +266,7 @@ Error FileStoreTemplate::read(InodeId_t id, void *data, FsSize_t dataSiz if (size) { *size = src.size(); } - return 0; + return OxError(0); } else { oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not read data section of item:" << id; oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Item data section size:" << srcData.size(); @@ -262,7 +274,7 @@ Error FileStoreTemplate::read(InodeId_t id, void *data, FsSize_t dataSiz } else { oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not find requested item:" << id; } - return 1; + return OxError(1); } template @@ -277,7 +289,7 @@ Error FileStoreTemplate::read(InodeId_t id, FsSize_t readStart, FsSize_t if (size) { *size = sub.size(); } - return 0; + return OxError(0); } else { oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not read requested data sub-section of item:" << id; } @@ -287,12 +299,12 @@ Error FileStoreTemplate::read(InodeId_t id, FsSize_t readStart, FsSize_t } else { oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not find requested item:" << id; } - return 1; + return OxError(1); } template template -int FileStoreTemplate::read(InodeId_t id, FsSize_t readStart, +Error FileStoreTemplate::read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, T *data, FsSize_t *size) { auto src = find(id); if (src.valid()) { @@ -312,11 +324,11 @@ int FileStoreTemplate::read(InodeId_t id, FsSize_t readStart, if (size) { *size = sub.size(); } - return 0; + return OxError(0); } } } - return 1; + return OxError(1); } template @@ -374,30 +386,93 @@ typename FileStoreTemplate::FileStoreData *FileStoreTemplate::fi return nullptr; } +template +Error FileStoreTemplate::placeItem(ItemPtr item) { + auto fsData = fileStoreData(); + if (fsData) { + auto root = m_buffer->ptr(fsData->rootNode); + if (root.valid()) { + if (root->id == item->id) { + fsData->rootNode = item; + item->left = root->left; + item->right = root->right; + oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Overwrote Root Item:" << item->id; + return 0; + } else { + return placeItem(root, item); + } + } + } + return OxError(1); +} + template Error FileStoreTemplate::placeItem(ItemPtr root, ItemPtr item, int depth) { if (depth < 5000) { if (item->id > root->id) { auto right = m_buffer->ptr(root->right); if (!right.valid() || right->id == item->id) { - root->right = root.offset(); - return 0; + root->right = item.offset(); + if (right.valid()) { + item->left = right->left; + item->right = right->right; + } + oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Placed Item:" << item->id; + return OxError(0); } else { return placeItem(right, item, depth + 1); } } else if (item->id < root->id) { auto left = m_buffer->ptr(root->left); if (!left.valid() || left->id == item->id) { - root->left = root.offset(); - return 0; + root->left = item.offset(); + if (left.valid()) { + item->left = left->left; + item->right = left->right; + } + oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Placed Item:" << item->id; + return OxError(0); } else { return placeItem(left, item, depth + 1); } + } else { + oxTrace("ox::fs::FileStoreTemplate::placeItem::fail") << "Cannot insert an item on itself."; + return OxError(1); } } else { oxTrace("ox::fs::FileStoreTemplate::placeItem::fail") << "Excessive recursion depth, stopping before stack overflow."; + return OxError(2); } - return 1; +} + +template +Error FileStoreTemplate::unplaceItem(ItemPtr root, ItemPtr item, int depth) { + if (depth < 5000) { + if (item->id > root->id) { + auto right = m_buffer->ptr(root->right); + if (!right.valid() || right->id == item->id) { + root->right = item.offset(); + oxTrace("ox::fs::FileStoreTemplate::unplaceItem") << "Placed Item:" << item->id; + return OxError(0); + } else { + return unplaceItem(right, item, depth + 1); + } + } else if (item->id < root->id) { + auto left = m_buffer->ptr(root->left); + if (!left.valid() || left->id == item->id) { + root->left = item.offset(); + oxTrace("ox::fs::FileStoreTemplate::unplaceItem") << "Placed Item:" << item->id; + return OxError(0); + } else { + return unplaceItem(left, item, depth + 1); + } + } else { + oxTrace("ox::fs::FileStoreTemplate::unplaceItem::fail") << "Item already exists."; + } + } else { + oxTrace("ox::fs::FileStoreTemplate::unplaceItem::fail") << "Excessive recursion depth, stopping before stack overflow."; + } + return OxError(1); } template diff --git a/deps/ox/src/ox/fs/filesystem/pathiterator.cpp b/deps/ox/src/ox/fs/filesystem/pathiterator.cpp index f63b1010..25b35aab 100644 --- a/deps/ox/src/ox/fs/filesystem/pathiterator.cpp +++ b/deps/ox/src/ox/fs/filesystem/pathiterator.cpp @@ -24,22 +24,22 @@ PathIterator::PathIterator(const char *path): PathIterator(path, ox_strlen(path) /** * @return 0 if no error */ -int PathIterator::dirPath(char *out, std::size_t outSize) { +Error PathIterator::dirPath(char *out, std::size_t outSize) { int idx = ox_lastIndexOf(m_path, '/', m_maxSize); std::size_t size = idx + 1; if (idx >= 0 && size < outSize) { ox_memcpy(out, m_path, size); out[size] = 0; - return 0; + return OxError(0); } else { - return 1; + return OxError(1); } } /** * @return 0 if no error */ -int PathIterator::fileName(char *out, std::size_t outSize) { +Error PathIterator::fileName(char *out, std::size_t outSize) { auto idx = ox_lastIndexOf(m_path, '/', m_maxSize); if (idx >= 0) { idx++; // pass up the preceding / @@ -47,19 +47,51 @@ int PathIterator::fileName(char *out, std::size_t outSize) { if (fileNameSize < outSize) { ox_memcpy(out, &m_path[idx], fileNameSize); out[fileNameSize] = 0; - return 0; + return OxError(0); } else { - return 1; + return OxError(1); } } else { - return 2; + return OxError(2); } } -// Gets the next item in the path -int PathIterator::next(char *pathOut, std::size_t pathOutSize) { +// Gets the get item in the path +Error PathIterator::get(char *pathOut, std::size_t pathOutSize) { std::size_t size = 0; - int retval = 1; + Error retval = 1; + if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) { + retval = 0; + auto start = m_iterator; + if (m_path[start] == '/') { + start++; + } + // end is at the next / + const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); + // correct end if it is invalid, which happens if there is no next / + if (!substr) { + substr = ox_strchr(&m_path[start], 0, m_maxSize - start); + } + std::size_t end = substr - m_path; + size = end - start; + // cannot fit the output in the output parameter + if (size >= pathOutSize) { + return OxError(1); + } + ox_memcpy(pathOut, &m_path[start], size); + } + // truncate trailing / + if (size && pathOut[size - 1] == '/') { + size--; + } + pathOut[size] = 0; // end with null terminator + return OxError(retval); +} + +// Gets the get item in the path +Error PathIterator::next(char *pathOut, std::size_t pathOutSize) { + std::size_t size = 0; + Error retval = 1; if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) { retval = 0; if (m_path[m_iterator] == '/') { @@ -76,7 +108,7 @@ int PathIterator::next(char *pathOut, std::size_t pathOutSize) { size = end - start; // cannot fit the output in the output parameter if (size >= pathOutSize) { - return -1; + return OxError(1); } ox_memcpy(pathOut, &m_path[start], size); } @@ -86,13 +118,20 @@ int PathIterator::next(char *pathOut, std::size_t pathOutSize) { } pathOut[size] = 0; // end with null terminator m_iterator += size; - return retval; + return OxError(retval); } /** * @return 0 if no error */ -int PathIterator::next(BString *fileName) { +Error PathIterator::get(BString *fileName) { + return get(fileName->data(), fileName->cap()); +} + +/** + * @return 0 if no error + */ +Error PathIterator::next(BString *fileName) { return next(fileName->data(), fileName->cap()); } @@ -116,7 +155,7 @@ ValErr PathIterator::nextSize() const { size = end - start; } it += size; - return {size, retval}; + return {size, OxError(retval)}; } bool PathIterator::hasNext() const { @@ -138,12 +177,31 @@ bool PathIterator::hasNext() const { return size > 0; } -PathIterator PathIterator::operator+(int i) { - return PathIterator(m_path, m_maxSize, m_iterator + i); +bool PathIterator::valid() const { + return m_path[m_iterator] != 0; } -PathIterator PathIterator::operator-(int i) { - return PathIterator(m_path, m_maxSize, m_iterator - i); +PathIterator PathIterator::operator+(int i) const { + std::size_t size = 0; + Error retval = 1; + auto iterator = m_iterator; + if (iterator < m_maxSize && ox_strlen(&m_path[iterator])) { + retval = 0; + if (m_path[iterator] == '/') { + iterator++; + } + std::size_t start = iterator; + // end is at the next / + const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); + // correct end if it is invalid, which happens if there is no next / + if (!substr) { + substr = ox_strchr(&m_path[start], 0, m_maxSize - start); + } + std::size_t end = substr - m_path; + size = end - start; + } + iterator += size; + return PathIterator(m_path, m_maxSize, iterator + i); } } diff --git a/deps/ox/src/ox/fs/filesystem/pathiterator.hpp b/deps/ox/src/ox/fs/filesystem/pathiterator.hpp index cb2e7861..f68844cb 100644 --- a/deps/ox/src/ox/fs/filesystem/pathiterator.hpp +++ b/deps/ox/src/ox/fs/filesystem/pathiterator.hpp @@ -28,22 +28,32 @@ class PathIterator { /** * @return 0 if no error */ - int dirPath(char *pathOut, std::size_t pathOutSize); + Error dirPath(char *pathOut, std::size_t pathOutSize); /** * @return 0 if no error */ - int fileName(char *out, std::size_t outSize); + Error fileName(char *out, std::size_t outSize); /** * @return 0 if no error */ - int next(char *pathOut, std::size_t pathOutSize); + Error next(char *pathOut, std::size_t pathOutSize); /** * @return 0 if no error */ - int next(BString *fileName); + Error get(char *pathOut, std::size_t pathOutSize); + + /** + * @return 0 if no error + */ + Error next(BString *fileName); + + /** + * @return 0 if no error + */ + Error get(BString *fileName); /** * @return 0 if no error @@ -52,9 +62,9 @@ class PathIterator { bool hasNext() const; - PathIterator operator+(int i); + bool valid() const; - PathIterator operator-(int i); + PathIterator operator+(int i) const; }; diff --git a/deps/ox/src/ox/fs/filesystem2/directory.hpp b/deps/ox/src/ox/fs/filesystem2/directory.hpp index 6f6122ad..19aca689 100644 --- a/deps/ox/src/ox/fs/filesystem2/directory.hpp +++ b/deps/ox/src/ox/fs/filesystem2/directory.hpp @@ -18,52 +18,55 @@ namespace ox::fs { template struct __attribute__((packed)) DirectoryEntry { - struct __attribute__((packed)) DirectoryEntryData { - // DirectoryEntry fields - LittleEndian inode = 0; - char name[MaxFileNameLength]; - }; + public: + struct __attribute__((packed)) DirectoryEntryData { + // DirectoryEntry fields + LittleEndian inode = 0; + char name[MaxFileNameLength]; + }; - // NodeBuffer fields - LittleEndian prev = 0; - LittleEndian next = 0; + // NodeBuffer fields + LittleEndian prev = 0; + LittleEndian next = 0; - DirectoryEntry() = default; - DirectoryEntry(InodeId_t inode, const char *name) { - auto d = data(); - if (d.valid()) { - d->inode = inode; - ox_strncpy(d->name, name, MaxFileNameLength); + private: + LittleEndian m_bufferSize = sizeof(DirectoryEntry); + + public: + DirectoryEntry() = default; + + DirectoryEntry(InodeId_t inode, const char *name, InodeId_t bufferSize) { + auto d = data(); + if (d.valid()) { + d->inode = inode; + ox_strncpy(d->name, name, MaxFileNameLength); + m_bufferSize = bufferSize; + } } - } - ptrarith::Ptr data() { - return ptrarith::Ptr(this, this->fullSize(), sizeof(*this), this->size()); - } - - /** - * @return the size of the data + the size of the Item type - */ - InodeId_t fullSize() const { - const auto d = const_cast(this)->data(); - if (d.valid()) { - return sizeof(*this) + offsetof(DirectoryEntryData, name) + ox_strnlen(d->name, MaxFileNameLength); + ptrarith::Ptr data() { + return ptrarith::Ptr(this, this->fullSize(), sizeof(*this), this->size()); } - return 0; - } - InodeId_t size() const { - return fullSize() - offsetof(DirectoryEntryData, inode); - } + /** + * @return the size of the data + the size of the Item type + */ + InodeId_t fullSize() const { + return m_bufferSize; + } - void setSize(InodeId_t) { - // ignore set value - } + InodeId_t size() const { + return fullSize() - offsetof(DirectoryEntryData, inode); + } - static std::size_t spaceNeeded(std::size_t chars) { - return sizeof(DirectoryEntry) + chars; - } + void setSize(InodeId_t) { + // ignore set value + } + + static std::size_t spaceNeeded(std::size_t chars) { + return sizeof(DirectoryEntry) + offsetof(DirectoryEntryData, name) + chars; + } }; @@ -76,7 +79,6 @@ class Directory { InodeId_t m_inodeId = 0; std::size_t m_size = 0; - Buffer *m_buff = nullptr; FileStore *m_fs = nullptr; public: @@ -91,18 +93,17 @@ class Directory { Error rm(PathIterator it) noexcept; - ValErr find(const char *name) const noexcept; + ValErr find(const BString &name) const noexcept; }; template -Directory::Directory(FileStore *fs, InodeId_t id) { +Directory::Directory(FileStore *fs, InodeId_t inodeId) { m_fs = fs; - m_inodeId = id; - auto buff = fs->read(id).template to(); + m_inodeId = inodeId; + auto buff = fs->read(inodeId).template to(); if (buff.valid()) { m_size = buff.size(); - m_buff = buff; } } @@ -113,17 +114,37 @@ Error Directory::init() noexcept { auto buff = m_fs->read(m_inodeId); if (buff.valid()) { new (buff) Buffer(Size); - return 0; + m_size = Size; + return OxError(0); } - return 1; + m_size = 0; + return OxError(1); } template Error Directory::write(PathIterator path, InodeId_t inode) noexcept { - // find existing entry and update if exists + InodeId_t nextChild = 0; + if ((path + 1).hasNext()) { + oxTrace("ox::fs::Directory::write") << "Attempting to write to next sub-Directory"; - if (!path.hasNext()) { - Error err = 1; + // read the name and pop it off the stack as soon as possible to help + // avoid a stack overflow in the recursive calls + { + BString name; + path.get(&name); + nextChild = find(name); + } + + // It's important for the recursive call to be outside the block where name + // lived. This avoids allocation several BStrings on the + // stack at once, while also avoiding the use of heap memory. + if (nextChild) { + return Directory(m_fs, nextChild).write(path + 1, inode); + } + } else { + // insert the new entry on this directory + + // get the name BString name; path.next(&name); @@ -133,37 +154,50 @@ Error Directory::write(PathIterator path, InodeId_t inode) noexcept { const auto newSize = m_size + DirectoryEntry::spaceNeeded(name.size()); auto cpy = ox_malloca(newSize, Buffer, old); if (cpy != nullptr) { + // TODO: look for old version of this entry and delete it + cpy->setSize(newSize); auto val = cpy->malloc(name.size()); if (val.valid()) { - new (val) DirectoryEntry(inode, name.data()); - err = m_fs->write(m_inodeId, cpy, cpy->size()); + oxTrace("ox::fs::Directory::write") << "Attempting to write Directory to FileStore"; + new (val) DirectoryEntry(inode, name.data(), newSize); + return m_fs->write(m_inodeId, cpy, cpy->size()); + } else { + oxTrace("ox::fs::Directory::write::fail") << "Could not allocate memory for new directory entry"; } + } else { + oxTrace("ox::fs::Directory::write::fail") << "Could not allocate memory for copy of Directory"; } + } else { + oxTrace("ox::fs::Directory::write::fail") << "Could not read existing version of Directory"; } - return err; } - - // TODO: get sub directory and call its write instead of recursing on this directory - return write(path + 1, inode); + return OxError(1); } template Error Directory::rm(PathIterator) noexcept { - return 1; + return OxError(1); } template -ValErr Directory::find(const char *name) const noexcept { - ValErr retval = {0, 1}; +ValErr Directory::find(const BString &name) const noexcept { + oxTrace("ox::fs::Directory::find") << name.c_str(); auto buff = m_fs->read(m_inodeId).template to(); - for (auto i = buff->iterator(); i.hasNext(); i.next()) { - auto data = i->data(); - if (data.valid() && data->name == name) { - retval = static_cast(data->inode); + if (buff.valid()) { + oxTrace("ox::fs::Directory::find") << "Found directory buffer."; + for (auto i = buff->iterator(); i.valid(); i.next()) { + auto data = i->data(); + oxTrace("ox::fs::Directory::find::name") << name.c_str(); + if (data.valid() && data->name == name.c_str()) { + return static_cast(data->inode); + } } + oxTrace("ox::fs::Directory::find::fail"); + } else { + oxTrace("ox::fs::Directory::find::fail") << "Could not find directory buffer"; } - return retval; + return {0, OxError(1)}; } diff --git a/deps/ox/src/ox/fs/test/CMakeLists.txt b/deps/ox/src/ox/fs/test/CMakeLists.txt index c0c9308b..f2c392b2 100644 --- a/deps/ox/src/ox/fs/test/CMakeLists.txt +++ b/deps/ox/src/ox/fs/test/CMakeLists.txt @@ -60,6 +60,7 @@ add_test("Test\\ PathIterator::next2" FSTests PathIterator::next2) add_test("Test\\ PathIterator::next3" FSTests PathIterator::next3) add_test("Test\\ PathIterator::next4" FSTests PathIterator::next4) add_test("Test\\ PathIterator::next5" FSTests PathIterator::next5) +add_test("Test\\ PathIterator::hasNext" FSTests PathIterator::hasNext) add_test("Test\\ PathIterator::dirPath" FSTests PathIterator::dirPath) add_test("Test\\ PathIterator::fileName" FSTests PathIterator::fileName) diff --git a/deps/ox/src/ox/fs/test/tests.cpp b/deps/ox/src/ox/fs/test/tests.cpp index 78d40e71..6129a01d 100644 --- a/deps/ox/src/ox/fs/test/tests.cpp +++ b/deps/ox/src/ox/fs/test/tests.cpp @@ -32,9 +32,7 @@ map tests = { int retval = 0; string path = "/usr/share/charset.gbag"; PathIterator it(path.c_str(), path.size()); - const auto buffSize = 1024; - char buff[buffSize]; - assert(buffSize >= path.size()); + auto buff = static_cast(ox_alloca(path.size() + 1)); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0); @@ -47,9 +45,7 @@ map tests = { int retval = 0; string path = "/usr/share/"; PathIterator it(path.c_str(), path.size()); - const auto buffSize = 1024; - char buff[buffSize]; - assert(buffSize >= path.size()); + auto buff = static_cast(ox_alloca(path.size() + 1)); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0); return retval; @@ -61,9 +57,7 @@ map tests = { int retval = 0; string path = "/"; PathIterator it(path.c_str(), path.size()); - const auto buffSize = 1024; - char buff[buffSize]; - assert(buffSize >= path.size()); + auto buff = static_cast(ox_alloca(path.size() + 1)); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "\0") == 0); return retval; } @@ -74,9 +68,7 @@ map tests = { int retval = 0; string path = "usr/share/charset.gbag"; PathIterator it(path.c_str(), path.size()); - const auto buffSize = 1024; - char buff[buffSize]; - assert(buffSize >= path.size()); + auto buff = static_cast(ox_alloca(path.size() + 1)); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0); @@ -89,9 +81,7 @@ map tests = { int retval = 0; string path = "usr/share/"; PathIterator it(path.c_str(), path.size()); - const auto buffSize = 1024; - char buff[buffSize]; - assert(buffSize >= path.size()); + auto buff = static_cast(ox_alloca(path.size() + 1)); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0); retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0); return retval; @@ -103,9 +93,7 @@ map tests = { int retval = 0; string path = "/usr/share/charset.gbag"; PathIterator it(path.c_str(), path.size()); - const auto buffSize = 1024; - char buff[buffSize]; - assert(buffSize >= path.size()); + auto buff = static_cast(ox_alloca(path.size() + 1)); retval |= !(it.dirPath(buff, path.size()) == 0 && ox_strcmp(buff, "/usr/share/") == 0); return retval; } @@ -116,13 +104,22 @@ map tests = { int retval = 0; string path = "/usr/share/charset.gbag"; PathIterator it(path.c_str(), path.size()); - const auto buffSize = 1024; - char buff[buffSize]; - assert(buffSize >= path.size()); + auto buff = static_cast(ox_alloca(path.size() + 1)); retval |= !(it.fileName(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0); return retval; } }, + { + "PathIterator::hasNext", + [](string) { + int retval = 0; + const auto path = "/file1"; + PathIterator it(path, ox_strlen(path)); + oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext"); + oxAssert(!(it + 1).hasNext(), "PathIterator shows incorrect hasNext"); + return retval; + } + }, { "FileSystem32::findInodeOf /", [](string) { @@ -383,16 +380,27 @@ map tests = { { "Directory", [](string) { - //std::array fsBuff; - //std::array dirBuff; - //ox::fs::FileStore32 fileStore(fsBuff.data(), fsBuff.size()); - //fileStore.format(); - //ox::fs::Directory32 dir(&fileStore, dirBuff.data(), dirBuff.size()); - //dir.init(); - //dir.write("/file1", 1); - //oxAssert(dir.find("/file1") == 1, "Could not find /file1"); - //dir.write("/file3", 3); - //dir.write("/file2", 2); + std::array fsBuff; + ox::fs::FileStore32 fileStore(fsBuff.data(), fsBuff.size()); + fileStore.format(); + auto dir = ox_malloca(1000, ox::fs::Directory32, &fileStore, 100); + + oxTrace("ox::fs::test::Directory") << "Init"; + oxAssert(dir->init(), "Init failed"); + + oxTrace("ox::fs::test::Directory") << "write 1"; + oxAssert(dir->write("/file1", 1), "Directory write of file1 failed"); + + oxTrace("ox::fs::test::Directory") << "find"; + oxAssert(dir->find("file1").error, "Could not find file1"); + oxAssert(dir->find("file1") == 1, "Could not find file1"); + + //oxTrace("ox::fs::test::Directory") << "write 2"; + //oxAssert(dir->write("/file3", 3) == 0, "Directory write of file3 failed"); + + //oxTrace("ox::fs::test::Directory") << "write 3"; + //oxAssert(dir->write("/file2", 2) == 0, "Directory write of file2 failed"); + return 0; } }, diff --git a/deps/ox/src/ox/mc/optype.hpp b/deps/ox/src/ox/mc/optype.hpp index 7720bcc4..00490626 100644 --- a/deps/ox/src/ox/mc/optype.hpp +++ b/deps/ox/src/ox/mc/optype.hpp @@ -8,6 +8,8 @@ #pragma once +#include "ox/std/error.hpp" + namespace ox { enum class OpType { diff --git a/deps/ox/src/ox/ptrarith/nodebuffer.hpp b/deps/ox/src/ox/ptrarith/nodebuffer.hpp index ff73c711..56bad1d2 100644 --- a/deps/ox/src/ox/ptrarith/nodebuffer.hpp +++ b/deps/ox/src/ox/ptrarith/nodebuffer.hpp @@ -55,6 +55,10 @@ class __attribute__((packed)) NodeBuffer { return m_current; } + bool valid() { + return m_current.valid(); + } + bool hasNext() { if (m_current.valid()) { oxTrace("ox::ptrarith::NodeBuffer::Iterator::hasNext::current") << m_current.offset(); @@ -190,7 +194,6 @@ typename NodeBuffer::ItemPtr NodeBuffer::ptr(size_t // make sure this can be read as an Item, and then use Item::size for the size auto itemSpace = m_header.size - itemOffset; auto item = reinterpret_cast(reinterpret_cast(this) + itemOffset); - oxTrace("ox::ptrarith::NodeBuffer::ptr::itemOffset") << itemOffset << m_header.size - sizeof(Item); if (itemOffset >= sizeof(Header) && itemOffset < m_header.size - sizeof(Item) && itemSpace >= static_cast(sizeof(Item)) && @@ -271,10 +274,10 @@ template Error NodeBuffer::setSize(size_t size) { auto last = lastItem(); if ((last.valid() && last.end() >= size) || size < sizeof(m_header)) { - return 1; + return OxError(1); } else { m_header.size = size; - return 0; + return OxError(0); } } diff --git a/deps/ox/src/ox/std/CMakeLists.txt b/deps/ox/src/ox/std/CMakeLists.txt index c1d73b1c..7674b732 100644 --- a/deps/ox/src/ox/std/CMakeLists.txt +++ b/deps/ox/src/ox/std/CMakeLists.txt @@ -21,6 +21,7 @@ install( assert.hpp bitops.hpp byteswap.hpp + error.hpp math.hpp memops.hpp new.hpp diff --git a/deps/ox/src/ox/std/assert.cpp b/deps/ox/src/ox/std/assert.cpp index c7f27d7e..5785a0ec 100644 --- a/deps/ox/src/ox/std/assert.cpp +++ b/deps/ox/src/ox/std/assert.cpp @@ -33,11 +33,11 @@ void _assert([[maybe_unused]]const char *file, [[maybe_unused]]int line, if (err) { auto ei = ErrorInfo(err); std::cerr << "\033[31;1;1mASSERT FAILURE:\033[0m (" << file << ':' << line << "): " << msg << '\n'; - std::cerr << "\tError Info: " << ei.errCode; + std::cerr << "\tError Code:\t" << ei.errCode << '\n'; if (ei.file != nullptr) { - std::cerr << " (" << reinterpret_cast(ei.file) << ':' << ei.line << ')'; + std::cerr << "\tError Location:\t" << reinterpret_cast(ei.file) << ':' << ei.line << '\n'; } - std::cerr << std::endl; + std::cerr << std::flush; std::abort(); } #endif diff --git a/deps/ox/src/ox/std/assert.hpp b/deps/ox/src/ox/std/assert.hpp index 41bbe4c9..7f9bef36 100644 --- a/deps/ox/src/ox/std/assert.hpp +++ b/deps/ox/src/ox/std/assert.hpp @@ -14,7 +14,7 @@ #include -#include "types.hpp" +#include "error.hpp" namespace ox { diff --git a/deps/ox/src/ox/std/error.hpp b/deps/ox/src/ox/std/error.hpp new file mode 100644 index 00000000..bb7b605c --- /dev/null +++ b/deps/ox/src/ox/std/error.hpp @@ -0,0 +1,74 @@ +/* + * Copyright 2015 - 2018 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/. + */ + +#pragma once + +#include "types.hpp" + +#ifdef DEBUG +#define OxError(x) x ? reinterpret_cast(__FILE__) | _errorTags(__LINE__, x) : 0 +#else +#define OxError(x) x +#endif + +namespace ox { + +using Error = uint64_t; + +constexpr Error errCode(Error err) { + return (err >> 58) & onMask(5); +} + +struct ErrorInfo { + const char *file = nullptr; + int line = -1; + Error errCode = 0; + + ErrorInfo() = default; + + ErrorInfo(Error err) { + this->file = reinterpret_cast(err & onMask(48)); + this->line = static_cast((err >> 48) & onMask(11)); + this->errCode = ox::errCode(err); + } +}; + +static constexpr Error _errorTags(Error line, Error errCode) { + line &= onMask(11); + line <<= 48; + errCode &= onMask(5); + errCode <<= 59; + return errCode | line; +} + +template +struct ValErr { + T value; + Error error; + + inline constexpr ValErr() = default; + + inline constexpr ValErr(T value, Error error = 0): value(value), error(error) { + } + + inline constexpr operator const T&() const { + return value; + } + + inline constexpr operator T&() { + return value; + } + + inline constexpr bool ok() const { + return error == 0; + } + +}; + +} + diff --git a/deps/ox/src/ox/std/math.hpp b/deps/ox/src/ox/std/math.hpp index 71fa2f65..1a79e53a 100644 --- a/deps/ox/src/ox/std/math.hpp +++ b/deps/ox/src/ox/std/math.hpp @@ -13,17 +13,17 @@ namespace ox { template -inline const T &min(const T &a, const T &b) { +inline constexpr const T &min(const T &a, const T &b) { return a < b ? a : b; } template -inline const T &max(const T &a, const T &b) { +inline constexpr const T &max(const T &a, const T &b) { return a > b ? a : b; } template -inline I pow(I v, int e) { +inline constexpr I pow(I v, int e) { I out = 1; for (I i = 0; i < e; i++) { out *= v; diff --git a/deps/ox/src/ox/std/std.hpp b/deps/ox/src/ox/std/std.hpp index e4accc46..d69184f3 100644 --- a/deps/ox/src/ox/std/std.hpp +++ b/deps/ox/src/ox/std/std.hpp @@ -11,6 +11,7 @@ #include "assert.hpp" #include "bitops.hpp" #include "byteswap.hpp" +#include "error.hpp" #include "math.hpp" #include "memops.hpp" #include "new.hpp" diff --git a/deps/ox/src/ox/std/types.hpp b/deps/ox/src/ox/std/types.hpp index 891eea32..1bab5c16 100644 --- a/deps/ox/src/ox/std/types.hpp +++ b/deps/ox/src/ox/std/types.hpp @@ -52,68 +52,6 @@ typedef uint32_t uintptr_t; -namespace ox { - -using Error = uint64_t; - -struct ErrorInfo { - const char *file = nullptr; - int line = -1; - Error errCode = 0; - - ErrorInfo() = default; - - ErrorInfo(Error err) { - this->file = reinterpret_cast(err & onMask(48)); - this->line = static_cast((err >> 48) & onMask(11)); - this->errCode = (err >> 58) & onMask(5); - } -}; - -constexpr Error ErrorTags(Error line, Error errCode) { - line &= onMask(11); - line <<= 48; - errCode &= onMask(5); - errCode <<= 59; - return errCode | line; -} - -} - -#ifdef DEBUG -#define OxError(x) x ? reinterpret_cast(__FILE__) | ErrorTags(__LINE__, x) : 0 -#else -#define OxError(x) x -#endif - -namespace ox { - -template -struct ValErr { - T value; - Error error; - - inline constexpr ValErr() = default; - - inline constexpr ValErr(T value, Error error = 0): value(value), error(error) { - } - - inline constexpr operator const T&() const { - return value; - } - - inline constexpr operator T&() { - return value; - } - - inline constexpr bool ok() const { - return error == 0; - } - -}; - -} - namespace std { using nullptr_t = decltype(nullptr); diff --git a/deps/ox/src/ox/trace/trace.cpp b/deps/ox/src/ox/trace/trace.cpp index dcb70508..1d8ab763 100644 --- a/deps/ox/src/ox/trace/trace.cpp +++ b/deps/ox/src/ox/trace/trace.cpp @@ -54,4 +54,16 @@ NullStream::NullStream(const char*, int, const char*, const char*) { NullStream::~NullStream() { } + +void logError(const char *file, int line, Error err) { + if (err) { + ErrorInfo ei(err); + TraceStream trc(file, line, "ox::error"); + trc << "\tError:\t" << ei.errCode; + if (ei.file != nullptr) { + trc << " (" << reinterpret_cast(ei.file) << ':' << ei.line << ')'; + } + } +} + } diff --git a/deps/ox/src/ox/trace/trace.hpp b/deps/ox/src/ox/trace/trace.hpp index d55434fe..58316a59 100644 --- a/deps/ox/src/ox/trace/trace.hpp +++ b/deps/ox/src/ox/trace/trace.hpp @@ -91,6 +91,12 @@ class NullStream { }; +using TraceStream = StdOutStream; + +void logError(const char *file, int line, Error err); + } -#define oxTrace(ch) ox::trace::StdOutStream(__FILE__, __LINE__, ch) +#define oxLogError(err) ox::trace::logError(__FILE__, __LINE__, err) + +#define oxTrace(ch) ox::trace::TraceStream(__FILE__, __LINE__, ch)