diff --git a/src/ox/fs/filesystem.hpp b/src/ox/fs/filesystem.hpp index 31b47096b..3c0df7a10 100644 --- a/src/ox/fs/filesystem.hpp +++ b/src/ox/fs/filesystem.hpp @@ -20,8 +20,8 @@ enum FsType { }; enum FileType { - NormalFile = 1, - Directory = 2 + FileType_NormalFile = 1, + FileType_Directory = 2 }; struct FileStat { @@ -30,6 +30,167 @@ struct FileStat { uint8_t fileType; }; +template +struct DirectoryListing { + String name; + FileStat stat; + + DirectoryListing(const char *name) { + this->name = name; + } +}; + +template +struct __attribute__((packed)) DirectoryEntry { + InodeId_t inode; + + char *getName() { + return (char*) (this + 1); + } + + void setName(const char *name) { + auto data = getName(); + auto nameLen = ox_strlen(name); + ox_memcpy(data, name, nameLen); + data[nameLen] = 0; + } + + static uint64_t spaceNeeded(const char *fileName) { + return sizeof(DirectoryEntry) + ox_strlen(fileName) + 1; + } + + /** + * The size in bytes. + */ + uint64_t size() { + return spaceNeeded(getName()); + } +}; + +template +struct __attribute__((packed)) Directory { + /** + * Number of bytes after this Directory struct. + */ + FsSize_t size = 0; + FsSize_t children = 0; + + DirectoryEntry *files() { + return size ? (DirectoryEntry*) (this + 1) : nullptr; + } + + uint64_t getFileInode(const char *name, uint64_t buffSize); + + int getChildrenInodes(InodeId_t *inodes, size_t inodesLen); + + int rmFile(const char *name); + + int copy(Directory *dirOut); + + template + int ls(List *list); +}; + +template +uint64_t Directory::getFileInode(const char *name, uint64_t buffSize) { + uint64_t inode = 0; + auto current = files(); + if (current) { + for (uint64_t i = 0; ox_strcmp(current->getName(), name) != 0;) { + i += current->size(); + if (i < this->size) { + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + } else { + current = nullptr; + break; + } + } + if (current) { + inode = current->inode; + } + } + return inode; +} + +template +int Directory::getChildrenInodes(InodeId_t *inodes, size_t inodesLen) { + if (inodesLen >= this->children) { + auto current = files(); + if (current) { + for (uint64_t i = 0; i < this->children; i++) { + inodes[i] = current->inode; + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + } + return 0; + } else { + return 1; + } + } else { + return 2; + } +} + +template +int Directory::rmFile(const char *name) { + int err = 1; + auto current = files(); + if (current) { + for (uint64_t i = 0; i < this->size;) { + i += current->size(); + if (ox_strcmp(current->getName(), name) == 0) { + auto dest = (uint8_t*) current; + auto src = dest + current->size(); + ox_memcpy(dest, src, this->size - i); + this->size -= current->size(); + this->children--; + err = 0; + break; + } + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + } + } + return err; +} + +template +int Directory::copy(Directory *dirOut) { + auto current = files(); + auto dirBuff = (uint8_t*) dirOut; + dirBuff += sizeof(Directory); + dirOut->size = this->size; + dirOut->children = this->children; + if (current) { + for (uint64_t i = 0; i < this->children; i++) { + auto entry = (DirectoryEntry*) dirBuff; + entry->inode = current->inode; + entry->setName(current->getName()); + + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + dirBuff += entry->size(); + } + return 0; + } else { + return 1; + } +} + +template +template +int Directory::ls(List *list) { + auto current = files(); + if (current) { + for (uint64_t i = 0; i < this->children; i++) { + list->push_back(current->getName()); + list->at(i).stat.inode = current->inode; + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + } + return 0; + } else { + return 1; + } +} + + class FileSystem { public: virtual ~FileSystem() {}; @@ -38,6 +199,9 @@ class FileSystem { virtual int mkdir(const char *path) = 0; + template + int ls(const char *path, List *list); + virtual int read(const char *path, void *buffer, size_t buffSize) = 0; virtual int read(uint64_t inode, void *buffer, size_t size) = 0; @@ -52,12 +216,14 @@ class FileSystem { virtual void resize(uint64_t size = 0) = 0; - virtual int write(const char *path, void *buffer, uint64_t size, uint8_t fileType = NormalFile) = 0; + virtual int write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0; - virtual int write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = NormalFile) = 0; + virtual int write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0; virtual FileStat stat(uint64_t inode) = 0; + virtual FileStat stat(const char *path) = 0; + virtual uint64_t spaceNeeded(uint64_t size) = 0; virtual uint64_t available() = 0; @@ -65,8 +231,21 @@ class FileSystem { virtual uint64_t size() = 0; virtual uint8_t *buff() = 0; + + protected: + virtual int readDirectory(const char *path, Directory *dirOut) = 0; }; +template +int FileSystem::ls(const char *path, List *list) { + auto s = stat(path); + uint8_t dirBuff[s.size * 4]; + auto dir = (Directory*) dirBuff; + auto err = readDirectory(path, dir); + dir->ls(list); + return err; +} + FileSystem *createFileSystem(void *buff, size_t buffSize); /** @@ -84,50 +263,6 @@ template class FileSystemTemplate: public FileSystem { private: - struct __attribute__((packed)) DirectoryEntry { - typename FileStore::InodeId_t inode; - - char *getName() { - return (char*) (this + 1); - } - - void setName(const char *name) { - auto data = getName(); - auto nameLen = ox_strlen(name); - ox_memcpy(data, name, nameLen); - data[nameLen] = 0; - } - - static uint64_t spaceNeeded(const char *fileName) { - return sizeof(DirectoryEntry) + ox_strlen(fileName) + 1; - } - - /** - * The size in bytes. - */ - uint64_t size() { - return spaceNeeded(getName()); - } - }; - - struct __attribute__((packed)) Directory { - /** - * Number of bytes after this Directory struct. - */ - typename FileStore::FsSize_t size = 0; - typename FileStore::FsSize_t children = 0; - - DirectoryEntry *files() { - return size ? (DirectoryEntry*) (this + 1) : nullptr; - } - - uint64_t getFileInode(const char *name, uint64_t buffSize); - - int getChildrenInodes(typename FileStore::InodeId_t *inodes, size_t inodesLen); - - int rmFile(const char *name); - }; - FileStore *m_store = nullptr; public: @@ -140,6 +275,9 @@ class FileSystemTemplate: public FileSystem { int stripDirectories() override; + template + int ls(const char *path, List *list); + int mkdir(const char *path) override; int read(const char *path, void *buffer, size_t buffSize) override; @@ -156,11 +294,11 @@ class FileSystemTemplate: public FileSystem { int remove(const char *path, bool recursive = false) override; - int write(const char *path, void *buffer, uint64_t size, uint8_t fileType = NormalFile) override; + int write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override; - int write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = NormalFile) override; + int write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override; - FileStat stat(const char *path); + FileStat stat(const char *path) override; FileStat stat(uint64_t inode) override; @@ -188,6 +326,9 @@ class FileSystemTemplate: public FileSystem { static uint8_t *format(void *buffer, typename FileStore::FsSize_t size, bool useDirectories); + protected: + int readDirectory(const char *path, Directory *dirOut) override; + private: uint64_t generateInodeId(); @@ -210,13 +351,37 @@ typename FileStore::InodeId_t FileSystemTemplate::INODE_RESE template int FileSystemTemplate::stripDirectories() { - return m_store->removeAllType(FileType::Directory); + return m_store->removeAllType(FileType::FileType_Directory); +} + +template +template +int FileSystemTemplate::ls(const char *path, List *list) { + int err = 0; + auto inode = findInodeOf(path); + auto dirStat = stat(inode); + auto dirBuffLen = dirStat.size; + uint8_t dirBuff[dirBuffLen]; + auto dir = (Directory*) dirBuff; + + err = read(dirStat.inode, dirBuff, dirBuffLen); + if (!err) { + dir->ls(list); + + for (auto &i : *list) { + i.stat = stat(i.stat.inode); + } + + return 0; + } else { + return 1; + } } template int FileSystemTemplate::mkdir(const char *path) { - Directory dir; - return write(path, &dir, sizeof(dir), FileType::Directory); + Directory dir; + return write(path, &dir, sizeof(dir), FileType::FileType_Directory); } template @@ -335,14 +500,14 @@ int FileSystemTemplate::remove(const char *path, bool recurs template int FileSystemTemplate::remove(uint64_t inode, bool recursive) { auto fileType = stat(inode).fileType; - if (fileType != FileType::Directory) { + if (fileType != FileType::FileType_Directory) { return m_store->remove(inode); - } else if (fileType == FileType::Directory && recursive) { + } else if (fileType == FileType::FileType_Directory && recursive) { int err = 0; auto dirStat = stat(inode); auto dirBuffLen = dirStat.size; uint8_t dirBuff[dirBuffLen]; - auto dir = (Directory*) dirBuff; + auto dir = (Directory*) dirBuff; err = read(dirStat.inode, dirBuff, dirBuffLen); if (err) { @@ -424,11 +589,11 @@ uint64_t FileSystemTemplate::findInodeOf(const char *path) { uint64_t inode = INODE_ROOT_DIR; while (it.hasNext()) { auto dirStat = stat(inode); - if (dirStat.inode && dirStat.size >= sizeof(Directory)) { + if (dirStat.inode && dirStat.size >= sizeof(Directory)) { uint8_t dirBuffer[dirStat.size]; - auto dir = (Directory*) dirBuffer; + auto dir = (Directory*) dirBuffer; if (read(inode, dirBuffer, dirStat.size) == 0) { - if (dirStat.fileType == FileType::Directory && it.next(fileName, pathLen) == 0) { + if (dirStat.fileType == FileType::FileType_Directory && it.next(fileName, pathLen) == 0) { inode = dir->getFileInode(fileName, dirStat.size); } else { inode = 0; // null out inode and break @@ -482,9 +647,9 @@ uint8_t *FileSystemTemplate::format(void *buffer, typename F buffer = FileStore::format((uint8_t*) buffer, size, (uint16_t) FS_TYPE); if (buffer && useDirectories) { - Directory dir; + Directory dir; FileSystemTemplate fs(buffer); - fs.write(INODE_ROOT_DIR, &dir, sizeof(dir), FileType::Directory); + fs.write(INODE_ROOT_DIR, &dir, sizeof(dir), FileType::FileType_Directory); } return (uint8_t*) buffer; @@ -523,19 +688,19 @@ template int FileSystemTemplate::insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode) { auto s = stat(dirPath); if (s.inode) { - auto spaceNeeded = DirectoryEntry::spaceNeeded(fileName); + auto spaceNeeded = DirectoryEntry::spaceNeeded(fileName); size_t dirBuffSize = s.size + spaceNeeded; uint8_t dirBuff[dirBuffSize]; int err = read(s.inode, dirBuff, dirBuffSize); if (!err) { - auto dir = (Directory*) dirBuff; + auto dir = (Directory*) dirBuff; dir->size += spaceNeeded; dir->children++; - auto entry = (DirectoryEntry*) &dirBuff[s.size]; + auto entry = (DirectoryEntry*) &dirBuff[s.size]; entry->inode = inode; entry->setName(fileName); - return write(s.inode, dirBuff, dirBuffSize, FileType::Directory); + return write(s.inode, dirBuff, dirBuffSize, FileType::FileType_Directory); } else { return 1; } @@ -611,81 +776,35 @@ int FileSystemTemplate::rmDirectoryEntry(const char *path) { return err; } - auto dir = (Directory*) dirBuff; + auto dir = (Directory*) dirBuff; err = dir->rmFile(fileName); if (err) { return err; } - err = write(dirStat.inode, dirBuff, dirBuffLen - DirectoryEntry::spaceNeeded(fileName)); + err = write(dirStat.inode, dirBuff, dirBuffLen - DirectoryEntry::spaceNeeded(fileName)); return err; } - -// Directory - template -uint64_t FileSystemTemplate::Directory::getFileInode(const char *name, uint64_t buffSize) { - uint64_t inode = 0; - auto current = files(); - if (current) { - for (uint64_t i = 0; ox_strcmp(current->getName(), name) != 0;) { - i += current->size(); - if (i < this->size) { - current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); - } else { - current = nullptr; - break; - } - } - if (current) { - inode = current->inode; - } - } - return inode; -} +int FileSystemTemplate::readDirectory(const char *path, Directory *dirOut) { + int err = 0; + auto inode = findInodeOf(path); + auto dirStat = stat(inode); + auto dirBuffLen = dirStat.size; + uint8_t dirBuff[dirBuffLen]; + auto dir = (Directory*) dirBuff; -template -int FileSystemTemplate::Directory::getChildrenInodes(typename FileStore::InodeId_t *inodes, size_t inodesLen) { - if (inodesLen >= this->children) { - auto current = files(); - if (current) { - for (uint64_t i = 0; i < this->children; i++) { - inodes[i] = current->inode; - current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); - } - return 0; - } else { - return 1; - } + err = read(dirStat.inode, dirBuff, dirBuffLen); + if (!err) { + return dir->copy(dirOut); } else { - return 2; + return 1; } } -template -int FileSystemTemplate::Directory::rmFile(const char *name) { - int err = 1; - auto current = files(); - if (current) { - for (uint64_t i = 0; i < this->size;) { - i += current->size(); - if (ox_strcmp(current->getName(), name) == 0) { - auto dest = (uint8_t*) current; - auto src = dest + current->size(); - ox_memcpy(dest, src, this->size - i); - this->size -= current->size(); - this->children--; - err = 0; - break; - } - current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); - } - } - return err; -} typedef FileSystemTemplate FileSystem16; typedef FileSystemTemplate FileSystem32; diff --git a/src/ox/fs/test/CMakeLists.txt b/src/ox/fs/test/CMakeLists.txt index 8ca81bcf6..be393710a 100644 --- a/src/ox/fs/test/CMakeLists.txt +++ b/src/ox/fs/test/CMakeLists.txt @@ -43,3 +43,4 @@ add_test("Test\\ FileSystem32::rmDirectoryEntry\\(string\\)" FSTests "FileSystem add_test("Test\\ FileSystem32::remove\\(string,\\ true\\)" FSTests "FileSystem32::remove(string, true)") add_test("Test\\ FileSystem32::move" FSTests "FileSystem32::move") add_test("Test\\ FileSystem32::stripDirectories" FSTests "FileSystem32::stripDirectories") +add_test("Test\\ FileSystem32::ls" FSTests "FileSystem32::ls") diff --git a/src/ox/fs/test/tests.cpp b/src/ox/fs/test/tests.cpp index 8646730c0..d29d3b323 100644 --- a/src/ox/fs/test/tests.cpp +++ b/src/ox/fs/test/tests.cpp @@ -288,6 +288,40 @@ map tests = { delete []buff; delete []dataOut; + return retval; + } + }, + { + "FileSystem32::ls", + [](string) { + int retval = 0; + auto dataIn = "test string"; + auto dataOutLen = ox_strlen(dataIn) + 1; + auto dataOut = new char[dataOutLen]; + vector inodes; + vector> files; + + const auto size = 1024 * 1024; + auto buff = new uint8_t[size]; + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + auto fs = (FileSystem32*) createFileSystem(buff, size); + + retval |= fs->mkdir("/usr"); + retval |= fs->mkdir("/usr/share"); + retval |= fs->write("/usr/share/a.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + retval |= fs->write("/usr/share/b.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + retval |= fs->write("/usr/share/c.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + + fs->ls("/usr/share/", &files); + + retval |= !(files[0].name == "a.txt"); + retval |= !(files[1].name == "b.txt"); + retval |= !(files[2].name == "c.txt"); + + delete fs; + delete []buff; + delete []dataOut; + return retval; } },