Compare commits
21 Commits
af339e6086
...
73ec7f2252
Author | SHA1 | Date | |
---|---|---|---|
73ec7f2252 | |||
5450ffc280 | |||
a9125196ce | |||
ab9765582a | |||
060b2b70dc | |||
739a31538f | |||
67595b4d45 | |||
c5003e0ee6 | |||
984657a5dd | |||
2930933f19 | |||
72a6f5ae08 | |||
7a96a8cbf3 | |||
0b4befd823 | |||
151b6775b0 | |||
47a6bdbcd2 | |||
20ab95380a | |||
73afdaedb9 | |||
a231c2afaf | |||
74109d1195 | |||
2bd847b833 | |||
2d74fb30de |
@ -33,25 +33,32 @@ protected:
|
|||||||
virtual ~remote_open_file_table() = default;
|
virtual ~remote_open_file_table() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct compat_open_info {
|
struct compat_open_info final {
|
||||||
std::size_t count{0U};
|
|
||||||
std::string client_id;
|
std::string client_id;
|
||||||
|
std::vector<remote::file_handle> handles;
|
||||||
std::string path;
|
std::string path;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct open_info {
|
struct open_info final {
|
||||||
std::size_t count{0U};
|
|
||||||
std::string client_id;
|
std::string client_id;
|
||||||
PVOID directory_buffer{nullptr};
|
PVOID directory_buffer{nullptr};
|
||||||
|
std::vector<native_handle> handles;
|
||||||
std::string path;
|
std::string path;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<remote::file_handle, compat_open_info> compat_lookup_;
|
std::unordered_map<std::string, std::unique_ptr<compat_open_info>>
|
||||||
std::recursive_mutex compat_mutex_;
|
compat_file_lookup_;
|
||||||
|
std::unordered_map<remote::file_handle, std::string> compat_handle_lookup_;
|
||||||
|
|
||||||
|
private:
|
||||||
std::unordered_map<std::string, std::vector<std::uint64_t>> directory_lookup_;
|
std::unordered_map<std::string, std::vector<std::uint64_t>> directory_lookup_;
|
||||||
std::recursive_mutex directory_mutex_;
|
|
||||||
std::unordered_map<native_handle, open_info> file_lookup_;
|
private:
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<open_info>> file_lookup_;
|
||||||
|
std::unordered_map<native_handle, std::string> handle_lookup_;
|
||||||
|
|
||||||
|
private:
|
||||||
mutable std::recursive_mutex file_mutex_;
|
mutable std::recursive_mutex file_mutex_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -64,11 +71,11 @@ protected:
|
|||||||
PVOID *&buffer) -> bool;
|
PVOID *&buffer) -> bool;
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_open_file_path(const native_handle &handle)
|
||||||
get_open_file_path(const native_handle &handle) -> std::string;
|
-> std::string;
|
||||||
|
|
||||||
[[nodiscard]] auto get_open_info(const native_handle &handle,
|
[[nodiscard]] auto get_open_info(const native_handle &handle, open_info &oi)
|
||||||
open_info &oi) -> bool;
|
-> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto has_open_directory(const std::string &client_id,
|
[[nodiscard]] auto has_open_directory(const std::string &client_id,
|
||||||
std::uint64_t handle) -> bool;
|
std::uint64_t handle) -> bool;
|
||||||
@ -77,20 +84,21 @@ protected:
|
|||||||
int error_return) -> int;
|
int error_return) -> int;
|
||||||
|
|
||||||
template <typename error_type>
|
template <typename error_type>
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto has_open_info(const native_handle &handle,
|
||||||
has_open_info(const native_handle &handle,
|
const error_type &error_return)
|
||||||
const error_type &error_return) -> error_type {
|
-> error_type {
|
||||||
recur_mutex_lock file_lock(file_mutex_);
|
recur_mutex_lock file_lock(file_mutex_);
|
||||||
return ((file_lookup_.find(handle) == file_lookup_.end()) ? error_return
|
return handle_lookup_.contains(handle) ? 0 : error_return;
|
||||||
: 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_all(const std::string &file_path);
|
void remove_all(const std::string &file_path);
|
||||||
|
|
||||||
|
void remove_and_close_all(const native_handle &handle);
|
||||||
|
|
||||||
void remove_compat_open_info(const remote::file_handle &handle);
|
void remove_compat_open_info(const remote::file_handle &handle);
|
||||||
|
|
||||||
auto remove_directory(const std::string &client_id,
|
auto remove_directory(const std::string &client_id, std::uint64_t handle)
|
||||||
std::uint64_t handle) -> bool;
|
-> bool;
|
||||||
|
|
||||||
void remove_open_info(const native_handle &handle);
|
void remove_open_info(const native_handle &handle);
|
||||||
|
|
||||||
@ -102,11 +110,11 @@ protected:
|
|||||||
void set_compat_open_info(const remote::file_handle &handle,
|
void set_compat_open_info(const remote::file_handle &handle,
|
||||||
const std::string &file_path);
|
const std::string &file_path);
|
||||||
|
|
||||||
void set_open_info(const native_handle &handle, open_info oi);
|
void set_open_info(const native_handle &handle, open_info op_info);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_open_file_count(const std::string &file_path) const
|
||||||
get_open_file_count(const std::string &file_path) const -> std::size_t;
|
-> std::size_t;
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -137,12 +137,12 @@ public:
|
|||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
this->set_client_id(file_desc, client_id);
|
this->set_client_id(file_desc, client_id);
|
||||||
#else
|
#else // !defined(_WIN32)
|
||||||
this->set_client_id(
|
this->set_client_id(
|
||||||
static_cast<native_handle>(
|
static_cast<native_handle>(
|
||||||
reinterpret_cast<std::uintptr_t>(file_desc)),
|
reinterpret_cast<std::uintptr_t>(file_desc)),
|
||||||
client_id);
|
client_id);
|
||||||
#endif
|
#endif // defined(_WIN32)
|
||||||
response.encode(file_desc);
|
response.encode(file_desc);
|
||||||
response.encode(file_info);
|
response.encode(file_info);
|
||||||
response.encode(normalized_name);
|
response.encode(normalized_name);
|
||||||
@ -277,12 +277,12 @@ public:
|
|||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
this->set_client_id(file_desc, client_id);
|
this->set_client_id(file_desc, client_id);
|
||||||
#else
|
#else // !defined(_WIN32)
|
||||||
this->set_client_id(
|
this->set_client_id(
|
||||||
static_cast<native_handle>(
|
static_cast<native_handle>(
|
||||||
reinterpret_cast<std::uintptr_t>(file_desc)),
|
reinterpret_cast<std::uintptr_t>(file_desc)),
|
||||||
client_id);
|
client_id);
|
||||||
#endif
|
#endif // defined(_WIN32)
|
||||||
response.encode(file_desc);
|
response.encode(file_desc);
|
||||||
response.encode(file_info);
|
response.encode(file_info);
|
||||||
response.encode(normalized_name);
|
response.encode(normalized_name);
|
||||||
@ -585,9 +585,9 @@ public:
|
|||||||
0) {
|
0) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
this->set_compat_client_id(handle, client_id);
|
this->set_compat_client_id(handle, client_id);
|
||||||
#else
|
#else // !defined(_WIN32)
|
||||||
this->set_client_id(static_cast<native_handle>(handle), client_id);
|
this->set_client_id(static_cast<native_handle>(handle), client_id);
|
||||||
#endif
|
#endif // defined(_WIN32)
|
||||||
response.encode(handle);
|
response.encode(handle);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -841,9 +841,9 @@ public:
|
|||||||
if ((ret = this->fuse_open(path.c_str(), flags, handle)) >= 0) {
|
if ((ret = this->fuse_open(path.c_str(), flags, handle)) >= 0) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
this->set_compat_client_id(handle, client_id);
|
this->set_compat_client_id(handle, client_id);
|
||||||
#else
|
#else // !defined(_WIN32)
|
||||||
this->set_client_id(static_cast<native_handle>(handle), client_id);
|
this->set_client_id(static_cast<native_handle>(handle), client_id);
|
||||||
#endif
|
#endif // defined(_WIN32)
|
||||||
response.encode(handle);
|
response.encode(handle);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -24,12 +24,13 @@
|
|||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "events/events.hpp"
|
#include "events/events.hpp"
|
||||||
#include "utils/collection.hpp"
|
#include "utils/collection.hpp"
|
||||||
|
#include "utils/config.hpp"
|
||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
void remote_open_file_table::add_directory(const std::string &client_id,
|
void remote_open_file_table::add_directory(const std::string &client_id,
|
||||||
std::uint64_t handle) {
|
std::uint64_t handle) {
|
||||||
recur_mutex_lock directory_lock(directory_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
auto &list = directory_lookup_[client_id];
|
auto &list = directory_lookup_[client_id];
|
||||||
if (utils::collection::excludes(list, handle)) {
|
if (utils::collection::excludes(list, handle)) {
|
||||||
directory_lookup_[client_id].emplace_back(handle);
|
directory_lookup_[client_id].emplace_back(handle);
|
||||||
@ -37,14 +38,32 @@ void remote_open_file_table::add_directory(const std::string &client_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void remote_open_file_table::close_all(const std::string &client_id) {
|
void remote_open_file_table::close_all(const std::string &client_id) {
|
||||||
std::vector<remote::file_handle> compat_handles;
|
unique_recur_mutex_lock lock(file_mutex_);
|
||||||
unique_recur_mutex_lock compat_lock(compat_mutex_);
|
auto compat_handles =
|
||||||
for (auto &&kv : compat_lookup_) {
|
std::accumulate(compat_file_lookup_.begin(), compat_file_lookup_.end(),
|
||||||
if (kv.second.client_id == client_id) {
|
std::vector<remote::file_handle>(),
|
||||||
compat_handles.emplace_back(kv.first);
|
[&client_id](auto &&list, auto &&value) {
|
||||||
}
|
auto &&op_info = value.second;
|
||||||
}
|
if (op_info->client_id == client_id) {
|
||||||
compat_lock.unlock();
|
list.insert(list.end(), op_info->handles.begin(),
|
||||||
|
op_info->handles.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto handles = std::accumulate(
|
||||||
|
file_lookup_.begin(), file_lookup_.end(), std::vector<native_handle>(),
|
||||||
|
[&client_id](auto &&list, auto &&value) {
|
||||||
|
auto &&op_info = value.second;
|
||||||
|
if (op_info->client_id == client_id) {
|
||||||
|
list.insert(list.end(), op_info->handles.begin(),
|
||||||
|
op_info->handles.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
for (auto &&handle : compat_handles) {
|
for (auto &&handle : compat_handles) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -55,32 +74,23 @@ void remote_open_file_table::close_all(const std::string &client_id) {
|
|||||||
remove_compat_open_info(handle);
|
remove_compat_open_info(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<native_handle> handles;
|
|
||||||
unique_recur_mutex_lock file_lock(file_mutex_);
|
|
||||||
for (auto &&kv : file_lookup_) {
|
|
||||||
if (kv.second.client_id == client_id) {
|
|
||||||
handles.emplace_back(kv.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_lock.unlock();
|
|
||||||
|
|
||||||
for (auto &&handle : handles) {
|
for (auto &&handle : handles) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
::CloseHandle(handle);
|
::CloseHandle(handle);
|
||||||
#else
|
#else // !defined(_WIN32)
|
||||||
close(handle);
|
close(handle);
|
||||||
#endif
|
#endif // defined(_WIN32)
|
||||||
remove_open_info(handle);
|
remove_open_info(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::uint64_t> dirs;
|
std::vector<std::uint64_t> dirs;
|
||||||
unique_recur_mutex_lock directory_lock(directory_mutex_);
|
lock.lock();
|
||||||
for (auto &&kv : directory_lookup_) {
|
for (auto &&kv : directory_lookup_) {
|
||||||
if (kv.first == client_id) {
|
if (kv.first == client_id) {
|
||||||
dirs.insert(dirs.end(), kv.second.begin(), kv.second.end());
|
dirs.insert(dirs.end(), kv.second.begin(), kv.second.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
directory_lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
for (auto &&dir : dirs) {
|
for (auto &&dir : dirs) {
|
||||||
remove_directory(client_id, dir);
|
remove_directory(client_id, dir);
|
||||||
@ -90,123 +100,123 @@ void remote_open_file_table::close_all(const std::string &client_id) {
|
|||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
auto remote_open_file_table::get_directory_buffer(const native_handle &handle,
|
auto remote_open_file_table::get_directory_buffer(const native_handle &handle,
|
||||||
PVOID *&buffer) -> bool {
|
PVOID *&buffer) -> bool {
|
||||||
recur_mutex_lock file_lock(file_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
if (file_lookup_.find(handle) != file_lookup_.end()) {
|
if (not handle_lookup_.contains(handle)) {
|
||||||
buffer = &file_lookup_[handle].directory_buffer;
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
buffer = &file_lookup_.at(handle_lookup_.at(handle))->directory_buffer;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
auto remote_open_file_table::get_open_file_count(
|
auto remote_open_file_table::get_open_file_count(
|
||||||
const std::string &file_path) const -> std::size_t {
|
const std::string &file_path) const -> std::size_t {
|
||||||
unique_recur_mutex_lock file_lock(file_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
const auto count = std::accumulate(
|
return (file_lookup_.contains(file_path)
|
||||||
file_lookup_.cbegin(), file_lookup_.cend(), std::size_t(0U),
|
? file_lookup_.at(file_path)->handles.size()
|
||||||
[&file_path](std::size_t total, const auto &kv) -> std::size_t {
|
: 0ULL) +
|
||||||
if (kv.second.path == file_path) {
|
(compat_file_lookup_.contains(file_path)
|
||||||
return ++total;
|
? compat_file_lookup_.at(file_path)->handles.size()
|
||||||
}
|
: 0ULL);
|
||||||
return total;
|
|
||||||
});
|
|
||||||
|
|
||||||
return std::accumulate(
|
|
||||||
compat_lookup_.cbegin(), compat_lookup_.cend(), count,
|
|
||||||
[&file_path](std::size_t total, const auto &kv) -> std::size_t {
|
|
||||||
if (kv.second.path == file_path) {
|
|
||||||
return ++total;
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_open_file_table::get_open_info(const native_handle &handle,
|
auto remote_open_file_table::get_open_info(const native_handle &handle,
|
||||||
open_info &oi) -> bool {
|
open_info &oi) -> bool {
|
||||||
recur_mutex_lock file_lock(file_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
if (file_lookup_.find(handle) != file_lookup_.end()) {
|
if (not handle_lookup_.contains(handle)) {
|
||||||
oi = file_lookup_[handle];
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
oi = *file_lookup_.at(handle_lookup_.at(handle)).get();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_open_file_table::get_open_file_path(const native_handle &handle)
|
auto remote_open_file_table::get_open_file_path(const native_handle &handle)
|
||||||
-> std::string {
|
-> std::string {
|
||||||
recur_mutex_lock file_lock(file_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
if (file_lookup_.find(handle) != file_lookup_.end()) {
|
if (not handle_lookup_.contains(handle)) {
|
||||||
return file_lookup_[handle].path;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return file_lookup_.at(handle_lookup_.at(handle))->path;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_open_file_table::has_open_directory(const std::string &client_id,
|
auto remote_open_file_table::has_open_directory(const std::string &client_id,
|
||||||
std::uint64_t handle) -> bool {
|
std::uint64_t handle) -> bool {
|
||||||
recur_mutex_lock directory_lock(directory_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
auto &list = directory_lookup_[client_id];
|
return (utils::collection::includes(directory_lookup_[client_id], handle));
|
||||||
return (utils::collection::includes(list, handle));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_open_file_table::has_compat_open_info(
|
auto remote_open_file_table::has_compat_open_info(
|
||||||
const remote::file_handle &handle, int error_return) -> int {
|
const remote::file_handle &handle, int error_return) -> int {
|
||||||
recur_mutex_lock compat_lock(compat_mutex_);
|
recur_mutex_lock compat_lock(file_mutex_);
|
||||||
const auto res =
|
auto res = compat_handle_lookup_.contains(handle) ? 0 : -1;
|
||||||
((compat_lookup_.find(handle) == compat_lookup_.end()) ? -1 : 0);
|
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
errno = error_return;
|
errno = error_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_open_file_table::remove_all(const std::string &file_path) {
|
void remote_open_file_table::remove_all(const std::string &file_path) {
|
||||||
unique_recur_mutex_lock file_lock(file_mutex_);
|
unique_recur_mutex_lock lock(file_mutex_);
|
||||||
const auto open_list = std::accumulate(
|
auto compat_open_list = std::accumulate(
|
||||||
file_lookup_.begin(), file_lookup_.end(), std::vector<native_handle>(),
|
compat_file_lookup_.begin(), compat_file_lookup_.end(),
|
||||||
[&file_path](std::vector<native_handle> v,
|
|
||||||
const auto &kv) -> std::vector<native_handle> {
|
|
||||||
if (kv.second.path == file_path) {
|
|
||||||
v.emplace_back(kv.first);
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto compat_open_list = std::accumulate(
|
|
||||||
compat_lookup_.begin(), compat_lookup_.end(),
|
|
||||||
std::vector<remote::file_handle>(),
|
std::vector<remote::file_handle>(),
|
||||||
[&file_path](std::vector<remote::file_handle> v,
|
[&file_path](auto &&list, auto &&kv) -> std::vector<remote::file_handle> {
|
||||||
const auto &kv) -> std::vector<remote::file_handle> {
|
if (kv.first == file_path) {
|
||||||
if (kv.second.path == file_path) {
|
auto *op_info = kv.second.get();
|
||||||
v.emplace_back(kv.first);
|
list.insert(list.end(), op_info->handles.begin(),
|
||||||
|
op_info->handles.end());
|
||||||
}
|
}
|
||||||
return v;
|
return list;
|
||||||
});
|
});
|
||||||
file_lock.unlock();
|
|
||||||
|
|
||||||
for (auto &&handle : open_list) {
|
auto open_list = std::accumulate(
|
||||||
remove_open_info(handle);
|
file_lookup_.begin(), file_lookup_.end(), std::vector<native_handle>(),
|
||||||
}
|
[&file_path](auto &&list, auto &&kv) -> std::vector<native_handle> {
|
||||||
|
if (kv.first == file_path) {
|
||||||
|
auto *op_info = kv.second.get();
|
||||||
|
list.insert(list.end(), op_info->handles.begin(),
|
||||||
|
op_info->handles.end());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
for (auto &&handle : compat_open_list) {
|
for (auto &&handle : compat_open_list) {
|
||||||
remove_compat_open_info(handle);
|
remove_compat_open_info(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto &&handle : open_list) {
|
||||||
|
remove_open_info(handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_open_file_table::remove_compat_open_info(
|
void remote_open_file_table::remove_compat_open_info(
|
||||||
const remote::file_handle &handle) {
|
const remote::file_handle &handle) {
|
||||||
recur_mutex_lock compat_lock(compat_mutex_);
|
recur_mutex_lock compat_lock(file_mutex_);
|
||||||
if (compat_lookup_[handle].count > 0) {
|
if (not compat_handle_lookup_.contains(handle)) {
|
||||||
compat_lookup_[handle].count--;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not compat_lookup_[handle].count) {
|
auto *op_info =
|
||||||
compat_lookup_.erase(handle);
|
compat_file_lookup_.at(compat_handle_lookup_.at(handle)).get();
|
||||||
|
utils::collection::remove_element(op_info->handles, handle);
|
||||||
|
compat_handle_lookup_.erase(handle);
|
||||||
|
|
||||||
|
if (not op_info->handles.empty()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto path = op_info->path;
|
||||||
|
compat_file_lookup_.erase(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_open_file_table::remove_directory(const std::string &client_id,
|
auto remote_open_file_table::remove_directory(const std::string &client_id,
|
||||||
std::uint64_t handle) -> bool {
|
std::uint64_t handle) -> bool {
|
||||||
recur_mutex_lock directory_lock(directory_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
auto &list = directory_lookup_[client_id];
|
auto &list = directory_lookup_[client_id];
|
||||||
if (utils::collection::includes(list, handle)) {
|
if (utils::collection::includes(list, handle)) {
|
||||||
utils::collection::remove_element(list, handle);
|
utils::collection::remove_element(list, handle);
|
||||||
@ -220,48 +230,93 @@ auto remote_open_file_table::remove_directory(const std::string &client_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void remote_open_file_table::remove_open_info(const native_handle &handle) {
|
void remote_open_file_table::remove_open_info(const native_handle &handle) {
|
||||||
recur_mutex_lock file_lock(file_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
if (file_lookup_[handle].count > 0) {
|
if (not handle_lookup_.contains(handle)) {
|
||||||
file_lookup_[handle].count--;
|
return;
|
||||||
}
|
}
|
||||||
if (not file_lookup_[handle].count) {
|
|
||||||
|
auto *op_info = file_lookup_.at(handle_lookup_.at(handle)).get();
|
||||||
|
utils::collection::remove_element(op_info->handles, handle);
|
||||||
|
handle_lookup_.erase(handle);
|
||||||
|
|
||||||
|
if (not op_info->handles.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
if (file_lookup_[handle].directory_buffer) {
|
if (op_info->directory_buffer) {
|
||||||
FspFileSystemDeleteDirectoryBuffer(
|
FspFileSystemDeleteDirectoryBuffer(&op_info->directory_buffer);
|
||||||
&file_lookup_[handle].directory_buffer);
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
file_lookup_.erase(handle);
|
|
||||||
|
auto path = op_info->path;
|
||||||
|
file_lookup_.erase(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remote_open_file_table::remove_and_close_all(const native_handle &handle) {
|
||||||
|
unique_recur_mutex_lock lock(file_mutex_);
|
||||||
|
if (not handle_lookup_.contains(handle)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto op_info = *file_lookup_.at(handle_lookup_.at(handle));
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
for (auto &&open_handle : op_info.handles) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
::CloseHandle(open_handle);
|
||||||
|
#else // !defined(_WIN32)
|
||||||
|
close(open_handle);
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
remove_open_info(open_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_open_file_table::set_compat_client_id(
|
void remote_open_file_table::set_compat_client_id(
|
||||||
const remote::file_handle &handle, const std::string &client_id) {
|
const remote::file_handle &handle, const std::string &client_id) {
|
||||||
recur_mutex_lock compat_lock(compat_mutex_);
|
recur_mutex_lock compat_lock(file_mutex_);
|
||||||
compat_lookup_[handle].client_id = client_id;
|
compat_file_lookup_.at(compat_handle_lookup_.at(handle))->client_id =
|
||||||
|
client_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_open_file_table::set_client_id(const native_handle &handle,
|
void remote_open_file_table::set_client_id(const native_handle &handle,
|
||||||
const std::string &client_id) {
|
const std::string &client_id) {
|
||||||
recur_mutex_lock file_lock(file_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
file_lookup_[handle].client_id = client_id;
|
file_lookup_.at(handle_lookup_.at(handle))->client_id = client_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_open_file_table::set_compat_open_info(
|
void remote_open_file_table::set_compat_open_info(
|
||||||
const remote::file_handle &handle, const std::string &file_path) {
|
const remote::file_handle &handle, const std::string &file_path) {
|
||||||
recur_mutex_lock compat_lock(compat_mutex_);
|
recur_mutex_lock compat_lock(file_mutex_);
|
||||||
if (compat_lookup_.find(handle) == compat_lookup_.end()) {
|
if (compat_handle_lookup_.contains(handle)) {
|
||||||
compat_lookup_[handle] = {0, "", file_path};
|
return;
|
||||||
}
|
}
|
||||||
compat_lookup_[handle].count++;
|
|
||||||
|
if (not compat_file_lookup_.contains(file_path)) {
|
||||||
|
compat_file_lookup_[file_path] =
|
||||||
|
std::make_unique<compat_open_info>(compat_open_info{
|
||||||
|
"",
|
||||||
|
{},
|
||||||
|
file_path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
compat_handle_lookup_[handle] = file_path;
|
||||||
|
compat_file_lookup_.at(file_path)->handles.emplace_back(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_open_file_table::set_open_info(const native_handle &handle,
|
void remote_open_file_table::set_open_info(const native_handle &handle,
|
||||||
open_info oi) {
|
open_info op_info) {
|
||||||
recur_mutex_lock file_lock(file_mutex_);
|
recur_mutex_lock lock(file_mutex_);
|
||||||
if (file_lookup_.find(handle) == file_lookup_.end()) {
|
if (handle_lookup_.contains(handle)) {
|
||||||
file_lookup_[handle] = std::move(oi);
|
return;
|
||||||
}
|
}
|
||||||
file_lookup_[handle].count++;
|
|
||||||
|
if (not file_lookup_.contains(op_info.path)) {
|
||||||
|
file_lookup_[op_info.path] = std::make_unique<open_info>(op_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_lookup_[handle] = op_info.path;
|
||||||
|
file_lookup_.at(op_info.path)->handles.emplace_back(handle);
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -160,10 +160,12 @@ auto remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_name,
|
|||||||
auto ret{
|
auto ret{
|
||||||
packet_client_.send(function_name, request, response, service_flags),
|
packet_client_.send(function_name, request, response, service_flags),
|
||||||
};
|
};
|
||||||
|
|
||||||
DECODE_OR_IGNORE(&response, was_closed);
|
DECODE_OR_IGNORE(&response, was_closed);
|
||||||
if (was_closed != 0U) {
|
if (was_closed != 0U) {
|
||||||
remove_all(file_path);
|
remove_all(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
RAISE_REMOTE_WINFSP_CLIENT_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_WINFSP_CLIENT_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -222,11 +224,16 @@ auto remote_client::winfsp_create(PWSTR file_name, UINT32 create_options,
|
|||||||
DECODE_OR_IGNORE(&response, *file_info);
|
DECODE_OR_IGNORE(&response, *file_info);
|
||||||
DECODE_OR_IGNORE(&response, normalized_name);
|
DECODE_OR_IGNORE(&response, normalized_name);
|
||||||
DECODE_OR_IGNORE(&response, exists);
|
DECODE_OR_IGNORE(&response, exists);
|
||||||
|
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
*file_desc = reinterpret_cast<PVOID>(handle);
|
*file_desc = reinterpret_cast<PVOID>(handle);
|
||||||
set_open_info(
|
set_open_info(to_handle(*file_desc),
|
||||||
to_handle(*file_desc),
|
open_info{
|
||||||
open_info{0, "", nullptr, utils::string::to_utf8(file_name)});
|
"",
|
||||||
|
nullptr,
|
||||||
|
{},
|
||||||
|
utils::string::to_utf8(file_name),
|
||||||
|
});
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
if (exists) {
|
if (exists) {
|
||||||
::SetLastError(ERROR_ALREADY_EXISTS);
|
::SetLastError(ERROR_ALREADY_EXISTS);
|
||||||
@ -390,9 +397,13 @@ auto remote_client::winfsp_open(PWSTR file_name, UINT32 create_options,
|
|||||||
|
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
*file_desc = reinterpret_cast<PVOID>(handle);
|
*file_desc = reinterpret_cast<PVOID>(handle);
|
||||||
set_open_info(
|
set_open_info(to_handle(*file_desc),
|
||||||
to_handle(*file_desc),
|
open_info{
|
||||||
open_info{0, "", nullptr, utils::string::to_utf8(file_name)});
|
"",
|
||||||
|
nullptr,
|
||||||
|
{},
|
||||||
|
utils::string::to_utf8(file_name),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -945,12 +945,12 @@ auto remote_server::winfsp_cleanup(PVOID file_desc, PWSTR /*file_name*/,
|
|||||||
auto *handle = reinterpret_cast<HANDLE>(file_desc);
|
auto *handle = reinterpret_cast<HANDLE>(file_desc);
|
||||||
auto ret = has_open_info(handle, STATUS_INVALID_HANDLE);
|
auto ret = has_open_info(handle, STATUS_INVALID_HANDLE);
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
if ((flags & FileSystemBase::CleanupDelete) != 0U) {
|
if ((flags & FspCleanupDelete) != 0U) {
|
||||||
::CloseHandle(handle);
|
remove_and_close_all(file_desc);
|
||||||
remove_open_info(file_desc);
|
|
||||||
was_closed = TRUE;
|
was_closed = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RAISE_REMOTE_WINFSP_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_WINFSP_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1005,8 +1005,12 @@ auto remote_server::winfsp_create(PWSTR file_name, UINT32 create_options,
|
|||||||
if (handle != INVALID_HANDLE_VALUE) {
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
*file_desc = reinterpret_cast<PVOID>(handle);
|
*file_desc = reinterpret_cast<PVOID>(handle);
|
||||||
normalized_name = utils::string::to_utf8(file_name);
|
normalized_name = utils::string::to_utf8(file_name);
|
||||||
set_open_info(*file_desc,
|
set_open_info(*file_desc, open_info{
|
||||||
open_info{0, "", nullptr, utils::string::to_utf8(file_path)});
|
"",
|
||||||
|
nullptr,
|
||||||
|
{},
|
||||||
|
utils::string::to_utf8(file_path),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret =
|
auto ret =
|
||||||
@ -1140,8 +1144,12 @@ auto remote_server::winfsp_open(PWSTR file_name, UINT32 create_options,
|
|||||||
if (handle != INVALID_HANDLE_VALUE) {
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
*file_desc = reinterpret_cast<PVOID>(handle);
|
*file_desc = reinterpret_cast<PVOID>(handle);
|
||||||
normalized_name = utils::string::to_utf8(file_name);
|
normalized_name = utils::string::to_utf8(file_name);
|
||||||
set_open_info(*file_desc,
|
set_open_info(*file_desc, open_info{
|
||||||
open_info{0, "", nullptr, utils::string::to_utf8(file_path)});
|
"",
|
||||||
|
nullptr,
|
||||||
|
{},
|
||||||
|
utils::string::to_utf8(file_path),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret =
|
auto ret =
|
||||||
|
@ -213,9 +213,10 @@ auto remote_winfsp_drive::Init(PVOID host) -> NTSTATUS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
file_system_host->SetCasePreservedNames(TRUE);
|
file_system_host->SetCasePreservedNames(TRUE);
|
||||||
file_system_host->SetCaseSensitiveSearch(FALSE);
|
file_system_host->SetCaseSensitiveSearch(TRUE);
|
||||||
file_system_host->SetFileInfoTimeout(1000);
|
file_system_host->SetFileInfoTimeout(1000);
|
||||||
file_system_host->SetFlushAndPurgeOnCleanup(TRUE);
|
file_system_host->SetFlushAndPurgeOnCleanup(TRUE);
|
||||||
|
file_system_host->SetMaxComponentLength(255U);
|
||||||
file_system_host->SetNamedStreams(FALSE);
|
file_system_host->SetNamedStreams(FALSE);
|
||||||
file_system_host->SetPassQueryDirectoryPattern(FALSE);
|
file_system_host->SetPassQueryDirectoryPattern(FALSE);
|
||||||
file_system_host->SetPersistentAcls(FALSE);
|
file_system_host->SetPersistentAcls(FALSE);
|
||||||
|
@ -203,15 +203,15 @@ VOID winfsp_drive::Cleanup(PVOID file_node, PVOID file_desc,
|
|||||||
FspFileSystemDeleteDirectoryBuffer(&directory_buffer);
|
FspFileSystemDeleteDirectoryBuffer(&directory_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directory) {
|
if (not directory) {
|
||||||
if (provider_.get_directory_item_count(api_path) == 0) {
|
return handle_error(fm_->remove_file(api_path));
|
||||||
return handle_error(provider_.remove_directory(api_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
return handle_error(api_error::directory_not_empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handle_error(fm_->remove_file(api_path));
|
if (provider_.get_directory_item_count(api_path) == 0) {
|
||||||
|
return handle_error(provider_.remove_directory(api_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle_error(api_error::directory_not_empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((flags & FspCleanupSetArchiveBit) != 0U) && not directory) {
|
if (((flags & FspCleanupSetArchiveBit) != 0U) && not directory) {
|
||||||
|
@ -73,6 +73,7 @@ protected:
|
|||||||
});
|
});
|
||||||
|
|
||||||
mount_location = utils::path::combine(test_directory, {"mount"});
|
mount_location = utils::path::combine(test_directory, {"mount"});
|
||||||
|
|
||||||
ASSERT_TRUE(utils::file::directory(mount_location).create_directory());
|
ASSERT_TRUE(utils::file::directory(mount_location).create_directory());
|
||||||
|
|
||||||
cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
||||||
@ -170,6 +171,17 @@ public:
|
|||||||
return file_path;
|
return file_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto create_directory_and_test(std::string &dir_name) -> std::string {
|
||||||
|
dir_name += std::to_string(++idx);
|
||||||
|
|
||||||
|
auto dir_path = utils::path::combine(mount_location, {dir_name});
|
||||||
|
EXPECT_TRUE(utils::file::directory(dir_path).create_directory());
|
||||||
|
|
||||||
|
EXPECT_TRUE(utils::file::directory(dir_path).exists());
|
||||||
|
EXPECT_FALSE(utils::file::file(dir_path).exists());
|
||||||
|
return dir_path;
|
||||||
|
}
|
||||||
|
|
||||||
static auto create_root_file(std::string &file_name) -> std::string {
|
static auto create_root_file(std::string &file_name) -> std::string {
|
||||||
auto file_path = create_file_and_test(file_name);
|
auto file_path = create_file_and_test(file_name);
|
||||||
auto api_path = utils::path::create_api_path(file_name);
|
auto api_path = utils::path::create_api_path(file_name);
|
||||||
@ -204,11 +216,18 @@ public:
|
|||||||
EXPECT_TRUE(unmounted);
|
EXPECT_TRUE(unmounted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rmdir_and_test(std::string_view dir_path) {
|
||||||
|
EXPECT_TRUE(utils::file::directory(dir_path).remove());
|
||||||
|
EXPECT_FALSE(utils::file::directory(dir_path).exists());
|
||||||
|
|
||||||
|
EXPECT_FALSE(utils::file::file(dir_path).exists());
|
||||||
|
}
|
||||||
|
|
||||||
static void unlink_file_and_test(std::string_view file_path) {
|
static void unlink_file_and_test(std::string_view file_path) {
|
||||||
EXPECT_TRUE(utils::file::file(file_path).remove());
|
EXPECT_TRUE(utils::file::file(file_path).remove());
|
||||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||||
|
|
||||||
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
||||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unlink_root_file(const std::string &file_path) {
|
static void unlink_root_file(const std::string &file_path) {
|
||||||
|
@ -75,6 +75,8 @@ protected:
|
|||||||
static void SetUpTestCase() {
|
static void SetUpTestCase() {
|
||||||
current_directory = std::filesystem::current_path();
|
current_directory = std::filesystem::current_path();
|
||||||
|
|
||||||
|
mount_location = utils::string::to_lower(std::string{"U:"});
|
||||||
|
|
||||||
const auto mount_s3 = [&]() {
|
const auto mount_s3 = [&]() {
|
||||||
{
|
{
|
||||||
auto test_directory = utils::path::combine(
|
auto test_directory = utils::path::combine(
|
||||||
@ -84,8 +86,6 @@ protected:
|
|||||||
app_config::get_provider_name(provider_type::s3),
|
app_config::get_provider_name(provider_type::s3),
|
||||||
});
|
});
|
||||||
|
|
||||||
mount_location = "U:";
|
|
||||||
|
|
||||||
auto cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
auto cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
||||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||||
|
|
||||||
@ -124,8 +124,6 @@ protected:
|
|||||||
app_config::get_provider_name(provider_type::sia),
|
app_config::get_provider_name(provider_type::sia),
|
||||||
});
|
});
|
||||||
|
|
||||||
mount_location = "U:";
|
|
||||||
|
|
||||||
auto cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
auto cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
||||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||||
|
|
||||||
@ -166,7 +164,7 @@ protected:
|
|||||||
});
|
});
|
||||||
|
|
||||||
mount_location2 = mount_location;
|
mount_location2 = mount_location;
|
||||||
mount_location = "V:";
|
mount_location = utils::string::to_lower(std::string{"V:"});
|
||||||
|
|
||||||
auto cfg_directory = utils::path::combine(test_directory, {"cfg2"});
|
auto cfg_directory = utils::path::combine(test_directory, {"cfg2"});
|
||||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||||
@ -275,8 +273,9 @@ std::string winfsp_test<provider_t>::mount_location;
|
|||||||
|
|
||||||
template <typename provider_t>
|
template <typename provider_t>
|
||||||
std::string winfsp_test<provider_t>::mount_location2;
|
std::string winfsp_test<provider_t>::mount_location2;
|
||||||
// using winfsp_provider_types = ::testing::Types<local_s3, local_sia,
|
|
||||||
// remote_s3, remote_sia>;
|
// using winfsp_provider_types = ::testing::Types<local_s3, remote_s3,
|
||||||
|
// local_sia, remote_sia>;
|
||||||
using winfsp_provider_types = ::testing::Types<local_s3, remote_s3>;
|
using winfsp_provider_types = ::testing::Types<local_s3, remote_s3>;
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
75
repertory/repertory_test/src/fuse_drive_chmod_test.cpp
Normal file
75
repertory/repertory_test/src/fuse_drive_chmod_test.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
|
||||||
|
#include "fixtures/fuse_fixture.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
TYPED_TEST_CASE(fuse_test, fuse_provider_types);
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_chmod_if_owner) {
|
||||||
|
std::string file_name{"chmod_test"};
|
||||||
|
auto file_path = this->create_file_and_test(file_name);
|
||||||
|
|
||||||
|
EXPECT_EQ(0, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
||||||
|
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
stat64(file_path.c_str(), &unix_st);
|
||||||
|
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR),
|
||||||
|
ACCESSPERMS & unix_st.st_mode);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chmod_if_not_owner) {
|
||||||
|
std::string file_name{"chmod_test"};
|
||||||
|
auto file_path = this->create_root_file(file_name);
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
this->unlink_root_file(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chmod_setgid_if_not_root) {
|
||||||
|
std::string file_name{"chmod_test"};
|
||||||
|
auto file_path = this->create_file_and_test(file_name);
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISGID));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chmod_setuid_if_not_root) {
|
||||||
|
std::string file_name{"chmod_test"};
|
||||||
|
auto file_path = this->create_file_and_test(file_name);
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISUID));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
#endif // !defined(_WIN32)
|
113
repertory/repertory_test/src/fuse_drive_chown_test.cpp
Normal file
113
repertory/repertory_test/src/fuse_drive_chown_test.cpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
|
||||||
|
#include "fixtures/fuse_fixture.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
TYPED_TEST_CASE(fuse_test, fuse_provider_types);
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chmod_set_sticky_if_not_root) {
|
||||||
|
std::string file_name{"chown_test"};
|
||||||
|
auto file_path = this->create_file_and_test(file_name);
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISVTX));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_chown_group_if_owner_and_a_member_of_the_group) {
|
||||||
|
std::string file_name{"chown_test"};
|
||||||
|
auto file_path = this->create_file_and_test(file_name);
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
|
|
||||||
|
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
|
||||||
|
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||||
|
|
||||||
|
struct stat64 unix_st2{};
|
||||||
|
stat64(file_path.c_str(), &unix_st2);
|
||||||
|
EXPECT_EQ(getgid(), unix_st2.st_gid);
|
||||||
|
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test,
|
||||||
|
can_not_chown_group_if_owner_but_not_a_member_of_the_group) {
|
||||||
|
std::string file_name{"chown_test"};
|
||||||
|
auto file_path = this->create_file_and_test(file_name);
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
struct stat64 unix_st2{};
|
||||||
|
stat64(file_path.c_str(), &unix_st2);
|
||||||
|
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||||
|
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chown_group_if_not_the_owner) {
|
||||||
|
std::string file_name{"chown_test"};
|
||||||
|
auto file_path = this->create_root_file(file_name);
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
struct stat64 unix_st2{};
|
||||||
|
stat64(file_path.c_str(), &unix_st2);
|
||||||
|
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||||
|
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||||
|
|
||||||
|
this->unlink_root_file(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chown_user_if_not_root) {
|
||||||
|
std::string file_name{"chown_test"};
|
||||||
|
auto file_path = this->create_file_and_test(file_name);
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
struct stat64 unix_st2{};
|
||||||
|
stat64(file_path.c_str(), &unix_st2);
|
||||||
|
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||||
|
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
#endif // !defined(_WIN32)
|
51
repertory/repertory_test/src/fuse_drive_directory_test.cpp
Normal file
51
repertory/repertory_test/src/fuse_drive_directory_test.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
|
||||||
|
#include "fixtures/fuse_fixture.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
TYPED_TEST_CASE(fuse_test, fuse_provider_types);
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_create_and_remove_directory) {
|
||||||
|
auto dir_name = std::string{"dir"} + std::to_string(++this->idx);
|
||||||
|
|
||||||
|
auto dir_path = utils::path::combine(this->mount_location, {dir_name});
|
||||||
|
EXPECT_EQ(0, mkdir(dir_path.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
|
||||||
|
S_IWGRP | S_IXGRP));
|
||||||
|
|
||||||
|
EXPECT_TRUE(utils::file::is_directory(dir_path));
|
||||||
|
EXPECT_FALSE(utils::file::is_file(dir_path));
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
stat64(dir_path.c_str(), &unix_st);
|
||||||
|
|
||||||
|
EXPECT_EQ(getgid(), unix_st.st_gid);
|
||||||
|
EXPECT_EQ(getuid(), unix_st.st_uid);
|
||||||
|
|
||||||
|
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
|
||||||
|
S_IWGRP | S_IXGRP),
|
||||||
|
ACCESSPERMS & unix_st.st_mode);
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
#endif // !defined(_WIN32)
|
@ -1,29 +1,3 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
|
|
||||||
#include "fixtures/fuse_fixture.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
// static void rmdir_and_test(const std::string &directory_path) {
|
// static void rmdir_and_test(const std::string &directory_path) {
|
||||||
// std::cout << __FUNCTION__ << std::endl;
|
// std::cout << __FUNCTION__ << std::endl;
|
||||||
// int ret = 0;
|
// int ret = 0;
|
||||||
@ -400,14 +374,6 @@ namespace repertory {
|
|||||||
// }
|
// }
|
||||||
// #endif
|
// #endif
|
||||||
//
|
//
|
||||||
// // file_path = create_file_and_test(mount_location, "chown_test");
|
|
||||||
// // test_chown(utils::path::create_api_path("chown_test"), file_path);
|
|
||||||
// // unlink_file_and_test(file_path);
|
|
||||||
// //
|
|
||||||
// // file_path = utils::path::combine(mount_location, {"mkdir_test"});
|
|
||||||
// // test_mkdir(utils::path::create_api_path("mkdir_test"), file_path);
|
|
||||||
// // rmdir_and_test(file_path);
|
|
||||||
// //
|
|
||||||
// // file_path = create_file_and_test(mount_location,
|
// // file_path = create_file_and_test(mount_location,
|
||||||
// // "write_read_test");
|
// // "write_read_test");
|
||||||
// // test_write_and_read(utils::path::create_api_path("write_read_test"),
|
// // test_write_and_read(utils::path::create_api_path("write_read_test"),
|
||||||
@ -514,136 +480,3 @@ namespace repertory {
|
|||||||
// // test_xattr_removexattr(file_path);
|
// // test_xattr_removexattr(file_path);
|
||||||
// // unlink_file_and_test(file_path);
|
// // unlink_file_and_test(file_path);
|
||||||
// // #endif
|
// // #endif
|
||||||
|
|
||||||
TYPED_TEST_CASE(fuse_test, fuse_provider_types);
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_chmod_if_owner) {
|
|
||||||
std::string file_name{"chmod_test"};
|
|
||||||
auto file_path = this->create_file_and_test(file_name);
|
|
||||||
|
|
||||||
EXPECT_EQ(0, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
|
||||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
|
||||||
|
|
||||||
struct stat64 unix_st {};
|
|
||||||
stat64(file_path.c_str(), &unix_st);
|
|
||||||
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR),
|
|
||||||
ACCESSPERMS & unix_st.st_mode);
|
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_not_chmod_if_not_owner) {
|
|
||||||
std::string file_name{"chmod_test"};
|
|
||||||
auto file_path = this->create_root_file(file_name);
|
|
||||||
|
|
||||||
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
|
||||||
EXPECT_EQ(EPERM, errno);
|
|
||||||
|
|
||||||
this->unlink_root_file(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_not_chmod_setgid_if_not_root) {
|
|
||||||
std::string file_name{"chmod_test"};
|
|
||||||
auto file_path = this->create_file_and_test(file_name);
|
|
||||||
|
|
||||||
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISGID));
|
|
||||||
EXPECT_EQ(EPERM, errno);
|
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_not_chmod_setuid_if_not_root) {
|
|
||||||
std::string file_name{"chmod_test"};
|
|
||||||
auto file_path = this->create_file_and_test(file_name);
|
|
||||||
|
|
||||||
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISUID));
|
|
||||||
EXPECT_EQ(EPERM, errno);
|
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_not_chmod_set_sticky_if_not_root) {
|
|
||||||
std::string file_name{"chown_test"};
|
|
||||||
auto file_path = this->create_file_and_test(file_name);
|
|
||||||
|
|
||||||
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISVTX));
|
|
||||||
EXPECT_EQ(EPERM, errno);
|
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_chown_group_if_owner_and_a_member_of_the_group) {
|
|
||||||
std::string file_name{"chown_test"};
|
|
||||||
auto file_path = this->create_file_and_test(file_name);
|
|
||||||
|
|
||||||
struct stat64 unix_st {};
|
|
||||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
|
||||||
|
|
||||||
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
|
|
||||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
|
||||||
|
|
||||||
struct stat64 unix_st2 {};
|
|
||||||
stat64(file_path.c_str(), &unix_st2);
|
|
||||||
EXPECT_EQ(getgid(), unix_st2.st_gid);
|
|
||||||
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test,
|
|
||||||
can_not_chown_group_if_owner_but_not_a_member_of_the_group) {
|
|
||||||
std::string file_name{"chown_test"};
|
|
||||||
auto file_path = this->create_file_and_test(file_name);
|
|
||||||
|
|
||||||
struct stat64 unix_st {};
|
|
||||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
|
||||||
|
|
||||||
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
|
|
||||||
EXPECT_EQ(EPERM, errno);
|
|
||||||
|
|
||||||
struct stat64 unix_st2 {};
|
|
||||||
stat64(file_path.c_str(), &unix_st2);
|
|
||||||
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
|
||||||
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_not_chown_group_if_not_the_owner) {
|
|
||||||
std::string file_name{"chown_test"};
|
|
||||||
auto file_path = this->create_root_file(file_name);
|
|
||||||
|
|
||||||
struct stat64 unix_st {};
|
|
||||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
|
||||||
|
|
||||||
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
|
|
||||||
EXPECT_EQ(EPERM, errno);
|
|
||||||
|
|
||||||
struct stat64 unix_st2 {};
|
|
||||||
stat64(file_path.c_str(), &unix_st2);
|
|
||||||
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
|
||||||
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
|
||||||
|
|
||||||
this->unlink_root_file(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_not_chown_user_if_not_root) {
|
|
||||||
std::string file_name{"chown_test"};
|
|
||||||
auto file_path = this->create_file_and_test(file_name);
|
|
||||||
|
|
||||||
struct stat64 unix_st {};
|
|
||||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
|
||||||
|
|
||||||
EXPECT_EQ(-1, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
|
|
||||||
EXPECT_EQ(EPERM, errno);
|
|
||||||
|
|
||||||
struct stat64 unix_st2 {};
|
|
||||||
stat64(file_path.c_str(), &unix_st2);
|
|
||||||
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
|
||||||
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // !defined(_WIN32)
|
|
@ -31,48 +31,52 @@ namespace repertory {
|
|||||||
TYPED_TEST_CASE(winfsp_test, winfsp_provider_types);
|
TYPED_TEST_CASE(winfsp_test, winfsp_provider_types);
|
||||||
|
|
||||||
TYPED_TEST(winfsp_test, cr8_nl_can_create_file_of_max_component_length) {
|
TYPED_TEST(winfsp_test, cr8_nl_can_create_file_of_max_component_length) {
|
||||||
if (this->current_provider != provider_type::s3) {
|
if (this->current_provider == provider_type::s3) {
|
||||||
DWORD max_length{};
|
return;
|
||||||
EXPECT_TRUE(::GetVolumeInformationA(this->mount_location.c_str(), nullptr,
|
|
||||||
0, nullptr, &max_length, nullptr,
|
|
||||||
nullptr, 0));
|
|
||||||
EXPECT_EQ(255U, max_length);
|
|
||||||
|
|
||||||
auto file_path = utils::path::combine(this->mount_location,
|
|
||||||
{
|
|
||||||
std::string(max_length, 'a'),
|
|
||||||
});
|
|
||||||
|
|
||||||
auto handle = ::CreateFileA(
|
|
||||||
file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
|
||||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
|
||||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
|
||||||
EXPECT_TRUE(::CloseHandle(handle));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD max_length{};
|
||||||
|
EXPECT_TRUE(::GetVolumeInformationA(this->mount_location.c_str(), nullptr, 0,
|
||||||
|
nullptr, &max_length, nullptr, nullptr,
|
||||||
|
0));
|
||||||
|
EXPECT_EQ(255U, max_length);
|
||||||
|
|
||||||
|
auto file_path = utils::path::combine(this->mount_location,
|
||||||
|
{
|
||||||
|
std::string(max_length, 'a'),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto handle =
|
||||||
|
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
EXPECT_TRUE(::CloseHandle(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(winfsp_test,
|
TYPED_TEST(winfsp_test,
|
||||||
cr8_nl_can_not_create_file_greater_than_max_component_length) {
|
cr8_nl_can_not_create_file_greater_than_max_component_length) {
|
||||||
if (this->current_provider != provider_type::s3) {
|
if (this->current_provider == provider_type::s3) {
|
||||||
DWORD max_length{};
|
return;
|
||||||
EXPECT_TRUE(::GetVolumeInformationA(this->mount_location.c_str(), nullptr,
|
|
||||||
0, nullptr, &max_length, nullptr,
|
|
||||||
nullptr, 0));
|
|
||||||
EXPECT_EQ(255U, max_length);
|
|
||||||
|
|
||||||
auto file_path = utils::path::combine(this->mount_location,
|
|
||||||
{
|
|
||||||
std::string(max_length + 1U, 'a'),
|
|
||||||
});
|
|
||||||
|
|
||||||
auto handle = ::CreateFileA(
|
|
||||||
file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
|
||||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
|
||||||
ASSERT_EQ(INVALID_HANDLE_VALUE, handle);
|
|
||||||
EXPECT_EQ(ERROR_INVALID_NAME, ::GetLastError());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD max_length{};
|
||||||
|
EXPECT_TRUE(::GetVolumeInformationA(this->mount_location.c_str(), nullptr, 0,
|
||||||
|
nullptr, &max_length, nullptr, nullptr,
|
||||||
|
0));
|
||||||
|
EXPECT_EQ(255U, max_length);
|
||||||
|
|
||||||
|
auto file_path = utils::path::combine(this->mount_location,
|
||||||
|
{
|
||||||
|
std::string(max_length + 1U, 'a'),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto handle =
|
||||||
|
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||||
|
ASSERT_EQ(INVALID_HANDLE_VALUE, handle);
|
||||||
|
EXPECT_EQ(ERROR_INVALID_NAME, ::GetLastError());
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ TYPED_TEST(winfsp_test, delete_can_delete_on_close_after_mapping) {
|
|||||||
16U * sys_info.dwAllocationGranularity, nullptr);
|
16U * sys_info.dwAllocationGranularity, nullptr);
|
||||||
EXPECT_TRUE(mapping != nullptr);
|
EXPECT_TRUE(mapping != nullptr);
|
||||||
|
|
||||||
auto *view = MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
auto *view = ::MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||||
EXPECT_TRUE(view != nullptr);
|
EXPECT_TRUE(view != nullptr);
|
||||||
|
|
||||||
for (PUINT8 ptr = reinterpret_cast<PUINT8>(view),
|
for (PUINT8 ptr = reinterpret_cast<PUINT8>(view),
|
||||||
|
@ -124,8 +124,7 @@ TYPED_TEST(winfsp_test, info_can_get_file_name_info) {
|
|||||||
|
|
||||||
auto *info = reinterpret_cast<FILE_NAME_INFO *>(name_info.data());
|
auto *info = reinterpret_cast<FILE_NAME_INFO *>(name_info.data());
|
||||||
auto expected_name{
|
auto expected_name{
|
||||||
std::string{"\\repertory\\"} +
|
std::string{"\\repertory\\"} + this->mount_location.at(0U) +
|
||||||
utils::string::to_lower(this->mount_location).at(0U) +
|
|
||||||
"\\test_file_2",
|
"\\test_file_2",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -229,8 +228,7 @@ TYPED_TEST(winfsp_test, info_can_get_file_path) {
|
|||||||
VOLUME_NAME_NONE | FILE_NAME_OPENED);
|
VOLUME_NAME_NONE | FILE_NAME_OPENED);
|
||||||
|
|
||||||
auto expected_name{
|
auto expected_name{
|
||||||
std::string{"\\repertory\\"} +
|
std::string{"\\repertory\\"} + this->mount_location.at(0U) +
|
||||||
utils::string::to_lower(this->mount_location).at(0U) +
|
|
||||||
"\\test_file_2",
|
"\\test_file_2",
|
||||||
};
|
};
|
||||||
EXPECT_EQ(result, static_cast<DWORD>(expected_name.size()));
|
EXPECT_EQ(result, static_cast<DWORD>(expected_name.size()));
|
||||||
|
214
repertory/repertory_test/src/winfsp_drive_read_write_test.cpp
Normal file
214
repertory/repertory_test/src/winfsp_drive_read_write_test.cpp
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <array>
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implemented test cases based on WinFsp tests:
|
||||||
|
// https://github.com/winfsp/winfsp/blob/v2.0/tst/winfsp-tests
|
||||||
|
//
|
||||||
|
#include "fixtures/winfsp_fixture.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
TYPED_TEST_CASE(winfsp_test, winfsp_provider_types);
|
||||||
|
|
||||||
|
static void test_file(auto &&file_path, auto &&flags) {
|
||||||
|
auto handle =
|
||||||
|
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | flags, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
|
||||||
|
auto pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
|
||||||
|
EXPECT_EQ(0, pointer);
|
||||||
|
|
||||||
|
auto write_buffer = utils::generate_secure_random<data_buffer>(16U);
|
||||||
|
|
||||||
|
DWORD bytes_written{};
|
||||||
|
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), write_buffer.size(),
|
||||||
|
&bytes_written, nullptr));
|
||||||
|
|
||||||
|
EXPECT_EQ(static_cast<DWORD>(write_buffer.size()), bytes_written);
|
||||||
|
EXPECT_EQ(pointer + bytes_written,
|
||||||
|
::SetFilePointer(handle, 0, 0, FILE_CURRENT));
|
||||||
|
|
||||||
|
pointer = ::SetFilePointer(handle, 2U * write_buffer.size(), 0, FILE_BEGIN);
|
||||||
|
EXPECT_EQ(static_cast<DWORD>(2U * write_buffer.size()), pointer);
|
||||||
|
|
||||||
|
EXPECT_TRUE(::WriteFile(handle, write_buffer.data(), write_buffer.size(),
|
||||||
|
&bytes_written, nullptr));
|
||||||
|
EXPECT_EQ(static_cast<DWORD>(write_buffer.size()), bytes_written);
|
||||||
|
EXPECT_EQ(pointer + bytes_written,
|
||||||
|
::SetFilePointer(handle, 0, 0, FILE_CURRENT));
|
||||||
|
|
||||||
|
pointer = ::SetFilePointer(handle, 0, 0, FILE_BEGIN);
|
||||||
|
EXPECT_EQ(0U, pointer);
|
||||||
|
|
||||||
|
DWORD bytes_read{};
|
||||||
|
std::array<std::uint8_t, 16U> read_buffer{};
|
||||||
|
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), read_buffer.size(),
|
||||||
|
&bytes_read, nullptr));
|
||||||
|
|
||||||
|
EXPECT_EQ(static_cast<DWORD>(16U), bytes_read);
|
||||||
|
EXPECT_EQ(pointer + bytes_read, ::SetFilePointer(handle, 0, 0, FILE_CURRENT));
|
||||||
|
EXPECT_EQ(0,
|
||||||
|
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
|
||||||
|
|
||||||
|
for (auto idx = 0U; idx < 2U; ++idx) {
|
||||||
|
pointer = ::SetFilePointer(handle, 2U * write_buffer.size(), 0, FILE_BEGIN);
|
||||||
|
EXPECT_EQ(2U * write_buffer.size(), pointer);
|
||||||
|
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), read_buffer.size(),
|
||||||
|
&bytes_read, nullptr));
|
||||||
|
EXPECT_EQ(static_cast<DWORD>(16U), bytes_read);
|
||||||
|
EXPECT_EQ(pointer + bytes_read,
|
||||||
|
::SetFilePointer(handle, 0, 0, FILE_CURRENT));
|
||||||
|
EXPECT_EQ(0,
|
||||||
|
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer = ::SetFilePointer(handle, 3U * write_buffer.size(), 0, FILE_BEGIN);
|
||||||
|
EXPECT_EQ(3U * write_buffer.size(), pointer);
|
||||||
|
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(), read_buffer.size(),
|
||||||
|
&bytes_read, nullptr));
|
||||||
|
EXPECT_EQ(static_cast<DWORD>(16U), bytes_read);
|
||||||
|
EXPECT_EQ(pointer + bytes_read, ::SetFilePointer(handle, 0, 0, FILE_CURRENT));
|
||||||
|
EXPECT_EQ(0,
|
||||||
|
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
|
||||||
|
|
||||||
|
// FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN);
|
||||||
|
// ASSERT(0 == FilePointer);
|
||||||
|
// Success = WriteFile(Handle, Buffer[0], 2 * SystemInfo.dwPageSize,
|
||||||
|
// &BytesTransferred, 0);
|
||||||
|
// ASSERT(Success);
|
||||||
|
// ASSERT(2 * SystemInfo.dwPageSize == BytesTransferred);
|
||||||
|
// ASSERT(FilePointer + BytesTransferred ==
|
||||||
|
// SetFilePointer(Handle, 0, 0, FILE_CURRENT));
|
||||||
|
//
|
||||||
|
// FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN);
|
||||||
|
// ASSERT(0 == FilePointer);
|
||||||
|
// memset(AllocBuffer[1], 0, AllocBufferSize);
|
||||||
|
// Success = ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize,
|
||||||
|
// &BytesTransferred, 0);
|
||||||
|
// ASSERT(Success);
|
||||||
|
// ASSERT(2 * SystemInfo.dwPageSize == BytesTransferred);
|
||||||
|
// ASSERT(FilePointer + BytesTransferred ==
|
||||||
|
// SetFilePointer(Handle, 0, 0, FILE_CURRENT));
|
||||||
|
// ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred));
|
||||||
|
//
|
||||||
|
// Buffer[0] = AllocBuffer[0];
|
||||||
|
// Buffer[1] = AllocBuffer[0];
|
||||||
|
//
|
||||||
|
// FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN);
|
||||||
|
// ASSERT(0 == FilePointer);
|
||||||
|
// Success = WriteFile(Handle, Buffer[0], 2 * SystemInfo.dwPageSize,
|
||||||
|
// &BytesTransferred, 0);
|
||||||
|
// ASSERT(Success);
|
||||||
|
// ASSERT(2 * SystemInfo.dwPageSize == BytesTransferred);
|
||||||
|
// ASSERT(FilePointer + BytesTransferred ==
|
||||||
|
// SetFilePointer(Handle, 0, 0, FILE_CURRENT));
|
||||||
|
//
|
||||||
|
// FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN);
|
||||||
|
// ASSERT(0 == FilePointer);
|
||||||
|
// memset(AllocBuffer[1], 0, AllocBufferSize);
|
||||||
|
// Success = ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize,
|
||||||
|
// &BytesTransferred, 0);
|
||||||
|
// ASSERT(Success);
|
||||||
|
// ASSERT(2 * SystemInfo.dwPageSize == BytesTransferred);
|
||||||
|
// ASSERT(FilePointer + BytesTransferred ==
|
||||||
|
// SetFilePointer(Handle, 0, 0, FILE_CURRENT));
|
||||||
|
// ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred));
|
||||||
|
//
|
||||||
|
// FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN);
|
||||||
|
// ASSERT(0 == FilePointer);
|
||||||
|
// Success =
|
||||||
|
// WriteFile(Handle, Buffer[0], 2 * SystemInfo.dwPageSize +
|
||||||
|
// BytesPerSector,
|
||||||
|
// &BytesTransferred, 0);
|
||||||
|
// ASSERT(Success);
|
||||||
|
// ASSERT(2 * SystemInfo.dwPageSize + BytesPerSector == BytesTransferred);
|
||||||
|
// ASSERT(FilePointer + BytesTransferred ==
|
||||||
|
// SetFilePointer(Handle, 0, 0, FILE_CURRENT));
|
||||||
|
//
|
||||||
|
// FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN);
|
||||||
|
// ASSERT(0 == FilePointer);
|
||||||
|
// memset(AllocBuffer[1], 0, AllocBufferSize);
|
||||||
|
// Success =
|
||||||
|
// ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize + BytesPerSector,
|
||||||
|
// &BytesTransferred, 0);
|
||||||
|
// ASSERT(Success);
|
||||||
|
// ASSERT(2 * SystemInfo.dwPageSize + BytesPerSector == BytesTransferred);
|
||||||
|
// ASSERT(FilePointer + BytesTransferred ==
|
||||||
|
// SetFilePointer(Handle, 0, 0, FILE_CURRENT));
|
||||||
|
// ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred));
|
||||||
|
//
|
||||||
|
EXPECT_TRUE(::CloseHandle(handle));
|
||||||
|
|
||||||
|
handle = ::CreateFileA(
|
||||||
|
file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | flags | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
|
||||||
|
// FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN);
|
||||||
|
// ASSERT(0 == FilePointer);
|
||||||
|
// memset(AllocBuffer[1], 0, AllocBufferSize);
|
||||||
|
// Success =
|
||||||
|
// ReadFile(Handle, Buffer[1], 2 * SystemInfo.dwPageSize + BytesPerSector,
|
||||||
|
// &BytesTransferred, 0);
|
||||||
|
// ASSERT(Success);
|
||||||
|
// ASSERT(2 * SystemInfo.dwPageSize + BytesPerSector == BytesTransferred);
|
||||||
|
// ASSERT(FilePointer + BytesTransferred ==
|
||||||
|
// SetFilePointer(Handle, 0, 0, FILE_CURRENT));
|
||||||
|
// ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred));
|
||||||
|
//
|
||||||
|
EXPECT_TRUE(::CloseHandle(handle));
|
||||||
|
|
||||||
|
handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
OPEN_EXISTING, 0, nullptr);
|
||||||
|
ASSERT_EQ(INVALID_HANDLE_VALUE, handle);
|
||||||
|
ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_no_flags) {
|
||||||
|
auto file_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_file_5"}),
|
||||||
|
};
|
||||||
|
test_file(file_path, 0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_no_buffering) {
|
||||||
|
auto file_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_file_5"}),
|
||||||
|
};
|
||||||
|
test_file(file_path, FILE_FLAG_NO_BUFFERING);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rdrw_can_read_and_write_file_write_through) {
|
||||||
|
auto file_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_file_5"}),
|
||||||
|
};
|
||||||
|
test_file(file_path, FILE_FLAG_WRITE_THROUGH);
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
#endif // defined(_WIN32)
|
260
repertory/repertory_test/src/winfsp_drive_rename_test.cpp
Normal file
260
repertory/repertory_test/src/winfsp_drive_rename_test.cpp
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implemented test cases based on WinFsp tests:
|
||||||
|
// https://github.com/winfsp/winfsp/blob/v2.0/tst/winfsp-tests
|
||||||
|
//
|
||||||
|
#include "fixtures/winfsp_fixture.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
TYPED_TEST_CASE(winfsp_test, winfsp_provider_types);
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rename_can_rename_file_if_dest_does_not_exist) {
|
||||||
|
if (this->current_provider == provider_type::s3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
||||||
|
};
|
||||||
|
auto file_path{
|
||||||
|
utils::path::combine(dir_path, {"test_file_4"}),
|
||||||
|
};
|
||||||
|
auto file_path2{
|
||||||
|
utils::path::combine(dir_path, {"test_file2_4"}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
|
||||||
|
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
::CloseHandle(handle);
|
||||||
|
|
||||||
|
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
||||||
|
|
||||||
|
EXPECT_TRUE(::DeleteFileA(file_path2.c_str()));
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rename_fails_if_dest_exists_and_replace_is_false) {
|
||||||
|
if (this->current_provider == provider_type::s3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
||||||
|
};
|
||||||
|
auto file_path{
|
||||||
|
utils::path::combine(dir_path, {"test_file_4"}),
|
||||||
|
};
|
||||||
|
auto file_path2{
|
||||||
|
utils::path::combine(dir_path, {"test_file2_4"}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
|
||||||
|
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
::CloseHandle(handle);
|
||||||
|
|
||||||
|
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
||||||
|
|
||||||
|
EXPECT_FALSE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
||||||
|
EXPECT_EQ(ERROR_ALREADY_EXISTS, ::GetLastError());
|
||||||
|
|
||||||
|
EXPECT_TRUE(::DeleteFileA(file_path2.c_str()));
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rename_succeeds_if_dest_exists_and_replace_is_true) {
|
||||||
|
if (this->current_provider == provider_type::s3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
||||||
|
};
|
||||||
|
auto file_path{
|
||||||
|
utils::path::combine(dir_path, {"test_file_4"}),
|
||||||
|
};
|
||||||
|
auto file_path2{
|
||||||
|
utils::path::combine(dir_path, {"test_file2_4"}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
|
||||||
|
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
::CloseHandle(handle);
|
||||||
|
|
||||||
|
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
||||||
|
|
||||||
|
handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
::CloseHandle(handle);
|
||||||
|
|
||||||
|
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(),
|
||||||
|
MOVEFILE_REPLACE_EXISTING));
|
||||||
|
|
||||||
|
EXPECT_TRUE(::DeleteFileA(file_path2.c_str()));
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rename_can_rename_dir_if_dest_does_not_exist) {
|
||||||
|
if (this->current_provider == provider_type::s3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
||||||
|
};
|
||||||
|
auto dir_path2{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
|
||||||
|
EXPECT_TRUE(::MoveFileExA(dir_path.c_str(), dir_path2.c_str(), 0));
|
||||||
|
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path2.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rename_dir_fails_if_dest_exists_and_replace_is_false) {
|
||||||
|
if (this->current_provider == provider_type::s3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
||||||
|
};
|
||||||
|
auto dir_path2{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path2.c_str(), nullptr));
|
||||||
|
|
||||||
|
EXPECT_FALSE(::MoveFileExA(dir_path.c_str(), dir_path2.c_str(), 0));
|
||||||
|
EXPECT_EQ(ERROR_ACCESS_DENIED, ::GetLastError());
|
||||||
|
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path2.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, rename_dir_fails_if_dest_exists_and_replace_is_true) {
|
||||||
|
if (this->current_provider == provider_type::s3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
||||||
|
};
|
||||||
|
auto dir_path2{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path2.c_str(), nullptr));
|
||||||
|
|
||||||
|
EXPECT_FALSE(::MoveFileExA(dir_path.c_str(), dir_path2.c_str(),
|
||||||
|
MOVEFILE_REPLACE_EXISTING));
|
||||||
|
EXPECT_EQ(ERROR_ACCESS_DENIED, ::GetLastError());
|
||||||
|
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path2.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test,
|
||||||
|
rename_dir_fails_directory_is_not_empty_and_replace_is_false) {
|
||||||
|
if (this->current_provider == provider_type::s3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
||||||
|
};
|
||||||
|
auto dir_path2{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
||||||
|
};
|
||||||
|
auto file_path{
|
||||||
|
utils::path::combine(dir_path, {"test_file_4"}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
|
||||||
|
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
::CloseHandle(handle);
|
||||||
|
|
||||||
|
EXPECT_FALSE(::MoveFileExA(dir_path.c_str(), dir_path2.c_str(), 0));
|
||||||
|
EXPECT_EQ(ERROR_ACCESS_DENIED, ::GetLastError());
|
||||||
|
|
||||||
|
EXPECT_TRUE(::DeleteFileA(file_path.c_str()));
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test,
|
||||||
|
rename_dir_fails_directory_is_not_empty_and_replace_is_true) {
|
||||||
|
if (this->current_provider == provider_type::s3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dir_path{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
||||||
|
};
|
||||||
|
auto dir_path2{
|
||||||
|
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
||||||
|
};
|
||||||
|
auto file_path{
|
||||||
|
utils::path::combine(dir_path, {"test_file_4"}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
|
||||||
|
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
::CloseHandle(handle);
|
||||||
|
|
||||||
|
EXPECT_FALSE(::MoveFileExA(dir_path.c_str(), dir_path2.c_str(),
|
||||||
|
MOVEFILE_REPLACE_EXISTING));
|
||||||
|
EXPECT_EQ(ERROR_ACCESS_DENIED, ::GetLastError());
|
||||||
|
|
||||||
|
EXPECT_TRUE(::DeleteFileA(file_path.c_str()));
|
||||||
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
#endif // defined(_WIN32)
|
@ -30,6 +30,17 @@
|
|||||||
// TODO revisit create_share
|
// TODO revisit create_share
|
||||||
// TODO revisit delete_access_test
|
// TODO revisit delete_access_test
|
||||||
// TODO revisit getfileattr_test
|
// TODO revisit getfileattr_test
|
||||||
|
// TODO revisit delete_ex_test
|
||||||
|
// TODO revisit rename_backslash_test
|
||||||
|
// TODO revisit rename_open_test
|
||||||
|
// TODO revisit rename_caseins_test
|
||||||
|
// TODO revisit rename_flipflop_test
|
||||||
|
// TODO revisit rename_mmap_test
|
||||||
|
// TODO revisit rename_standby_test
|
||||||
|
// TODO revisit rename_pid_test
|
||||||
|
// TODO revisit rename_ex_test
|
||||||
|
// TODO revisit setvolinfo_test
|
||||||
|
// TODO revisit query_winfsp_test
|
||||||
|
|
||||||
//
|
//
|
||||||
// Implemented test cases based on WinFsp tests:
|
// Implemented test cases based on WinFsp tests:
|
||||||
|
100
repertory/repertory_test/src/winfsp_drive_volume_test.cpp
Normal file
100
repertory/repertory_test/src/winfsp_drive_volume_test.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implemented test cases based on WinFsp tests:
|
||||||
|
// https://github.com/winfsp/winfsp/blob/v2.0/tst/winfsp-tests
|
||||||
|
//
|
||||||
|
#include "fixtures/winfsp_fixture.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
TYPED_TEST_CASE(winfsp_test, winfsp_provider_types);
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, volume_can_get_volume_info) {
|
||||||
|
std::string volume_label;
|
||||||
|
volume_label.resize(MAX_PATH + 1U);
|
||||||
|
|
||||||
|
std::string fs_name;
|
||||||
|
fs_name.resize(MAX_PATH + 1U);
|
||||||
|
|
||||||
|
DWORD flags{};
|
||||||
|
DWORD max_component_length{};
|
||||||
|
DWORD serial_num{};
|
||||||
|
EXPECT_TRUE(::GetVolumeInformationA(
|
||||||
|
this->mount_location.c_str(), volume_label.data(),
|
||||||
|
static_cast<DWORD>(volume_label.size()), &serial_num,
|
||||||
|
&max_component_length, &flags, fs_name.data(),
|
||||||
|
static_cast<DWORD>(fs_name.size())));
|
||||||
|
EXPECT_EQ(FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
|
||||||
|
FILE_UNICODE_ON_DISK,
|
||||||
|
flags);
|
||||||
|
EXPECT_EQ(255U, max_component_length);
|
||||||
|
EXPECT_EQ(0U, serial_num);
|
||||||
|
EXPECT_STREQ(
|
||||||
|
("repertory_" + app_config::get_provider_name(this->current_provider))
|
||||||
|
.c_str(),
|
||||||
|
volume_label.c_str());
|
||||||
|
EXPECT_STREQ(this->mount_location.c_str(), fs_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, volume_can_get_size_info) {
|
||||||
|
{
|
||||||
|
DWORD bytes_per_sector{};
|
||||||
|
DWORD free_clusters{};
|
||||||
|
DWORD sectors_per_cluster{};
|
||||||
|
DWORD total_clusters{};
|
||||||
|
EXPECT_TRUE(::GetDiskFreeSpaceA(this->mount_location.c_str(),
|
||||||
|
§ors_per_cluster, &bytes_per_sector,
|
||||||
|
&free_clusters, &total_clusters));
|
||||||
|
EXPECT_NE(0U, bytes_per_sector);
|
||||||
|
EXPECT_NE(0U, free_clusters);
|
||||||
|
EXPECT_NE(0U, sectors_per_cluster);
|
||||||
|
EXPECT_NE(0U, total_clusters);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ULARGE_INTEGER caller_free_bytes{};
|
||||||
|
ULARGE_INTEGER free_bytes{};
|
||||||
|
ULARGE_INTEGER total_bytes{};
|
||||||
|
EXPECT_TRUE(::GetDiskFreeSpaceExA(this->mount_location.c_str(),
|
||||||
|
&caller_free_bytes, &total_bytes,
|
||||||
|
&free_bytes));
|
||||||
|
EXPECT_NE(0U, caller_free_bytes.QuadPart);
|
||||||
|
EXPECT_NE(0U, total_bytes.QuadPart);
|
||||||
|
EXPECT_NE(0U, free_bytes.QuadPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(winfsp_test, volume_can_get_file_type) {
|
||||||
|
auto handle = ::CreateFileA(
|
||||||
|
this->mount_location.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
|
||||||
|
EXPECT_EQ(FILE_TYPE_REMOTE, ::GetFileType(handle));
|
||||||
|
|
||||||
|
::CloseHandle(handle);
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
#endif // defined(_WIN32)
|
Reference in New Issue
Block a user