242 lines
5.7 KiB
C++
242 lines
5.7 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: FS.Generic.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 <stdio.h>
|
|
|
|
// if your platform isn't supported, let's not assume we have these dino headers
|
|
#if defined(__has_include) && __has_include(<sys/stat.h>)
|
|
#define _AURUNTIME_HAS_STAT
|
|
#include <sys/stat.h>
|
|
#endif
|
|
|
|
// HAS_STD_FS might exist, who knows, let's hope
|
|
|
|
namespace Aurora::IO::FS
|
|
{
|
|
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 void *data, AuUInt length)
|
|
{
|
|
auto file = fopen(NormalizePathRet(path).c_str(), "wb");
|
|
if (!file)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto bytesWritten = fwrite(data, 1, length, file);
|
|
fclose(file);
|
|
return bytesWritten == length;
|
|
}
|
|
|
|
AUKN_SYM bool ReadFile(const AuString &path, AuList<AuUInt8> &buffer)
|
|
{
|
|
auto file = fopen(NormalizePathRet(path).c_str(), "rb");
|
|
if (!file)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (fseek(file, 0, SEEK_END) < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto size = ftell(file);
|
|
|
|
if (fseek(file, 0, SEEK_CUR) < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
buffer.resize(size);
|
|
|
|
auto bytesRead = fread(buffer.data(), 1, size, file);
|
|
fclose(file);
|
|
return bytesRead == size;
|
|
}
|
|
|
|
AUKN_SYM bool FileExists(const AuString &path)
|
|
{
|
|
auto file = fopen(NormalizePathRet(path).c_str(), "rb");
|
|
if (!file) return false;
|
|
fclose(file);
|
|
return true;
|
|
}
|
|
|
|
AUKN_SYM bool DirExists(const AuString &path)
|
|
{
|
|
|
|
#if defined(_AURUNTIME_HAS_STAT)
|
|
Stat stat;
|
|
|
|
if (!StatFile(path, stat))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return stat.existsDirectory;
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
AUKN_SYM bool DirMk(const AuString &path)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
AUKN_SYM bool Remove(const AuString &path)
|
|
{
|
|
#if defined(HAS_STD_FS)
|
|
try
|
|
{
|
|
std::filesystem::remove(std::filesystem::u8path(NormalizePathRet(path)));
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
#else
|
|
return ::remove(NormalizePathRet(path).c_str());
|
|
#endif
|
|
}
|
|
|
|
AUKN_SYM bool Relink(const AuString &src, const AuString &dest)
|
|
{
|
|
#if defined(HAS_STD_FS)
|
|
try
|
|
{
|
|
std::filesystem::rename(std::filesystem::u8path(NormalizePathRet(src)), std::filesystem::u8path(NormalizePathRet(dest)));
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
#else
|
|
if (!Copy(src, dest))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Remove(src);
|
|
#endif
|
|
}
|
|
|
|
AUKN_SYM bool Copy(const AuString &src, const AuString &dest)
|
|
{
|
|
#if defined(HAS_STD_FS)
|
|
try
|
|
{
|
|
std::filesystem::copy(std::filesystem::u8path(NormalizePathRet(src)), std::filesystem::u8path(NormalizePathRet(dest)));
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
#else
|
|
// im not even going to bother writing a crt stream copy here
|
|
// what are you doing with this reference implemention?
|
|
AuList<AuUInt8> buffered;
|
|
if (!ReadFile(src, buffered))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return WriteFile(dest, buffered);
|
|
#endif
|
|
}
|
|
|
|
#if defined(_AURUNTIME_HAS_STAT)
|
|
|
|
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, 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 of path {}, stat mode {}", path, s.st_mode);
|
|
return false;
|
|
}
|
|
|
|
stat.size = s.st_size;
|
|
|
|
stat.created = ConvertUnixTimespecToMs(s.st_ctime);
|
|
stat.modified = ConvertUnixTimespecToMs(s.st_mtime);
|
|
stat.accessed = ConvertUnixTimespecToMs(s.st_atime);
|
|
|
|
err = lstat(path.c_str(), &s);
|
|
if (err != -1)
|
|
{
|
|
stat.symLink = S_ISLNK(s.st_mode);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#else
|
|
|
|
AUKN_SYM bool StatFile(const AuString &path, Stat &stat)
|
|
{
|
|
stat = {};
|
|
|
|
stat.existsDirectory = DirExists(path);
|
|
stat.existsFile = FileExists(path);
|
|
stat.exists = stat.existsDirectory || stat.existsFile;
|
|
|
|
if (stat.exists)
|
|
{
|
|
auto time = Time::CurrentClockMS();
|
|
stat.created = time;
|
|
stat.modified = time;
|
|
stat.accessed = time;
|
|
}
|
|
else
|
|
{
|
|
stat = {};
|
|
}
|
|
|
|
return stat.exists;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
#endif |