[*] (Mostly Linux) Harden FS apis

This commit is contained in:
Reece Wilson 2023-09-16 01:13:41 +01:00 committed by Jamie Reece Wilson
parent 9bfd895fc4
commit 9a294cf955
3 changed files with 304 additions and 73 deletions

View File

@ -87,6 +87,12 @@ namespace Aurora::IO::FS
AUKN_SYM AuSPtr<IReadDir> ReadDir(const AuString &string)
{
if (string.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return {};
}
auto pObj = AuMakeShared<ReadDirStructure>();
if (!pObj)
{
@ -143,12 +149,6 @@ namespace Aurora::IO::FS
AUKN_SYM bool DirsInDirectory(const AuString &string, AuList<AuString> &dirs)
{
if (string.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto itr = ReadDir(string);
if (!itr)
{
@ -346,16 +346,35 @@ namespace Aurora::IO::FS
return false;
}
if (::DeleteFileW(translatedPath.c_str()))
DWORD dwAttrib = ::GetFileAttributesW(translatedPath.c_str());
if (dwAttrib == INVALID_FILE_ATTRIBUTES)
{
return true;
SysPushErrorIO("Couldn't open file ({}) for removal", path);
return false;
}
if (::RemoveDirectoryW(translatedPath.c_str()))
if (dwAttrib & FILE_ATTRIBUTE_READONLY)
{
return true;
SysPushErrorIO("Couldn't open file ({}) for removal (read-only)", path);
return false;
}
if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)
{
if (::RemoveDirectoryW(translatedPath.c_str()))
{
return true;
}
}
else
{
if (::DeleteFileW(translatedPath.c_str()))
{
return true;
}
}
return false;
}
catch (...)
@ -369,12 +388,28 @@ namespace Aurora::IO::FS
{
try
{
auto srcPathNormalized = NormalizePathRet(src);
auto destPathNormalized = NormalizePathRet(dest);
CreateDirectories(destPathNormalized, true);
if (src.empty() ||
dest.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
return ::MoveFileW(Locale::ConvertFromUTF8(srcPathNormalized).c_str(),
Locale::ConvertFromUTF8(destPathNormalized).c_str());
auto pathSrcExpanded = Locale::ConvertFromUTF8(NormalizePathRet(src));
auto pathExpandedA = NormalizePathRet(dest);
auto pathExpanded = Locale::ConvertFromUTF8(pathExpandedA);
if (pathSrcExpanded.empty() ||
pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
CreateDirectories(pathExpandedA, true);
return ::MoveFileW(pathSrcExpanded.c_str(),
pathExpanded.c_str());
}
catch (...)
{
@ -386,12 +421,28 @@ namespace Aurora::IO::FS
{
try
{
auto srcPathNormalized = NormalizePathRet(src);
auto destPathNormalized = NormalizePathRet(dest);
CreateDirectories(destPathNormalized, true);
if (src.empty() ||
dest.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
return ::CopyFileW(Locale::ConvertFromUTF8(srcPathNormalized).c_str(),
Locale::ConvertFromUTF8(destPathNormalized).c_str(), true);
auto pathSrcExpanded = Locale::ConvertFromUTF8(NormalizePathRet(src));
auto pathExpandedA = NormalizePathRet(dest);
auto pathExpanded = Locale::ConvertFromUTF8(pathExpandedA);
if (pathSrcExpanded.empty() ||
pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
CreateDirectories(pathExpandedA, true);
return ::CopyFileW(pathSrcExpanded.c_str(),
pathExpanded.c_str(), true);
}
catch (...)
{
@ -406,7 +457,20 @@ namespace Aurora::IO::FS
stat = {};
if (!::GetFileAttributesExW(Locale::ConvertFromUTF8(NormalizePathRet(path)).c_str(), GetFileExInfoStandard, &data))
if (path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto translatedPath = Locale::ConvertFromUTF8(NormalizePathRet(path));
if (translatedPath.empty())
{
SysPushErrorMemory();
return false;
}
if (!::GetFileAttributesExW(translatedPath.c_str(), GetFileExInfoStandard, &data))
{
stat.bExists = false;
return false;

View File

@ -126,6 +126,12 @@ namespace Aurora::IO::FS
static AuSPtr<IReadDir> ReadDirEx(const AuString &string, bool bFast)
{
if (string.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return {};
}
auto pObj = AuMakeShared<ReadDirStructure>();
if (!pObj)
{
@ -216,6 +222,12 @@ namespace Aurora::IO::FS
{
AuMemoryViewWrite writeView;
if (path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
bool bIsStupidFD =
AuStartsWith(path, "/proc/") ||
AuStartsWith(path, "/sys/") ||
@ -281,41 +293,124 @@ namespace Aurora::IO::FS
AUKN_SYM bool FileExists(const AuString &path)
{
return UnixExists(NormalizePathRet(path), false);
if (path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto pathExpanded = NormalizePathRet(path);
if (pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
return UnixExists(pathExpanded, false);
}
AUKN_SYM bool DirExists(const AuString &path)
{
return UnixExists(NormalizePathRet(path), true);
if (path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto pathExpanded = NormalizePathRet(path);
if (pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
return UnixExists(pathExpanded, true);
}
AUKN_SYM bool DirMk(const AuString &path)
{
return CreateDirectories(NormalizePathRet(path), false);
if (path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto pathExpanded = NormalizePathRet(path);
if (pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
return CreateDirectories(pathExpanded, false);
}
AUKN_SYM bool Remove(const AuString &path)
{
return remove(NormalizePathRet(path).c_str()) != -1;
if (path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto pathExpanded = NormalizePathRet(path);
if (pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
return remove(pathExpanded.c_str()) != -1;
}
AUKN_SYM bool Relink(const AuString &src, const AuString &dest)
{
auto normalizedDestPath = NormalizePathRet(dest);
CreateDirectories(normalizedDestPath, true);
return ::rename(NormalizePathRet(src).c_str(), normalizedDestPath.c_str()) != -1;
if (src.empty() ||
dest.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto pathSrcExpanded = NormalizePathRet(src);
auto pathExpanded = NormalizePathRet(dest);
if (pathSrcExpanded.empty() ||
pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
return ::rename(pathSrcExpanded.c_str(), pathExpanded.c_str()) != -1;
}
#if defined(AURORA_IS_LINUX_DERIVED)
AUKN_SYM bool Copy(const AuString &src, const AuString &dest)
{
auto normalizedSrcPath = NormalizePathRet(src);
auto normalizedDestPath = NormalizePathRet(dest);
if (src.empty() ||
dest.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto pathSrcExpanded = NormalizePathRet(src);
auto pathExpanded = NormalizePathRet(dest);
if (pathSrcExpanded.empty() ||
pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
CreateDirectories(pathExpanded, true);
int input, output;
if ((input = ::open(normalizedSrcPath.c_str(), O_RDONLY | O_CLOEXEC)) == -1)
if ((input = ::open(pathSrcExpanded.c_str(), O_RDONLY | O_CLOEXEC)) == -1)
{
return false;
}
@ -324,12 +419,14 @@ namespace Aurora::IO::FS
if (::fstat(input, &fileinfo) != 0)
{
::close(input);
SysPushErrorIO("fstat failed");
return false;
}
if ((output = ::creat(normalizedDestPath.c_str(), fileinfo.st_mode)) == -1)
if ((output = ::creat(pathExpanded.c_str(), fileinfo.st_mode)) == -1)
{
::close(input);
SysPushErrorIO("creat failed");
return false;
}
@ -338,21 +435,35 @@ namespace Aurora::IO::FS
::close(input);
::close(output);
return result;
return bytesCopied == fileinfo.st_size;
}
#elif defined(AURORA_IS_BSD_DERIVED)
AUKN_SYM bool Copy(const AuString &src, const AuString &dest)
{
auto normalizedSrcPath = NormalizePathRet(src);
auto normalizedDestPath = NormalizePathRet(dest);
if (src.empty() ||
dest.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
CreateDirectories(normalizedDestPath, true);
auto pathSrcExpanded = NormalizePathRet(src);
auto pathExpanded = NormalizePathRet(dest);
if (pathSrcExpanded.empty() ||
pathExpanded.empty())
{
SysPushErrorMemory();
return false;
}
CreateDirectories(pathExpanded, true);
int input, output;
if ((input = ::open(normalizedSrcPath.c_str(), O_RDONLY | O_CLOEXEC)) == -1)
if ((input = ::open(pathSrcExpanded.c_str(), O_RDONLY | O_CLOEXEC)) == -1)
{
return false;
}
@ -361,12 +472,14 @@ namespace Aurora::IO::FS
if (::fstat(input, &fileinfo) != 0)
{
close(input)
SysPushErrorIO("fstat failed");
return false;
}
if ((output = ::creat(normalizedDestPath.c_str(), fileinfo.st_mode)) == -1)
if ((output = ::creat(pathExpanded.c_str(), fileinfo.st_mode)) == -1)
{
close(input);
SysPushErrorIO("creat failed");
return false;
}
@ -390,7 +503,19 @@ namespace Aurora::IO::FS
AUKN_SYM bool StatFile(const AuString &pathRel, Stat &stat)
{
stat = {};
if (pathRel.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
auto path = NormalizePathRet(pathRel);
if (path.empty())
{
SysPushErrorMemory();
return false;
}
struct stat s;
auto err = ::stat(path.c_str(), &s);

View File

@ -137,22 +137,29 @@ namespace Aurora::IO::FS
{
AU_LOCK_GUARD(this->spinlock_);
auto iOptSafe = this->pHandle_->GetOSWriteHandleSafe();
if (!iOptSafe)
int fd {};
if (auto pHandle = this->pHandle_)
{
iOptSafe = this->pHandle_->GetOSReadHandleSafe();
}
if (!pHandle->IsFile())
{
SysPushErrorIOResourceRejected();
return 0;
}
if (!iOptSafe)
{
return false;
if (auto opt = pHandle->GetOSHandleSafe())
{
fd = opt.Value();
}
else
{
SysPushErrorInvalidFd();
return 0;
}
}
auto fd = (int)iOptSafe.Value();
if (fd == -1)
else
{
SysPushErrorUninitialized();
return false;
return 0;
}
return PosixGetOffset(fd);
@ -162,24 +169,31 @@ namespace Aurora::IO::FS
{
AU_LOCK_GUARD(this->spinlock_);
auto iOptSafe = this->pHandle_->GetOSWriteHandleSafe();
if (!iOptSafe)
{
iOptSafe = this->pHandle_->GetOSReadHandleSafe();
}
if (!iOptSafe)
int fd {};
if (auto pHandle = this->pHandle_)
{
return false;
if (!pHandle->IsFile())
{
SysPushErrorIOResourceRejected();
return 0;
}
if (auto opt = pHandle->GetOSHandleSafe())
{
fd = opt.Value();
}
else
{
SysPushErrorInvalidFd();
return false;
}
}
auto fd = (int)iOptSafe.Value();
if (fd == -1)
else
{
SysPushErrorUninitialized();
return false;
}
return PosixSetOffset(fd, offset);
}
@ -187,17 +201,33 @@ namespace Aurora::IO::FS
{
AU_LOCK_GUARD(this->spinlock_);
auto iOptSafe = this->pHandle_->GetOSReadHandleSafe();
if (!iOptSafe)
int fd {};
if (auto pHandle = this->pHandle_)
{
return false;
}
if (!pHandle->IsFile())
{
// Intentionally suppressed (for the moment)
// I don't want to fill error stacks up under paths that can handle char-devs by reading until EoS
// If we do, we could hit an always-throw on AuErrorStack-catch
// Some users are completely unaware they can access/test the underlying handle
// Returning zero will do
return 0;
}
auto fd = (int)iOptSafe.Value();
if (fd == -1)
if (auto opt = pHandle->GetOSHandleSafe())
{
fd = opt.Value();
}
else
{
SysPushErrorInvalidFd();
return 0;
}
}
else
{
SysPushErrorUninitialized();
return false;
return 0;
}
return PosixGetLength(fd);
@ -259,7 +289,7 @@ namespace Aurora::IO::FS
return 0;
}
int fd = this->GetUnixHandle();
int fd = this->pHandle_->GetOSWriteHandleSafe().ValueOr((AuUInt)-1);
if (fd == -1)
{
SysPushErrorUninitialized();
@ -317,24 +347,36 @@ namespace Aurora::IO::FS
void PosixFileStream::Flush()
{
int fd = this->GetUnixHandle();
if (fd == -1)
if (!this->pHandle_)
{
SysPushErrorUninitialized();
return;
}
int fd = this->pHandle_->GetOSWriteHandleSafe().ValueOr((AuUInt)-1);
if (fd == -1)
{
SysPushErrorIOResourceRejected();
return;
}
::fsync(fd);
}
void PosixFileStream::WriteEoS()
{
int fd = this->GetUnixHandle();
if (fd == -1)
if (!this->pHandle_)
{
SysPushErrorUninitialized();
return;
}
int fd = this->pHandle_->GetOSWriteHandleSafe().ValueOr((AuUInt)-1);
if (fd == -1)
{
SysPushErrorIOResourceRejected();
return;
}
::ftruncate(fd, GetOffset());
}