Add method to check if filesystem is case sensitive.
This commit is contained in:
parent
6916349697
commit
97bcd8a631
|
@ -546,6 +546,10 @@ bool DirAccess::get_include_hidden() const {
|
||||||
return include_hidden;
|
return include_hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DirAccess::is_case_sensitive(const String &p_path) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void DirAccess::_bind_methods() {
|
void DirAccess::_bind_methods() {
|
||||||
ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
|
ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
|
||||||
ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
|
ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
|
||||||
|
@ -583,6 +587,8 @@ void DirAccess::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
|
ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
|
||||||
ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
|
ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("is_case_sensitive", "path"), &DirAccess::is_case_sensitive);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,8 @@ public:
|
||||||
void set_include_hidden(bool p_enable);
|
void set_include_hidden(bool p_enable);
|
||||||
bool get_include_hidden() const;
|
bool get_include_hidden() const;
|
||||||
|
|
||||||
|
virtual bool is_case_sensitive(const String &p_path) const;
|
||||||
|
|
||||||
DirAccess() {}
|
DirAccess() {}
|
||||||
virtual ~DirAccess() {}
|
virtual ~DirAccess() {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -204,6 +204,14 @@
|
||||||
Returns the available space on the current directory's disk, in bytes. Returns [code]0[/code] if the platform-specific method to query the available space fails.
|
Returns the available space on the current directory's disk, in bytes. Returns [code]0[/code] if the platform-specific method to query the available space fails.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="is_case_sensitive" qualifiers="const">
|
||||||
|
<return type="bool" />
|
||||||
|
<param index="0" name="path" type="String" />
|
||||||
|
<description>
|
||||||
|
Returns [code]true[/code] if the file system or directory use case sensitive file names.
|
||||||
|
[b]Note:[/b] This method is implemented on macOS and Windows. On other platforms, it always returns [code]true[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="list_dir_begin">
|
<method name="list_dir_begin">
|
||||||
<return type="int" enum="Error" />
|
<return type="int" enum="Error" />
|
||||||
<description>
|
<description>
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include "dir_access_windows.h"
|
#include "dir_access_windows.h"
|
||||||
|
|
||||||
|
#include "core/config/project_settings.h"
|
||||||
#include "core/os/memory.h"
|
#include "core/os/memory.h"
|
||||||
#include "core/string/print_string.h"
|
#include "core/string/print_string.h"
|
||||||
|
|
||||||
|
@ -40,6 +41,26 @@
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
typedef struct _NT_IO_STATUS_BLOCK {
|
||||||
|
union {
|
||||||
|
LONG Status;
|
||||||
|
PVOID Pointer;
|
||||||
|
} DUMMY;
|
||||||
|
ULONG_PTR Information;
|
||||||
|
} NT_IO_STATUS_BLOCK;
|
||||||
|
|
||||||
|
typedef struct _NT_FILE_CASE_SENSITIVE_INFO {
|
||||||
|
ULONG Flags;
|
||||||
|
} NT_FILE_CASE_SENSITIVE_INFO;
|
||||||
|
|
||||||
|
typedef enum _NT_FILE_INFORMATION_CLASS {
|
||||||
|
FileCaseSensitiveInformation = 71,
|
||||||
|
} NT_FILE_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
#define NT_FILE_CS_FLAG_CASE_SENSITIVE_DIR 0x00000001
|
||||||
|
|
||||||
|
extern "C" NTSYSAPI LONG NTAPI NtQueryInformationFile(HANDLE FileHandle, NT_IO_STATUS_BLOCK *IoStatusBlock, PVOID FileInformation, ULONG Length, NT_FILE_INFORMATION_CLASS FileInformationClass);
|
||||||
|
|
||||||
struct DirAccessWindowsPrivate {
|
struct DirAccessWindowsPrivate {
|
||||||
HANDLE h; // handle for FindFirstFile.
|
HANDLE h; // handle for FindFirstFile.
|
||||||
WIN32_FIND_DATA f;
|
WIN32_FIND_DATA f;
|
||||||
|
@ -340,6 +361,33 @@ String DirAccessWindows::get_filesystem_type() const {
|
||||||
ERR_FAIL_V("");
|
ERR_FAIL_V("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
HANDLE h_file = ::CreateFileW((LPCWSTR)(f.utf16().get_data()), 0,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||||
|
|
||||||
|
if (h_file == INVALID_HANDLE_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NT_IO_STATUS_BLOCK io_status_block;
|
||||||
|
NT_FILE_CASE_SENSITIVE_INFO file_info;
|
||||||
|
LONG out = NtQueryInformationFile(h_file, &io_status_block, &file_info, sizeof(NT_FILE_CASE_SENSITIVE_INFO), FileCaseSensitiveInformation);
|
||||||
|
::CloseHandle(h_file);
|
||||||
|
|
||||||
|
if (out >= 0) {
|
||||||
|
return file_info.Flags & NT_FILE_CS_FLAG_CASE_SENSITIVE_DIR;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DirAccessWindows::DirAccessWindows() {
|
DirAccessWindows::DirAccessWindows() {
|
||||||
p = memnew(DirAccessWindowsPrivate);
|
p = memnew(DirAccessWindowsPrivate);
|
||||||
p->h = INVALID_HANDLE_VALUE;
|
p->h = INVALID_HANDLE_VALUE;
|
||||||
|
|
|
@ -84,6 +84,7 @@ public:
|
||||||
uint64_t get_space_left() override;
|
uint64_t get_space_left() override;
|
||||||
|
|
||||||
virtual String get_filesystem_type() const override;
|
virtual String get_filesystem_type() const override;
|
||||||
|
virtual bool is_case_sensitive(const String &p_path) const override;
|
||||||
|
|
||||||
DirAccessWindows();
|
DirAccessWindows();
|
||||||
~DirAccessWindows();
|
~DirAccessWindows();
|
||||||
|
|
|
@ -1776,12 +1776,12 @@ void FileSystemDock::_rename_operation_confirm() {
|
||||||
|
|
||||||
// Present a more user friendly warning for name conflict.
|
// Present a more user friendly warning for name conflict.
|
||||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||||
#if defined(WINDOWS_ENABLED)
|
|
||||||
// Workaround case insensitivity on Windows.
|
bool new_exist = (da->file_exists(new_path) || da->dir_exists(new_path));
|
||||||
if ((da->file_exists(new_path) || da->dir_exists(new_path)) && new_path.to_lower() != old_path.to_lower()) {
|
if (!da->is_case_sensitive(new_path.get_base_dir())) {
|
||||||
#else
|
new_exist = new_exist && (new_path.to_lower() != old_path.to_lower());
|
||||||
if (da->file_exists(new_path) || da->dir_exists(new_path)) {
|
}
|
||||||
#endif
|
if (new_exist) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists."));
|
EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists."));
|
||||||
s->set_text(col_index, old_name);
|
s->set_text(col_index, old_name);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -49,6 +49,7 @@ protected:
|
||||||
virtual String get_drive(int p_drive) override;
|
virtual String get_drive(int p_drive) override;
|
||||||
|
|
||||||
virtual bool is_hidden(const String &p_name) override;
|
virtual bool is_hidden(const String &p_name) override;
|
||||||
|
virtual bool is_case_sensitive(const String &p_path) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // UNIX ENABLED
|
#endif // UNIX ENABLED
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include "dir_access_macos.h"
|
#include "dir_access_macos.h"
|
||||||
|
|
||||||
|
#include "core/config/project_settings.h"
|
||||||
|
|
||||||
#if defined(UNIX_ENABLED)
|
#if defined(UNIX_ENABLED)
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -78,4 +80,19 @@ bool DirAccessMacOS::is_hidden(const String &p_name) {
|
||||||
return [hidden boolValue];
|
return [hidden boolValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DirAccessMacOS::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);
|
||||||
|
|
||||||
|
NSURL *url = [NSURL fileURLWithPath:@(f.utf8().get_data())];
|
||||||
|
NSNumber *cs = nil;
|
||||||
|
if (![url getResourceValue:&cs forKey:NSURLVolumeSupportsCaseSensitiveNamesKey error:nil]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return [cs boolValue];
|
||||||
|
}
|
||||||
|
|
||||||
#endif // UNIX_ENABLED
|
#endif // UNIX_ENABLED
|
||||||
|
|
|
@ -419,6 +419,7 @@ def configure_msvc(env, vcvars_msvc_config):
|
||||||
"dwmapi",
|
"dwmapi",
|
||||||
"dwrite",
|
"dwrite",
|
||||||
"wbemuuid",
|
"wbemuuid",
|
||||||
|
"ntdll",
|
||||||
]
|
]
|
||||||
|
|
||||||
if env.debug_features:
|
if env.debug_features:
|
||||||
|
@ -610,6 +611,7 @@ def configure_mingw(env):
|
||||||
"dwmapi",
|
"dwmapi",
|
||||||
"dwrite",
|
"dwrite",
|
||||||
"wbemuuid",
|
"wbemuuid",
|
||||||
|
"ntdll",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue