/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuIOHandle.Unix.cpp Date: 2023-8-11 Author: Reece ***/ #include #include "AuIOHandle.hpp" #include "AuIOHandle.Unix.hpp" #include "FS/FS.hpp" #include "FS/FileAdvisory.Unix.hpp" #include "FS/FileStream.Unix.hpp" #include #include #include #if defined(AURORA_COMPILER_CLANG) // warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch #pragma clang diagnostic ignored "-Wswitch" // Yea, I don't give a shit. #endif 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; }; bool UnixIOHandle::InitFromPath(HandleCreate create) { 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(); } AUKN_SYM bool IsHandleTTY(AuUInt uHandle) { if ((AuSInt)uHandle < 0) { SysPushErrorArg(); return false; } return ::isatty((int)uHandle); } AUKN_SYM bool IsHandlePipe(AuUInt uHandle) { struct stat st; if ((AuSInt)uHandle < 0) { SysPushErrorArg(); return false; } if (::fstat((int)uHandle, &st) != 0) { SysPushErrorIO("fstat failed"); return false; } return S_ISFIFO(st.st_mode); } AUKN_SYM bool IsHandleFile(AuUInt uHandle) { struct stat st; if ((AuSInt)uHandle < 0) { SysPushErrorArg(); return false; } if (::fstat((int)uHandle, &st) != 0) { SysPushErrorIO("fstat failed"); return false; } return S_ISREG(st.st_mode); } AUKN_SYM IIOHandle *IOHandleNew() { return _new UnixIOHandle(); } AUKN_SYM void IOHandleRelease(IIOHandle *pIOHandle) { AuSafeDelete(pIOHandle); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, IOHandle, UnixIOHandle) }