Added option to resolve external symlinks and fixed symlink handling.
This commit is contained in:
@@ -23,6 +23,7 @@ struct file_data {
|
||||
|
||||
enum FilerStatusCodes : uint8_t {
|
||||
Success = 0,
|
||||
IsDirectory = 248,
|
||||
AccessDenied = 249,
|
||||
FileExists = 250,
|
||||
DirectoryNotEmpty = 251,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <system_error>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
@@ -13,6 +14,14 @@ class LocalFiler : public IPlugin, public Filer {
|
||||
public:
|
||||
LocalFiler() {}
|
||||
|
||||
bool initialize(const std::map<std::string, std::string>& config) {
|
||||
auto symreslv_it = config.find("resolve_external_symlinks");
|
||||
this->resolve_ext_symlinks = (symreslv_it != config.end()) ?
|
||||
(symreslv_it->second == "on" || symreslv_it->second == "true" || symreslv_it->second == "yes") :
|
||||
false;
|
||||
return true;
|
||||
}
|
||||
|
||||
file_data setRoot(std::string _root) {
|
||||
struct file_data fd;
|
||||
try {
|
||||
@@ -74,6 +83,10 @@ public:
|
||||
}
|
||||
|
||||
bool resolvePath(const std::string& path, fs::path* target) {
|
||||
return this->resolvePath(path, target, true);
|
||||
}
|
||||
|
||||
bool resolvePath(const std::string& path, fs::path* target, bool resolve_symlink) {
|
||||
try {
|
||||
if (path.empty() || path == ".") {
|
||||
*target = root / cwd.relative_path();
|
||||
@@ -88,13 +101,19 @@ public:
|
||||
*target = root / cwd.relative_path() / path;
|
||||
}
|
||||
|
||||
// Remove .. and . components
|
||||
*target = fs::weakly_canonical(*target);
|
||||
|
||||
// Make sure we haven't escaped the root
|
||||
if (!(*target).string().starts_with(root.string()))
|
||||
*target = fs::path(*target).lexically_normal();
|
||||
if (fs::is_symlink(*target) && resolve_symlink) {
|
||||
fs::path resolved_sym = fs::weakly_canonical(*target);
|
||||
logger->print(LOGLEVEL_DEBUG, "Resolved symlink path: %s", resolved_sym.c_str());
|
||||
if (!resolve_ext_symlinks) {
|
||||
if (!resolved_sym.string().starts_with(root.string()))
|
||||
return false;
|
||||
} else *target = resolved_sym;
|
||||
} else if (!(*target).string().starts_with(root.string()))
|
||||
return false;
|
||||
|
||||
logger->print(LOGLEVEL_DEBUG, "Resolved path: %s", target->c_str());
|
||||
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
logger->print(LOGLEVEL_ERROR, "Path resolution error: %s", e.what());
|
||||
@@ -206,24 +225,24 @@ public:
|
||||
struct file_data fd;
|
||||
try {
|
||||
fs::path resolved;
|
||||
if (!resolvePath(name, &resolved)) {
|
||||
if (!resolvePath(name, &resolved, false)) {
|
||||
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||
return fd;
|
||||
}
|
||||
fd.path = resolved.string().c_str();
|
||||
fd.path = resolved.c_str();
|
||||
|
||||
if (!fs::exists(resolved)) {
|
||||
fd.error = file_error{FilerStatusCodes::NotFound, "File Not Found"};
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (fs::is_directory(resolved) && !fs::is_empty(resolved)) {
|
||||
fd.error = file_error{FilerStatusCodes::DirectoryNotEmpty, "Directory not empty"};
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (fs::remove_all(resolved) == 0) {
|
||||
fd.error = file_error{FilerStatusCodes::NoPermission, "Unable to delete file"};
|
||||
std::error_code err;
|
||||
if (!fs::remove(resolved, err)) {
|
||||
if (err == std::errc::no_such_file_or_directory)
|
||||
fd.error = file_error{FilerStatusCodes::NotFound, "File Not Found"};
|
||||
else if (err == std::errc::permission_denied)
|
||||
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||
else if (err == std::errc::directory_not_empty)
|
||||
fd.error = file_error{FilerStatusCodes::DirectoryNotEmpty, "Directory not empty"};
|
||||
else if (err == std::errc::is_a_directory)
|
||||
fd.error = file_error{FilerStatusCodes::IsDirectory, "Is A Directory"};
|
||||
else
|
||||
fd.error = file_error{FilerStatusCodes::NoPermission, "Unable to delete file"};
|
||||
}
|
||||
} catch (const std::filesystem::filesystem_error& ex) {
|
||||
logger->print(LOGLEVEL_ERROR, ex.what());
|
||||
@@ -405,6 +424,7 @@ public:
|
||||
private:
|
||||
fs::path root;
|
||||
fs::path cwd;
|
||||
bool resolve_ext_symlinks = false;
|
||||
char type = 'I';
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user