266 lines
6.7 KiB
C++
Executable File
266 lines
6.7 KiB
C++
Executable File
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: FS.Unix.cpp
|
|
Date: 2021-6-12
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "FS.hpp"
|
|
#include "FS.Generic.hpp"
|
|
#include <Source/Time/Time.hpp>
|
|
|
|
#if !defined(_AURUNTIME_GENERICFS)
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#if defined(AURORA_IS_LINUX_DERIVED)
|
|
#include <sys/sendfile.h>
|
|
#endif
|
|
|
|
namespace Aurora::IO::FS
|
|
{
|
|
bool _MkDir(const AuString &path)
|
|
{
|
|
return mkdir(path.c_str(), 0775) == 0;
|
|
}
|
|
|
|
AUKN_SYM bool FilesInDirectory(const AuString &string, AuList<AuString> &files)
|
|
{
|
|
return IterateDirEntriesSTL(string, true, files);
|
|
}
|
|
|
|
AUKN_SYM bool DirsInDirectory(const AuString &string, AuList<AuString> &dirs)
|
|
{
|
|
return IterateDirEntriesSTL(string, false, dirs);
|
|
}
|
|
|
|
AUKN_SYM bool WriteFile(const AuString &path, const Memory::MemoryViewRead &blob)
|
|
{
|
|
auto file = OpenWriteUnique(path);
|
|
SysCheckReturn(file, false);
|
|
|
|
AuUInt written = blob.length;
|
|
if (!file->Write(Memory::MemoryViewStreamRead(blob, written)))
|
|
{
|
|
SysPushErrorMem();
|
|
return false;
|
|
}
|
|
|
|
if (written != blob.length)
|
|
{
|
|
SysPushErrorIO();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
AUKN_SYM bool ReadFile(const AuString &path, AuByteBuffer &buffer)
|
|
{
|
|
AuUInt read;
|
|
|
|
auto file = OpenReadUnique(path, EFileAdvisoryLockLevel::eNoSafety);
|
|
SysCheckReturn(file, false);
|
|
|
|
auto len = file->GetLength();
|
|
|
|
// NOTE: Linux file systems are such a cluster fuck of unimplemented interface
|
|
// It's not unusual for these sockets to be unstreamable across NIX-like oses
|
|
if (len == 0)
|
|
{
|
|
if (AuStartsWith(path, "/proc/") ||
|
|
AuStartsWith(path, "/sys/") ||
|
|
AuStartsWith(path, "/dev/"))
|
|
{
|
|
len = 4096;
|
|
}
|
|
else
|
|
{
|
|
buffer.clear();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!AuTryResize(buffer, len))
|
|
{
|
|
SysPushErrorMem();
|
|
return false;
|
|
}
|
|
|
|
if (!file->Read(Memory::MemoryViewStreamWrite {buffer.begin(), buffer.end(), read}))
|
|
{
|
|
SysPushErrorIO();
|
|
return false;
|
|
}
|
|
|
|
// NOTE: File devices love to lie
|
|
// Do not entertain an arbitrarily large page length provided by non-regular fds
|
|
|
|
return AuTryResize(buffer, read);
|
|
}
|
|
|
|
static bool UnixExists(const AuString &path, bool dir)
|
|
{
|
|
struct stat s;
|
|
int err = stat(path.c_str(), &s);
|
|
if (-1 == err)
|
|
{
|
|
SysAssert(ENOENT == errno, "General File IO Error, path {}", path);
|
|
return false;
|
|
}
|
|
return dir ? S_ISDIR(s.st_mode) : S_ISREG(s.st_mode);
|
|
}
|
|
|
|
AUKN_SYM bool FileExists(const AuString &path)
|
|
{
|
|
return UnixExists(NormalizePathRet(path), false);
|
|
}
|
|
|
|
AUKN_SYM bool DirExists(const AuString &path)
|
|
{
|
|
return UnixExists(NormalizePathRet(path), true);
|
|
}
|
|
|
|
AUKN_SYM bool DirMk(const AuString &path)
|
|
{
|
|
return CreateDirectories(NormalizePathRet(path), false);
|
|
}
|
|
|
|
AUKN_SYM bool Remove(const AuString &path)
|
|
{
|
|
return remove(NormalizePathRet(path).c_str()) != -1;
|
|
}
|
|
|
|
AUKN_SYM bool Relink(const AuString &src, const AuString &dest)
|
|
{
|
|
return rename(NormalizePathRet(src).c_str(), NormalizePathRet(dest).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);
|
|
|
|
int input, output;
|
|
|
|
if ((input = open(normalizedSrcPath.c_str(), O_RDONLY)) == -1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
struct stat fileinfo = { 0 };
|
|
if (fstat(input, &fileinfo) != 0)
|
|
{
|
|
close(input);
|
|
return false;
|
|
}
|
|
|
|
if ((output = creat(normalizedDestPath.c_str(), fileinfo.st_mode)) == -1)
|
|
{
|
|
close(input);
|
|
return false;
|
|
}
|
|
|
|
off_t bytesCopied = 0;
|
|
auto result = sendfile(output, input, &bytesCopied, fileinfo.st_size) != -1;
|
|
|
|
close(input);
|
|
close(output);
|
|
return result;
|
|
}
|
|
|
|
#elif defined(AURORA_IS_BSD_DERIVED)
|
|
|
|
AUKN_SYM bool Copy(const AuString &src, const AuString &dest)
|
|
{
|
|
auto normalizedSrcPath = NormalizePathRet(src);
|
|
auto normalizedDestPath = NormalizePathRet(dest);
|
|
|
|
int input, output;
|
|
|
|
if ((input = open(normalizedSrcPath.c_str(), O_RDONLY)) == -1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
struct stat fileinfo = { 0 };
|
|
if (fstat(input, &fileinfo) != 0)
|
|
{
|
|
close(input)
|
|
return false;
|
|
}
|
|
|
|
if ((output = creat(normalizedDestPath.c_str(), fileinfo.st_mode)) == -1)
|
|
{
|
|
close(input);
|
|
return false;
|
|
}
|
|
|
|
auto result = fcopyfile(input, output, 0, COPYFILE_ALL) == 0;
|
|
|
|
close(input);
|
|
close(output);
|
|
return result;
|
|
}
|
|
|
|
#else
|
|
|
|
AUKN_SYM bool Copy(const AuString &src, const AuString &dest)
|
|
{
|
|
// TODO: not that i care
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
|
|
AUKN_SYM bool StatFile(const AuString &pathRel, Stat &stat)
|
|
{
|
|
stat = {};
|
|
auto path = NormalizePathRet(pathRel);
|
|
|
|
struct stat s;
|
|
auto err = ::stat(path.c_str(), &s);
|
|
|
|
if (err == -1)
|
|
{
|
|
if (ENOENT != errno)
|
|
{
|
|
LogWarn("Critical IO error while stating file (errno: {}, path: {})", errno, path);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
stat.existsFile = S_ISREG(s.st_mode);
|
|
stat.existsDirectory = S_ISDIR(s.st_mode);
|
|
stat.existsSystemResource = S_ISSOCK(s.st_mode);
|
|
stat.exists = stat.existsFile || stat.existsDirectory || stat.existsSystemResource;
|
|
|
|
if (!stat.exists)
|
|
{
|
|
LogWarn("Missing attribute type in stat mode {} (of path {})", s.st_mode, path);
|
|
return false;
|
|
}
|
|
|
|
stat.size = s.st_size;
|
|
|
|
stat.created = Time::CTimeToMS(s.st_ctime);
|
|
stat.modified = Time::CTimeToMS(s.st_mtime);
|
|
stat.accessed = Time::CTimeToMS(s.st_atime);
|
|
|
|
err = lstat(path.c_str(), &s);
|
|
if (err != -1)
|
|
{
|
|
stat.symLink = S_ISLNK(s.st_mode);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|