482 lines
12 KiB
C++
482 lines
12 KiB
C++
#include "fs.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <dirent.h>
|
|
#include <sys/time.h>
|
|
// #include <filesystem>
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <vector>
|
|
#include <sys/stat.h>
|
|
#include "util.h"
|
|
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
#include "windows.h"
|
|
#endif
|
|
|
|
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)
|
|
{
|
|
rmdir(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);
|
|
}
|
|
|
|
int IsFolder(const std::string &path)
|
|
{
|
|
struct stat dir_stat = {0};
|
|
if (stat(path.c_str(), &dir_stat) != 0)
|
|
return -1;
|
|
if (S_ISDIR(dir_stat.st_mode))
|
|
return 1;
|
|
return 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(), "ab");
|
|
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, 1, size, 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(), "rb");
|
|
if (fd == nullptr)
|
|
return std::vector<char>(0);
|
|
const auto size = GetSize(path);
|
|
std::vector<char> data(size);
|
|
|
|
const auto read = fread(data.data(), 1, data.size(), fd);
|
|
fclose(fd);
|
|
if (read < 0)
|
|
return std::vector<char>(0);
|
|
|
|
data.resize(read+1);
|
|
data[data.size()-1]=0;
|
|
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;
|
|
}
|
|
|
|
bool Save(const std::string &path, const void *data, uint32_t size)
|
|
{
|
|
FILE *fd = fopen(path.c_str(), "w+");
|
|
if (fd == nullptr)
|
|
return false;
|
|
|
|
const char *data8 = static_cast<const char *>(data);
|
|
while (size != 0)
|
|
{
|
|
int written = fwrite(data8, 1, size, fd);
|
|
fclose(fd);
|
|
if (written <= 0)
|
|
return false;
|
|
data8 += written;
|
|
size -= written;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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 defined(EZREMOTE_ENABLE_UI)
|
|
if (stop_activity)
|
|
return 1;
|
|
#else
|
|
bool stop_activity = false;
|
|
#endif
|
|
|
|
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)
|
|
{
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], new_path);
|
|
#endif
|
|
closedir(dfd);
|
|
return ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETING], new_path);
|
|
#endif
|
|
int ret = remove(new_path);
|
|
if (ret < 0)
|
|
{
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], new_path);
|
|
#endif
|
|
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)
|
|
{
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], path.c_str());
|
|
#endif
|
|
return ret;
|
|
}
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETED], path.c_str());
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
int ret = remove(path.c_str());
|
|
if (ret < 0)
|
|
{
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], path.c_str());
|
|
#endif
|
|
return ret;
|
|
}
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_DELETED], path.c_str());
|
|
#endif
|
|
}
|
|
|
|
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)
|
|
{
|
|
#if !defined(EZREMOTE_ENABLE_UI)
|
|
uint64_t bytes_to_download;
|
|
uint64_t bytes_transfered;
|
|
#endif
|
|
MkDirs(to, true);
|
|
if (from.compare(to) == 0)
|
|
return 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;
|
|
#if defined(EZREMOTE_ENABLE_UI)
|
|
prev_tick = Util::GetTick();
|
|
#endif
|
|
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)
|
|
{
|
|
if (from.compare(to) == 0)
|
|
return true;
|
|
|
|
errno = 0;
|
|
int ret = rename(from.c_str(), to.c_str());
|
|
if (ret != 0 && (errno == EXDEV || errno == EEXIST))
|
|
{
|
|
bool res = Copy(from, to);
|
|
if (res)
|
|
Rm(from);
|
|
else
|
|
return res;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|