Files
T
2023-03-09 23:55:12 -08:00

546 lines
14 KiB
C++

#include "fs.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <dirent.h>
#include <filesystem>
#include <stdio.h>
#include <unistd.h>
#include <vector>
#include "util.h"
#include "lang.h"
#include "system.h"
#include "windows.h"
namespace FS
{
int hasEndSlash(const char *path)
{
return path[strlen(path) - 1] == '/';
}
void MkDirs(const std::string &ppath, bool prev)
{
std::string path = ppath;
if (!prev)
{
path.push_back('/');
}
auto ptr = path.begin();
while (true)
{
ptr = std::find(ptr, path.end(), '/');
if (ptr == path.end())
break;
char last = *ptr;
*ptr = 0;
int err = mkdir(path.c_str(), 0777);
*ptr = last;
++ptr;
}
}
void Rm(const std::string &file)
{
remove(file.c_str());
}
void RmDir(const std::string &path)
{
remove(path.c_str());
}
int64_t GetSize(const std::string &path)
{
struct stat file_stat = {0};
int err = stat(path.c_str(), &file_stat);
if (err < 0)
{
return -1;
}
return file_stat.st_size;
}
bool FileExists(const std::string &path)
{
struct stat file_stat = {0};
return (stat(path.c_str(), std::addressof(file_stat)) == 0 && S_ISREG(file_stat.st_mode));
}
bool FolderExists(const std::string &path)
{
struct stat dir_stat = {0};
return (stat(path.c_str(), &dir_stat) == 0);
}
void Rename(const std::string &from, const std::string &to)
{
int res = rename(from.c_str(), to.c_str());
}
FILE *Create(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "w");
return fd;
}
FILE *OpenRW(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "w+");
return fd;
}
FILE *OpenRead(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "rb");
return fd;
}
FILE *Append(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "a");
return fd;
}
int64_t Seek(FILE *f, uint64_t offset)
{
auto const pos = fseek(f, offset, SEEK_SET);
return pos;
}
int Read(FILE *f, void *buffer, uint32_t size)
{
const auto read = fread(buffer, 1, size, f);
return read;
}
int Write(FILE *f, const void *buffer, uint32_t size)
{
int write = fwrite(buffer, size, 1, f);
return write;
}
void Close(FILE *fd)
{
int err = fclose(fd);
}
std::vector<char> Load(const std::string &path)
{
FILE *fd = fopen(path.c_str(), "r");
if (fd == nullptr)
return std::vector<char>(0);
const auto size = fseek(fd, 0, SEEK_END);
fseek(fd, 0, SEEK_SET);
std::vector<char> data(size);
const auto read = fread(data.data(), data.size(), 1, fd);
fclose(fd);
if (read < 0)
return std::vector<char>(0);
data.resize(read);
return data;
}
bool LoadText(std::vector<std::string> *lines, const std::string &path)
{
FILE *fd = fopen(path.c_str(), "rb");
if (fd == nullptr)
return false;
lines->clear();
char buffer[1024];
short bytes_read;
std::vector<char> line = std::vector<char>(0);
do
{
bytes_read = fread(buffer, sizeof(char), 1024, fd);
if (bytes_read < 0)
{
fclose(fd);
return false;
}
for (short i = 0; i < bytes_read; i++)
{
if (buffer[i] != '\r' && buffer[i] != '\n')
{
line.push_back(buffer[i]);
}
else
{
lines->push_back(std::string(line.data(), line.size()));
line = std::vector<char>(0);
if (buffer[i] == '\r' && buffer[i+1] == '\n')
i++;
}
}
} while (bytes_read == 1024);
if (line.size()>0)
lines->push_back(std::string(line.data(), line.size()));
fclose(fd);
if (lines->size() == 0)
lines->push_back("");
return true;
}
bool SaveText(std::vector<std::string> *lines, const std::string &path)
{
FILE *fd = OpenRW(path);
if (fd == nullptr)
return false;
char nl[1] = {'\n'};
for (int i=0; i < lines->size(); i++)
{
Write(fd, lines->at(i).c_str(), lines->at(i).length());
Write(fd, nl, 1);
}
fclose(fd);
return true;
}
void Save(const std::string &path, const void *data, uint32_t size)
{
FILE *fd = fopen(path.c_str(), "w+");
if (fd == nullptr)
return;
const char *data8 = static_cast<const char *>(data);
while (size != 0)
{
int written = fwrite(data8, size, 1, fd);
fclose(fd);
if (written <= 0)
return;
data8 += written;
size -= written;
}
}
std::vector<DirEntry> ListDir(const std::string &ppath, int *err)
{
std::vector<DirEntry> out;
DirEntry entry;
std::string path = ppath;
memset(&entry, 0, sizeof(DirEntry));
sprintf(entry.directory, "%s", path.c_str());
sprintf(entry.name, "..");
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
sprintf(entry.path, "%s", path.c_str());
entry.file_size = 0;
entry.isDir = true;
entry.selectable = false;
out.push_back(entry);
DIR *fd = opendir(path.c_str());
*err = 0;
if (fd == NULL)
{
*err = 1;
return out;
}
while (true)
{
struct dirent *dirent;
DirEntry entry;
dirent = readdir(fd);
if (dirent == NULL)
{
closedir(fd);
return out;
}
else
{
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
{
continue;
}
snprintf(entry.directory, 512, "%s", path.c_str());
snprintf(entry.name, 256, "%s", dirent->d_name);
entry.selectable = true;
if (hasEndSlash(path.c_str()))
{
sprintf(entry.path, "%s%s", path.c_str(), dirent->d_name);
}
else
{
sprintf(entry.path, "%s/%s", path.c_str(), dirent->d_name);
}
struct stat file_stat = {0};
stat(entry.path, &file_stat);
struct tm tm = *localtime(&file_stat.st_mtim.tv_sec);
OrbisDateTime gmt;
OrbisDateTime lt;
gmt.day = tm.tm_mday;
gmt.month = tm.tm_mon + 1;
gmt.year = tm.tm_year + 1900;
gmt.hour = tm.tm_hour;
gmt.minute = tm.tm_min;
gmt.second = tm.tm_sec;
convertUtcToLocalTime(&gmt, &lt);
entry.modified.day = lt.day;
entry.modified.month = lt.month;
entry.modified.year = lt.year;
entry.modified.hours = lt.hour;
entry.modified.minutes = lt.minute;
entry.modified.seconds = lt.second;
entry.file_size = file_stat.st_size;
if (dirent->d_type & DT_DIR)
{
entry.isDir = true;
entry.file_size = 0;
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
}
else
{
if (entry.file_size < 1024)
{
sprintf(entry.display_size, "%luB", entry.file_size);
}
else if (entry.file_size < 1024 * 1024)
{
sprintf(entry.display_size, "%.2fKB", entry.file_size * 1.0f / 1024);
}
else if (entry.file_size < 1024 * 1024 * 1024)
{
sprintf(entry.display_size, "%.2fMB", entry.file_size * 1.0f / (1024 * 1024));
}
else
{
sprintf(entry.display_size, "%.2fGB", entry.file_size * 1.0f / (1024 * 1024 * 1024));
}
entry.isDir = false;
}
out.push_back(entry);
}
}
closedir(fd);
return out;
}
std::vector<std::string> ListFiles(const std::string &path)
{
DIR *fd = opendir(path.c_str());
if (fd == NULL)
return std::vector<std::string>(0);
std::vector<std::string> out;
while (true)
{
struct dirent *dirent;
dirent = readdir(fd);
if (dirent == NULL)
{
closedir(fd);
return out;
}
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
{
continue;
}
if (dirent->d_type & DT_DIR)
{
std::vector<std::string> files = FS::ListFiles(path + "/" + dirent->d_name);
for (std::vector<std::string>::iterator it = files.begin(); it != files.end();)
{
out.push_back(std::string(dirent->d_name) + "/" + *it);
++it;
}
}
else
{
out.push_back(dirent->d_name);
}
}
closedir(fd);
return out;
}
int RmRecursive(const std::string &path)
{
if (stop_activity)
return 1;
DIR *dfd = opendir(path.c_str());
if (dfd != NULL)
{
struct dirent *dir = NULL;
do
{
dir = readdir(dfd);
if (dir == NULL || strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
{
continue;
}
char new_path[512];
snprintf(new_path, 512, "%s%s%s", path.c_str(), hasEndSlash(path.c_str()) ? "" : "/", dir->d_name);
if (dir->d_type & DT_DIR)
{
int ret = RmRecursive(new_path);
if (ret <= 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], new_path);
closedir(dfd);
return ret;
}
}
else
{
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETING], new_path);
int ret = remove(new_path);
if (ret < 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], new_path);
closedir(dfd);
return ret;
}
}
} while (dir != NULL && !stop_activity);
closedir(dfd);
if (stop_activity)
return 0;
int ret = rmdir(path.c_str());
if (ret < 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], path.c_str());
return ret;
}
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETED], path.c_str());
}
else
{
int ret = remove(path.c_str());
if (ret < 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], path.c_str());
return ret;
}
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETED], path.c_str());
}
return 1;
}
std::string GetPath(const std::string &ppath1, const std::string &ppath2)
{
std::string path1 = ppath1;
std::string path2 = ppath2;
path2 = Util::Rtrim(Util::Trim(path2, " "), "/");
return path1 + "/" + path2;
}
int Head(const std::string &path, void *buffer, uint16_t len)
{
FILE *file = OpenRead(path);
if (file == nullptr)
return 0;
int ret = Read(file, buffer, len);
if (ret != len)
{
Close(file);
return 0;
}
Close(file);
return 1;
}
bool Copy(const std::string &from, const std::string &to)
{
MkDirs(to, true);
FILE *src = fopen(from.c_str(), "rb");
if (!src)
{
return false;
}
struct stat file_stat = {0};
if (stat(from.c_str(), &file_stat) != 0)
{
return false;
}
bytes_to_download = file_stat.st_size;
FILE *dest = fopen(to.c_str(), "wb");
if (!dest)
{
fclose(src);
return false;
}
size_t bytes_read = 0;
bytes_transfered = 0;
const size_t buf_size = 0x10000;
unsigned char *buf = new unsigned char[buf_size];
do
{
bytes_read = fread(buf, sizeof(unsigned char), buf_size, src);
if (bytes_read < 0)
{
delete[] buf;
fclose(src);
fclose(dest);
return false;
}
size_t bytes_written = fwrite(buf, sizeof(unsigned char), bytes_read, dest);
if (bytes_written != bytes_read)
{
delete[] buf;
fclose(src);
fclose(dest);
return false;
}
bytes_transfered += bytes_read;
} while (bytes_transfered < bytes_to_download);
delete[] buf;
fclose(src);
fclose(dest);
return true;
}
bool Move(const std::string &from, const std::string &to)
{
bool res = Copy(from, to);
if (res)
Rm(from);
else
return res;
return true;
}
}