From b8345246dcc2121bcb6d1515a9341789de20199f Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Sun, 27 Oct 2024 09:04:05 -0500 Subject: First crack at file objects. --- source/fud_file.cpp | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 source/fud_file.cpp (limited to 'source/fud_file.cpp') diff --git a/source/fud_file.cpp b/source/fud_file.cpp new file mode 100644 index 0000000..e27a46d --- /dev/null +++ b/source/fud_file.cpp @@ -0,0 +1,201 @@ +/* + * libfud + * Copyright 2024 Dominick Allen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fud_file.hpp" + +#include +#include +#include +#include +#include +#include + +namespace fud { + +FileResult RegularFile::open( + StringView filename, + FileAccessMode mode, + OpenFlags flags, + Option 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(); + + open_how openHow{}; + zeroObject(openHow); + openHow.flags = openFlags; + openHow.resolve = RESOLVE_NO_SYMLINKS; + + 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 ENOENT: + return FudStatus::NotFound; + case EFBIG: + case EOVERFLOW: + case EINVAL: + case EISDIR: + case ENAMETOOLONG: + return FudStatus::ArgumentInvalid; + case EROFS: + case EACCES: + case EPERM: + return FudStatus::PermissionDenied; + case ELOOP: + case EXDEV: + case ENFILE: + case E2BIG: + default: + return FudStatus::Failure; + } + } + fudAssert(status <= std::numeric_limits::max()); + file.m_fd = static_cast(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; +} + +/* + static FileResult RegularFile::create( + StringView filename, + FileAccessMode mode, + OpenFlags flags, + bool exclusive, + Option dirFdOption, + Allocator* allocator = &globalFudAllocator); +{ +} +*/ + +RegularFile::~RegularFile() +{ + static_cast(this->close()); +} + +RegularFile::RegularFile(RegularFile&& rhs) noexcept : m_fd{rhs.m_fd}, m_modeFlags{rhs.m_modeFlags} +{ + rhs.m_fd = -1; +} + +RegularFile& RegularFile::operator=(RegularFile&& rhs) noexcept +{ + if (&rhs == this) { + return *this; + } + + static_cast(this->close()); + + m_fd = rhs.m_fd; + m_modeFlags = rhs.m_modeFlags; + + rhs.m_fd = -1; + return *this; +} + +FudStatus RegularFile::take(RegularFile& rhs) +{ + if (&rhs == this) { + return FudStatus::Success; + } + + auto status = this->close(); + if (status != FudStatus::Success) { + return status; + } + + m_fd = rhs.m_fd; + m_modeFlags = rhs.m_modeFlags; + + rhs.m_fd = -1; + return status; +} + +FudStatus RegularFile::close() +{ + FudStatus status = FudStatus::Success; + if (m_fd != -1) { + auto closeStatus = ::close(m_fd); + if (closeStatus == -1) { + switch (errno) { + case EBADF: + status = FudStatus::HandleInvalid; + break; + case EINTR: + case EIO: + case ENOSPC: + case EDQUOT: + status = FudStatus::Partial; + break; + default: + status = FudStatus::Failure; + break; + } + } + m_fd = -1; + } + return status; +} + +} // namespace fud -- cgit v1.2.3