First pass at converting FSNode to std::filesystem.

This code is broken; do not attempt to use!
This commit is contained in:
Stephen Anthony 2022-06-19 19:50:59 -02:30
parent e253be49d5
commit 686a5e289d
5 changed files with 175 additions and 94 deletions

View File

@ -16,6 +16,7 @@
//============================================================================
#include <cstdio>
#include <filesystem>
#include "SqliteDatabase.hxx"
#include "Logger.hxx"
@ -25,7 +26,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteDatabase::SqliteDatabase(const string& databaseDirectory,
const string& databaseName)
: myDatabaseFile{databaseDirectory + databaseName + ".sqlite3"}
: myDatabaseFile{(std::filesystem::path(databaseDirectory) /
(databaseName + ".sqlite3")).string()}
{
}

View File

@ -50,6 +50,12 @@ void FSNode::setPath(const string& path)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FSNode& FSNode::operator/=(const string& path)
{
#if 0
_fspath /= path;
setFlags();
return *this;
#else
if (path != EmptyString)
{
string newPath = getPath();
@ -60,6 +66,7 @@ FSNode& FSNode::operator/=(const string& path)
}
return *this;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -232,8 +239,7 @@ const string& FSNode::getName() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FSNode::setName(const string& name)
{
if (_realNode)
_realNode->setName(name);
if (_realNode) _realNode->setName(name);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -251,6 +257,15 @@ string FSNode::getShortPath() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string FSNode::getNameWithExt(const string& ext) const
{
#if 1
fs::path p = getName();
if (ext != EmptyString)
p.replace_extension(ext);
else
p.replace_extension();
return p.string();
#else
if (!_realNode)
return EmptyString;
@ -260,6 +275,7 @@ string FSNode::getNameWithExt(const string& ext) const
pos = s.find_last_of('.');
return (pos != string::npos) ? s.replace(pos, string::npos, ext) : s + ext;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -335,117 +351,47 @@ size_t FSNode::getSize() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FSNode::read(ByteBuffer& buffer, size_t size) const
{
size_t sizeRead = 0;
// File must actually exist
if (!(exists() && isReadable()))
throw runtime_error("File not found/readable");
// First let the private subclass attempt to open the file
size_t sizeRead = 0;
if (_realNode && (sizeRead = _realNode->read(buffer, size)) > 0)
return sizeRead;
// Otherwise, the default behaviour is to read from a normal C++ ifstream
std::ifstream in(getPath(), std::ios::binary);
if (in)
{
in.seekg(0, std::ios::end);
sizeRead = static_cast<size_t>(in.tellg());
in.seekg(0, std::ios::beg);
if (sizeRead == 0)
throw runtime_error("Zero-byte file");
else if (size > 0) // If a requested size to read is provided, honour it
sizeRead = std::min(sizeRead, size);
buffer = make_unique<uInt8[]>(sizeRead);
in.read(reinterpret_cast<char*>(buffer.get()), sizeRead);
}
else
throw runtime_error("File open/read error");
return sizeRead;
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FSNode::read(stringstream& buffer) const
{
size_t sizeRead = 0;
// File must actually exist
if (!(exists() && isReadable()))
throw runtime_error("File not found/readable");
// First let the private subclass attempt to open the file
size_t sizeRead = 0;
if (_realNode && (sizeRead = _realNode->read(buffer)) > 0)
return sizeRead;
// Otherwise, the default behaviour is to read from a normal C++ ifstream
// and convert to a stringstream
std::ifstream in(getPath());
if (in)
{
in.seekg(0, std::ios::end);
sizeRead = static_cast<size_t>(in.tellg());
in.seekg(0, std::ios::beg);
if (sizeRead == 0)
throw runtime_error("Zero-byte file");
buffer << in.rdbuf();
}
else
throw runtime_error("File open/read error");
return sizeRead;
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FSNode::write(const ByteBuffer& buffer, size_t size) const
{
size_t sizeWritten = 0;
// First let the private subclass attempt to open the file
if (_realNode && (sizeWritten = _realNode->write(buffer, size)) > 0)
return sizeWritten;
// Otherwise, the default behaviour is to write to a normal C++ ofstream
std::ofstream out(getPath(), std::ios::binary);
if (out)
{
out.write(reinterpret_cast<const char*>(buffer.get()), size);
out.seekp(0, std::ios::end);
sizeWritten = static_cast<size_t>(out.tellp());
out.seekp(0, std::ios::beg);
}
else
throw runtime_error("File open/write error");
return sizeWritten;
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FSNode::write(const stringstream& buffer) const
{
size_t sizeWritten = 0;
// First let the private subclass attempt to open the file
if (_realNode && (sizeWritten = _realNode->write(buffer)) > 0)
return sizeWritten;
// Otherwise, the default behaviour is to write to a normal C++ ofstream
std::ofstream out(getPath());
if (out)
{
out << buffer.rdbuf();
out.seekp(0, std::ios::end);
sizeWritten = static_cast<size_t>(out.tellp());
out.seekp(0, std::ios::beg);
}
else
throw runtime_error("File open/write error");
return sizeWritten;
return 0;
}

View File

@ -18,6 +18,7 @@
#ifndef FS_NODE_HXX
#define FS_NODE_HXX
#include <filesystem>
#include <functional>
#include "bspf.hxx"
@ -34,6 +35,7 @@
class FSNode;
class AbstractFSNode;
using AbstractFSNodePtr = shared_ptr<AbstractFSNode>;
namespace fs = std::filesystem;
/**
* List of multiple file system nodes. E.g. the contents of a given directory.
@ -462,7 +464,7 @@ class AbstractFSNode
* This method can throw exceptions, and should be used inside
* a try-catch block.
*/
virtual size_t read(ByteBuffer& buffer, size_t size) const { return 0; }
virtual size_t read(ByteBuffer& buffer, size_t size) const = 0;
/**
* Read data (text format) into the given stream.
@ -473,7 +475,7 @@ class AbstractFSNode
* This method can throw exceptions, and should be used inside
* a try-catch block.
*/
virtual size_t read(stringstream& buffer) const { return 0; }
virtual size_t read(stringstream& buffer) const = 0;
/**
* Write data (binary format) from the given buffer.
@ -485,7 +487,7 @@ class AbstractFSNode
* This method can throw exceptions, and should be used inside
* a try-catch block.
*/
virtual size_t write(const ByteBuffer& buffer, size_t size) const { return 0; }
virtual size_t write(const ByteBuffer& buffer, size_t size) const = 0;
/**
* Write data (text format) from the given stream.
@ -496,7 +498,7 @@ class AbstractFSNode
* This method can throw exceptions, and should be used inside
* a try-catch block.
*/
virtual size_t write(const stringstream& buffer) const { return 0; }
virtual size_t write(const stringstream& buffer) const = 0;
/**
* Returns the last component of a given path.

View File

@ -37,7 +37,11 @@ FSNodePOSIX::FSNodePOSIX(const string& path, bool verify)
// Expand '~' to the HOME environment variable
if(_path[0] == '~')
{
#if defined(BSPF_WINDOWS)
#else
const char* home = std::getenv("HOME");
#endif
if (home != nullptr)
_path.replace(0, 1, home);
}
@ -49,7 +53,9 @@ FSNodePOSIX::FSNodePOSIX(const string& path, bool verify)
_path = buf.data();
}
_displayName = lastPathComponent(_path);
_fspath = _path;
_displayName = _fspath.filename();
_path = _fspath.string();
if(verify)
setFlags();
@ -58,6 +64,34 @@ FSNodePOSIX::FSNodePOSIX(const string& path, bool verify)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FSNodePOSIX::setFlags()
{
#if 1
// cerr << "_fspath: " << _fspath << endl;
std::error_code ec;
const auto s = fs::status(_fspath, ec);
if (!ec)
{
const auto p = s.permissions();
_isValid = true;
_isFile = fs::is_regular_file(s);
_isDirectory = fs::is_directory(s);
_isReadable = (p & (fs::perms::owner_read |
fs::perms::group_read |
fs::perms::others_read)) != fs::perms::none;
_isWriteable = (p & (fs::perms::owner_write |
fs::perms::group_write |
fs::perms::others_write)) != fs::perms::none;
// cerr << "_isValid: " << _isValid << endl
// << "_isFile: " << _isFile << endl
// << "_isDirectory: " << _isDirectory << endl
// << "_isReadable: " << _isReadable << endl
// << "_isWriteable: " << _isWriteable << endl
// << endl;
}
else
_isValid = _isFile = _isDirectory = _isReadable = _isWriteable = false;
#else
struct stat st;
_isValid = (0 == stat(_path.c_str(), &st));
@ -72,13 +106,18 @@ void FSNodePOSIX::setFlags()
}
else
_isDirectory = _isFile = false;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string FSNodePOSIX::getShortPath() const
{
// If the path starts with the home directory, replace it with '~'
#if defined(BSPF_WINDOWS)
#else
const char* env_home = std::getenv("HOME");
#endif
const string& home = env_home != nullptr ? env_home : EmptyString;
if(home != EmptyString && BSPF::startsWithIgnoreCase(_path, home))
@ -101,6 +140,7 @@ bool FSNodePOSIX::hasParent() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FSNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode) const
{
cerr << "getChildren: " << _path << endl;
assert(_isDirectory);
DIR* dirp = opendir(_path.c_str());
@ -187,6 +227,91 @@ size_t FSNodePOSIX::getSize() const
return (stat(_path.c_str(), &st) == 0) ? st.st_size : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FSNodePOSIX::read(ByteBuffer& buffer, size_t size) const
{
size_t sizeRead = 0;
std::ifstream in(getPath(), std::ios::binary);
if (in)
{
in.seekg(0, std::ios::end);
sizeRead = static_cast<size_t>(in.tellg());
in.seekg(0, std::ios::beg);
if (sizeRead == 0)
throw runtime_error("Zero-byte file");
else if (size > 0) // If a requested size to read is provided, honour it
sizeRead = std::min(sizeRead, size);
buffer = make_unique<uInt8[]>(sizeRead);
in.read(reinterpret_cast<char*>(buffer.get()), sizeRead);
}
else
throw runtime_error("File open/read error");
return sizeRead;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FSNodePOSIX::read(stringstream& buffer) const
{
size_t sizeRead = 0;
std::ifstream in(getPath());
if (in)
{
in.seekg(0, std::ios::end);
sizeRead = static_cast<size_t>(in.tellg());
in.seekg(0, std::ios::beg);
if (sizeRead == 0)
throw runtime_error("Zero-byte file");
buffer << in.rdbuf();
}
else
throw runtime_error("File open/read error");
return sizeRead;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FSNodePOSIX::write(const ByteBuffer& buffer, size_t size) const
{
size_t sizeWritten = 0;
std::ofstream out(getPath(), std::ios::binary);
if (out)
{
out.write(reinterpret_cast<const char*>(buffer.get()), size);
out.seekp(0, std::ios::end);
sizeWritten = static_cast<size_t>(out.tellp());
out.seekp(0, std::ios::beg);
}
else
throw runtime_error("File open/write error");
return sizeWritten;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FSNodePOSIX::write(const stringstream& buffer) const
{
size_t sizeWritten = 0;
std::ofstream out(getPath());
if (out)
{
out << buffer.rdbuf();
out.seekp(0, std::ios::end);
sizeWritten = static_cast<size_t>(out.tellp());
out.seekp(0, std::ios::beg);
}
else
throw runtime_error("File open/write error");
return sizeWritten;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FSNodePOSIX::makeDir()
{

View File

@ -39,9 +39,11 @@
#endif
/*
* Implementation of the Stella file system API based on POSIX (for Linux and macOS)
* Implementation of the Stella filesystem API for regular files,
* based on the std::filesystem API in C++17.
*
* Parts of this class are documented in the base interface class, AbstractFSNode.
* Parts of this class are documented in the base interface classes,
* AbstractFSNode and FSNode. See those classes for more information.
*/
class FSNodePOSIX : public AbstractFSNode
{
@ -60,7 +62,7 @@ class FSNodePOSIX : public AbstractFSNode
*/
explicit FSNodePOSIX(const string& path, bool verify = true);
bool exists() const override { return access(_path.c_str(), F_OK) == 0; }
bool exists() const override { return fs::exists(_fspath); }
const string& getName() const override { return _displayName; }
void setName(const string& name) override { _displayName = name; }
const string& getPath() const override { return _path; }
@ -68,21 +70,25 @@ class FSNodePOSIX : public AbstractFSNode
bool hasParent() const override;
bool isDirectory() const override { return _isDirectory; }
bool isFile() const override { return _isFile; }
bool isReadable() const override { return access(_path.c_str(), R_OK) == 0; }
bool isWritable() const override { return access(_path.c_str(), W_OK) == 0; }
bool isReadable() const override { return _isReadable; }
bool isWritable() const override { return _isWriteable; }
bool makeDir() override;
bool rename(const string& newfile) override;
size_t getSize() const override;
size_t read(ByteBuffer& buffer, size_t size) const override;
size_t read(stringstream& buffer) const override;
size_t write(const ByteBuffer& buffer, size_t size) const override;
size_t write(const stringstream& buffer) const override;
bool getChildren(AbstractFSList& list, ListMode mode) const override;
AbstractFSNodePtr getParent() const override;
protected:
string _path;
string _displayName;
bool _isValid{true};
bool _isFile{false};
bool _isDirectory{true};
fs::path _fspath;
string _path, _displayName;
bool _isValid{false}, _isFile{false}, _isDirectory{false},
_isReadable{false}, _isWriteable{false};
private:
/**