AuroraRuntime/Source/IO/AuIOHandle.Unix.cpp

273 lines
6.7 KiB
C++

/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIOHandle.Unix.cpp
Date: 2023-8-11
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "AuIOHandle.hpp"
#include "AuIOHandle.Unix.hpp"
#include "FS/FS.hpp"
#include "FS/FileAdvisory.Unix.hpp"
#include "FS/FileStream.Unix.hpp"
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
namespace Aurora::IO
{
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess)
{
int fd = dup(uOSHandle);
if (fd < 0)
{
return 0;
}
return AuUInt64(fd);
}
void AFileHandle::CloseHandle(AuUInt64 uOSHandle)
{
int fd = (int)uOSHandle;
if (fd < 0)
{
return;
}
::close(fd);
}
struct UnixIOHandle final : AFileHandle
{
bool InitFromPath(HandleCreate create) override
{
int iFileDescriptor { -1 };
if (create.path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
if (!FS::EFileOpenModeIsValid(create.eMode))
{
SysPushErrorParam("Invalid open mode");
return false;
}
if (!FS::EFileAdvisoryLockLevelIsValid(create.eAdvisoryLevel))
{
SysPushErrorParam("Invalid lock mode");
return false;
}
auto pathex = FS::NormalizePathRet(create.path);
if (pathex.empty())
{
SysPushErrorMemory();
return false;
}
if (create.bAsyncHandle ||
create.bDirectIOMode)
{
this->bDirectIO = true;
}
switch (create.eMode)
{
case FS::EFileOpenMode::eRead:
{
break;
}
case FS::EFileOpenMode::eReadWrite:
case FS::EFileOpenMode::eWrite:
{
if (create.bAlwaysCreateDirTree)
{
FS::CreateDirectories(pathex, true);
}
if (create.bFailIfNonEmptyFile)
{
if (AuFS::FileExists(pathex.c_str()))
{
SysPushErrorResourceExists("File {} already exists", create.path);
return false;
}
}
break;
}
};
iFileDescriptor = ::open(pathex.c_str(),
(create.eMode == FS::EFileOpenMode::eRead ? O_RDONLY : (O_RDWR | O_CREAT)) | O_CLOEXEC | (this->bDirectIO ? O_DIRECT : 0),
0664);
if (iFileDescriptor < 0)
{
SysPushErrorIO("Couldn't open file: {} ({}) {}", path, pathex, errno);
return false;
}
if (!FS::ApplyDumbAdvisoryLock(iFileDescriptor, create.eAdvisoryLevel))
{
SysPushErrorIO("Couldn't open file: {}. File node (not section) is locked.", path);
::close(iFileDescriptor);
return false;
}
if (create.bFailIfNonEmptyFile)
{
if (FS::PosixGetLength(iFileDescriptor))
{
SysPushErrorResourceExists("File {} already exists", create.path);
::close(iFileDescriptor);
return false;
}
}
switch (create.eMode)
{
case FS::EFileOpenMode::eRead:
{
this->uOSReadHandle = AuUInt64(iFileDescriptor);
break;
}
case FS::EFileOpenMode::eReadWrite:
{
this->uOSWriteHandle = AuUInt64(iFileDescriptor);
this->uOSReadHandle = AuUInt64(iFileDescriptor);
break;
}
case FS::EFileOpenMode::eWrite:
{
this->uOSWriteHandle = AuUInt64(iFileDescriptor);
break;
}
};
this->bIsAsync = create.bAsyncHandle;
this->path = create.path;
return this->IsValid();
}
bool IsFile() override;
bool IsTTY() override;
bool IsPipe() override;
AuOptionalEx<bool> optIsFile {};
AuOptionalEx<bool> optIsPipe {};
AuOptionalEx<bool> optIsTTY {};
};
bool UnixIOHandle::IsFile()
{
bool bIsFile {};
struct stat st;
int iFileDescriptor {};
if (auto file = this->optIsFile)
{
return file.value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
iFileDescriptor = (int)optHandle.value();
}
else
{
SysPushErrorUninitialized();
return false;
}
if (::fstat(iFileDescriptor, &st) != 0)
{
SysPushErrorIO("fstat failed");
return false;
}
bIsFile = S_ISREG(st.st_mode);
this->optIsFile = bIsFile;
return bIsFile;
}
bool UnixIOHandle::IsTTY()
{
bool bIsTTY {};
int iFileDescriptor {};
if (auto file = this->optIsTTY)
{
return file.value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
iFileDescriptor = (int)optHandle.value();
}
else
{
SysPushErrorUninitialized();
return false;
}
bIsTTY = ::isatty(iFileDescriptor);
this->optIsTTY = bIsTTY;
return bIsTTY;
}
bool UnixIOHandle::IsPipe()
{
bool bIsPipe {};
struct stat st;
int iFileDescriptor {};
if (auto file = this->optIsPipe)
{
return file.value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
iFileDescriptor = (int)optHandle.value();
}
else
{
SysPushErrorUninitialized();
return false;
}
if (::fstat(iFileDescriptor, &st) != 0)
{
SysPushErrorIO("fstat failed");
return false;
}
bIsPipe = S_ISFIFO(st.st_mode);
this->optIsPipe = bIsPipe;
return bIsPipe;
}
AUKN_SYM IIOHandle *IOHandleNew()
{
return _new UnixIOHandle();
}
AUKN_SYM void IOHandleRelease(IIOHandle *pIOHandle)
{
AuSafeDelete<UnixIOHandle *>(pIOHandle);
}
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, IOHandle, UnixIOHandle)
}