This commit is contained in:
Scott E. Graves 2024-10-28 13:51:24 -05:00
parent d07e1f9cce
commit c22c68ef28
2 changed files with 413 additions and 398 deletions

View File

@ -75,8 +75,14 @@ private:
std::unique_ptr<remote_winfsp::remote_server> 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();

View File

@ -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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
std::shared_ptr<i_open_file> 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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
std::shared_ptr<i_open_file> 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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
PVOID directory_buffer{nullptr};
std::shared_ptr<i_open_file> 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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
error = api_error::invalid_handle;
std::shared_ptr<i_open_file> 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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
std::shared_ptr<i_open_file> 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<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 (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<remote_winfsp::remote_server>(
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<PVOID>(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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
std::shared_ptr<i_open_file> 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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
if (length > 0U) {
std::shared_ptr<i_open_file> 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<ULONG>(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<ULONG>(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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
std::shared_ptr<i_open_file> 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<UINT32>(~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<UINT32>(~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<i_open_file> 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<FileSystemHost *>(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<drive_unmount_pending>(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<i_open_file> 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<std::uint64_t>(reinterpret_cast<std::uintptr_t>(file_desc));
if (handle != 0U) {
std::shared_ptr<i_open_file> 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<ULONG>(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<ULONG>(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<ULONG>(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<ULONG>(bytes_written);
return handle_error(api_error::success);
}
} // namespace repertory