[*] (Mostly Linux) Harden FS apis
This commit is contained in:
parent
9bfd895fc4
commit
9a294cf955
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user