Add support for writing file by path

This commit is contained in:
2017-04-24 02:38:23 -05:00
parent 7c54d3fb47
commit 7abbf8768f
14 changed files with 308 additions and 41 deletions
+68 -26
View File
@@ -89,7 +89,7 @@ class FileSystemTemplate: public FileSystem {
void setName(const char *name) { void setName(const char *name) {
auto data = getName(); auto data = getName();
auto nameLen = ox_strlen(name); auto nameLen = ox_strlen(name);
ox_memcpy(data, &name, nameLen); ox_memcpy(data, name, nameLen);
data[nameLen] = 0; data[nameLen] = 0;
} }
@@ -101,7 +101,7 @@ class FileSystemTemplate: public FileSystem {
} }
static uint64_t spaceNeeded(const char *fileName) { static uint64_t spaceNeeded(const char *fileName) {
return sizeof(DirectoryEntry) + ox_strlen(fileName); return sizeof(DirectoryEntry) + ox_strlen(fileName) + 1;
} }
}; };
@@ -109,7 +109,7 @@ class FileSystemTemplate: public FileSystem {
/** /**
* Number of files in this directory. * Number of files in this directory.
*/ */
typename FileStore::InodeId_t size = 0; typename FileStore::FsSize_t size = 0;
DirectoryEntry *files() { DirectoryEntry *files() {
return size ? (DirectoryEntry*) (this + 1) : nullptr; return size ? (DirectoryEntry*) (this + 1) : nullptr;
@@ -161,7 +161,7 @@ class FileSystemTemplate: public FileSystem {
static uint8_t *format(void *buffer, typename FileStore::FsSize_t size, bool useDirectories); static uint8_t *format(void *buffer, typename FileStore::FsSize_t size, bool useDirectories);
private: private:
int insertDirectoryEntry(uint64_t inode, const char *dirPath, const char *fileName); int insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode);
}; };
template<typename FileStore, FsType FS_TYPE> template<typename FileStore, FsType FS_TYPE>
@@ -179,7 +179,12 @@ int FileSystemTemplate<FileStore, FS_TYPE>::mkdir(const char *path) {
template<typename FileStore, FsType FS_TYPE> template<typename FileStore, FsType FS_TYPE>
FileStat FileSystemTemplate<FileStore, FS_TYPE>::stat(const char *path) { FileStat FileSystemTemplate<FileStore, FS_TYPE>::stat(const char *path) {
auto inode = findInodeOf(path);
FileStat stat; FileStat stat;
auto s = m_store->stat(inode);
stat.size = s.size;
stat.inode = s.inodeId;
stat.fileType = s.fileType;
return stat; return stat;
} }
@@ -289,17 +294,34 @@ int FileSystemTemplate<FileStore, FS_TYPE>::remove(uint64_t inode) {
#endif #endif
template<typename FileStore, FsType FS_TYPE> template<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) { int FileSystemTemplate<FileStore, FS_TYPE>::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) {
int retval = -1; int err = 0;
size_t pathLen = ox_strlen(path);
// find the inode for the given path char dirPath[pathLen];
auto inode = findInodeOf(path); char fileName[pathLen];
PathIterator pathReader(path, pathLen);
// if inode exists, read the data into buffer err |= pathReader.fileName(fileName, pathLen);
if (inode) { err |= pathReader.dirPath(dirPath, pathLen);
retval = write(inode, buffer, size, fileType); if (err) {
return err;
} }
return retval; uint64_t inode = findInodeOf(path);
// find an inode value for the given path
if (!inode) {
while (!inode) {
inode = ox_rand() >> 48;
// make sure this does not already exist
if (stat(inode).inode) {
// that result was unusable, try again
inode = 0;
}
}
insertDirectoryEntry(dirPath, fileName, inode);
}
err = write(inode, buffer, size, fileType);
return err;
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(default:4244) #pragma warning(default:4244)
@@ -325,26 +347,25 @@ uint64_t FileSystemTemplate<FileStore, FS_TYPE>::findInodeOf(const char *path) {
PathIterator it(path, pathLen); PathIterator it(path, pathLen);
char fileName[pathLen]; char fileName[pathLen];
uint64_t inode = INODE_ROOT_DIR; uint64_t inode = INODE_ROOT_DIR;
while (inode) { while (it.hasNext()) {
auto dirStat = m_store->stat(inode); auto dirStat = m_store->stat(inode);
if (dirStat.size >= sizeof(Directory)) { if (dirStat.size >= sizeof(Directory)) {
uint8_t dirBuffer[dirStat.size]; uint8_t dirBuffer[dirStat.size];
auto dir = (Directory*) dirBuffer; auto dir = (Directory*) dirBuffer;
if (read(inode, dirBuffer, dirStat.size) == 0) { if (read(inode, dirBuffer, dirStat.size) == 0) {
if (dirStat.fileType == FileType::Directory && it.next(fileName, pathLen) == 0) { if (dirStat.fileType == FileType::Directory && it.next(fileName, pathLen) == 0) {
if (!it.hasNext()) {
// no further name components, inode points to the correct file
break;
}
inode = dir->getFileInode(fileName, dirStat.size); inode = dir->getFileInode(fileName, dirStat.size);
} else { } else {
inode = 0; // null out inode and break inode = 0; // null out inode and break
break;
} }
} else { } else {
inode = 0; // null out inode and break inode = 0; // null out inode and break
break;
} }
} else { } else {
inode = 0; // null out inode and break inode = 0; // null out inode and break
break;
} }
} }
return inode; return inode;
@@ -401,30 +422,51 @@ uint8_t *FileSystemTemplate<FileStore, FS_TYPE>::format(void *buffer, typename F
#pragma warning(disable:4244) #pragma warning(disable:4244)
#endif #endif
template<typename FileStore, FsType FS_TYPE> template<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::insertDirectoryEntry(uint64_t inode, const char *dirPath, const char *fileName) { int FileSystemTemplate<FileStore, FS_TYPE>::insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode) {
return 0; auto s = stat(dirPath);
if (s.inode) {
size_t dirBuffSize = s.size + DirectoryEntry::spaceNeeded(fileName) + 100;
uint8_t dirBuff[dirBuffSize];
int err = read(s.inode, dirBuff, dirBuffSize);
if (!err) {
auto dir = (Directory*) dirBuff;
dir->size += DirectoryEntry::spaceNeeded(fileName);
auto entry = (DirectoryEntry*) &dirBuff[s.size];
entry->inode = inode;
entry->setName(fileName);
return write(s.inode, dirBuff, dirBuffSize, FileType::Directory);
} else {
return 1;
}
} else {
return 2;
}
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(default:4244) #pragma warning(default:4244)
#endif #endif
// Directory // Directory
template<typename FileStore, FsType FS_TYPE> template<typename FileStore, FsType FS_TYPE>
uint64_t FileSystemTemplate<FileStore, FS_TYPE>::Directory::getFileInode(const char *name, uint64_t buffSize) { uint64_t FileSystemTemplate<FileStore, FS_TYPE>::Directory::getFileInode(const char *name, uint64_t buffSize) {
uint64_t retval = 0; uint64_t inode = 0;
auto current = files(); auto current = files();
if (current) { if (current) {
auto end = (DirectoryEntry*) ((uint8_t*) files()) + buffSize; auto end = (DirectoryEntry*) (((uint8_t*) files()) + buffSize);
while (current && ox_strcmp(current->getName(), name) != 0) { while (current && ox_strcmp(current->getName(), name) != 0) {
current = (DirectoryEntry*) ((uint8_t*) current) + current->size(); current = (DirectoryEntry*) (((uint8_t*) current) + current->size());
if (current < end) { if (current >= end) {
current = nullptr; current = nullptr;
} }
} }
retval = current->inode; if (current) {
inode = current->inode;
}
} }
return retval; return inode;
} }
typedef FileSystemTemplate<FileStore16, OxFS_16> FileSystem16; typedef FileSystemTemplate<FileStore16, OxFS_16> FileSystem16;
+38 -1
View File
@@ -18,6 +18,41 @@ PathIterator::PathIterator(const char *path, size_t maxSize) {
m_maxSize = maxSize; m_maxSize = maxSize;
} }
/**
* @return 0 if no error
*/
int PathIterator::dirPath(char *out, size_t outSize) {
int idx = ox_lastIndexOf(m_path, '/', m_maxSize);
size_t size = idx + 1;
if (idx >= 0 && size < outSize) {
ox_memcpy(out, m_path, size);
out[size] = 0;
return 0;
} else {
return 1;
}
}
/**
* @return 0 if no error
*/
int PathIterator::fileName(char *out, size_t outSize) {
auto idx = ox_lastIndexOf(m_path, '/', m_maxSize);
if (idx >= 0) {
idx++; // pass up the preceding /
size_t fileNameSize = ox_strlen(&m_path[idx]);
if (fileNameSize < outSize) {
ox_memcpy(out, &m_path[idx], fileNameSize);
out[fileNameSize] = 0;
return 0;
} else {
return 1;
}
} else {
return 2;
}
}
int PathIterator::next(char *pathOut, size_t pathOutSize) { int PathIterator::next(char *pathOut, size_t pathOutSize) {
size_t size = 0; size_t size = 0;
int retval = 1; int retval = 1;
@@ -46,6 +81,9 @@ bool PathIterator::hasNext() {
size_t size = 0; size_t size = 0;
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) { if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) {
size_t start = m_iterator; size_t start = m_iterator;
if (m_path[start] == '/') {
start++;
}
// end is at the next / // end is at the next /
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
// correct end if it is invalid, which happens if there is no next / // correct end if it is invalid, which happens if there is no next /
@@ -55,7 +93,6 @@ bool PathIterator::hasNext() {
size_t end = substr - m_path; size_t end = substr - m_path;
size = end - start; size = end - start;
} }
m_iterator += size;
return size > 0; return size > 0;
} }
+10
View File
@@ -22,6 +22,16 @@ class PathIterator {
public: public:
PathIterator(const char *path, size_t maxSize); PathIterator(const char *path, size_t maxSize);
/**
* @return 0 if no error
*/
int dirPath(char *pathOut, size_t pathOutSize);
/**
* @return 0 if no error
*/
int fileName(char *out, size_t outSize);
/** /**
* @return 0 if no error * @return 0 if no error
*/ */
+10 -6
View File
@@ -28,10 +28,14 @@ target_link_libraries(FSTests OxFS OxStd)
add_test("FileStoreFormat" FileStoreFormat) add_test("FileStoreFormat" FileStoreFormat)
add_test("FileSystemFormat" FileSystemFormat) add_test("FileSystemFormat" FileSystemFormat)
add_test("FileStoreIO" FileStoreIO) add_test("FileStoreIO" FileStoreIO)
add_test("Test\\ PathIterator1" FSTests PathIterator1) add_test("Test\\ PathIterator::next1" FSTests PathIterator::next1)
add_test("Test\\ PathIterator2" FSTests PathIterator2) add_test("Test\\ PathIterator::next2" FSTests PathIterator::next2)
add_test("Test\\ PathIterator3" FSTests PathIterator3) add_test("Test\\ PathIterator::next3" FSTests PathIterator::next3)
add_test("Test\\ PathIterator4" FSTests PathIterator4) add_test("Test\\ PathIterator::next4" FSTests PathIterator::next4)
add_test("Test\\ PathIterator5" FSTests PathIterator5) add_test("Test\\ PathIterator::next5" FSTests PathIterator::next5)
add_test("Test\\ FileSystem32::findInodeOf" FSTests FileSystem32::findInodeOf) add_test("Test\\ PathIterator::dirPath" FSTests PathIterator::dirPath)
add_test("Test\\ PathIterator::fileName" FSTests PathIterator::fileName)
add_test("Test\\ FileSystem32::findInodeOf\\ /" FSTests "FileSystem32::findInodeOf /")
add_test("Test\\ FileSystem32::write\\(string\\)" FSTests "FileSystem32::write(string)")
+56 -8
View File
@@ -15,12 +15,11 @@
using namespace std; using namespace std;
using namespace ox::fs; using namespace ox::fs;
using namespace ox::std;
map<string, int(*)(string)> tests = { map<string, function<int(string)>> tests = {
{ {
{ {
"PathIterator1", "PathIterator::next1",
[](string) { [](string) {
int retval = 0; int retval = 0;
string path = "/usr/share/charset.gbag"; string path = "/usr/share/charset.gbag";
@@ -35,7 +34,7 @@ map<string, int(*)(string)> tests = {
} }
}, },
{ {
"PathIterator2", "PathIterator::next2",
[](string) { [](string) {
int retval = 0; int retval = 0;
string path = "/usr/share/"; string path = "/usr/share/";
@@ -49,7 +48,7 @@ map<string, int(*)(string)> tests = {
} }
}, },
{ {
"PathIterator3", "PathIterator::next3",
[](string) { [](string) {
int retval = 0; int retval = 0;
string path = "/"; string path = "/";
@@ -62,7 +61,7 @@ map<string, int(*)(string)> tests = {
} }
}, },
{ {
"PathIterator4", "PathIterator::next4",
[](string) { [](string) {
int retval = 0; int retval = 0;
string path = "usr/share/charset.gbag"; string path = "usr/share/charset.gbag";
@@ -77,7 +76,7 @@ map<string, int(*)(string)> tests = {
} }
}, },
{ {
"PathIterator5", "PathIterator::next5",
[](string) { [](string) {
int retval = 0; int retval = 0;
string path = "usr/share/"; string path = "usr/share/";
@@ -91,7 +90,33 @@ map<string, int(*)(string)> tests = {
} }
}, },
{ {
"FileSystem32::findInodeOf", "PathIterator::dirPath",
[] (string) {
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());
retval |= !(it.dirPath(buff, path.size()) == 0 && ox_strcmp(buff, "/usr/share/") == 0);
return retval;
}
},
{
"PathIterator::fileName",
[](string) {
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());
retval |= !(it.fileName(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0);
return retval;
}
},
{
"FileSystem32::findInodeOf /",
[](string) { [](string) {
int retval = 0; int retval = 0;
const auto size = 1024; const auto size = 1024;
@@ -103,6 +128,29 @@ map<string, int(*)(string)> tests = {
return retval; return retval;
} }
}, },
{
"FileSystem32::write(string)",
[](string) {
// this value will likely need to change if anything about the
// random number generator changes
const auto targetInode = 58542;
int retval = 0;
auto path = "/charset.gbag";
auto data = "test";
const auto size = 1024;
uint8_t buff[size];
FileSystem32::format(buff, (FileStore32::FsSize_t) size, true);
auto fs = (FileSystem32*) createFileSystem(buff, size);
retval |= fs->write(path, &data, ox_strlen(data));
retval |= !(fs->findInodeOf(path) == targetInode);
delete fs;
return retval;
}
},
}, },
}; };
+1
View File
@@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8)
add_library( add_library(
OxStd OxStd
memops.cpp memops.cpp
random.cpp
strops.cpp strops.cpp
) )
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright 2015 - 2017 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"
namespace ox {
inline uint64_t rotateLeft(uint64_t i, int shift) {
return (i << shift) | (i >> (64 - shift));
}
}
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright 2015 - 2017 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/.
*/
#include "bitops.hpp"
#include "random.hpp"
namespace ox {
RandomSeed Random::DEFAULT_SEED = {540932923848, 540932540932};
Random::Random(RandomSeed seed) {
m_seed[0] = seed[0];
m_seed[1] = seed[1];
}
uint64_t Random::gen() {
auto s0 = m_seed[0];
auto s1 = m_seed[1];
auto retval = s0 + s1;
s1 ^= s0;
m_seed[0] = ox::rotateLeft(s0, 55) ^ s1 ^ (s1 << 14);
m_seed[1] = ox::rotateLeft(s1, 36);
return retval;
}
}
uint64_t ox_rand() {
static ox::Random rand;
return rand.gen();
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright 2015 - 2017 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
uint64_t ox_rand();
namespace ox {
typedef uint64_t RandomSeed[2];
class Random {
public:
static RandomSeed DEFAULT_SEED;
private:
RandomSeed m_seed;
public:
Random(RandomSeed seed = DEFAULT_SEED);
uint64_t gen();
};
}
+2
View File
@@ -7,7 +7,9 @@
*/ */
#pragma once #pragma once
#include "bitops.hpp"
#include "byteswap.hpp" #include "byteswap.hpp"
#include "memops.hpp" #include "memops.hpp"
#include "random.hpp"
#include "strops.hpp" #include "strops.hpp"
#include "types.hpp" #include "types.hpp"
+20
View File
@@ -58,6 +58,26 @@ char *ox_strchr(char *str, int character, size_t maxLen) {
return nullptr; return nullptr;
} }
int ox_lastIndexOf(const char *str, int character, int maxLen) {
int retval = -1;
for (int i = 0; i < maxLen && str[i]; i++) {
if (str[i] == character) {
retval = i;
}
}
return retval;
}
int ox_lastIndexOf(char *str, int character, int maxLen) {
int retval = -1;
for (int i = 0; i < maxLen && str[i]; i++) {
if (str[i] == character) {
retval = i;
}
}
return retval;
}
int ox_atoi(const char *str) { int ox_atoi(const char *str) {
int total = 0; int total = 0;
int multiplier = 1; int multiplier = 1;
+4
View File
@@ -20,4 +20,8 @@ const char *ox_strchr(const char *str, int character, size_t maxLen = 0xFFFFFFFF
char *ox_strchr(char *str, int character, size_t maxLen = 0xFFFFFFFF); char *ox_strchr(char *str, int character, size_t maxLen = 0xFFFFFFFF);
int ox_lastIndexOf(const char *str, int character, int maxLen = 0xFFFFFFFF);
int ox_lastIndexOf(char *str, int character, int maxLen = 0xFFFFFFFF);
int ox_atoi(const char *str); int ox_atoi(const char *str);
+1
View File
@@ -30,6 +30,7 @@ add_test("Test\\ ox_strcmp\\ resize\\ !=\\ read" StrOpsTest "resize > read")
add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest "resize == resize") add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest "resize == resize")
add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest " == ") add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest " == ")
add_test("Test\\ ox_strchr\\ 0" StrOpsTest "ox_strchr 0") add_test("Test\\ ox_strchr\\ 0" StrOpsTest "ox_strchr 0")
add_test("Test\\ ox_lastIndexOf\\ aaaa\\ a" StrOpsTest "ox_lastIndexOf aaaa a")
################################################################################ ################################################################################
+10
View File
@@ -56,6 +56,16 @@ map<string, function<int()>> tests = {
return !(ox_strchr(testStr, 0, 4) == &testStr[4]); return !(ox_strchr(testStr, 0, 4) == &testStr[4]);
} }
}, },
{
"ox_lastIndexOf aaaa a",
[]() {
int retval = 0;
auto testStr = "aaaa";
retval |= !(ox_lastIndexOf((char*) testStr, 'a', ox_strlen(testStr)) == 3);
retval |= !(ox_lastIndexOf((const char*) testStr, 'a', ox_strlen(testStr)) == 3);
return retval;
}
},
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {