diff options
Diffstat (limited to 'drivers/windows/file_access_windows.cpp')
-rw-r--r-- | drivers/windows/file_access_windows.cpp | 72 |
1 files changed, 43 insertions, 29 deletions
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 9885d9d7ee..f6f721639c 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -73,8 +73,18 @@ bool FileAccessWindows::is_path_invalid(const String &p_path) { String FileAccessWindows::fix_path(const String &p_path) const { String r_path = FileAccess::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("/", "\\"); + + if (r_path.is_relative_path()) { + Char16String current_dir_name; + size_t str_len = GetCurrentDirectoryW(0, nullptr); + current_dir_name.resize(str_len + 1); + GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); + r_path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(r_path); + } + 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; } @@ -108,9 +118,6 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) { return ERR_INVALID_PARAMETER; } - /* Pretty much every implementation that uses fopen as primary - backend supports utf8 encoding. */ - struct _stat st; if (_wstat((LPCWSTR)(path.utf16().get_data()), &st) == 0) { if (!S_ISREG(st.st_mode)) { @@ -125,7 +132,7 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) { // platforms), we only check for relative paths, or paths in res:// or user://, // other paths aren't likely to be portable anyway. if (p_mode_flags == READ && (p_path.is_relative_path() || get_access_type() != ACCESS_FILESYSTEM)) { - String base_path = path; + String base_path = p_path; String working_path; String proper_path; @@ -144,23 +151,17 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) { } proper_path = "user://"; } + working_path = fix_path(working_path); WIN32_FIND_DATAW d; - Vector<String> parts = base_path.split("/"); + Vector<String> parts = base_path.simplify_path().split("/"); bool mismatch = false; for (const String &part : parts) { - working_path = working_path.path_join(part); - - // Skip if relative. - if (part == "." || part == "..") { - proper_path = proper_path.path_join(part); - continue; - } + working_path = working_path + "\\" + part; HANDLE fnd = FindFirstFileW((LPCWSTR)(working_path.utf16().get_data()), &d); - if (fnd == INVALID_HANDLE_VALUE) { mismatch = false; break; @@ -186,12 +187,22 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) { if (is_backup_save_enabled() && p_mode_flags == WRITE) { save_path = path; // Create a temporary file in the same directory as the target file. - WCHAR tmpFileName[MAX_PATH]; - if (GetTempFileNameW((LPCWSTR)(path.get_base_dir().utf16().get_data()), (LPCWSTR)(path.get_file().utf16().get_data()), 0, tmpFileName) == 0) { - last_error = ERR_FILE_CANT_OPEN; - return last_error; + // Note: do not use GetTempFileNameW, it's not long path aware! + String tmpfile; + uint64_t id = OS::get_singleton()->get_ticks_usec(); + while (true) { + tmpfile = path + itos(id++) + ".tmp"; + 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) { + last_error = ERR_FILE_CANT_WRITE; + return FAILED; + } } - path = tmpFileName; + path = tmpfile; } f = _wfsopen((LPCWSTR)(path.utf16().get_data()), mode_string, is_backup_save_enabled() ? _SH_SECURE : _SH_DENYNO); @@ -235,7 +246,7 @@ void FileAccessWindows::_close() { } else { // Either the target exists and is locked (temporarily, hopefully) // or it doesn't exist; let's assume the latter before re-trying. - rename_error = _wrename((LPCWSTR)(path_utf16.get_data()), (LPCWSTR)(save_path_utf16.get_data())) != 0; + rename_error = MoveFileW((LPCWSTR)(path_utf16.get_data()), (LPCWSTR)(save_path_utf16.get_data())) == 0; } if (!rename_error) { @@ -262,7 +273,7 @@ String FileAccessWindows::get_path() const { } String FileAccessWindows::get_path_absolute() const { - return path; + return path.trim_prefix(R"(\\?\)").replace("\\", "/"); } bool FileAccessWindows::is_open() const { @@ -548,10 +559,11 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) { return 0; } - String file = fix_path(p_file); + String file = p_file; if (file.ends_with("/") && file != "/") { file = file.substr(0, file.length() - 1); } + file = fix_path(file); struct _stat st; int rv = _wstat((LPCWSTR)(file.utf16().get_data()), &st); @@ -582,14 +594,15 @@ bool FileAccessWindows::_get_hidden_attribute(const String &p_file) { Error FileAccessWindows::_set_hidden_attribute(const String &p_file, bool p_hidden) { String file = fix_path(p_file); + const Char16String &file_utf16 = file.utf16(); - DWORD attrib = GetFileAttributesW((LPCWSTR)file.utf16().get_data()); + DWORD attrib = GetFileAttributesW((LPCWSTR)file_utf16.get_data()); ERR_FAIL_COND_V_MSG(attrib == INVALID_FILE_ATTRIBUTES, FAILED, "Failed to get attributes for: " + p_file); BOOL ok; if (p_hidden) { - ok = SetFileAttributesW((LPCWSTR)file.utf16().get_data(), attrib | FILE_ATTRIBUTE_HIDDEN); + ok = SetFileAttributesW((LPCWSTR)file_utf16.get_data(), attrib | FILE_ATTRIBUTE_HIDDEN); } else { - ok = SetFileAttributesW((LPCWSTR)file.utf16().get_data(), attrib & ~FILE_ATTRIBUTE_HIDDEN); + ok = SetFileAttributesW((LPCWSTR)file_utf16.get_data(), attrib & ~FILE_ATTRIBUTE_HIDDEN); } ERR_FAIL_COND_V_MSG(!ok, FAILED, "Failed to set attributes for: " + p_file); @@ -606,14 +619,15 @@ bool FileAccessWindows::_get_read_only_attribute(const String &p_file) { Error FileAccessWindows::_set_read_only_attribute(const String &p_file, bool p_ro) { String file = fix_path(p_file); + const Char16String &file_utf16 = file.utf16(); - DWORD attrib = GetFileAttributesW((LPCWSTR)file.utf16().get_data()); + DWORD attrib = GetFileAttributesW((LPCWSTR)file_utf16.get_data()); ERR_FAIL_COND_V_MSG(attrib == INVALID_FILE_ATTRIBUTES, FAILED, "Failed to get attributes for: " + p_file); BOOL ok; if (p_ro) { - ok = SetFileAttributesW((LPCWSTR)file.utf16().get_data(), attrib | FILE_ATTRIBUTE_READONLY); + ok = SetFileAttributesW((LPCWSTR)file_utf16.get_data(), attrib | FILE_ATTRIBUTE_READONLY); } else { - ok = SetFileAttributesW((LPCWSTR)file.utf16().get_data(), attrib & ~FILE_ATTRIBUTE_READONLY); + ok = SetFileAttributesW((LPCWSTR)file_utf16.get_data(), attrib & ~FILE_ATTRIBUTE_READONLY); } ERR_FAIL_COND_V_MSG(!ok, FAILED, "Failed to set attributes for: " + p_file); |