summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominick Allen <djallen@librehumanitas.org>2024-09-28 11:14:31 -0500
committerDominick Allen <djallen@librehumanitas.org>2024-09-28 11:14:31 -0500
commitb6967c8a9190efa4e9128850fa723fe3ea3140f7 (patch)
tree101be12055abd27968fce2666d573c80f8afe22d
parent987466c74332025fae74d196ff680a57ccb247a2 (diff)
Expand directory interface, remove FileStatus for FudStatus.
-rw-r--r--include/fud_c_file.hpp53
-rw-r--r--include/fud_directory.hpp43
-rw-r--r--source/fud_c_file.cpp46
-rw-r--r--source/fud_directory.cpp158
-rw-r--r--test/test_directory.cpp5
5 files changed, 182 insertions, 123 deletions
diff --git a/include/fud_c_file.hpp b/include/fud_c_file.hpp
index 674130c..9605ff0 100644
--- a/include/fud_c_file.hpp
+++ b/include/fud_c_file.hpp
@@ -18,6 +18,7 @@
#ifndef FUD_C_FILE_HPP
#define FUD_C_FILE_HPP
+#include "fud_status.hpp"
#include "fud_result.hpp"
#include "fud_string.hpp"
@@ -77,64 +78,40 @@ constexpr const char* CTextFileModeFromFlags(CFileMode mode)
}
}
-enum class FileStatus
-{
- Success,
- PartialSuccess,
- InvalidName,
- InvalidArgument,
- InvalidState,
- NullPointer,
- Error,
-};
-
-static inline const char* FileStatusToString(FileStatus status)
-{
- switch (status) {
- case FileStatus::Success:
- return "Success";
- case FileStatus::PartialSuccess:
- return "PartialSuccess";
- case FileStatus::InvalidName:
- return "InvalidName";
- case FileStatus::InvalidArgument:
- return "InvalidArgument";
- case FileStatus::InvalidState:
- return "InvalidState";
- case FileStatus::NullPointer:
- return "NullPointer";
- case FileStatus::Error:
- return "Error";
- default:
- return "Unknown";
- }
-}
-
struct [[nodiscard]] ReadResult {
size_t bytesRead{0};
- FileStatus status{FileStatus::Success};
+ FudStatus status{FudStatus::Success};
};
struct [[nodiscard]] WriteResult {
size_t bytesWritten{0};
- FileStatus status{FileStatus::Success};
+ FudStatus status{FudStatus::Success};
};
class CBinaryFile {
public:
CBinaryFile(const String& filename, CFileMode mode);
+
CBinaryFile(const String& filename, CFileMode mode, const String& extraFlags);
+
CBinaryFile(const CBinaryFile& rhs) = delete;
+
~CBinaryFile();
+
CBinaryFile& operator=(const CBinaryFile& rhs) = delete;
- FileStatus open();
+
+ CBinaryFile& operator=(CBinaryFile&& rhs);
+
+ FudStatus open();
+
void close();
+
const FILE* file() const;
[[nodiscard]] FILE* file();
[[nodiscard]] bool isOpen() const;
- [[nodiscard]] Result<size_t, FileStatus> size() const;
+ [[nodiscard]] Result<size_t, FudStatus> size() const;
[[nodiscard]] ReadResult read(void* destination, size_t destinationSize, size_t length);
@@ -179,7 +156,7 @@ class CBinaryFile {
}
private:
- FileStatus reset() const;
+ FudStatus reset() const;
const String m_filename;
String m_extraFlags{};
diff --git a/include/fud_directory.hpp b/include/fud_directory.hpp
index ac48b7b..5a988dc 100644
--- a/include/fud_directory.hpp
+++ b/include/fud_directory.hpp
@@ -24,9 +24,9 @@
#include <cstdint>
#include <cstdio>
+#include <ctime>
#include <dirent.h>
#include <optional>
-#include <ctime>
namespace fud {
@@ -42,6 +42,31 @@ enum class DirectoryEntryType : uint8_t
Unknown
};
+constexpr const char* DirectoryEntryTypeToString(DirectoryEntryType entryType)
+{
+ switch (entryType) {
+ case DirectoryEntryType::Block:
+ return "Block";
+ case DirectoryEntryType::Character:
+ return "Character";
+ case DirectoryEntryType::Directory:
+ return "Directory";
+ case DirectoryEntryType::NamedPipe:
+ return "Named Pipe";
+ case DirectoryEntryType::SymbolicLink:
+ return "Symbolic Link";
+ case DirectoryEntryType::RegularFile:
+ return "Regular File";
+ case DirectoryEntryType::UnixSocket:
+ return "Unix Socket";
+ case DirectoryEntryType::Unknown:
+ default:
+ return "Unknown";
+ }
+}
+
+struct Stat;
+
/** \brief Simplified Directory Entry */
struct DirectoryEntry {
String name;
@@ -49,6 +74,18 @@ struct DirectoryEntry {
size_t links;
time_t modificationTime;
DirectoryEntryType entryType;
+
+ static Result<DirectoryEntry, FudStatus> fromStat(const String& name, const Stat& statBuffer);
+
+ [[nodiscard]] constexpr bool isDirectory() const
+ {
+ return entryType == DirectoryEntryType::Directory;
+ }
+
+ [[nodiscard]] constexpr bool isRegularFile() const
+ {
+ return entryType == DirectoryEntryType::RegularFile;
+ }
};
class Directory {
@@ -70,11 +107,15 @@ class Directory {
return m_errorCode;
}
+ Result<DirectoryEntry, FudStatus> info();
+
Result<std::optional<DirectoryEntry>, FudStatus> getNextEntry();
FudStatus reset();
private:
+ bool valid() const;
+
String m_name{};
DIR* m_directory{nullptr};
FudStatus m_status{FudStatus::ObjectInvalid};
diff --git a/source/fud_c_file.cpp b/source/fud_c_file.cpp
index cad4c9d..b323847 100644
--- a/source/fud_c_file.cpp
+++ b/source/fud_c_file.cpp
@@ -38,13 +38,13 @@ CBinaryFile::~CBinaryFile() {
close();
}
-FileStatus CBinaryFile::open()
+FudStatus CBinaryFile::open()
{
if (!m_filename.valid()) {
- return FileStatus::InvalidName;
+ return FudStatus::ObjectInvalid;
}
m_file = fopen(m_filename.c_str(), m_mode.c_str());
- return m_file != nullptr ? FileStatus::Success : FileStatus::Error;
+ return m_file != nullptr ? FudStatus::Success : FudStatus::Failure;
}
void CBinaryFile::close()
@@ -70,27 +70,27 @@ bool CBinaryFile::isOpen() const
return m_file != nullptr;
}
-Result<size_t, FileStatus> CBinaryFile::size() const
+Result<size_t, FudStatus> CBinaryFile::size() const
{
- using RetType = Result<size_t, FileStatus>;
+ using RetType = Result<size_t, FudStatus>;
if (!isOpen()) {
- return RetType::error(FileStatus::InvalidState);
+ return RetType::error(FudStatus::OperationInvalid);
}
auto seekStatus = fseek(m_file, 0, SEEK_END);
if (seekStatus != 0) {
- return RetType::error(FileStatus::Error);
+ return RetType::error(FudStatus::Failure);
}
auto fileSizeResult = ftell(m_file);
if (fileSizeResult < 0) {
- return RetType::error(FileStatus::Error);
+ return RetType::error(FudStatus::Failure);
}
auto fileSize = static_cast<size_t>(fileSizeResult);
auto resetStatus = reset();
- if (resetStatus != FileStatus::Success) {
+ if (resetStatus != FudStatus::Success) {
return RetType::error(resetStatus);
}
@@ -110,12 +110,12 @@ ReadResult CBinaryFile::read(void* destination, size_t destinationSize, size_t l
}
if (destination == nullptr) {
- result.status = FileStatus::NullPointer;
+ result.status = FudStatus::NullPointer;
return result;
}
if (offset > LONG_MAX || SIZE_MAX - offset < length || destinationSize < length) {
- result.status = FileStatus::InvalidArgument;
+ result.status = FudStatus::InvalidInput;
return result;
}
@@ -127,13 +127,13 @@ ReadResult CBinaryFile::read(void* destination, size_t destinationSize, size_t l
auto fileSize = fileSizeResult.getOkay();
if (offset + length > fileSize) {
- result.status = FileStatus::InvalidArgument;
+ result.status = FudStatus::InvalidInput;
return result;
}
auto seekResult = fseek(m_file, static_cast<long>(offset), SEEK_SET);
if (seekResult != 0) {
- result.status = FileStatus::Error;
+ result.status = FudStatus::Failure;
return result;
}
@@ -141,9 +141,9 @@ ReadResult CBinaryFile::read(void* destination, size_t destinationSize, size_t l
result.bytesRead = fread(destBytes, 1, length, m_file);
static_cast<void>(reset());
if (result.bytesRead != length) {
- result.status = FileStatus::PartialSuccess;
+ result.status = FudStatus::Partial;
} else {
- result.status = FileStatus::Success;
+ result.status = FudStatus::Success;
}
return result;
@@ -167,12 +167,12 @@ WriteResult CBinaryFile::write(const void* source, size_t sourceSize, size_t len
}
if (source == nullptr) {
- result.status = FileStatus::NullPointer;
+ result.status = FudStatus::NullPointer;
return result;
}
if (offset > LONG_MAX || SIZE_MAX - offset < length || sourceSize < length) {
- result.status = FileStatus::InvalidArgument;
+ result.status = FudStatus::InvalidInput;
return result;
}
@@ -192,7 +192,7 @@ WriteResult CBinaryFile::write(const void* source, size_t sourceSize, size_t len
}
if (seekResult != 0) {
- result.status = FileStatus::Error;
+ result.status = FudStatus::Failure;
return result;
}
@@ -200,20 +200,20 @@ WriteResult CBinaryFile::write(const void* source, size_t sourceSize, size_t len
result.bytesWritten = fwrite(sourceBytes, 1, length, m_file);
static_cast<void>(reset());
if (result.bytesWritten != length) {
- result.status = FileStatus::PartialSuccess;
+ result.status = FudStatus::Partial;
} else {
- result.status = FileStatus::Success;
+ result.status = FudStatus::Success;
}
return result;
}
-FileStatus CBinaryFile::reset() const {
+FudStatus CBinaryFile::reset() const {
if (!isOpen()) {
- return FileStatus::InvalidState;
+ return FudStatus::OperationInvalid;
}
auto result = fseek(m_file, 0, SEEK_SET);
- return result == 0 ? FileStatus::Success : FileStatus::Error;
+ return result == 0 ? FudStatus::Success : FudStatus::Failure;
}
} // namespace fud
diff --git a/source/fud_directory.cpp b/source/fud_directory.cpp
index 39f2e10..99f3600 100644
--- a/source/fud_directory.cpp
+++ b/source/fud_directory.cpp
@@ -23,6 +23,57 @@
namespace fud {
+using CStat = struct stat;
+struct Stat : public CStat {};
+
+Result<DirectoryEntry, FudStatus> DirectoryEntry::fromStat(const String& name, const Stat& statBuffer)
+{
+ using RetType = Result<DirectoryEntry, FudStatus>;
+ static_assert(std::is_same_v<decltype(statBuffer.st_size), long>);
+ static_assert(sizeof(decltype(statBuffer.st_size)) <= sizeof(size_t));
+
+ static_assert(std::is_same_v<decltype(statBuffer.st_nlink), unsigned long>);
+ static_assert(sizeof(decltype(statBuffer.st_nlink)) <= sizeof(size_t));
+
+ size_t size{0};
+ if (statBuffer.st_size < 0) {
+ return RetType::error(FudStatus::Failure);
+ } else {
+ size = static_cast<size_t>(statBuffer.st_size);
+ }
+
+ DirectoryEntryType entryType;
+ switch (statBuffer.st_mode & S_IFMT) {
+ case S_IFBLK:
+ entryType = DirectoryEntryType::Block;
+ break;
+ case S_IFCHR:
+ entryType = DirectoryEntryType::Character;
+ break;
+ case S_IFDIR:
+ entryType = DirectoryEntryType::Directory;
+ break;
+ case S_IFIFO:
+ entryType = DirectoryEntryType::NamedPipe;
+ break;
+ case S_IFLNK:
+ entryType = DirectoryEntryType::SymbolicLink;
+ break;
+ case S_IFREG:
+ entryType = DirectoryEntryType::RegularFile;
+ break;
+ case S_IFSOCK:
+ entryType = DirectoryEntryType::UnixSocket;
+ break;
+ default:
+ entryType = DirectoryEntryType::Unknown;
+ break;
+ }
+
+ return RetType::okay(
+ DirectoryEntry{name, size, static_cast<size_t>(statBuffer.st_nlink), statBuffer.st_mtime, entryType});
+}
+
Directory::Directory(String name) : m_name{name}
{
if (!m_name.valid()) {
@@ -81,11 +132,45 @@ Directory::~Directory()
}
}
+bool Directory::valid() const
+{
+ return m_directory != nullptr && m_dirFd != -1;
+}
+
+Result<DirectoryEntry, FudStatus> Directory::info()
+{
+ using RetType = Result<DirectoryEntry, FudStatus>;
+
+ if (!valid()) {
+ m_status = FudStatus::ObjectInvalid;
+ return RetType::error(m_status);
+ }
+
+ Stat statBuffer{};
+ auto status = fstat(m_dirFd, &statBuffer);
+ if (status == -1) {
+ m_errorCode = errno;
+ m_status = FudStatus::Failure;
+ return RetType::error(m_status);
+ }
+
+ auto retValue = DirectoryEntry::fromStat(m_name, statBuffer);
+
+ if (retValue.isOkay()) {
+ m_errorCode = 0;
+ m_status = FudStatus::Success;
+ } else {
+ m_status = retValue.getError();
+ }
+
+ return retValue;
+}
+
Result<std::optional<DirectoryEntry>, FudStatus> Directory::getNextEntry()
{
using RetType = Result<std::optional<DirectoryEntry>, FudStatus>;
- if (m_directory == nullptr || m_dirFd == -1) {
+ if (!valid()) {
m_status = FudStatus::ObjectInvalid;
return RetType::error(m_status);
}
@@ -102,8 +187,8 @@ Result<std::optional<DirectoryEntry>, FudStatus> Directory::getNextEntry()
}
}
- const char* entryName = dirEntry->d_name;
- if (entryName == nullptr) {
+ const char* entryNameCString = dirEntry->d_name;
+ if (entryNameCString == nullptr) {
m_errorCode = -1;
m_status = FudStatus::NullPointer;
return RetType::error(m_status);
@@ -111,82 +196,39 @@ Result<std::optional<DirectoryEntry>, FudStatus> Directory::getNextEntry()
m_errorCode = 0;
- using Stat = struct stat;
Stat statBuffer{};
auto flags = 0;
- auto status = fstatat(m_dirFd, entryName, &statBuffer, flags);
+ auto status = fstatat(m_dirFd, entryNameCString, &statBuffer, flags);
if (status == -1) {
m_errorCode = errno;
m_status = FudStatus::Failure;
return RetType::error(m_status);
}
- DirectoryEntryType entryType;
- switch (statBuffer.st_mode & S_IFMT) {
- case S_IFBLK:
- entryType = DirectoryEntryType::Block;
- break;
- case S_IFCHR:
- entryType = DirectoryEntryType::Character;
- break;
- case S_IFDIR:
- entryType = DirectoryEntryType::Directory;
- break;
- case S_IFIFO:
- entryType = DirectoryEntryType::NamedPipe;
- break;
- case S_IFLNK:
- entryType = DirectoryEntryType::SymbolicLink;
- break;
- case S_IFREG:
- entryType = DirectoryEntryType::RegularFile;
- break;
- case S_IFSOCK:
- entryType = DirectoryEntryType::UnixSocket;
- break;
- default:
- entryType = DirectoryEntryType::Unknown;
- break;
- }
-
- static_assert(std::is_same_v<decltype(statBuffer.st_size), long>);
- static_assert(sizeof(decltype(statBuffer.st_size)) <= sizeof(size_t));
+ auto entryName = String{entryNameCString};
+ auto retValue = DirectoryEntry::fromStat(entryName, statBuffer);
- size_t size{0};
- if (statBuffer.st_size < 0) {
- size = SIZE_MAX;
- } else {
- size = static_cast<size_t>(statBuffer.st_size);
+ if (retValue.isOkay()) {
+ m_errorCode = 0;
+ m_status = FudStatus::Success;
+ return RetType::okay(retValue.getOkay());
}
- static_assert(std::is_same_v<decltype(statBuffer.st_nlink), unsigned long>);
- static_assert(sizeof(decltype(statBuffer.st_nlink)) <= sizeof(size_t));
-
- DirectoryEntry entry{
- String{dirEntry->d_name},
- size,
- static_cast<size_t>(statBuffer.st_nlink),
- statBuffer.st_mtime,
- entryType};
-
- if (!entry.name.valid()) {
- m_status = FudStatus::StringInvalid;
- return RetType::error(m_status);
- }
-
- m_status = FudStatus::Success;
- return RetType::okay(std::move(entry));
+ m_status = retValue.getError();
+ return RetType::error(retValue.getError());
}
FudStatus Directory::reset()
{
+ if (!valid()) {
+ }
if (m_directory != nullptr) {
rewinddir(m_directory);
} else {
m_status = FudStatus::ObjectInvalid;
return m_status;
}
- return FudStatus::NotImplemented;
+ return FudStatus::Success;
}
} // namespace fud
diff --git a/test/test_directory.cpp b/test/test_directory.cpp
index 9cec80d..45d0c77 100644
--- a/test/test_directory.cpp
+++ b/test/test_directory.cpp
@@ -100,9 +100,9 @@ TEST(FudDirectory, Basic)
const auto fname = testDirNamePrefix.catenate(fnameBase);
ASSERT_TRUE(fname.utf8Valid());
CBinaryFile file{fname, CFileMode::ReadWriteTruncate};
- ASSERT_EQ(file.open(), FileStatus::Success);
+ ASSERT_EQ(file.open(), FudStatus::Success);
Array<utf8, 5> data{"test"};
- WriteResult expected{data.size(), FileStatus::Success};
+ WriteResult expected{data.size(), FudStatus::Success};
auto writeResult = file.write(data);
ASSERT_EQ(writeResult.bytesWritten, expected.bytesWritten);
ASSERT_EQ(writeResult.status, expected.status);
@@ -134,7 +134,6 @@ TEST(FudDirectory, Basic)
[&dirEntry](const DirectoryEntry& entry) { return entry.name.compare(dirEntry.name) && entry.entryType == dirEntry.entryType; });
EXPECT_NE(expected, nullptr);
EXPECT_NE(expected, expectedFiles.end());
- printf("%s %u\n", dirEntry.name.c_str(), static_cast<uint8_t>(dirEntry.entryType));
}
auto finalDirEntryResult = directory.getNextEntry();