Add support for writing file by path
This commit is contained in:
+68
-26
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8)
|
||||
add_library(
|
||||
OxStd
|
||||
memops.cpp
|
||||
random.cpp
|
||||
strops.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -7,7 +7,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "bitops.hpp"
|
||||
#include "byteswap.hpp"
|
||||
#include "memops.hpp"
|
||||
#include "random.hpp"
|
||||
#include "strops.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
################################################################################
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user