Compare commits
29 Commits
9562ac2c62
...
a031f9d867
Author | SHA1 | Date | |
---|---|---|---|
a031f9d867 | |||
2f6fa792df | |||
be0f977dc7 | |||
73efae7c2f | |||
6b67cd676d | |||
2db38a87e3 | |||
213511a77d | |||
a38a033143 | |||
619d5939b3 | |||
68a26d2bc6 | |||
2661885cf2 | |||
6a820837cc | |||
02b74402f4 | |||
3535a61844 | |||
eb4fe4ff60 | |||
793ec5b4a5 | |||
c14b637536 | |||
489d9b1960 | |||
2f60890d29 | |||
19d4b0a247 | |||
69d190e485 | |||
2df84f53ed | |||
876a1e9cd8 | |||
2945793de9 | |||
0de0e511ee | |||
c16d9f9712 | |||
0903d4b83e | |||
0bd1f72017 | |||
7bc1440b8b |
@ -50,10 +50,10 @@ public:
|
||||
|
||||
private:
|
||||
app_config &config_;
|
||||
lock_data &lock_;
|
||||
remote_winfsp_drive &drive_;
|
||||
const std::vector<std::string> drive_args_;
|
||||
FileSystemHost host_;
|
||||
lock_data &lock_;
|
||||
|
||||
protected:
|
||||
auto OnStart(ULONG, PWSTR *) -> NTSTATUS override;
|
||||
@ -75,8 +75,8 @@ private:
|
||||
static void set_file_info(FileInfo &dest, const remote::file_info &src);
|
||||
|
||||
public:
|
||||
auto CanDelete(PVOID file_node, PVOID file_desc,
|
||||
PWSTR file_name) -> NTSTATUS override;
|
||||
auto CanDelete(PVOID file_node, PVOID file_desc, PWSTR file_name)
|
||||
-> NTSTATUS override;
|
||||
|
||||
VOID Cleanup(PVOID file_node, PVOID file_desc, PWSTR file_name,
|
||||
ULONG flags) override;
|
||||
@ -88,11 +88,11 @@ public:
|
||||
UINT64 allocation_size, PVOID *file_node, PVOID *file_desc,
|
||||
OpenFileInfo *ofi) -> NTSTATUS override;
|
||||
|
||||
auto Flush(PVOID file_node, PVOID file_desc,
|
||||
FileInfo *file_info) -> NTSTATUS override;
|
||||
auto Flush(PVOID file_node, PVOID file_desc, FileInfo *file_info)
|
||||
-> NTSTATUS override;
|
||||
|
||||
auto GetFileInfo(PVOID file_node, PVOID file_desc,
|
||||
FileInfo *file_info) -> NTSTATUS override;
|
||||
auto GetFileInfo(PVOID file_node, PVOID file_desc, FileInfo *file_info)
|
||||
-> NTSTATUS override;
|
||||
|
||||
auto GetSecurityByName(PWSTR file_name, PUINT32 attributes,
|
||||
PSECURITY_DESCRIPTOR descriptor,
|
||||
@ -107,8 +107,8 @@ public:
|
||||
auto Mounted(PVOID host) -> NTSTATUS override;
|
||||
|
||||
auto Open(PWSTR file_name, UINT32 create_options, UINT32 granted_access,
|
||||
PVOID *file_node, PVOID *file_desc,
|
||||
OpenFileInfo *ofi) -> NTSTATUS override;
|
||||
PVOID *file_node, PVOID *file_desc, OpenFileInfo *ofi)
|
||||
-> NTSTATUS override;
|
||||
|
||||
auto Overwrite(PVOID file_node, PVOID file_desc, UINT32 attributes,
|
||||
BOOLEAN replace_attributes, UINT64 allocation_size,
|
||||
@ -122,8 +122,8 @@ public:
|
||||
PULONG bytes_transferred) -> NTSTATUS override;
|
||||
|
||||
auto Rename(PVOID file_node, PVOID file_desc, PWSTR file_name,
|
||||
PWSTR new_file_name,
|
||||
BOOLEAN replace_if_exists) -> NTSTATUS override;
|
||||
PWSTR new_file_name, BOOLEAN replace_if_exists)
|
||||
-> NTSTATUS override;
|
||||
|
||||
auto SetBasicInfo(PVOID file_node, PVOID file_desc, UINT32 attributes,
|
||||
UINT64 creation_time, UINT64 last_access_time,
|
||||
@ -131,15 +131,15 @@ public:
|
||||
FileInfo *file_info) -> NTSTATUS override;
|
||||
|
||||
auto SetFileSize(PVOID file_node, PVOID file_desc, UINT64 new_size,
|
||||
BOOLEAN set_allocation_size,
|
||||
FileInfo *file_info) -> NTSTATUS override;
|
||||
BOOLEAN set_allocation_size, FileInfo *file_info)
|
||||
-> NTSTATUS override;
|
||||
|
||||
VOID Unmounted(PVOID host) override;
|
||||
|
||||
auto Write(PVOID file_node, PVOID file_desc, PVOID buffer, UINT64 offset,
|
||||
ULONG length, BOOLEAN write_to_end, BOOLEAN constrained_io,
|
||||
PULONG bytes_transferred,
|
||||
FileInfo *file_info) -> NTSTATUS override;
|
||||
PULONG bytes_transferred, FileInfo *file_info)
|
||||
-> NTSTATUS override;
|
||||
|
||||
void shutdown() { ::GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); }
|
||||
|
||||
|
@ -53,11 +53,11 @@ private:
|
||||
~winfsp_service() override = default;
|
||||
|
||||
private:
|
||||
lock_data &lock_;
|
||||
winfsp_drive &drive_;
|
||||
const std::vector<std::string> drive_args_;
|
||||
FileSystemHost host_;
|
||||
app_config &config_;
|
||||
winfsp_drive &drive_;
|
||||
std::vector<std::string> drive_args_;
|
||||
FileSystemHost host_;
|
||||
lock_data &lock_;
|
||||
|
||||
protected:
|
||||
auto OnStart(ULONG, PWSTR *) -> NTSTATUS override;
|
||||
|
@ -69,6 +69,8 @@ private:
|
||||
std::unique_ptr<std::thread> upload_thread_;
|
||||
|
||||
private:
|
||||
void close_all(const std::string &api_path);
|
||||
|
||||
void close_timed_out_files();
|
||||
|
||||
auto get_open_file_by_handle(std::uint64_t handle) const
|
||||
@ -111,8 +113,6 @@ public:
|
||||
public:
|
||||
void close(std::uint64_t handle);
|
||||
|
||||
void close_all(const std::string &api_path);
|
||||
|
||||
[[nodiscard]] auto create(const std::string &api_path, api_meta_map &meta,
|
||||
open_file_data ofd, std::uint64_t &handle,
|
||||
std::shared_ptr<i_open_file> &file) -> api_error;
|
||||
@ -136,8 +136,8 @@ public:
|
||||
|
||||
[[nodiscard]] auto has_no_open_file_handles() const -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
is_processing(const std::string &api_path) const -> bool override;
|
||||
[[nodiscard]] auto is_processing(const std::string &api_path) const
|
||||
-> bool override;
|
||||
|
||||
#if defined(PROJECT_TESTING)
|
||||
[[nodiscard]] auto open(std::shared_ptr<i_closeable_open_file> of,
|
||||
@ -150,13 +150,13 @@ public:
|
||||
|
||||
[[nodiscard]] auto remove_file(const std::string &api_path) -> api_error;
|
||||
|
||||
[[nodiscard]] auto
|
||||
rename_directory(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> api_error;
|
||||
[[nodiscard]] auto rename_directory(const std::string &from_api_path,
|
||||
const std::string &to_api_path)
|
||||
-> api_error;
|
||||
|
||||
[[nodiscard]] auto rename_file(const std::string &from_api_path,
|
||||
const std::string &to_api_path,
|
||||
bool overwrite) -> api_error;
|
||||
const std::string &to_api_path, bool overwrite)
|
||||
-> api_error;
|
||||
|
||||
void start();
|
||||
|
||||
|
@ -40,25 +40,25 @@ public:
|
||||
|
||||
[[nodiscard]] virtual auto get_filesystem_item() const -> filesystem_item = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_open_data() -> std::map<std::uint64_t, open_file_data> & = 0;
|
||||
[[nodiscard]] virtual auto get_open_data()
|
||||
-> std::map<std::uint64_t, open_file_data> & = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_open_data() const -> const std::map<std::uint64_t, open_file_data> & = 0;
|
||||
[[nodiscard]] virtual auto get_open_data() const
|
||||
-> const std::map<std::uint64_t, open_file_data> & = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_open_data(std::uint64_t handle) -> open_file_data & = 0;
|
||||
[[nodiscard]] virtual auto get_open_data(std::uint64_t handle)
|
||||
-> open_file_data & = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_open_data(std::uint64_t handle) const -> const open_file_data & = 0;
|
||||
[[nodiscard]] virtual auto get_open_data(std::uint64_t handle) const
|
||||
-> const open_file_data & = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_open_file_count() const -> std::size_t = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_read_state() const -> boost::dynamic_bitset<> = 0;
|
||||
[[nodiscard]] virtual auto get_read_state() const
|
||||
-> boost::dynamic_bitset<> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_read_state(std::size_t chunk) const -> bool = 0;
|
||||
[[nodiscard]] virtual auto get_read_state(std::size_t chunk) const
|
||||
-> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_source_path() const -> std::string = 0;
|
||||
|
||||
@ -74,11 +74,11 @@ public:
|
||||
native_operation_callback callback) -> api_error = 0;
|
||||
|
||||
[[nodiscard]] virtual auto read(std::size_t read_size,
|
||||
std::uint64_t read_offset,
|
||||
data_buffer &data) -> api_error = 0;
|
||||
std::uint64_t read_offset, data_buffer &data)
|
||||
-> api_error = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
resize(std::uint64_t new_file_size) -> api_error = 0;
|
||||
[[nodiscard]] virtual auto resize(std::uint64_t new_file_size)
|
||||
-> api_error = 0;
|
||||
|
||||
virtual void set_api_path(const std::string &api_path) = 0;
|
||||
|
||||
@ -97,8 +97,8 @@ public:
|
||||
|
||||
virtual auto close() -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_handles() const -> std::vector<std::uint64_t> = 0;
|
||||
[[nodiscard]] virtual auto get_handles() const
|
||||
-> std::vector<std::uint64_t> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto is_complete() const -> bool = 0;
|
||||
|
||||
@ -107,6 +107,8 @@ public:
|
||||
[[nodiscard]] virtual auto is_write_supported() const -> bool = 0;
|
||||
|
||||
virtual void remove(std::uint64_t handle) = 0;
|
||||
|
||||
virtual void remove_all() = 0;
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
|
@ -109,6 +109,8 @@ public:
|
||||
|
||||
void remove(std::uint64_t handle) override;
|
||||
|
||||
void remove_all() override;
|
||||
|
||||
[[nodiscard]] auto read(std::size_t read_size, std::uint64_t read_offset,
|
||||
data_buffer &data) -> api_error override;
|
||||
|
||||
|
@ -187,6 +187,8 @@ public:
|
||||
|
||||
void remove(std::uint64_t handle) override;
|
||||
|
||||
void remove_all() override;
|
||||
|
||||
void set_api_path(const std::string &api_path) override;
|
||||
};
|
||||
} // namespace repertory
|
||||
|
@ -41,20 +41,19 @@ namespace repertory::remote_winfsp {
|
||||
remote_winfsp_drive::winfsp_service::winfsp_service(
|
||||
lock_data &lock, remote_winfsp_drive &drive,
|
||||
std::vector<std::string> drive_args, app_config &config)
|
||||
: Service(&(L"RepertoryRemote_" +
|
||||
utils::string::from_utf8(lock.get_unique_id()))[0U]),
|
||||
: Service(std::wstring{REPERTORY_W}.data()),
|
||||
config_(config),
|
||||
lock_(lock),
|
||||
drive_(drive),
|
||||
drive_args_(std::move(drive_args)),
|
||||
host_(drive) {}
|
||||
host_(drive),
|
||||
lock_(lock) {}
|
||||
|
||||
auto remote_winfsp_drive::winfsp_service::OnStart(ULONG, PWSTR *) -> NTSTATUS {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
const auto mount_location = utils::string::to_lower(utils::path::absolute(
|
||||
auto mount_location = utils::string::to_lower(utils::path::absolute(
|
||||
(drive_args_.size() > 1U) ? drive_args_.at(1U) : ""));
|
||||
const auto drive_letter =
|
||||
auto drive_letter =
|
||||
((mount_location.size() == 2U) ||
|
||||
((mount_location.size() == 3U) && (mount_location.at(2U) == '\\'))) &&
|
||||
(mount_location.at(1U) == ':');
|
||||
@ -137,7 +136,7 @@ auto remote_winfsp_drive::Create(PWSTR file_name, UINT32 create_options,
|
||||
file_desc, &fi, normalized_name, exists);
|
||||
if (ret == STATUS_SUCCESS) {
|
||||
set_file_info(ofi->FileInfo, fi);
|
||||
const auto file_path = utils::string::from_utf8(normalized_name);
|
||||
auto file_path = utils::string::from_utf8(normalized_name);
|
||||
wcsncpy(ofi->NormalizedName, file_path.data(), wcslen(file_path.c_str()));
|
||||
ofi->NormalizedNameSize =
|
||||
static_cast<UINT16>(wcslen(file_path.c_str()) * sizeof(WCHAR));
|
||||
@ -196,8 +195,7 @@ auto remote_winfsp_drive::GetVolumeInfo(VolumeInfo *volume_info) -> NTSTATUS {
|
||||
auto ret = remote_instance_->winfsp_get_volume_info(
|
||||
volume_info->TotalSize, volume_info->FreeSize, volume_label);
|
||||
if (ret == STATUS_SUCCESS) {
|
||||
const auto byte_size =
|
||||
static_cast<UINT16>(volume_label.size() * sizeof(WCHAR));
|
||||
auto byte_size = static_cast<UINT16>(volume_label.size() * sizeof(WCHAR));
|
||||
wcscpy_s(&volume_info->VolumeLabel[0U], 32,
|
||||
utils::string::from_utf8(volume_label).c_str());
|
||||
volume_info->VolumeLabelLength =
|
||||
@ -213,20 +211,20 @@ auto remote_winfsp_drive::Init(PVOID host) -> NTSTATUS {
|
||||
&(L"\\repertory\\" +
|
||||
std::wstring(file_system_host->FileSystemName()).substr(0U, 1U))[0U]);
|
||||
}
|
||||
file_system_host->SetFileSystemName(std::wstring{REPERTORY_W}.data());
|
||||
|
||||
file_system_host->SetCasePreservedNames(TRUE);
|
||||
file_system_host->SetCaseSensitiveSearch(FALSE);
|
||||
file_system_host->SetFileInfoTimeout(1000);
|
||||
file_system_host->SetFlushAndPurgeOnCleanup(TRUE);
|
||||
file_system_host->SetNamedStreams(FALSE);
|
||||
file_system_host->SetPassQueryDirectoryPattern(FALSE);
|
||||
file_system_host->SetPersistentAcls(FALSE);
|
||||
file_system_host->SetPostCleanupWhenModifiedOnly(TRUE);
|
||||
file_system_host->SetReparsePoints(FALSE);
|
||||
file_system_host->SetReparsePointsAccessCheck(FALSE);
|
||||
file_system_host->SetSectorSize(WINFSP_ALLOCATION_UNIT);
|
||||
file_system_host->SetSectorsPerAllocationUnit(1);
|
||||
file_system_host->SetFileInfoTimeout(1000);
|
||||
file_system_host->SetCaseSensitiveSearch(FALSE);
|
||||
file_system_host->SetCasePreservedNames(TRUE);
|
||||
file_system_host->SetNamedStreams(FALSE);
|
||||
file_system_host->SetUnicodeOnDisk(TRUE);
|
||||
file_system_host->SetPersistentAcls(FALSE);
|
||||
file_system_host->SetPostCleanupWhenModifiedOnly(TRUE);
|
||||
file_system_host->SetPassQueryDirectoryPattern(FALSE);
|
||||
file_system_host->SetVolumeCreationTime(utils::time::get_time_now());
|
||||
file_system_host->SetVolumeSerialNumber(0);
|
||||
return STATUS_SUCCESS;
|
||||
@ -236,10 +234,10 @@ auto remote_winfsp_drive::mount(const std::vector<std::string> &drive_args)
|
||||
-> int {
|
||||
std::vector<std::string> parsed_drive_args;
|
||||
|
||||
const auto force_no_console = utils::collection::includes(drive_args, "-nc");
|
||||
auto force_no_console = utils::collection::includes(drive_args, "-nc");
|
||||
|
||||
auto enable_console = false;
|
||||
for (const auto &arg : drive_args) {
|
||||
for (auto &&arg : drive_args) {
|
||||
if (arg == "-f") {
|
||||
if (not force_no_console) {
|
||||
enable_console = true;
|
||||
@ -289,7 +287,7 @@ auto remote_winfsp_drive::Open(PWSTR file_name, UINT32 create_options,
|
||||
file_desc, &fi, normalize_name);
|
||||
if (ret == STATUS_SUCCESS) {
|
||||
set_file_info(ofi->FileInfo, fi);
|
||||
const auto file_path = utils::string::from_utf8(normalize_name);
|
||||
auto file_path = utils::string::from_utf8(normalize_name);
|
||||
wcsncpy(ofi->NormalizedName, file_path.data(), wcslen(file_path.c_str()));
|
||||
ofi->NormalizedNameSize =
|
||||
static_cast<UINT16>(wcslen(file_path.c_str()) * sizeof(WCHAR));
|
||||
@ -312,7 +310,7 @@ auto remote_winfsp_drive::Overwrite(PVOID /*file_node*/, PVOID file_desc,
|
||||
|
||||
void remote_winfsp_drive::populate_file_info(const json &item,
|
||||
FSP_FSCTL_FILE_INFO &file_info) {
|
||||
const auto di = directory_item::from_json(item);
|
||||
auto di = directory_item::from_json(item);
|
||||
file_info.FileSize = di.directory ? 0 : di.size;
|
||||
file_info.AllocationSize =
|
||||
utils::divide_with_ceiling(file_info.FileSize, WINFSP_ALLOCATION_UNIT) *
|
||||
@ -353,9 +351,9 @@ auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,
|
||||
directory_buffer, static_cast<BOOLEAN>(nullptr == marker),
|
||||
&ret)) {
|
||||
auto item_found = false;
|
||||
for (const auto &item : item_list) {
|
||||
const auto item_path = item["path"].get<std::string>();
|
||||
const auto display_name = utils::string::from_utf8(
|
||||
for (auto &&item : item_list) {
|
||||
auto item_path = item["path"].get<std::string>();
|
||||
auto display_name = utils::string::from_utf8(
|
||||
utils::path::strip_to_file_name(item_path));
|
||||
if (not marker || (marker && item_found)) {
|
||||
// if (not utils::path::is_ads_file_path(item_path)) {
|
||||
|
@ -61,11 +61,11 @@ winfsp_drive::winfsp_service::winfsp_service(
|
||||
lock_data &lock, winfsp_drive &drive, std::vector<std::string> drive_args,
|
||||
app_config &config)
|
||||
: Service(std::wstring{REPERTORY_W}.data()),
|
||||
lock_(lock),
|
||||
config_(config),
|
||||
drive_(drive),
|
||||
drive_args_(std::move(drive_args)),
|
||||
host_(drive),
|
||||
config_(config) {}
|
||||
lock_(lock) {}
|
||||
|
||||
auto winfsp_drive::handle_error(std::string_view function_name,
|
||||
const std::string &api_path, api_error error,
|
||||
@ -554,25 +554,24 @@ auto winfsp_drive::Init(PVOID host) -> NTSTATUS {
|
||||
auto *file_system_host = reinterpret_cast<FileSystemHost *>(host);
|
||||
if (not config_.get_enable_mount_manager()) {
|
||||
file_system_host->SetPrefix(
|
||||
(L"\\repertory\\" +
|
||||
std::wstring(file_system_host->FileSystemName()).substr(0, 1))
|
||||
.data());
|
||||
&(L"\\repertory\\" +
|
||||
std::wstring(file_system_host->FileSystemName()).substr(0U, 1U))[0U]);
|
||||
}
|
||||
|
||||
file_system_host->SetCasePreservedNames(TRUE);
|
||||
file_system_host->SetCaseSensitiveSearch(TRUE);
|
||||
file_system_host->SetFileInfoTimeout(1000);
|
||||
file_system_host->SetFlushAndPurgeOnCleanup(TRUE);
|
||||
file_system_host->SetMaxComponentLength(255U);
|
||||
file_system_host->SetNamedStreams(FALSE);
|
||||
file_system_host->SetPassQueryDirectoryPattern(FALSE);
|
||||
file_system_host->SetPersistentAcls(FALSE);
|
||||
file_system_host->SetPostCleanupWhenModifiedOnly(TRUE);
|
||||
file_system_host->SetReparsePoints(FALSE);
|
||||
file_system_host->SetReparsePointsAccessCheck(FALSE);
|
||||
file_system_host->SetSectorSize(WINFSP_ALLOCATION_UNIT);
|
||||
file_system_host->SetSectorsPerAllocationUnit(1);
|
||||
file_system_host->SetFileInfoTimeout(1000);
|
||||
file_system_host->SetCaseSensitiveSearch(TRUE);
|
||||
file_system_host->SetCasePreservedNames(TRUE);
|
||||
file_system_host->SetNamedStreams(FALSE);
|
||||
file_system_host->SetUnicodeOnDisk(TRUE);
|
||||
file_system_host->SetMaxComponentLength(255U);
|
||||
file_system_host->SetPersistentAcls(FALSE);
|
||||
file_system_host->SetPostCleanupWhenModifiedOnly(TRUE);
|
||||
file_system_host->SetPassQueryDirectoryPattern(FALSE);
|
||||
file_system_host->SetVolumeCreationTime(utils::time::get_time_now());
|
||||
file_system_host->SetVolumeSerialNumber(0);
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -126,28 +126,31 @@ file_manager::~file_manager() {
|
||||
}
|
||||
|
||||
void file_manager::close(std::uint64_t handle) {
|
||||
recur_mutex_lock file_lock(open_file_mtx_);
|
||||
unique_recur_mutex_lock file_lock(open_file_mtx_);
|
||||
auto closeable_file = get_open_file_by_handle(handle);
|
||||
if (closeable_file) {
|
||||
closeable_file->remove(handle);
|
||||
if (not closeable_file) {
|
||||
return;
|
||||
}
|
||||
file_lock.unlock();
|
||||
|
||||
closeable_file->remove(handle);
|
||||
}
|
||||
|
||||
void file_manager::close_all(const std::string &api_path) {
|
||||
recur_mutex_lock file_lock(open_file_mtx_);
|
||||
std::vector<std::uint64_t> handles;
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
unique_recur_mutex_lock file_lock(open_file_mtx_);
|
||||
auto file_iter = open_file_lookup_.find(api_path);
|
||||
if (file_iter == open_file_lookup_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto closeable_file = file_iter->second;
|
||||
|
||||
handles = closeable_file->get_handles();
|
||||
for (auto &&handle : handles) {
|
||||
closeable_file->remove(handle);
|
||||
}
|
||||
open_file_lookup_.erase(api_path);
|
||||
file_lock.unlock();
|
||||
|
||||
closeable_file->remove_all();
|
||||
closeable_file->close();
|
||||
}
|
||||
|
||||
void file_manager::close_timed_out_files() {
|
||||
@ -234,7 +237,7 @@ auto file_manager::evict_file(const std::string &api_path) -> bool {
|
||||
|
||||
open_file_lookup_.erase(api_path);
|
||||
|
||||
auto removed = utils::file::file(source_path).remove();
|
||||
auto removed = utils::file::file{source_path}.remove();
|
||||
if (removed) {
|
||||
event_system::instance().raise<filesystem_item_evicted>(api_path,
|
||||
source_path);
|
||||
@ -505,6 +508,7 @@ void file_manager::queue_upload(const std::string &api_path,
|
||||
if (not no_lock) {
|
||||
lock = std::make_unique<mutex_lock>(upload_mtx_);
|
||||
}
|
||||
|
||||
remove_upload(api_path, true);
|
||||
|
||||
auto result =
|
||||
@ -542,24 +546,12 @@ auto file_manager::remove_file(const std::string &api_path) -> api_error {
|
||||
|
||||
close_all(api_path);
|
||||
|
||||
remove_upload(api_path, true);
|
||||
|
||||
auto result = utils::db::sqlite::db_delete{*db_, resume_table}
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
if (not result.ok()) {
|
||||
utils::error::raise_api_path_error(function_name, api_path,
|
||||
api_error::error,
|
||||
"failed to remove from resume table");
|
||||
}
|
||||
|
||||
res = provider_.remove_file(api_path);
|
||||
if (res != api_error::success) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (not utils::file::file(fsi.source_path).remove()) {
|
||||
if (not utils::file::file{fsi.source_path}.remove()) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, fsi.api_path, fsi.source_path,
|
||||
utils::get_last_error_code(), "failed to delete source");
|
||||
|
@ -117,8 +117,8 @@ void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
||||
return;
|
||||
}
|
||||
|
||||
const auto data_offset = chunk * chunk_size_;
|
||||
const auto data_size =
|
||||
auto data_offset = chunk * chunk_size_;
|
||||
auto data_size =
|
||||
(chunk == read_state_.size() - 1U) ? last_chunk_size_ : chunk_size_;
|
||||
if (active_downloads_.empty() && (read_state_.count() == 0U)) {
|
||||
event_system::instance().raise<download_begin>(fsi_.api_path,
|
||||
@ -258,12 +258,12 @@ auto open_file::native_operation(
|
||||
}
|
||||
file_lock.unlock();
|
||||
|
||||
const auto is_empty_file = new_file_size == 0U;
|
||||
const auto last_chunk =
|
||||
is_empty_file ? std::size_t(0U)
|
||||
: static_cast<std::size_t>(utils::divide_with_ceiling(
|
||||
new_file_size, chunk_size_)) -
|
||||
1U;
|
||||
auto is_empty_file = new_file_size == 0U;
|
||||
auto last_chunk = is_empty_file
|
||||
? std::size_t(0U)
|
||||
: static_cast<std::size_t>(utils::divide_with_ceiling(
|
||||
new_file_size, chunk_size_)) -
|
||||
1U;
|
||||
|
||||
file_lock.lock();
|
||||
if (not is_empty_file && (last_chunk < read_state_.size())) {
|
||||
@ -277,7 +277,7 @@ auto open_file::native_operation(
|
||||
file_lock.lock();
|
||||
}
|
||||
|
||||
const auto original_file_size = get_file_size();
|
||||
auto original_file_size = get_file_size();
|
||||
|
||||
auto res = do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
||||
if (res != api_error::success) {
|
||||
@ -319,7 +319,7 @@ auto open_file::native_operation(
|
||||
set_modified();
|
||||
|
||||
fsi_.size = new_file_size;
|
||||
const auto now = std::to_string(utils::time::get_time_now());
|
||||
auto now = std::to_string(utils::time::get_time_now());
|
||||
res = provider_.set_item_meta(
|
||||
fsi_.api_path, {
|
||||
{META_CHANGED, now},
|
||||
@ -372,8 +372,8 @@ auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
||||
}
|
||||
file_lock.unlock();
|
||||
|
||||
const auto start_chunk = static_cast<std::size_t>(read_offset / chunk_size_);
|
||||
const auto end_chunk =
|
||||
auto start_chunk = static_cast<std::size_t>(read_offset / chunk_size_);
|
||||
auto end_chunk =
|
||||
static_cast<std::size_t>((read_size + read_offset) / chunk_size_);
|
||||
|
||||
update_background_reader(start_chunk);
|
||||
@ -402,6 +402,18 @@ void open_file::remove(std::uint64_t handle) {
|
||||
}
|
||||
}
|
||||
|
||||
void open_file::remove_all() {
|
||||
recur_mutex_lock file_lock(file_mtx_);
|
||||
open_file_base::remove_all();
|
||||
|
||||
modified_ = false;
|
||||
removed_ = true;
|
||||
|
||||
mgr_.remove_upload(get_api_path());
|
||||
|
||||
set_api_error(api_error::success);
|
||||
}
|
||||
|
||||
auto open_file::resize(std::uint64_t new_file_size) -> api_error {
|
||||
if (fsi_.directory) {
|
||||
return api_error::invalid_operation;
|
||||
@ -417,65 +429,74 @@ auto open_file::resize(std::uint64_t new_file_size) -> api_error {
|
||||
auto open_file::close() -> bool {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
if (not fsi_.directory && not stop_requested_) {
|
||||
stop_requested_ = true;
|
||||
if (fsi_.directory || stop_requested_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unique_mutex_lock reader_lock(io_thread_mtx_);
|
||||
io_thread_notify_.notify_all();
|
||||
reader_lock.unlock();
|
||||
stop_requested_ = true;
|
||||
|
||||
if (reader_thread_) {
|
||||
reader_thread_->join();
|
||||
reader_thread_.reset();
|
||||
unique_mutex_lock reader_lock(io_thread_mtx_);
|
||||
io_thread_notify_.notify_all();
|
||||
reader_lock.unlock();
|
||||
|
||||
if (reader_thread_) {
|
||||
reader_thread_->join();
|
||||
reader_thread_.reset();
|
||||
}
|
||||
|
||||
if (not open_file_base::close()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto err = get_api_error();
|
||||
if (err == api_error::success || err == api_error::download_incomplete ||
|
||||
err == api_error::download_stopped) {
|
||||
if (modified_ && not read_state_.all()) {
|
||||
set_api_error(api_error::download_incomplete);
|
||||
} else if (not modified_ && (fsi_.size > 0U) && not read_state_.all()) {
|
||||
set_api_error(api_error::download_stopped);
|
||||
}
|
||||
|
||||
if (open_file_base::close()) {
|
||||
{
|
||||
const auto err = get_api_error();
|
||||
if (err == api_error::success ||
|
||||
err == api_error::download_incomplete ||
|
||||
err == api_error::download_stopped) {
|
||||
if (modified_ && not read_state_.all()) {
|
||||
set_api_error(api_error::download_incomplete);
|
||||
} else if (not modified_ && (fsi_.size > 0U) &&
|
||||
not read_state_.all()) {
|
||||
set_api_error(api_error::download_stopped);
|
||||
}
|
||||
}
|
||||
}
|
||||
err = get_api_error();
|
||||
}
|
||||
|
||||
nf_->close();
|
||||
nf_->close();
|
||||
|
||||
if (modified_ && (get_api_error() == api_error::success)) {
|
||||
mgr_.queue_upload(*this);
|
||||
} else if (modified_ &&
|
||||
(get_api_error() == api_error::download_incomplete)) {
|
||||
mgr_.store_resume(*this);
|
||||
} else if (get_api_error() != api_error::success) {
|
||||
mgr_.remove_resume(get_api_path(), get_source_path());
|
||||
if (not utils::file::file(fsi_.source_path).remove()) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, get_api_path(), fsi_.source_path,
|
||||
utils::get_last_error_code(), "failed to delete file");
|
||||
}
|
||||
|
||||
auto parent = utils::path::get_parent_path(fsi_.source_path);
|
||||
fsi_.source_path =
|
||||
utils::path::combine(parent, {utils::create_uuid_string()});
|
||||
const auto res = provider_.set_item_meta(fsi_.api_path, META_SOURCE,
|
||||
fsi_.source_path);
|
||||
if (res != api_error::success) {
|
||||
utils::error::raise_api_path_error(function_name, get_api_path(),
|
||||
fsi_.source_path, res,
|
||||
"failed to set file meta");
|
||||
}
|
||||
}
|
||||
if (modified_) {
|
||||
if (err == api_error::success) {
|
||||
mgr_.queue_upload(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (err == api_error::download_incomplete) {
|
||||
mgr_.store_resume(*this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (err == api_error::success) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
mgr_.remove_resume(get_api_path(), get_source_path());
|
||||
if (not utils::file::file(fsi_.source_path).remove()) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, get_api_path(), fsi_.source_path,
|
||||
utils::get_last_error_code(), "failed to delete file");
|
||||
}
|
||||
|
||||
auto parent = utils::path::get_parent_path(fsi_.source_path);
|
||||
fsi_.source_path =
|
||||
utils::path::combine(parent, {utils::create_uuid_string()});
|
||||
auto res =
|
||||
provider_.set_item_meta(fsi_.api_path, META_SOURCE, fsi_.source_path);
|
||||
if (res != api_error::success) {
|
||||
utils::error::raise_api_path_error(function_name, get_api_path(),
|
||||
fsi_.source_path, res,
|
||||
"failed to set file meta");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void open_file::set_modified() {
|
||||
@ -544,8 +565,8 @@ auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
||||
}
|
||||
write_lock.unlock();
|
||||
|
||||
const auto start_chunk = static_cast<std::size_t>(write_offset / chunk_size_);
|
||||
const auto end_chunk =
|
||||
auto start_chunk = static_cast<std::size_t>(write_offset / chunk_size_);
|
||||
auto end_chunk =
|
||||
static_cast<std::size_t>((write_offset + data.size()) / chunk_size_);
|
||||
|
||||
update_background_reader(start_chunk);
|
||||
@ -576,7 +597,7 @@ auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
||||
return set_api_error(res);
|
||||
}
|
||||
|
||||
const auto now = std::to_string(utils::time::get_time_now());
|
||||
auto now = std::to_string(utils::time::get_time_now());
|
||||
res = provider_.set_item_meta(fsi_.api_path, {
|
||||
{META_CHANGED, now},
|
||||
{META_MODIFIED, now},
|
||||
|
@ -237,13 +237,37 @@ auto open_file_base::is_modified() const -> bool {
|
||||
|
||||
void open_file_base::remove(std::uint64_t handle) {
|
||||
recur_mutex_lock file_lock(file_mtx_);
|
||||
if (open_data_.find(handle) == open_data_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
open_data_.erase(handle);
|
||||
event_system::instance().raise<filesystem_item_handle_closed>(
|
||||
fsi_.api_path, handle, fsi_.source_path, fsi_.directory, modified_);
|
||||
if (open_data_.empty()) {
|
||||
event_system::instance().raise<filesystem_item_closed>(
|
||||
fsi_.api_path, fsi_.source_path, fsi_.directory, modified_);
|
||||
if (not open_data_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
event_system::instance().raise<filesystem_item_closed>(
|
||||
fsi_.api_path, fsi_.source_path, fsi_.directory, modified_);
|
||||
}
|
||||
|
||||
void open_file_base::remove_all() {
|
||||
recur_mutex_lock file_lock(file_mtx_);
|
||||
if (open_data_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto open_data = open_data_;
|
||||
open_data_.clear();
|
||||
|
||||
for (auto &&data : open_data) {
|
||||
event_system::instance().raise<filesystem_item_handle_closed>(
|
||||
fsi_.api_path, data.first, fsi_.source_path, fsi_.directory, modified_);
|
||||
}
|
||||
|
||||
event_system::instance().raise<filesystem_item_closed>(
|
||||
fsi_.api_path, fsi_.source_path, fsi_.directory, modified_);
|
||||
}
|
||||
|
||||
void open_file_base::reset_timeout() {
|
||||
|
@ -98,6 +98,8 @@ public:
|
||||
MOCK_METHOD(bool, is_write_supported, (), (const, override));
|
||||
|
||||
MOCK_METHOD(void, remove, (std::uint64_t handle), (override));
|
||||
|
||||
MOCK_METHOD(void, remove_all, (), (override));
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
|
@ -36,8 +36,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_create_new_file_with_normal_attribute) {
|
||||
};
|
||||
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
@ -53,8 +53,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_create_new_file_with_read_only_attribute) {
|
||||
};
|
||||
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_READONLY, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_READONLY, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
@ -73,8 +73,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_create_new_file_with_read_only_attribute) {
|
||||
//
|
||||
// auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ |
|
||||
// GENERIC_WRITE,
|
||||
// FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
// CREATE_NEW, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
// FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
// CREATE_NEW, FILE_ATTRIBUTE_SYSTEM, nullptr);
|
||||
// ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
// ::CloseHandle(handle);
|
||||
//
|
||||
@ -93,8 +93,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_create_new_file_with_hidden_attribute) {
|
||||
};
|
||||
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_HIDDEN, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
@ -112,8 +112,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_create_always_file_with_normal_attribute) {
|
||||
};
|
||||
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
@ -129,8 +129,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_create_file_with_read_only_attribute) {
|
||||
};
|
||||
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
@ -150,8 +150,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_create_file_with_read_only_attribute) {
|
||||
//
|
||||
// auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ |
|
||||
// GENERIC_WRITE,
|
||||
// FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
// CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
// FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
// CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM, nullptr);
|
||||
// ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
// ::CloseHandle(handle);
|
||||
//
|
||||
@ -170,8 +170,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_create_always_file_with_hidden_attribute) {
|
||||
};
|
||||
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
@ -199,8 +199,8 @@ TYPED_TEST(winfsp_test, cr8_attr_can_handle_read_only_directory) {
|
||||
EXPECT_EQ((FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY), attr);
|
||||
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
|
@ -43,10 +43,10 @@ TYPED_TEST(winfsp_test, cr8_nl_can_create_file_of_max_component_length) {
|
||||
std::string(max_length, 'a'),
|
||||
});
|
||||
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
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));
|
||||
}
|
||||
@ -66,10 +66,10 @@ TYPED_TEST(winfsp_test,
|
||||
std::string(max_length + 1U, 'a'),
|
||||
});
|
||||
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
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());
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ TYPED_TEST(winfsp_test, cr8_file_can_create_file) {
|
||||
utils::path::combine(this->mount_location, {"test_file_0"}),
|
||||
};
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
@ -46,8 +46,8 @@ TYPED_TEST(winfsp_test, cr8_file_create_new_fails_when_file_exists) {
|
||||
utils::path::combine(this->mount_location, {"test_file_0"}),
|
||||
};
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_EQ(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_EQ(ERROR_FILE_EXISTS, ::GetLastError());
|
||||
}
|
||||
@ -57,8 +57,8 @@ TYPED_TEST(winfsp_test, cr8_file_can_open_existing_file) {
|
||||
utils::path::combine(this->mount_location, {"test_file_0"}),
|
||||
};
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
@ -68,8 +68,8 @@ TYPED_TEST(winfsp_test, cr8_file_create_always_succeeds_when_file_exists) {
|
||||
utils::path::combine(this->mount_location, {"test_file_0"}),
|
||||
};
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
// EXPECT file_size is 0
|
||||
::CloseHandle(handle);
|
||||
@ -79,15 +79,16 @@ TYPED_TEST(winfsp_test, cr8_file_can_delete_file_after_close) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_0"}),
|
||||
};
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
|
||||
FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_EQ(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||
|
||||
@ -101,8 +102,8 @@ TYPED_TEST(winfsp_test,
|
||||
}) {
|
||||
auto handle = ::CreateFileA(
|
||||
(this->mount_location + "\\" + invalid_char + "\\test_file_0").c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_EQ(INVALID_HANDLE_VALUE, handle);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
std::cout << "char: " << invalid_char << std::endl;
|
||||
@ -121,8 +122,8 @@ TYPED_TEST(winfsp_test,
|
||||
}),
|
||||
};
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_EQ(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_EQ(ERROR_INVALID_NAME, ::GetLastError());
|
||||
}
|
||||
@ -153,35 +154,35 @@ TYPED_TEST(winfsp_test, cr8_file_directory_delete_fails_if_not_empty) {
|
||||
};
|
||||
|
||||
auto handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
handle =
|
||||
::CreateFileA(dir_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
handle = ::CreateFileA(
|
||||
dir_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
|
||||
FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
handle =
|
||||
::CreateFileA(dir_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
handle = ::CreateFileA(
|
||||
dir_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
::CloseHandle(handle);
|
||||
|
||||
handle =
|
||||
::CreateFileA(dir_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
handle = ::CreateFileA(
|
||||
dir_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_EQ(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||
}
|
||||
|
279
repertory/repertory_test/src/winfsp_drive_delete_test.cpp
Normal file
279
repertory/repertory_test/src/winfsp_drive_delete_test.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
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, delete_directory_fails_if_directory_not_empty) {
|
||||
auto dir_path{
|
||||
utils::path::combine(this->mount_location, {"test_dir_3"}),
|
||||
};
|
||||
|
||||
auto file_path{
|
||||
utils::path::combine(dir_path, {"test_file_3"}),
|
||||
};
|
||||
|
||||
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(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_EQ(ERROR_DIR_NOT_EMPTY, ::GetLastError());
|
||||
|
||||
EXPECT_TRUE(::DeleteFileA(file_path.c_str()));
|
||||
EXPECT_FALSE(::DeleteFileA(file_path.c_str()));
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||
|
||||
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_FALSE(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test,
|
||||
delete_read_file_attributes_fails_if_delete_is_pending) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_3"}),
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
handle = ::CreateFileA(file_path.c_str(), DELETE, FILE_SHARE_DELETE, nullptr,
|
||||
OPEN_EXISTING, 0, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
|
||||
typedef struct {
|
||||
BOOLEAN Disposition;
|
||||
} MY_FILE_DISPOSITION_INFO;
|
||||
|
||||
MY_FILE_DISPOSITION_INFO disp_info{TRUE};
|
||||
EXPECT_TRUE(::SetFileInformationByHandle(handle, FileDispositionInfo,
|
||||
&disp_info, sizeof disp_info));
|
||||
auto handle2 = ::CreateFileA(file_path.c_str(), FILE_READ_ATTRIBUTES, 0,
|
||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
EXPECT_EQ(INVALID_HANDLE_VALUE, handle2);
|
||||
EXPECT_EQ(ERROR_ACCESS_DENIED, ::GetLastError());
|
||||
|
||||
::CloseHandle(handle);
|
||||
|
||||
EXPECT_FALSE(::DeleteFileA(file_path.c_str()));
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, delete_can_handle_mmap_after_file_deletion) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_3"}),
|
||||
};
|
||||
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
|
||||
SYSTEM_INFO sys_info{};
|
||||
::GetSystemInfo(&sys_info);
|
||||
|
||||
auto *mapping =
|
||||
::CreateFileMappingA(handle, nullptr, PAGE_READWRITE, 0,
|
||||
sys_info.dwAllocationGranularity, nullptr);
|
||||
EXPECT_TRUE(mapping != nullptr);
|
||||
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);
|
||||
EXPECT_EQ(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||
|
||||
EXPECT_TRUE(::CloseHandle(mapping));
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, delete_can_delete_after_mapping) {
|
||||
auto dir_path{
|
||||
utils::path::combine(this->mount_location, {"test_dir_3"}),
|
||||
};
|
||||
auto file_path{
|
||||
utils::path::combine(dir_path, {"test_file_3"}),
|
||||
};
|
||||
auto file_path2{
|
||||
utils::path::combine(dir_path, {"test_file2_3"}),
|
||||
};
|
||||
|
||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||
|
||||
auto seed = static_cast<unsigned>(std::time(nullptr));
|
||||
srand(seed);
|
||||
|
||||
SYSTEM_INFO sys_info{};
|
||||
::GetSystemInfo(&sys_info);
|
||||
|
||||
{
|
||||
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);
|
||||
|
||||
auto *mapping =
|
||||
::CreateFileMappingA(handle, nullptr, PAGE_READWRITE, 0,
|
||||
16U * sys_info.dwAllocationGranularity, nullptr);
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
ASSERT_TRUE(mapping != nullptr);
|
||||
|
||||
auto *view = ::MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
ASSERT_TRUE(view != nullptr);
|
||||
|
||||
for (PUINT8 ptr = reinterpret_cast<PUINT8>(view),
|
||||
end = ptr + 16U * sys_info.dwAllocationGranularity;
|
||||
end > ptr; ++ptr) {
|
||||
*ptr = rand() & 0xFF;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(::UnmapViewOfFile(view));
|
||||
EXPECT_TRUE(::CloseHandle(mapping));
|
||||
}
|
||||
|
||||
{
|
||||
auto handle =
|
||||
::CreateFileA(file_path2.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);
|
||||
|
||||
auto mapping =
|
||||
::CreateFileMappingA(handle, nullptr, PAGE_READWRITE, 0,
|
||||
16U * sys_info.dwAllocationGranularity, nullptr);
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
ASSERT_TRUE(mapping != nullptr);
|
||||
|
||||
auto view = ::MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
EXPECT_TRUE(view != nullptr);
|
||||
|
||||
for (PUINT8 ptr = reinterpret_cast<PUINT8>(view),
|
||||
end = ptr + 16U * sys_info.dwAllocationGranularity;
|
||||
end > ptr; ++ptr) {
|
||||
*ptr = rand() & 0xFF;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(::UnmapViewOfFile(view));
|
||||
EXPECT_TRUE(::CloseHandle(mapping));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(::DeleteFileA(file_path.c_str()));
|
||||
EXPECT_TRUE(::DeleteFileA(file_path2.c_str()));
|
||||
|
||||
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_FALSE(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, delete_can_delete_on_close_after_mapping) {
|
||||
auto dir_path{
|
||||
utils::path::combine(this->mount_location, {"test_dir_3"}),
|
||||
};
|
||||
auto file_path{
|
||||
utils::path::combine(dir_path, {"test_file_3"}),
|
||||
};
|
||||
auto file_path2{
|
||||
utils::path::combine(dir_path, {"test_file2_3"}),
|
||||
};
|
||||
|
||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||
|
||||
auto seed = static_cast<unsigned>(std::time(nullptr));
|
||||
srand(seed);
|
||||
|
||||
SYSTEM_INFO sys_info{};
|
||||
::GetSystemInfo(&sys_info);
|
||||
|
||||
{
|
||||
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);
|
||||
|
||||
auto *mapping =
|
||||
::CreateFileMappingA(handle, nullptr, PAGE_READWRITE, 0,
|
||||
16U * sys_info.dwAllocationGranularity, nullptr);
|
||||
EXPECT_TRUE(mapping != nullptr);
|
||||
|
||||
auto *view = ::MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
EXPECT_TRUE(view != nullptr);
|
||||
for (PUINT8 ptr = reinterpret_cast<PUINT8>(view),
|
||||
end = ptr + 16U * sys_info.dwAllocationGranularity;
|
||||
end > ptr; ++ptr) {
|
||||
*ptr = rand() & 0xFF;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(::UnmapViewOfFile(view));
|
||||
EXPECT_TRUE(::CloseHandle(mapping));
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
}
|
||||
|
||||
{
|
||||
auto handle = ::CreateFileA(
|
||||
file_path2.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);
|
||||
|
||||
auto *mapping =
|
||||
::CreateFileMappingA(handle, nullptr, PAGE_READWRITE, 0,
|
||||
16U * sys_info.dwAllocationGranularity, nullptr);
|
||||
EXPECT_TRUE(mapping != nullptr);
|
||||
|
||||
auto *view = MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
EXPECT_TRUE(view != nullptr);
|
||||
|
||||
for (PUINT8 ptr = reinterpret_cast<PUINT8>(view),
|
||||
end = ptr + 16U * sys_info.dwAllocationGranularity;
|
||||
end > ptr; ++ptr) {
|
||||
*ptr = rand() & 0xFF;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(::UnmapViewOfFile(view));
|
||||
EXPECT_TRUE(::CloseHandle(mapping));
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_FALSE(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
|
||||
}
|
||||
} // namespace repertory
|
||||
|
||||
#endif // defined(_WIN32)
|
@ -36,8 +36,8 @@ TYPED_TEST(winfsp_test, info_can_get_tag_info) {
|
||||
};
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
|
||||
FILE_ATTRIBUTE_TAG_INFO tag_info{};
|
||||
@ -53,7 +53,7 @@ TYPED_TEST(winfsp_test, info_can_get_basic_info) {
|
||||
FILETIME file_time{};
|
||||
::GetSystemTimeAsFileTime(&file_time);
|
||||
|
||||
auto time_low = ((PLARGE_INTEGER)&file_time)->QuadPart;
|
||||
auto time_low = reinterpret_cast<PLARGE_INTEGER>(&file_time)->QuadPart;
|
||||
auto time_high = time_low + 10000 * 10000 /* 10 seconds */;
|
||||
|
||||
auto file_path{
|
||||
@ -61,8 +61,8 @@ TYPED_TEST(winfsp_test, info_can_get_basic_info) {
|
||||
};
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
|
||||
FILE_BASIC_INFO basic_info{};
|
||||
@ -91,8 +91,8 @@ TYPED_TEST(winfsp_test, info_can_get_standard_info) {
|
||||
};
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
|
||||
FILE_STANDARD_INFO std_info{};
|
||||
@ -113,8 +113,8 @@ TYPED_TEST(winfsp_test, info_can_get_file_name_info) {
|
||||
};
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
|
||||
std::array<std::uint8_t, sizeof(FILE_NAME_INFO) + MAX_PATH> name_info{};
|
||||
@ -137,11 +137,33 @@ TYPED_TEST(winfsp_test, info_can_get_file_name_info) {
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_get_file_name_info_buffer_too_small) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_2"}),
|
||||
};
|
||||
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);
|
||||
|
||||
std::array<std::uint8_t, sizeof(FILE_NAME_INFO)> name_info{};
|
||||
EXPECT_FALSE(
|
||||
::GetFileInformationByHandleEx(handle, FileNameInfo, name_info.data(),
|
||||
static_cast<DWORD>(name_info.size())));
|
||||
EXPECT_EQ(ERROR_MORE_DATA, ::GetLastError());
|
||||
|
||||
auto *info = reinterpret_cast<FILE_NAME_INFO *>(name_info.data());
|
||||
EXPECT_EQ('\\', info->FileName[0U]);
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_can_get_file_info) {
|
||||
FILETIME file_time{};
|
||||
::GetSystemTimeAsFileTime(&file_time);
|
||||
|
||||
auto time_low = ((PLARGE_INTEGER)&file_time)->QuadPart;
|
||||
auto time_low = reinterpret_cast<PLARGE_INTEGER>(&file_time)->QuadPart;
|
||||
auto time_high = time_low + 10000 * 10000 /* 10 seconds */;
|
||||
|
||||
auto file_path{
|
||||
@ -149,21 +171,33 @@ TYPED_TEST(winfsp_test, info_can_get_file_info) {
|
||||
};
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info));
|
||||
|
||||
EXPECT_LE(time_low, ((PLARGE_INTEGER)&file_info.ftCreationTime)->QuadPart);
|
||||
EXPECT_GT(time_high, ((PLARGE_INTEGER)&file_info.ftCreationTime)->QuadPart);
|
||||
EXPECT_LE(
|
||||
time_low,
|
||||
reinterpret_cast<PLARGE_INTEGER>(&file_info.ftCreationTime)->QuadPart);
|
||||
EXPECT_GT(
|
||||
time_high,
|
||||
reinterpret_cast<PLARGE_INTEGER>(&file_info.ftCreationTime)->QuadPart);
|
||||
|
||||
EXPECT_LE(time_low, ((PLARGE_INTEGER)&file_info.ftLastAccessTime)->QuadPart);
|
||||
EXPECT_GT(time_high, ((PLARGE_INTEGER)&file_info.ftLastAccessTime)->QuadPart);
|
||||
EXPECT_LE(
|
||||
time_low,
|
||||
reinterpret_cast<PLARGE_INTEGER>(&file_info.ftLastAccessTime)->QuadPart);
|
||||
EXPECT_GT(
|
||||
time_high,
|
||||
reinterpret_cast<PLARGE_INTEGER>(&file_info.ftLastAccessTime)->QuadPart);
|
||||
|
||||
EXPECT_LE(time_low, ((PLARGE_INTEGER)&file_info.ftLastWriteTime)->QuadPart);
|
||||
EXPECT_GT(time_high, ((PLARGE_INTEGER)&file_info.ftLastWriteTime)->QuadPart);
|
||||
EXPECT_LE(
|
||||
time_low,
|
||||
reinterpret_cast<PLARGE_INTEGER>(&file_info.ftLastWriteTime)->QuadPart);
|
||||
EXPECT_GT(
|
||||
time_high,
|
||||
reinterpret_cast<PLARGE_INTEGER>(&file_info.ftLastWriteTime)->QuadPart);
|
||||
|
||||
EXPECT_EQ(0U, file_info.nFileSizeHigh);
|
||||
EXPECT_EQ(0U, file_info.nFileSizeLow);
|
||||
@ -176,6 +210,199 @@ TYPED_TEST(winfsp_test, info_can_get_file_info) {
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_can_get_file_path) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_2"}),
|
||||
};
|
||||
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);
|
||||
|
||||
std::string final_path;
|
||||
final_path.resize(MAX_PATH + 1U);
|
||||
|
||||
auto result = ::GetFinalPathNameByHandleA(
|
||||
handle, final_path.data(), final_path.size() - 1U,
|
||||
VOLUME_NAME_NONE | FILE_NAME_OPENED);
|
||||
|
||||
auto expected_name{
|
||||
std::string{"\\repertory\\"} +
|
||||
utils::string::to_lower(this->mount_location).at(0U) +
|
||||
"\\test_file_2",
|
||||
};
|
||||
EXPECT_EQ(result, static_cast<DWORD>(expected_name.size()));
|
||||
EXPECT_STREQ(expected_name.c_str(), final_path.c_str());
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_can_set_file_info_attributes_to_hidden) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_2"}),
|
||||
};
|
||||
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(::SetFileAttributesA(file_path.c_str(), FILE_ATTRIBUTE_HIDDEN));
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info));
|
||||
EXPECT_EQ(FILE_ATTRIBUTE_HIDDEN, file_info.dwFileAttributes);
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(
|
||||
winfsp_test,
|
||||
info_can_set_file_info_attributes_to_hidden_ignoring_directory_attribute) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_2"}),
|
||||
};
|
||||
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(::SetFileAttributesA(
|
||||
file_path.c_str(), FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN));
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info));
|
||||
EXPECT_EQ(FILE_ATTRIBUTE_HIDDEN, file_info.dwFileAttributes);
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_can_set_creation_file_time) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_2"}),
|
||||
};
|
||||
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);
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION orig_file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &orig_file_info));
|
||||
|
||||
static constexpr const UINT64 file_time{
|
||||
116444736000000000ULL + 0x4200000042ULL,
|
||||
};
|
||||
|
||||
EXPECT_TRUE(::SetFileTime(handle,
|
||||
reinterpret_cast<const FILETIME *>(&file_time),
|
||||
nullptr, nullptr));
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info));
|
||||
|
||||
EXPECT_EQ(file_time, *reinterpret_cast<PUINT64>(&file_info.ftCreationTime));
|
||||
|
||||
EXPECT_EQ(*reinterpret_cast<PUINT64>(&orig_file_info.ftLastAccessTime),
|
||||
*reinterpret_cast<PUINT64>(&file_info.ftLastAccessTime));
|
||||
EXPECT_EQ(*reinterpret_cast<PUINT64>(&orig_file_info.ftLastWriteTime),
|
||||
*reinterpret_cast<PUINT64>(&file_info.ftLastWriteTime));
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_can_set_accessed_file_time) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_2"}),
|
||||
};
|
||||
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);
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION orig_file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &orig_file_info));
|
||||
|
||||
static constexpr const UINT64 file_time{
|
||||
116444736000000000ULL + 0x4200000042ULL,
|
||||
};
|
||||
|
||||
EXPECT_TRUE(::SetFileTime(handle, nullptr,
|
||||
reinterpret_cast<const FILETIME *>(&file_time),
|
||||
nullptr));
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info));
|
||||
|
||||
EXPECT_EQ(file_time, *reinterpret_cast<PUINT64>(&file_info.ftLastAccessTime));
|
||||
EXPECT_EQ(*reinterpret_cast<PUINT64>(&orig_file_info.ftCreationTime),
|
||||
*reinterpret_cast<PUINT64>(&file_info.ftCreationTime));
|
||||
EXPECT_EQ(*reinterpret_cast<PUINT64>(&orig_file_info.ftLastWriteTime),
|
||||
*reinterpret_cast<PUINT64>(&file_info.ftLastWriteTime));
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_can_set_written_file_time) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_2"}),
|
||||
};
|
||||
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);
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION orig_file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &orig_file_info));
|
||||
|
||||
static constexpr const UINT64 file_time{
|
||||
116444736000000000ULL + 0x4200000042ULL,
|
||||
};
|
||||
|
||||
EXPECT_TRUE(::SetFileTime(handle, nullptr, nullptr,
|
||||
reinterpret_cast<const FILETIME *>(&file_time)));
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info));
|
||||
|
||||
EXPECT_EQ(file_time, *reinterpret_cast<PUINT64>(&file_info.ftLastWriteTime));
|
||||
|
||||
EXPECT_EQ(*reinterpret_cast<PUINT64>(&orig_file_info.ftLastAccessTime),
|
||||
*reinterpret_cast<PUINT64>(&file_info.ftLastAccessTime));
|
||||
EXPECT_EQ(*reinterpret_cast<PUINT64>(&orig_file_info.ftCreationTime),
|
||||
*reinterpret_cast<PUINT64>(&file_info.ftCreationTime));
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_can_set_file_size) {
|
||||
auto file_path{
|
||||
utils::path::combine(this->mount_location, {"test_file_2"}),
|
||||
};
|
||||
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);
|
||||
|
||||
auto offset = ::SetFilePointer(handle, 42, nullptr, FILE_BEGIN);
|
||||
EXPECT_EQ(42U, offset);
|
||||
|
||||
EXPECT_TRUE(::SetEndOfFile(handle));
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info));
|
||||
|
||||
EXPECT_EQ(0U, file_info.nFileSizeHigh);
|
||||
EXPECT_EQ(42U, file_info.nFileSizeLow);
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
} // namespace repertory
|
||||
|
||||
#endif // defined(_WIN32)
|
||||
|
@ -28,6 +28,7 @@
|
||||
// TODO revisit create_backup
|
||||
// TODO revisit create_restore
|
||||
// TODO revisit create_share
|
||||
// TODO revisit delete_access_test
|
||||
// TODO revisit getfileattr_test
|
||||
|
||||
//
|
||||
|
Reference in New Issue
Block a user