diff options
Diffstat (limited to 'drivers/windows/dir_access_windows.cpp')
-rw-r--r-- | drivers/windows/dir_access_windows.cpp | 192 |
1 files changed, 89 insertions, 103 deletions
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 63ba6a6c96..f7632842ed 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -35,6 +35,7 @@ #include "core/config/project_settings.h" #include "core/os/memory.h" +#include "core/os/os.h" #include "core/string/print_string.h" #include <stdio.h> @@ -69,9 +70,19 @@ struct DirAccessWindowsPrivate { }; String DirAccessWindows::fix_path(const String &p_path) const { - String r_path = DirAccess::fix_path(p_path); - if (r_path.is_absolute_path() && !r_path.is_network_share_path() && r_path.length() > MAX_PATH) { - r_path = "\\\\?\\" + r_path.replace("/", "\\"); + String r_path = DirAccess::fix_path(p_path.trim_prefix(R"(\\?\)").replace("\\", "/")); + if (r_path.ends_with(":")) { + r_path += "/"; + } + if (r_path.is_relative_path()) { + r_path = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/").path_join(r_path); + } else if (r_path == ".") { + r_path = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/"); + } + r_path = r_path.simplify_path(); + r_path = r_path.replace("/", "\\"); + if (!r_path.is_network_share_path() && !r_path.begins_with(R"(\\?\)")) { + r_path = R"(\\?\)" + r_path; } return r_path; } @@ -140,28 +151,33 @@ String DirAccessWindows::get_drive(int p_drive) { Error DirAccessWindows::change_dir(String p_dir) { GLOBAL_LOCK_FUNCTION - p_dir = fix_path(p_dir); + String dir = fix_path(p_dir); - WCHAR real_current_dir_name[2048]; - GetCurrentDirectoryW(2048, real_current_dir_name); - String prev_dir = String::utf16((const char16_t *)real_current_dir_name); + Char16String real_current_dir_name; + size_t str_len = GetCurrentDirectoryW(0, nullptr); + real_current_dir_name.resize(str_len + 1); + GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw()); + String prev_dir = String::utf16((const char16_t *)real_current_dir_name.get_data()); SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data())); - bool worked = (SetCurrentDirectoryW((LPCWSTR)(p_dir.utf16().get_data())) != 0); + bool worked = (SetCurrentDirectoryW((LPCWSTR)(dir.utf16().get_data())) != 0); String base = _get_root_path(); if (!base.is_empty()) { - GetCurrentDirectoryW(2048, real_current_dir_name); - String new_dir = String::utf16((const char16_t *)real_current_dir_name).replace("\\", "/"); + str_len = GetCurrentDirectoryW(0, nullptr); + real_current_dir_name.resize(str_len + 1); + GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw()); + String new_dir = String::utf16((const char16_t *)real_current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/"); if (!new_dir.begins_with(base)) { worked = false; } } if (worked) { - GetCurrentDirectoryW(2048, real_current_dir_name); - current_dir = String::utf16((const char16_t *)real_current_dir_name); - current_dir = current_dir.replace("\\", "/"); + str_len = GetCurrentDirectoryW(0, nullptr); + real_current_dir_name.resize(str_len + 1); + GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw()); + current_dir = String::utf16((const char16_t *)real_current_dir_name.get_data()); } SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data())); @@ -172,12 +188,6 @@ Error DirAccessWindows::change_dir(String p_dir) { Error DirAccessWindows::make_dir(String p_dir) { GLOBAL_LOCK_FUNCTION - p_dir = fix_path(p_dir); - if (p_dir.is_relative_path()) { - p_dir = current_dir.path_join(p_dir); - p_dir = fix_path(p_dir); - } - if (FileAccessWindows::is_path_invalid(p_dir)) { #ifdef DEBUG_ENABLED WARN_PRINT("The path :" + p_dir + " is a reserved Windows system pipe, so it can't be used for creating directories."); @@ -185,12 +195,12 @@ Error DirAccessWindows::make_dir(String p_dir) { return ERR_INVALID_PARAMETER; } - p_dir = p_dir.simplify_path().replace("/", "\\"); + String dir = fix_path(p_dir); bool success; int err; - success = CreateDirectoryW((LPCWSTR)(p_dir.utf16().get_data()), nullptr); + success = CreateDirectoryW((LPCWSTR)(dir.utf16().get_data()), nullptr); err = GetLastError(); if (success) { @@ -205,9 +215,10 @@ Error DirAccessWindows::make_dir(String p_dir) { } String DirAccessWindows::get_current_dir(bool p_include_drive) const { + String cdir = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/"); String base = _get_root_path(); if (!base.is_empty()) { - String bd = current_dir.replace("\\", "/").replace_first(base, ""); + String bd = cdir.replace_first(base, ""); if (bd.begins_with("/")) { return _get_root_string() + bd.substr(1, bd.length()); } else { @@ -216,30 +227,25 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) const { } if (p_include_drive) { - return current_dir; + return cdir; } else { if (_get_root_string().is_empty()) { - int pos = current_dir.find(":"); + int pos = cdir.find(":"); if (pos != -1) { - return current_dir.substr(pos + 1); + return cdir.substr(pos + 1); } } - return current_dir; + return cdir; } } bool DirAccessWindows::file_exists(String p_file) { GLOBAL_LOCK_FUNCTION - if (!p_file.is_absolute_path()) { - p_file = get_current_dir().path_join(p_file); - } - - p_file = fix_path(p_file); + String file = fix_path(p_file); DWORD fileAttr; - - fileAttr = GetFileAttributesW((LPCWSTR)(p_file.utf16().get_data())); + fileAttr = GetFileAttributesW((LPCWSTR)(file.utf16().get_data())); if (INVALID_FILE_ATTRIBUTES == fileAttr) { return false; } @@ -250,14 +256,10 @@ bool DirAccessWindows::file_exists(String p_file) { bool DirAccessWindows::dir_exists(String p_dir) { GLOBAL_LOCK_FUNCTION - if (p_dir.is_relative_path()) { - p_dir = get_current_dir().path_join(p_dir); - } - - p_dir = fix_path(p_dir); + String dir = fix_path(p_dir); DWORD fileAttr; - fileAttr = GetFileAttributesW((LPCWSTR)(p_dir.utf16().get_data())); + fileAttr = GetFileAttributesW((LPCWSTR)(dir.utf16().get_data())); if (INVALID_FILE_ATTRIBUTES == fileAttr) { return false; } @@ -265,66 +267,63 @@ bool DirAccessWindows::dir_exists(String p_dir) { } Error DirAccessWindows::rename(String p_path, String p_new_path) { - if (p_path.is_relative_path()) { - p_path = get_current_dir().path_join(p_path); - } - - p_path = fix_path(p_path); - - if (p_new_path.is_relative_path()) { - p_new_path = get_current_dir().path_join(p_new_path); - } - - p_new_path = fix_path(p_new_path); + String path = fix_path(p_path); + String new_path = fix_path(p_new_path); // If we're only changing file name case we need to do a little juggling - if (p_path.to_lower() == p_new_path.to_lower()) { - if (dir_exists(p_path)) { + if (path.to_lower() == new_path.to_lower()) { + if (dir_exists(path)) { // The path is a dir; just rename - return ::_wrename((LPCWSTR)(p_path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED; + return MoveFileW((LPCWSTR)(path.utf16().get_data()), (LPCWSTR)(new_path.utf16().get_data())) != 0 ? OK : FAILED; } // The path is a file; juggle - WCHAR tmpfile[MAX_PATH]; - - if (!GetTempFileNameW((LPCWSTR)(fix_path(get_current_dir()).utf16().get_data()), nullptr, 0, tmpfile)) { - return FAILED; + // Note: do not use GetTempFileNameW, it's not long path aware! + Char16String tmpfile_utf16; + uint64_t id = OS::get_singleton()->get_ticks_usec(); + while (true) { + tmpfile_utf16 = (path + itos(id++) + ".tmp").utf16(); + HANDLE handle = CreateFileW((LPCWSTR)tmpfile_utf16.get_data(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + break; + } + if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_SHARING_VIOLATION) { + return FAILED; + } } - if (!::ReplaceFileW(tmpfile, (LPCWSTR)(p_path.utf16().get_data()), nullptr, 0, nullptr, nullptr)) { - DeleteFileW(tmpfile); + if (!::ReplaceFileW((LPCWSTR)tmpfile_utf16.get_data(), (LPCWSTR)(path.utf16().get_data()), nullptr, 0, nullptr, nullptr)) { + DeleteFileW((LPCWSTR)tmpfile_utf16.get_data()); return FAILED; } - return ::_wrename(tmpfile, (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED; + return MoveFileW((LPCWSTR)tmpfile_utf16.get_data(), (LPCWSTR)(new_path.utf16().get_data())) != 0 ? OK : FAILED; } else { - if (file_exists(p_new_path)) { - if (remove(p_new_path) != OK) { + if (file_exists(new_path)) { + if (remove(new_path) != OK) { return FAILED; } } - return ::_wrename((LPCWSTR)(p_path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED; + return MoveFileW((LPCWSTR)(path.utf16().get_data()), (LPCWSTR)(new_path.utf16().get_data())) != 0 ? OK : FAILED; } } Error DirAccessWindows::remove(String p_path) { - if (p_path.is_relative_path()) { - p_path = get_current_dir().path_join(p_path); - } - - p_path = fix_path(p_path); + String path = fix_path(p_path); + const Char16String &path_utf16 = path.utf16(); DWORD fileAttr; - fileAttr = GetFileAttributesW((LPCWSTR)(p_path.utf16().get_data())); + fileAttr = GetFileAttributesW((LPCWSTR)(path_utf16.get_data())); if (INVALID_FILE_ATTRIBUTES == fileAttr) { return FAILED; } if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY)) { - return ::_wrmdir((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED; + return RemoveDirectoryW((LPCWSTR)(path_utf16.get_data())) != 0 ? OK : FAILED; } else { - return ::_wunlink((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED; + return DeleteFileW((LPCWSTR)(path_utf16.get_data())) != 0 ? OK : FAILED; } } @@ -339,16 +338,16 @@ uint64_t DirAccessWindows::get_space_left() { } String DirAccessWindows::get_filesystem_type() const { - String path = fix_path(const_cast<DirAccessWindows *>(this)->get_current_dir()); - - int unit_end = path.find(":"); - ERR_FAIL_COND_V(unit_end == -1, String()); - String unit = path.substr(0, unit_end + 1) + "\\"; + String path = current_dir.trim_prefix(R"(\\?\)"); 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) + "\\"; + WCHAR szVolumeName[100]; WCHAR szFileSystemName[10]; DWORD dwSerialNumber = 0; @@ -370,11 +369,7 @@ String DirAccessWindows::get_filesystem_type() const { } bool DirAccessWindows::is_case_sensitive(const String &p_path) const { - String f = p_path; - if (!f.is_absolute_path()) { - f = get_current_dir().path_join(f); - } - f = fix_path(f); + String f = fix_path(p_path); HANDLE h_file = ::CreateFileW((LPCWSTR)(f.utf16().get_data()), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -397,12 +392,7 @@ bool DirAccessWindows::is_case_sensitive(const String &p_path) const { } bool DirAccessWindows::is_link(String p_file) { - String f = p_file; - - if (!f.is_absolute_path()) { - f = get_current_dir().path_join(f); - } - f = fix_path(f); + String f = fix_path(p_file); DWORD attr = GetFileAttributesW((LPCWSTR)(f.utf16().get_data())); if (attr == INVALID_FILE_ATTRIBUTES) { @@ -413,12 +403,7 @@ bool DirAccessWindows::is_link(String p_file) { } String DirAccessWindows::read_link(String p_file) { - String f = p_file; - - if (!f.is_absolute_path()) { - f = get_current_dir().path_join(f); - } - f = fix_path(f); + String f = fix_path(p_file); HANDLE hfile = CreateFileW((LPCWSTR)(f.utf16().get_data()), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (hfile == INVALID_HANDLE_VALUE) { @@ -434,22 +419,18 @@ String DirAccessWindows::read_link(String p_file) { GetFinalPathNameByHandleW(hfile, (LPWSTR)cs.ptrw(), ret, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED); CloseHandle(hfile); - return String::utf16((const char16_t *)cs.ptr(), ret).trim_prefix(R"(\\?\)"); + return String::utf16((const char16_t *)cs.ptr(), ret).trim_prefix(R"(\\?\)").replace("\\", "/"); } Error DirAccessWindows::create_link(String p_source, String p_target) { - if (p_target.is_relative_path()) { - p_target = get_current_dir().path_join(p_target); - } + String source = fix_path(p_source); + String target = fix_path(p_target); - p_source = fix_path(p_source); - p_target = fix_path(p_target); - - DWORD file_attr = GetFileAttributesW((LPCWSTR)(p_source.utf16().get_data())); + DWORD file_attr = GetFileAttributesW((LPCWSTR)(source.utf16().get_data())); bool is_dir = (file_attr & FILE_ATTRIBUTE_DIRECTORY); DWORD flags = ((is_dir) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; - if (CreateSymbolicLinkW((LPCWSTR)p_target.utf16().get_data(), (LPCWSTR)p_source.utf16().get_data(), flags) != 0) { + if (CreateSymbolicLinkW((LPCWSTR)target.utf16().get_data(), (LPCWSTR)source.utf16().get_data(), flags) != 0) { return OK; } else { return FAILED; @@ -459,7 +440,12 @@ Error DirAccessWindows::create_link(String p_source, String p_target) { DirAccessWindows::DirAccessWindows() { p = memnew(DirAccessWindowsPrivate); p->h = INVALID_HANDLE_VALUE; - current_dir = "."; + + Char16String real_current_dir_name; + size_t str_len = GetCurrentDirectoryW(0, nullptr); + real_current_dir_name.resize(str_len + 1); + GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw()); + current_dir = String::utf16((const char16_t *)real_current_dir_name.get_data()); DWORD mask = GetLogicalDrives(); |