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) {
auto data = getName();
auto nameLen = ox_strlen(name);
ox_memcpy(data, &name, nameLen);
ox_memcpy(data, name, nameLen);
data[nameLen] = 0;
}
@@ -101,7 +101,7 @@ class FileSystemTemplate: public FileSystem {
}
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.
*/
typename FileStore::InodeId_t size = 0;
typename FileStore::FsSize_t size = 0;
DirectoryEntry *files() {
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);
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>
@@ -179,7 +179,12 @@ int FileSystemTemplate<FileStore, FS_TYPE>::mkdir(const char *path) {
template<typename FileStore, FsType FS_TYPE>
FileStat FileSystemTemplate<FileStore, FS_TYPE>::stat(const char *path) {
auto inode = findInodeOf(path);
FileStat stat;
auto s = m_store->stat(inode);
stat.size = s.size;
stat.inode = s.inodeId;
stat.fileType = s.fileType;
return stat;
}
@@ -289,17 +294,34 @@ int FileSystemTemplate<FileStore, FS_TYPE>::remove(uint64_t inode) {
#endif
template<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) {
int retval = -1;
// find the inode for the given path
auto inode = findInodeOf(path);
// if inode exists, read the data into buffer
if (inode) {
retval = write(inode, buffer, size, fileType);
int err = 0;
size_t pathLen = ox_strlen(path);
char dirPath[pathLen];
char fileName[pathLen];
PathIterator pathReader(path, pathLen);
err |= pathReader.fileName(fileName, pathLen);
err |= pathReader.dirPath(dirPath, pathLen);
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
#pragma warning(default:4244)
@@ -325,26 +347,25 @@ uint64_t FileSystemTemplate<FileStore, FS_TYPE>::findInodeOf(const char *path) {
PathIterator it(path, pathLen);
char fileName[pathLen];
uint64_t inode = INODE_ROOT_DIR;
while (inode) {
while (it.hasNext()) {
auto dirStat = m_store->stat(inode);
if (dirStat.size >= sizeof(Directory)) {
uint8_t dirBuffer[dirStat.size];
auto dir = (Directory*) dirBuffer;
if (read(inode, dirBuffer, dirStat.size) == 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);
} else {
inode = 0; // null out inode and break
break;
}
} else {
inode = 0; // null out inode and break
break;
}
} else {
inode = 0; // null out inode and break
break;
}
}
return inode;
@@ -401,30 +422,51 @@ uint8_t *FileSystemTemplate<FileStore, FS_TYPE>::format(void *buffer, typename F
#pragma warning(disable:4244)
#endif
template<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::insertDirectoryEntry(uint64_t inode, const char *dirPath, const char *fileName) {
return 0;
int FileSystemTemplate<FileStore, FS_TYPE>::insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode) {
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
#pragma warning(default:4244)
#endif
// Directory
template<typename FileStore, FsType FS_TYPE>
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();
if (current) {
auto end = (DirectoryEntry*) ((uint8_t*) files()) + buffSize;
auto end = (DirectoryEntry*) (((uint8_t*) files()) + buffSize);
while (current && ox_strcmp(current->getName(), name) != 0) {
current = (DirectoryEntry*) ((uint8_t*) current) + current->size();
if (current < end) {
current = (DirectoryEntry*) (((uint8_t*) current) + current->size());
if (current >= end) {
current = nullptr;
}
}
retval = current->inode;
if (current) {
inode = current->inode;
}
}
return retval;
return inode;
}
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;
}
/**
* @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) {
size_t size = 0;
int retval = 1;
@@ -46,6 +81,9 @@ bool PathIterator::hasNext() {
size_t size = 0;
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) {
size_t 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 /
@@ -55,7 +93,6 @@ bool PathIterator::hasNext() {
size_t end = substr - m_path;
size = end - start;
}
m_iterator += size;
return size > 0;
}
+10
View File
@@ -22,6 +22,16 @@ class PathIterator {
public:
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
*/
+10 -6
View File
@@ -28,10 +28,14 @@ target_link_libraries(FSTests OxFS OxStd)
add_test("FileStoreFormat" FileStoreFormat)
add_test("FileSystemFormat" FileSystemFormat)
add_test("FileStoreIO" FileStoreIO)
add_test("Test\\ PathIterator1" FSTests PathIterator1)
add_test("Test\\ PathIterator2" FSTests PathIterator2)
add_test("Test\\ PathIterator3" FSTests PathIterator3)
add_test("Test\\ PathIterator4" FSTests PathIterator4)
add_test("Test\\ PathIterator5" FSTests PathIterator5)
add_test("Test\\ PathIterator::next1" FSTests PathIterator::next1)
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\\ 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 ox::fs;
using namespace ox::std;
map<string, int(*)(string)> tests = {
map<string, function<int(string)>> tests = {
{
{
"PathIterator1",
"PathIterator::next1",
[](string) {
int retval = 0;
string path = "/usr/share/charset.gbag";
@@ -35,7 +34,7 @@ map<string, int(*)(string)> tests = {
}
},
{
"PathIterator2",
"PathIterator::next2",
[](string) {
int retval = 0;
string path = "/usr/share/";
@@ -49,7 +48,7 @@ map<string, int(*)(string)> tests = {
}
},
{
"PathIterator3",
"PathIterator::next3",
[](string) {
int retval = 0;
string path = "/";
@@ -62,7 +61,7 @@ map<string, int(*)(string)> tests = {
}
},
{
"PathIterator4",
"PathIterator::next4",
[](string) {
int retval = 0;
string path = "usr/share/charset.gbag";
@@ -77,7 +76,7 @@ map<string, int(*)(string)> tests = {
}
},
{
"PathIterator5",
"PathIterator::next5",
[](string) {
int retval = 0;
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) {
int retval = 0;
const auto size = 1024;
@@ -103,6 +128,29 @@ map<string, int(*)(string)> tests = {
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(
OxStd
memops.cpp
random.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
#include "bitops.hpp"
#include "byteswap.hpp"
#include "memops.hpp"
#include "random.hpp"
#include "strops.hpp"
#include "types.hpp"
+20
View File
@@ -58,6 +58,26 @@ char *ox_strchr(char *str, int character, size_t maxLen) {
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 total = 0;
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);
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);
+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 " == ")
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]);
}
},
{
"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) {