summaryrefslogtreecommitdiff
path: root/source/fud_file.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/fud_file.cpp')
-rw-r--r--source/fud_file.cpp123
1 files changed, 114 insertions, 9 deletions
diff --git a/source/fud_file.cpp b/source/fud_file.cpp
index e27a46d..8dab031 100644
--- a/source/fud_file.cpp
+++ b/source/fud_file.cpp
@@ -82,6 +82,7 @@ FileResult RegularFile::open(
return FudStatus::Partial;
case ENOENT:
return FudStatus::NotFound;
+ case EBADF:
case EFBIG:
case EOVERFLOW:
case EINVAL:
@@ -117,17 +118,100 @@ FileResult RegularFile::open(
return file;
}
-/*
- static FileResult RegularFile::create(
- StringView filename,
- FileAccessMode mode,
- OpenFlags flags,
- bool exclusive,
- Option<int> dirFdOption,
- Allocator* allocator = &globalFudAllocator);
+FileResult RegularFile::create(
+ StringView filename,
+ FileAccessMode mode,
+ OpenFlags flags,
+ Permissions permissions,
+ bool exclusive,
+ Option<int> dirFdOption,
+ Allocator* allocator)
{
+ if (allocator == nullptr) {
+ return FudStatus::NullPointer;
+ }
+
+ if (!filename.nullTerminated()) {
+ return FudStatus::ArgumentInvalid;
+ }
+
+ int dirFd = dirFdOption.valueOr(AT_FDCWD);
+
+ RegularFile file{};
+
+ uint32_t openFlags = 0;
+ switch (mode) {
+ case FileAccessMode::Read:
+ openFlags = O_RDONLY;
+ break;
+ case FileAccessMode::Write:
+ openFlags = O_WRONLY;
+ break;
+ case FileAccessMode::ReadWrite:
+ openFlags = O_RDWR;
+ break;
+ default:
+ return FudStatus::ArgumentInvalid;
+ }
+
+ if (flags.hasFlag(OpenFlagEnum::Append) && flags.hasFlag(OpenFlagEnum::Truncate)) {
+ return FudStatus::OperationInvalid;
+ }
+
+ openFlags |= flags.flags() | O_CREAT | (O_EXCL * static_cast<uint8_t>(exclusive));
+
+ open_how openHow{};
+ zeroObject(openHow);
+ openHow.flags = openFlags;
+ openHow.resolve = RESOLVE_NO_SYMLINKS;
+ openHow.mode = permissions.mode();
+
+ auto status = syscall(SYS_openat2, dirFd, filename.data(), &openHow, sizeof(openHow));
+ if (status == -1) {
+ if constexpr (EAGAIN != EWOULDBLOCK && status == EWOULDBLOCK) {
+ return FudStatus::Partial;
+ }
+ switch (errno) {
+ case ETXTBSY:
+ case EAGAIN:
+ return FudStatus::Partial;
+ case EBADF:
+ case EFBIG:
+ case EOVERFLOW:
+ case EINVAL:
+ case EISDIR:
+ case ENAMETOOLONG:
+ return FudStatus::ArgumentInvalid;
+ case EROFS:
+ case EACCES:
+ case EPERM:
+ return FudStatus::PermissionDenied;
+ case EDQUOT:
+ case ENOENT:
+ case ELOOP:
+ case EXDEV:
+ case ENFILE:
+ case E2BIG:
+ default:
+ return FudStatus::Failure;
+ }
+ }
+ fudAssert(status <= std::numeric_limits<decltype(file.m_fd)>::max());
+ file.m_fd = static_cast<decltype(file.m_fd)>(status);
+
+ using Stat = struct stat;
+ Stat sBuffer{};
+ auto fStatus = fstat(file.m_fd, &sBuffer);
+ if (fStatus == -1) {
+ return FudStatus::Failure;
+ }
+
+ if ((sBuffer.st_mode & S_IFMT) != S_IFREG) {
+ return FudStatus::ObjectInvalid;
+ }
+
+ return file;
}
-*/
RegularFile::~RegularFile()
{
@@ -198,4 +282,25 @@ FudStatus RegularFile::close()
return status;
}
+Result<size_t, FudStatus> RegularFile::size() const
+{
+ auto fileSize = lseek(m_fd, 0, SEEK_END);
+ if (fileSize == -1) {
+ switch (errno) {
+ case EBADF:
+ case ESPIPE:
+ return FudStatus::ObjectInvalid;
+ default:
+ return FudStatus::Failure;
+ }
+ }
+
+ auto seekBegin = lseek(m_fd, 0, SEEK_SET);
+ if (seekBegin == -1) {
+ return FudStatus::Failure;
+ }
+
+ return static_cast<size_t>(fileSize);
+}
+
} // namespace fud