From 11a7997a6795fae2c7cd6d3f1537e5e2e48e1d80 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Mon, 13 Jun 2022 09:20:40 +0300 Subject: [PATCH] [Windows, 3.x] Add support for handling network share paths. --- core/os/dir_access.cpp | 8 +++++-- core/ustring.cpp | 30 +++++++++++++++++++++++--- core/ustring.h | 1 + drivers/windows/dir_access_windows.cpp | 11 ++++++++-- editor/editor_file_dialog.cpp | 15 ++++++++++--- editor/editor_file_dialog.h | 2 +- scene/gui/file_dialog.cpp | 15 ++++++++++--- scene/gui/file_dialog.h | 2 +- 8 files changed, 69 insertions(+), 15 deletions(-) diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index e1dbea28d23..49233f15681 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -148,14 +148,18 @@ Error DirAccess::make_dir_recursive(String p_dir) { full_dir = full_dir.replace("\\", "/"); - //int slices = full_dir.get_slice_count("/"); - String base; if (full_dir.begins_with("res://")) { base = "res://"; } else if (full_dir.begins_with("user://")) { base = "user://"; + } else if (full_dir.is_network_share_path()) { + int pos = full_dir.find("/", 2); + ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER); + pos = full_dir.find("/", pos + 1); + ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER); + base = full_dir.substr(0, pos + 1); } else if (full_dir.begins_with("/")) { base = "/"; } else if (full_dir.find(":/") != -1) { diff --git a/core/ustring.cpp b/core/ustring.cpp index 5f01f9e2adc..2c294e7a878 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -3268,6 +3268,10 @@ String String::rstrip(const String &p_chars) const { return substr(0, end + 1); } +bool String::is_network_share_path() const { + return begins_with("//") || begins_with("\\\\"); +} + String String::simplify_path() const { String s = *this; String drive; @@ -3280,6 +3284,9 @@ String String::simplify_path() const { } else if (s.begins_with("user://")) { drive = "user://"; s = s.substr(7, s.length()); + } else if (is_network_share_path()) { + drive = s.substr(0, 2); + s = s.substr(2, s.length() - 2); } else if (s.begins_with("/") || s.begins_with("\\")) { drive = s.substr(0, 1); s = s.substr(1, s.length() - 1); @@ -4017,13 +4024,13 @@ bool String::is_rel_path() const { String String::get_base_dir() const { int end = 0; - // url scheme style base + // URL scheme style base. int basepos = find("://"); if (basepos != -1) { end = basepos + 3; } - // windows top level directory base + // Windows top level directory base. if (end == 0) { basepos = find(":/"); if (basepos == -1) { @@ -4034,7 +4041,24 @@ String String::get_base_dir() const { } } - // unix root directory base + // Windows UNC network share path. + if (end == 0) { + if (is_network_share_path()) { + basepos = find("/", 2); + if (basepos == -1) { + basepos = find("\\", 2); + } + int servpos = find("/", basepos + 1); + if (servpos == -1) { + servpos = find("\\", basepos + 1); + } + if (servpos != -1) { + end = servpos + 1; + } + } + } + + // Unix root directory base. if (end == 0) { if (begins_with("/")) { end = 1; diff --git a/core/ustring.h b/core/ustring.h index 4a1d0e27fea..4adfab2b36e 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -329,6 +329,7 @@ public: String get_file() const; static String humanize_size(uint64_t p_size); String simplify_path() const; + bool is_network_share_path() const; String xml_escape(bool p_escape_quotes = false) const; String xml_unescape() const; diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 8b2e32c41f6..8de5908c122 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -159,8 +159,11 @@ Error DirAccessWindows::make_dir(String p_dir) { bool success; int err; - p_dir = "\\\\?\\" + p_dir; //done according to - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx + if (!p_dir.is_network_share_path()) { + p_dir = "\\\\?\\" + p_dir; + // Add "\\?\" to the path to extend max. path length past 248, if it's not a network share UNC path. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx + } success = CreateDirectoryW(p_dir.c_str(), NULL); err = GetLastError(); @@ -344,6 +347,10 @@ uint64_t DirAccessWindows::get_space_left() { String DirAccessWindows::get_filesystem_type() const { String path = fix_path(const_cast(this)->get_current_dir()); + if (path.is_network_share_path()) { + return "Network Share"; + } + int unit_end = path.find(":"); ERR_FAIL_COND_V(unit_end == -1, String()); String unit = path.substr(0, unit_end + 1) + "\\"; diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 1118d0c7ed8..0476b1f8b60 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -203,7 +203,14 @@ Vector EditorFileDialog::get_selected_files() const { void EditorFileDialog::update_dir() { if (drives->is_visible()) { - drives->select(dir_access->get_current_drive()); + if (dir_access->get_current_dir().is_network_share_path()) { + _update_drives(false); + drives->add_item(RTR("Network")); + drives->set_item_disabled(drives->get_item_count() - 1, true); + drives->select(drives->get_item_count() - 1); + } else { + drives->select(dir_access->get_current_drive()); + } } dir->set_text(dir_access->get_current_dir_without_drive()); @@ -1125,7 +1132,7 @@ void EditorFileDialog::_select_drive(int p_idx) { _push_history(); } -void EditorFileDialog::_update_drives() { +void EditorFileDialog::_update_drives(bool p_select) { int dc = dir_access->get_drive_count(); if (dc == 0 || access != ACCESS_FILESYSTEM) { drives->hide(); @@ -1144,7 +1151,9 @@ void EditorFileDialog::_update_drives() { drives->add_item(dir_access->get_drive(i)); } - drives->select(dir_access->get_current_drive()); + if (p_select) { + drives->select(dir_access->get_current_drive()); + } } } diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 49c4f016ced..be79aacfa67 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -179,7 +179,7 @@ private: void _delete_items(); - void _update_drives(); + void _update_drives(bool p_select = true); void _go_up(); void _go_back(); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index c1e33789479..2f6ccc6538a 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -129,7 +129,14 @@ void FileDialog::update_dir() { dir->set_text(dir_access->get_current_dir_without_drive()); if (drives->is_visible()) { - drives->select(dir_access->get_current_drive()); + if (dir_access->get_current_dir().is_network_share_path()) { + _update_drives(false); + drives->add_item(RTR("Network")); + drives->set_item_disabled(drives->get_item_count() - 1, true); + drives->select(drives->get_item_count() - 1); + } else { + drives->select(dir_access->get_current_drive()); + } } // Deselect any item, to make "Select Current Folder" button text by default. @@ -749,7 +756,7 @@ void FileDialog::_select_drive(int p_idx) { update_dir(); } -void FileDialog::_update_drives() { +void FileDialog::_update_drives(bool p_select) { int dc = dir_access->get_drive_count(); if (dc == 0 || access != ACCESS_FILESYSTEM) { drives->hide(); @@ -767,7 +774,9 @@ void FileDialog::_update_drives() { drives->add_item(dir_access->get_drive(i)); } - drives->select(dir_access->get_current_drive()); + if (p_select) { + drives->select(dir_access->get_current_drive()); + } } } diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index dcc99e7297d..11fba15b9d8 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -121,7 +121,7 @@ private: void _make_dir_confirm(); void _go_up(); - void _update_drives(); + void _update_drives(bool p_select = true); void _unhandled_input(const Ref &p_event);