29 Commits

Author SHA1 Message Date
a031f9d867 refactor
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2024-11-07 14:34:01 -06:00
2f6fa792df refactor 2024-11-07 14:32:57 -06:00
be0f977dc7 refactor 2024-11-07 14:32:12 -06:00
73efae7c2f refactor 2024-11-07 14:31:56 -06:00
6b67cd676d refactor 2024-11-07 14:29:47 -06:00
2db38a87e3 refactor 2024-11-07 14:28:25 -06:00
213511a77d fix 2024-11-07 14:27:13 -06:00
a38a033143 refactor 2024-11-07 14:22:49 -06:00
619d5939b3 refactor 2024-11-07 14:22:03 -06:00
68a26d2bc6 refactor 2024-11-07 14:20:14 -06:00
2661885cf2 refactor 2024-11-07 14:19:26 -06:00
6a820837cc refactor 2024-11-07 14:16:27 -06:00
02b74402f4 refactor 2024-11-07 14:13:30 -06:00
3535a61844 refactor 2024-11-07 14:12:44 -06:00
eb4fe4ff60 refactor 2024-11-07 14:12:17 -06:00
793ec5b4a5 refactor 2024-11-07 14:08:08 -06:00
c14b637536 winfsp unit tests and fixes 2024-11-07 14:06:39 -06:00
489d9b1960 winfsp unit tests and fixes 2024-11-07 12:37:35 -06:00
2f60890d29 winfsp unit tests and fixes 2024-11-07 12:36:24 -06:00
19d4b0a247 winfsp unit tests and fixes 2024-11-07 12:33:15 -06:00
69d190e485 winfsp unit tests and fixes 2024-11-07 12:32:07 -06:00
2df84f53ed winfsp unit tests and fixes 2024-11-07 11:14:38 -06:00
876a1e9cd8 refactor 2024-11-07 09:57:21 -06:00
2945793de9 fix 2024-11-07 09:25:51 -06:00
0de0e511ee winfsp unit tests and fixes 2024-11-07 09:22:24 -06:00
c16d9f9712 winfsp unit tests and fixes 2024-11-07 09:21:00 -06:00
0903d4b83e winfsp unit tests and fixes 2024-11-07 09:17:32 -06:00
0bd1f72017 winfsp unit tests and fixes 2024-11-07 08:56:18 -06:00
7bc1440b8b winfsp unit tests and fixes 2024-11-07 08:31:39 -06:00
18 changed files with 800 additions and 250 deletions

View File

@ -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); }

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)) {

View File

@ -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;

View File

@ -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");

View File

@ -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},

View File

@ -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() {

View File

@ -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

View File

@ -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);

View File

@ -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());
}

View File

@ -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());
}

View 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)

View File

@ -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)

View File

@ -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
//