diff --git a/repertory/librepertory/include/drives/winfsp/winfsp_drive.hpp b/repertory/librepertory/include/drives/winfsp/winfsp_drive.hpp index b6d1d49c..5764c73a 100644 --- a/repertory/librepertory/include/drives/winfsp/winfsp_drive.hpp +++ b/repertory/librepertory/include/drives/winfsp/winfsp_drive.hpp @@ -75,8 +75,14 @@ private: std::unique_ptr remote_server_; private: - static auto - parse_mount_location(const std::wstring &mount_location) -> std::string; + [[nodiscard]] auto handle_error(std::string_view function_name, + const std::string &api_path, api_error error, + FileInfo *file_info, std::uint64_t file_size, + bool raise_on_failure_only = false) const + -> NTSTATUS; + + static auto parse_mount_location(const std::wstring &mount_location) + -> std::string; void populate_file_info(const std::string &api_path, std::uint64_t file_size, const api_meta_map &meta, @@ -89,8 +95,8 @@ private: const FSP_FSCTL_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; @@ -102,8 +108,8 @@ 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; [[nodiscard]] auto get_directory_item_count(const std::string &api_path) const -> std::uint64_t override; @@ -111,24 +117,25 @@ public: [[nodiscard]] auto get_directory_items(const std::string &api_path) const -> directory_item_list 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; - [[nodiscard]] auto - get_file_size(const std::string &api_path) const -> std::uint64_t override; + [[nodiscard]] auto get_file_size(const std::string &api_path) const + -> std::uint64_t override; - [[nodiscard]] auto - get_item_meta(const std::string &api_path, - api_meta_map &meta) const -> api_error override; + [[nodiscard]] auto get_item_meta(const std::string &api_path, + api_meta_map &meta) const + -> api_error override; - [[nodiscard]] auto - get_item_meta(const std::string &api_path, const std::string &name, - std::string &value) const -> api_error override; + [[nodiscard]] auto get_item_meta(const std::string &api_path, + const std::string &name, + std::string &value) const + -> api_error override; - [[nodiscard]] auto - get_security_by_name(PWSTR file_name, PUINT32 attributes, - PSECURITY_DESCRIPTOR descriptor, - std::uint64_t *descriptor_size) -> NTSTATUS override; + [[nodiscard]] auto get_security_by_name(PWSTR file_name, PUINT32 attributes, + PSECURITY_DESCRIPTOR descriptor, + std::uint64_t *descriptor_size) + -> NTSTATUS override; auto GetSecurityByName(PWSTR file_name, PUINT32 attributes, PSECURITY_DESCRIPTOR descriptor, @@ -152,16 +159,16 @@ 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, FileInfo *file_info) -> NTSTATUS override; - [[nodiscard]] auto - populate_file_info(const std::string &api_path, - remote::file_info &file_info) -> api_error override; + [[nodiscard]] auto populate_file_info(const std::string &api_path, + remote::file_info &file_info) + -> api_error override; auto Read(PVOID file_node, PVOID file_desc, PVOID buffer, UINT64 offset, ULONG length, PULONG bytes_transferred) -> NTSTATUS override; @@ -171,8 +178,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, @@ -180,15 +187,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(); diff --git a/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp b/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp index 4eeda8d4..6641c017 100644 --- a/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp +++ b/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp @@ -67,13 +67,35 @@ winfsp_drive::winfsp_service::winfsp_service( host_(drive), config_(config) {} +auto winfsp_drive::handle_error(std::string_view function_name, + const std::string &api_path, api_error error, + FileInfo *file_info, std::uint64_t file_size, + bool raise_on_failure_only) const -> NTSTATUS { + auto ret = utils::from_api_error(error); + if (not raise_on_failure_only || error != api_error::success) { + RAISE_WINFSP_EVENT(function_name, api_path, ret); + } + + if (file_info == nullptr || error != api_error::success) { + return ret; + } + + api_meta_map meta; + if (provider_.get_item_meta(api_path, meta) != api_error::success) { + return ret; + } + + populate_file_info(file_size, meta, *file_info); + return ret; +} + auto winfsp_drive::winfsp_service::OnStart(ULONG /*Argc*/, PWSTR * /*Argv*/) -> NTSTATUS { REPERTORY_USES_FUNCTION_NAME(); - const auto mount_location = utils::string::to_lower( + auto mount_location = utils::string::to_lower( utils::path::absolute((drive_args_.size() > 1U) ? drive_args_[1U] : "")); - const auto drive_letter = + auto drive_letter = ((mount_location.size() == 2U) || ((mount_location.size() == 3U) && (mount_location[2U] == '\\'))) && (mount_location[1U] == ':'); @@ -132,27 +154,26 @@ auto winfsp_drive::CanDelete(PVOID /*file_node*/, PVOID file_desc, REPERTORY_USES_FUNCTION_NAME(); std::string api_path; - auto error = api_error::invalid_handle; + std::shared_ptr file; + const auto handle_error = [this, &api_path](api_error error) -> NTSTATUS { + return this->handle_error(function_name, api_path, error, nullptr, 0U); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - std::shared_ptr file; - if (fm_->get_open_file(handle, false, file)) { - api_path = file->get_api_path(); - if (file->is_directory()) { - error = provider_.get_directory_item_count(api_path) != 0U - ? api_error::directory_not_empty - : api_error::success; - } else { - error = fm_->is_processing(api_path) ? api_error::file_in_use - : api_error::success; - } - } + if (handle == 0U || not fm_->get_open_file(handle, false, file)) { + return handle_error(api_error::invalid_handle); } - auto ret = utils::from_api_error(error); - RAISE_WINFSP_EVENT(function_name, api_path, ret); - return ret; + api_path = file->get_api_path(); + if (file->is_directory()) { + return handle_error(provider_.get_directory_item_count(api_path) == 0U + ? api_error::success + : api_error::directory_not_empty); + } + + return handle_error(fm_->is_processing(api_path) ? api_error::file_in_use + : api_error::success); } VOID winfsp_drive::Cleanup(PVOID file_node, PVOID file_desc, @@ -160,130 +181,126 @@ VOID winfsp_drive::Cleanup(PVOID file_node, PVOID file_desc, REPERTORY_USES_FUNCTION_NAME(); std::string api_path; + std::shared_ptr file; + const auto handle_error = [this, &api_path](api_error error) { + [[maybe_unused]] auto ret = + this->handle_error(function_name, api_path, error, nullptr, 0U); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - std::shared_ptr file; - if (fm_->get_open_file(handle, false, file)) { - api_path = file->get_api_path(); + if (handle == 0U || not fm_->get_open_file(handle, false, file)) { + return handle_error(api_error::invalid_handle); + } - const auto directory = file->is_directory(); - if ((flags & FspCleanupDelete) != 0U) { - auto *directory_buffer = file->get_open_data(handle).directory_buffer; - file.reset(); + api_path = file->get_api_path(); - if (directory_buffer != nullptr) { - FspFileSystemDeleteDirectoryBuffer(&directory_buffer); - } + auto directory = file->is_directory(); + if ((flags & FspCleanupDelete) != 0U) { + auto *directory_buffer = file->get_open_data(handle).directory_buffer; + file.reset(); - if (directory) { - if (provider_.get_directory_item_count(api_path) == 0) { - auto res = provider_.remove_directory(api_path); - if (res != api_error::success) { - utils::error::raise_api_path_error(function_name, api_path, res, - "failed to remove directory"); - } - } else { - utils::error::raise_api_path_error( - function_name, api_path, api_error::directory_not_empty, - "failed to remove non-empty directory"); - } - } else { - auto res = fm_->remove_file(api_path); - if (res != api_error::success) { - utils::error::raise_api_path_error(function_name, api_path, res, - "failed to remove file"); - } - } - } else { - if (((flags & FspCleanupSetArchiveBit) != 0U) && not directory) { - api_meta_map meta; - if (provider_.get_item_meta(api_path, meta) == api_error::success) { - auto res = provider_.set_item_meta( - api_path, META_ATTRIBUTES, - std::to_string(utils::get_attributes_from_meta(meta) | - FILE_ATTRIBUTE_ARCHIVE)); - if (res != api_error::success) { - utils::error::raise_api_path_error( - function_name, api_path, res, - "failed to set meta attributes"); - } - } - } + if (directory_buffer != nullptr) { + FspFileSystemDeleteDirectoryBuffer(&directory_buffer); + } - if ((flags & (FspCleanupSetLastAccessTime | FspCleanupSetLastWriteTime | - FspCleanupSetChangeTime)) != 0U) { - const auto now = utils::time::get_time_now(); - if ((flags & FspCleanupSetLastAccessTime) != 0U) { - auto res = provider_.set_item_meta(api_path, META_ACCESSED, - std::to_string(now)); - if (res != api_error::success) { - utils::error::raise_api_path_error( - function_name, api_path, res, - "failed to set meta accessed time"); - } - } + if (directory) { + if (provider_.get_directory_item_count(api_path) == 0) { + return handle_error(provider_.remove_directory(api_path)); + } - if ((flags & FspCleanupSetLastWriteTime) != 0U) { - auto res = provider_.set_item_meta(api_path, META_WRITTEN, - std::to_string(now)); - if (res != api_error::success) { - utils::error::raise_api_path_error( - function_name, api_path, res, - "failed to set meta written time"); - } - } + return handle_error(api_error::directory_not_empty); + } - if ((flags & FspCleanupSetChangeTime) != 0U) { - auto res = provider_.set_item_meta( - api_path, { - {META_CHANGED, std::to_string(now)}, - {META_MODIFIED, std::to_string(now)}, - }); - if (res != api_error::success) { - utils::error::raise_api_path_error( - function_name, api_path, res, - "failed to set meta modified time"); - } - } - } + return handle_error(fm_->remove_file(api_path)); + } - if ((flags & FspCleanupSetAllocationSize) != 0U) { - auto allocation_size = - utils::divide_with_ceiling(file->get_file_size(), - WINFSP_ALLOCATION_UNIT) * - WINFSP_ALLOCATION_UNIT; - SetFileSize(file_node, file_desc, allocation_size, TRUE, nullptr); - } + if (((flags & FspCleanupSetArchiveBit) != 0U) && not directory) { + api_meta_map meta; + if (provider_.get_item_meta(api_path, meta) == api_error::success) { + auto res = provider_.set_item_meta( + api_path, META_ATTRIBUTES, + std::to_string(utils::get_attributes_from_meta(meta) | + FILE_ATTRIBUTE_ARCHIVE)); + if (res != api_error::success) { + utils::error::raise_api_path_error(function_name, api_path, res, + "failed to set meta attributes"); } } } - RAISE_WINFSP_EVENT(function_name, api_path, 0); + if ((flags & (FspCleanupSetLastAccessTime | FspCleanupSetLastWriteTime | + FspCleanupSetChangeTime)) != 0U) { + auto now = utils::time::get_time_now(); + if ((flags & FspCleanupSetLastAccessTime) != 0U) { + auto res = + provider_.set_item_meta(api_path, META_ACCESSED, std::to_string(now)); + if (res != api_error::success) { + utils::error::raise_api_path_error(function_name, api_path, res, + "failed to set meta accessed time"); + } + } + + if ((flags & FspCleanupSetLastWriteTime) != 0U) { + auto res = + provider_.set_item_meta(api_path, META_WRITTEN, std::to_string(now)); + if (res != api_error::success) { + utils::error::raise_api_path_error(function_name, api_path, res, + "failed to set meta written time"); + } + } + + if ((flags & FspCleanupSetChangeTime) != 0U) { + auto res = provider_.set_item_meta( + api_path, { + {META_CHANGED, std::to_string(now)}, + {META_MODIFIED, std::to_string(now)}, + }); + if (res != api_error::success) { + utils::error::raise_api_path_error(function_name, api_path, res, + "failed to set meta modified time"); + } + } + } + + if ((flags & FspCleanupSetAllocationSize) != 0U) { + auto allocation_size = utils::divide_with_ceiling(file->get_file_size(), + WINFSP_ALLOCATION_UNIT) * + WINFSP_ALLOCATION_UNIT; + SetFileSize(file_node, file_desc, allocation_size, TRUE, nullptr); + } + + return handle_error(api_error::success); } VOID winfsp_drive::Close(PVOID /*file_node*/, PVOID file_desc) { REPERTORY_USES_FUNCTION_NAME(); std::string api_path; + std::shared_ptr file; + const auto handle_error = [this, &api_path](api_error error) { + [[maybe_unused]] auto ret = + this->handle_error(function_name, api_path, error, nullptr, 0U); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - PVOID directory_buffer{nullptr}; - - std::shared_ptr file; - if (fm_->get_open_file(handle, false, file)) { - api_path = file->get_api_path(); - directory_buffer = file->get_open_data(handle).directory_buffer; - file.reset(); - } - fm_->close(handle); - if (directory_buffer != nullptr) { - FspFileSystemDeleteDirectoryBuffer(&directory_buffer); - } + if (handle == 0U || not fm_->get_open_file(handle, false, file)) { + return handle_error(api_error::invalid_handle); } - RAISE_WINFSP_EVENT(function_name, api_path, 0); + PVOID directory_buffer{nullptr}; + + api_path = file->get_api_path(); + directory_buffer = file->get_open_data(handle).directory_buffer; + file.reset(); + fm_->close(handle); + + if (directory_buffer != nullptr) { + FspFileSystemDeleteDirectoryBuffer(&directory_buffer); + } + + return handle_error(api_error::success); } auto winfsp_drive::Create(PWSTR file_name, UINT32 create_options, @@ -306,7 +323,7 @@ auto winfsp_drive::Create(PWSTR file_name, UINT32 create_options, attributes |= FILE_ATTRIBUTE_ARCHIVE; } - const auto now = utils::time::get_time_now(); + auto now = utils::time::get_time_now(); auto meta = create_meta_attributes( now, attributes, now, now, (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0U, 0U, "", 0U, now, 0U, 0U, 0U, @@ -316,7 +333,7 @@ auto winfsp_drive::Create(PWSTR file_name, UINT32 create_options, {utils::create_uuid_string()}), 0U, now); - const auto api_path = + auto api_path = utils::path::create_api_path(utils::string::to_utf8(file_name)); open_file_data ofd{}; @@ -350,33 +367,27 @@ auto winfsp_drive::Flush(PVOID /*file_node*/, PVOID file_desc, REPERTORY_USES_FUNCTION_NAME(); std::string api_path; - auto error = api_error::success; + std::shared_ptr file; + const auto handle_error = [this, &api_path, &file, + &file_info](api_error error) -> NTSTATUS { + return this->handle_error(function_name, api_path, error, file_info, + file ? file->get_file_size() : 0U); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - error = api_error::invalid_handle; - std::shared_ptr file; - if (fm_->get_open_file(handle, false, file)) { - api_path = file->get_api_path(); - error = file->native_operation([&](native_handle op_handle) { - if (::FlushFileBuffers(op_handle) == 0) { - return api_error::os_error; - } - - return api_error::success; - }); - - // Populate file information - api_meta_map meta; - if (provider_.get_item_meta(api_path, meta) == api_error::success) { - populate_file_info(file->get_file_size(), meta, *file_info); - } - } + if (handle == 0U || not fm_->get_open_file(handle, false, file)) { + return handle_error(api_error::invalid_handle); } - auto ret = utils::from_api_error(error); - RAISE_WINFSP_EVENT(function_name, api_path, ret); - return ret; + api_path = file->get_api_path(); + return handle_error(file->native_operation([&](native_handle op_handle) { + if (::FlushFileBuffers(op_handle) == 0) { + return api_error::os_error; + } + + return api_error::success; + })); } auto winfsp_drive::get_directory_item_count(const std::string &api_path) const @@ -402,24 +413,20 @@ auto winfsp_drive::GetFileInfo(PVOID /*file_node*/, PVOID file_desc, REPERTORY_USES_FUNCTION_NAME(); std::string api_path; - auto error = api_error::invalid_handle; + std::shared_ptr file; + const auto handle_error = [this, &api_path, &file, + &file_info](api_error error) -> NTSTATUS { + return this->handle_error(function_name, api_path, error, file_info, + file ? file->get_file_size() : 0U); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - std::shared_ptr file; - if (fm_->get_open_file(handle, false, file)) { - api_path = file->get_api_path(); - api_meta_map meta; - error = provider_.get_item_meta(api_path, meta); - if (error == api_error::success) { - populate_file_info(file->get_file_size(), meta, *file_info); - } - } + if (handle == 0U || not fm_->get_open_file(handle, false, file)) { + return handle_error(api_error::invalid_handle); } - auto ret = utils::from_api_error(error); - RAISE_WINFSP_EVENT(function_name, api_path, ret); - return ret; + return handle_error(api_error::success); } auto winfsp_drive::get_file_size(const std::string &api_path) const @@ -457,7 +464,7 @@ auto winfsp_drive::get_security_by_name(PWSTR file_name, PUINT32 attributes, PSECURITY_DESCRIPTOR descriptor, std::uint64_t *descriptor_size) -> NTSTATUS { - const auto api_path = + auto api_path = utils::path::create_api_path(utils::string::to_utf8(file_name)); api_meta_map meta{}; @@ -494,7 +501,7 @@ auto winfsp_drive::GetSecurityByName(PWSTR file_name, PUINT32 attributes, SIZE_T *descriptor_size) -> NTSTATUS { REPERTORY_USES_FUNCTION_NAME(); - const auto api_path = + auto api_path = utils::path::create_api_path(utils::string::to_utf8(file_name)); std::uint64_t sds = descriptor_size == nullptr ? 0U : *descriptor_size; auto ret = get_security_by_name(file_name, attributes, descriptor, @@ -521,8 +528,8 @@ auto winfsp_drive::get_used_drive_space() const -> std::uint64_t { void winfsp_drive::get_volume_info(UINT64 &total_size, UINT64 &free_size, std::string &volume_label) const { - const auto total_bytes = provider_.get_total_drive_space(); - const auto total_used = provider_.get_used_drive_space(); + auto total_bytes = provider_.get_total_drive_space(); + auto total_used = provider_.get_used_drive_space(); free_size = total_bytes - total_used; total_size = total_bytes; volume_label = utils::create_volume_label(config_.get_provider_type()); @@ -533,8 +540,8 @@ auto winfsp_drive::GetVolumeInfo(VolumeInfo *volume_info) -> NTSTATUS { const std::wstring volume_label = utils::string::from_utf8( utils::create_volume_label(config_.get_provider_type())); - const auto total_bytes = provider_.get_total_drive_space(); - const auto total_used = provider_.get_used_drive_space(); + auto total_bytes = provider_.get_total_drive_space(); + auto total_used = provider_.get_used_drive_space(); volume_info->FreeSize = total_bytes - total_used; volume_info->TotalSize = total_bytes; wcscpy_s(&volume_info->VolumeLabel[0U], 32, volume_label.data()); @@ -577,7 +584,7 @@ auto winfsp_drive::Init(PVOID host) -> NTSTATUS { auto winfsp_drive::mount(const std::vector &drive_args) -> int { std::vector 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 (auto &&arg : drive_args) { @@ -638,8 +645,7 @@ auto winfsp_drive::Mounted(PVOID host) -> NTSTATUS { eviction_->start(); } - const auto mount_location = - parse_mount_location(file_system_host->MountPoint()); + auto mount_location = parse_mount_location(file_system_host->MountPoint()); if (config_.get_enable_remote_mount()) { remote_server_ = std::make_unique( config_, *this, mount_location); @@ -675,7 +681,7 @@ auto winfsp_drive::Open(PWSTR file_name, UINT32 create_options, REPERTORY_USES_FUNCTION_NAME(); *file_desc = reinterpret_cast(INVALID_HANDLE_VALUE); - const auto api_path = + auto api_path = utils::path::create_api_path(utils::string::to_utf8(file_name)); bool directory{}; @@ -723,49 +729,58 @@ auto winfsp_drive::Overwrite(PVOID /*file_node*/, PVOID file_desc, REPERTORY_USES_FUNCTION_NAME(); std::string api_path; - auto error = api_error::invalid_handle; + std::shared_ptr file; + const auto handle_error = [this, &api_path, &file, + &file_info](api_error error) -> NTSTATUS { + return this->handle_error(function_name, api_path, error, file_info, + file ? file->get_file_size() : 0U); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - std::shared_ptr file; - if (fm_->get_open_file(handle, true, file)) { - api_path = file->get_api_path(); - api_meta_map meta{}; - error = provider_.get_item_meta(api_path, meta); - if (error == api_error::success) { - error = file->resize(0U); - if (error == api_error::success) { - filesystem_item existing_fsi{}; - error = provider_.get_filesystem_item(api_path, false, existing_fsi); - if (error == api_error::success) { - // Handle replace attributes - if (replace_attributes != 0U) { - if (attributes == 0U || attributes == FILE_ATTRIBUTE_NORMAL) { - attributes = FILE_ATTRIBUTE_ARCHIVE; - } - meta[META_ATTRIBUTES] = std::to_string(attributes); - error = provider_.set_item_meta(api_path, meta); - } else if (attributes != 0U) { // Handle merge attributes - const auto current_attributes = - utils::get_attributes_from_meta(meta); - const auto merged_attributes = attributes | current_attributes; - if (merged_attributes != current_attributes) { - meta[META_ATTRIBUTES] = std::to_string(merged_attributes); - error = provider_.set_item_meta(api_path, meta); - } - } - } - } - - // Populate file information - populate_file_info(file->get_file_size(), meta, *file_info); - } - } + if (handle == 0U || not fm_->get_open_file(handle, true, file)) { + return handle_error(api_error::invalid_handle); } - auto ret = utils::from_api_error(error); - RAISE_WINFSP_EVENT(function_name, api_path, ret); - return ret; + api_path = file->get_api_path(); + api_meta_map meta{}; + auto res = provider_.get_item_meta(api_path, meta); + if (res != api_error::success) { + return handle_error(res); + } + + res = file->resize(0U); + if (res != api_error::success) { + return handle_error(res); + } + + filesystem_item existing_fsi{}; + res = provider_.get_filesystem_item(api_path, false, existing_fsi); + if (res != api_error::success) { + return handle_error(res); + } + + if (replace_attributes != 0U) { + if (attributes == 0U || attributes == FILE_ATTRIBUTE_NORMAL) { + attributes = FILE_ATTRIBUTE_ARCHIVE; + } + + meta[META_ATTRIBUTES] = std::to_string(attributes); + return handle_error(provider_.set_item_meta(api_path, meta)); + } + + if (attributes == 0U) { + return handle_error(api_error::success); + } + + auto current_attributes = utils::get_attributes_from_meta(meta); + auto merged_attributes = attributes | current_attributes; + if (merged_attributes != current_attributes) { + meta[META_ATTRIBUTES] = std::to_string(merged_attributes); + return handle_error(provider_.set_item_meta(api_path, meta)); + } + + return handle_error(api_error::success); } auto winfsp_drive::parse_mount_location(const std::wstring &mount_location) @@ -779,7 +794,7 @@ void winfsp_drive::populate_file_info(const std::string &api_path, std::uint64_t file_size, const api_meta_map &meta, FSP_FSCTL_OPEN_FILE_INFO &ofi) { - const auto file_path = utils::string::from_utf8( + auto file_path = utils::string::from_utf8( utils::string::replace_copy(api_path, '/', '\\')); wcscpy_s(ofi.NormalizedName, ofi.NormalizedNameSize / sizeof(WCHAR), @@ -829,47 +844,45 @@ auto winfsp_drive::Read(PVOID /*file_node*/, PVOID file_desc, PVOID buffer, *bytes_transferred = 0U; std::string api_path; - auto error = api_error::invalid_handle; + std::shared_ptr file; + const auto handle_error = [this, &api_path](api_error error) -> NTSTATUS { + return this->handle_error(function_name, api_path, error, nullptr, 0U); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - if (length > 0U) { - std::shared_ptr file; - if (fm_->get_open_file(handle, false, file)) { - api_path = file->get_api_path(); - data_buffer data; - error = file->read(length, offset, data); - if (error == api_error::success) { - *bytes_transferred = static_cast(data.size()); - if ((length > 0) && (data.size() != length)) { - ::SetLastError(ERROR_HANDLE_EOF); - } - - if (not data.empty()) { - ::CopyMemory(buffer, data.data(), data.size()); - data.clear(); - auto res = provider_.set_item_meta( - api_path, META_ACCESSED, - std::to_string(utils::time::get_time_now())); - if (res != api_error::success) { - utils::error::raise_api_path_error( - function_name, api_path, res, - "failed to set meta accessed time"); - } - } - } - } - } else { - error = api_error::success; - } + if (handle == 0U || not fm_->get_open_file(handle, false, file)) { + return handle_error(api_error::invalid_handle); } - auto ret = utils::from_api_error(error); - if (ret != STATUS_SUCCESS) { - RAISE_WINFSP_EVENT(function_name, api_path, ret); + api_path = file->get_api_path(); + + if (length == 0U) { + return handle_error(api_error::success); } - return ret; + data_buffer data; + auto res = file->read(length, offset, data); + if (res != api_error::success) { + return handle_error(res); + } + + *bytes_transferred = static_cast(data.size()); + if ((length > 0) && (data.size() != length)) { + ::SetLastError(ERROR_HANDLE_EOF); + } + + if (data.empty()) { + return handle_error(api_error::success); + } + + ::CopyMemory(buffer, data.data(), data.size()); + data.clear(); + + return handle_error( + provider_.set_item_meta(api_path, META_ACCESSED, + std::to_string(utils::time::get_time_now())), + true); } auto winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc, @@ -920,7 +933,7 @@ auto winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc, continue; } - const auto display_name = utils::string::from_utf8( + auto display_name = utils::string::from_utf8( utils::path::strip_to_file_name(dir_item.api_path)); union { UINT8 B[FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + @@ -977,29 +990,41 @@ auto winfsp_drive::Rename(PVOID /*file_node*/, PVOID /*file_desc*/, BOOLEAN replace_if_exists) -> NTSTATUS { REPERTORY_USES_FUNCTION_NAME(); - const auto from_api_path = + std::string api_path; + + auto from_api_path = utils::path::create_api_path(utils::string::to_utf8(file_name)); - const auto to_api_path = + + auto to_api_path = utils::path::create_api_path(utils::string::to_utf8(new_file_name)); - auto error = api_error::item_not_found; + const auto handle_error = [this, &from_api_path, + &to_api_path](api_error error) -> NTSTATUS { + return this->handle_error(function_name, from_api_path + '|' + to_api_path, + error, nullptr, 0U); + }; + bool exists{}; - error = provider_.is_file(from_api_path, exists); - if (error == api_error::success) { - if (exists) { - error = - fm_->rename_file(from_api_path, to_api_path, replace_if_exists != 0U); - } else { - error = provider_.is_directory(from_api_path, exists); - if (error == api_error::success && exists) { - error = fm_->rename_directory(from_api_path, to_api_path); - } - } + auto res = provider_.is_file(from_api_path, exists); + if res != api_error::success) { + return handle_error(res); } - auto ret = utils::from_api_error(error); - RAISE_WINFSP_EVENT(function_name, from_api_path + "|" + to_api_path, ret); - return ret; + if (exists) { + return handle_error( + fm_->rename_file(from_api_path, to_api_path, replace_if_exists != 0U)); + } + + res = provider_.is_directory(from_api_path, exists); + if (res != api_error::success) { + return handle_error(res); + } + + if (exists) { + return handle_error(fm_->rename_directory(from_api_path, to_api_path)); + } + + return handle_error(api_error::item_not_found); } auto winfsp_drive::SetBasicInfo(PVOID /*file_node*/, PVOID file_desc, @@ -1010,61 +1035,60 @@ auto winfsp_drive::SetBasicInfo(PVOID /*file_node*/, PVOID file_desc, REPERTORY_USES_FUNCTION_NAME(); std::string api_path; - auto error = api_error::invalid_handle; + std::shared_ptr file; + const auto handle_error = [this, &api_path, &file, + &file_info](api_error error) -> NTSTATUS { + return this->handle_error(function_name, api_path, error, file_info, + file ? file->get_file_size() : 0U); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - std::shared_ptr file; - if (fm_->get_open_file(handle, false, file)) { - api_path = file->get_api_path(); - if (attributes == INVALID_FILE_ATTRIBUTES) { - attributes = 0U; - } else if (attributes == 0U) { - attributes = file->is_directory() ? FILE_ATTRIBUTE_DIRECTORY - : FILE_ATTRIBUTE_ARCHIVE; - } - - api_meta_map meta; - if (attributes != 0U) { - auto next_attributes = - attributes & static_cast(~FILE_ATTRIBUTE_NORMAL); - if (next_attributes == 0U) { - next_attributes = attributes; - } - meta[META_ATTRIBUTES] = std::to_string(next_attributes); - } - if ((creation_time != 0U) && (creation_time != max_time)) { - meta[META_CREATION] = std::to_string( - utils::time::windows_time_to_unix_time(creation_time)); - } - if ((last_access_time != 0U) && (last_access_time != max_time)) { - meta[META_ACCESSED] = std::to_string( - utils::time::windows_time_to_unix_time(last_access_time)); - } - if ((last_write_time != 0U) && (last_write_time != max_time)) { - meta[META_WRITTEN] = std::to_string( - utils::time::windows_time_to_unix_time(last_write_time)); - } - if ((change_time != 0U) && (change_time != max_time)) { - meta[META_CHANGED] = - std::to_string(utils::time::windows_time_to_unix_time(change_time)); - meta[META_MODIFIED] = - std::to_string(utils::time::windows_time_to_unix_time(change_time)); - } - - error = provider_.set_item_meta(api_path, meta); - - // Populate file information - if (provider_.get_item_meta(api_path, meta) == api_error::success) { - populate_file_info(utils::string::to_uint64(meta[META_SIZE]), meta, - *file_info); - } - } + if (handle == 0U || not fm_->get_open_file(handle, true, file)) { + return handle_error(api_error::invalid_handle); } - auto ret = utils::from_api_error(error); - RAISE_WINFSP_EVENT(function_name, api_path, ret); - return ret; + api_path = file->get_api_path(); + if (attributes == INVALID_FILE_ATTRIBUTES) { + attributes = 0U; + } else if (attributes == 0U) { + attributes = file->is_directory() ? FILE_ATTRIBUTE_DIRECTORY + : FILE_ATTRIBUTE_ARCHIVE; + } + + api_meta_map meta; + if (attributes != 0U) { + auto next_attributes = + attributes & static_cast(~FILE_ATTRIBUTE_NORMAL); + if (next_attributes == 0U) { + next_attributes = attributes; + } + meta[META_ATTRIBUTES] = std::to_string(next_attributes); + } + + if ((creation_time != 0U) && (creation_time != max_time)) { + meta[META_CREATION] = + std::to_string(utils::time::windows_time_to_unix_time(creation_time)); + } + + if ((last_access_time != 0U) && (last_access_time != max_time)) { + meta[META_ACCESSED] = std::to_string( + utils::time::windows_time_to_unix_time(last_access_time)); + } + + if ((last_write_time != 0U) && (last_write_time != max_time)) { + meta[META_WRITTEN] = + std::to_string(utils::time::windows_time_to_unix_time(last_write_time)); + } + + if ((change_time != 0U) && (change_time != max_time)) { + meta[META_CHANGED] = + std::to_string(utils::time::windows_time_to_unix_time(change_time)); + meta[META_MODIFIED] = + std::to_string(utils::time::windows_time_to_unix_time(change_time)); + } + + return handle_error(provider_.set_item_meta(api_path, meta)); } void winfsp_drive::set_file_info(remote::file_info &dest, @@ -1090,19 +1114,9 @@ auto winfsp_drive::SetFileSize(PVOID /*file_node*/, PVOID file_desc, std::string api_path; std::shared_ptr file; const auto handle_error = [this, &api_path, &file, - &file_info](auto error) -> NTSTATUS { - auto ret = utils::from_api_error(error); - RAISE_WINFSP_EVENT(function_name, api_path, ret); - - if (file_info != nullptr && file && error == api_error::success) { - // Populate file information - api_meta_map meta; - if (provider_.get_item_meta(api_path, meta) == api_error::success) { - populate_file_info(file->get_file_size(), meta, *file_info); - } - } - - return ret; + &file_info](api_error error) -> NTSTATUS { + return this->handle_error(function_name, api_path, error, file_info, + file ? file->get_file_size() : 0U); }; auto handle = @@ -1146,8 +1160,7 @@ VOID winfsp_drive::Unmounted(PVOID host) { REPERTORY_USES_FUNCTION_NAME(); auto *file_system_host = reinterpret_cast(host); - const auto mount_location = - parse_mount_location(file_system_host->MountPoint()); + auto mount_location = parse_mount_location(file_system_host->MountPoint()); event_system::instance().raise(mount_location); if (remote_server_) { remote_server_.reset(); @@ -1180,55 +1193,50 @@ auto winfsp_drive::Write(PVOID /*file_node*/, PVOID file_desc, PVOID buffer, *bytes_transferred = 0; std::string api_path; - auto error = api_error::invalid_handle; + std::shared_ptr file; + const auto handle_error = [this, &api_path, &file, + &file_info](api_error error) -> NTSTATUS { + return this->handle_error(function_name, api_path, error, file_info, + file ? file->get_file_size() : 0U, true); + }; + auto handle = static_cast(reinterpret_cast(file_desc)); - if (handle != 0U) { - std::shared_ptr file; - if (fm_->get_open_file(handle, true, file)) { - api_path = file->get_api_path(); - if (write_to_end != 0U) { - offset = file->get_file_size(); - } + if (handle == 0U || not fm_->get_open_file(handle, true, file)) { + return handle_error(api_error::invalid_handle); + } - auto should_write = true; - if (constrained_io != 0U) { - if (offset >= file->get_file_size()) { - error = api_error::success; - should_write = false; - } else if (offset + length > file->get_file_size()) { - length = static_cast(file->get_file_size() - offset); - } - } + api_path = file->get_api_path(); + if (write_to_end != 0U) { + offset = file->get_file_size(); + } - if (should_write) { - if (length > 0U) { - std::size_t bytes_written{}; - data_buffer data(length); - std::memcpy(data.data(), buffer, length); - error = file->write(offset, data, bytes_written); - if (error == api_error::success) { - *bytes_transferred = static_cast(bytes_written); + auto should_write{true}; + if (constrained_io != 0U) { + if (offset >= file->get_file_size()) { + return handle_error(api_error::success); + } - // Populate file information - api_meta_map meta; - if (provider_.get_item_meta(api_path, meta) == api_error::success) { - populate_file_info(file->get_file_size(), meta, *file_info); - } - } - } - } else { - error = api_error::success; - } + if (offset + length > file->get_file_size()) { + length = static_cast(file->get_file_size() - offset); } } - auto ret = utils::from_api_error(error); - if (ret != STATUS_SUCCESS) { - RAISE_WINFSP_EVENT(function_name, api_path, ret); + if (length == 0U) { + return handle_error(api_error::success); } - return ret; + std::size_t bytes_written{}; + data_buffer data(length); + std::memcpy(data.data(), buffer, length); + + auto res = file->write(offset, data, bytes_written); + if (res != api_error::success) { + return handle_error(res); + } + + *bytes_transferred = static_cast(bytes_written); + return handle_error(api_error::success); } } // namespace repertory