Bladeren bron

Add method to check if filesystem is case sensitive.

bruvzg 1 jaar geleden
bovenliggende
commit
97bcd8a631

+ 6 - 0
core/io/dir_access.cpp

@@ -546,6 +546,10 @@ bool DirAccess::get_include_hidden() const {
 	return include_hidden;
 }
 
+bool DirAccess::is_case_sensitive(const String &p_path) const {
+	return true;
+}
+
 void DirAccess::_bind_methods() {
 	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);
@@ -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("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_hidden"), "set_include_hidden", "get_include_hidden");
 }

+ 2 - 0
core/io/dir_access.h

@@ -159,6 +159,8 @@ public:
 	void set_include_hidden(bool p_enable);
 	bool get_include_hidden() const;
 
+	virtual bool is_case_sensitive(const String &p_path) const;
+
 	DirAccess() {}
 	virtual ~DirAccess() {}
 };

+ 8 - 0
doc/classes/DirAccess.xml

@@ -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.
 			</description>
 		</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">
 			<return type="int" enum="Error" />
 			<description>

+ 48 - 0
drivers/windows/dir_access_windows.cpp

@@ -32,6 +32,7 @@
 
 #include "dir_access_windows.h"
 
+#include "core/config/project_settings.h"
 #include "core/os/memory.h"
 #include "core/string/print_string.h"
 
@@ -40,6 +41,26 @@
 #define WIN32_LEAN_AND_MEAN
 #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 {
 	HANDLE h; // handle for FindFirstFile.
 	WIN32_FIND_DATA f;
@@ -340,6 +361,33 @@ String DirAccessWindows::get_filesystem_type() const {
 	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() {
 	p = memnew(DirAccessWindowsPrivate);
 	p->h = INVALID_HANDLE_VALUE;

+ 1 - 0
drivers/windows/dir_access_windows.h

@@ -84,6 +84,7 @@ public:
 	uint64_t get_space_left() override;
 
 	virtual String get_filesystem_type() const override;
+	virtual bool is_case_sensitive(const String &p_path) const override;
 
 	DirAccessWindows();
 	~DirAccessWindows();

+ 6 - 6
editor/filesystem_dock.cpp

@@ -1776,12 +1776,12 @@ void FileSystemDock::_rename_operation_confirm() {
 
 	// Present a more user friendly warning for name conflict.
 	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
-#if defined(WINDOWS_ENABLED)
-	// Workaround case insensitivity on Windows.
-	if ((da->file_exists(new_path) || da->dir_exists(new_path)) && new_path.to_lower() != old_path.to_lower()) {
-#else
-	if (da->file_exists(new_path) || da->dir_exists(new_path)) {
-#endif
+
+	bool new_exist = (da->file_exists(new_path) || da->dir_exists(new_path));
+	if (!da->is_case_sensitive(new_path.get_base_dir())) {
+		new_exist = new_exist && (new_path.to_lower() != old_path.to_lower());
+	}
+	if (new_exist) {
 		EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists."));
 		s->set_text(col_index, old_name);
 		return;

+ 1 - 0
platform/macos/dir_access_macos.h

@@ -49,6 +49,7 @@ protected:
 	virtual String get_drive(int p_drive) override;
 
 	virtual bool is_hidden(const String &p_name) override;
+	virtual bool is_case_sensitive(const String &p_path) const override;
 };
 
 #endif // UNIX ENABLED

+ 17 - 0
platform/macos/dir_access_macos.mm

@@ -30,6 +30,8 @@
 
 #include "dir_access_macos.h"
 
+#include "core/config/project_settings.h"
+
 #if defined(UNIX_ENABLED)
 
 #include <errno.h>
@@ -78,4 +80,19 @@ bool DirAccessMacOS::is_hidden(const String &p_name) {
 	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

+ 2 - 0
platform/windows/detect.py

@@ -419,6 +419,7 @@ def configure_msvc(env, vcvars_msvc_config):
         "dwmapi",
         "dwrite",
         "wbemuuid",
+        "ntdll",
     ]
 
     if env.debug_features:
@@ -610,6 +611,7 @@ def configure_mingw(env):
             "dwmapi",
             "dwrite",
             "wbemuuid",
+            "ntdll",
         ]
     )