Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to check if filesystem is case sensitive. #82957

Merged
merged 1 commit into from Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions core/io/dir_access.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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 changes: 2 additions & 0 deletions core/io/dir_access.h
Expand Up @@ -159,6 +159,8 @@ class DirAccess : public RefCounted {
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() {}
};
Expand Down
8 changes: 8 additions & 0 deletions doc/classes/DirAccess.xml
Expand Up @@ -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>
Expand Down
48 changes: 48 additions & 0 deletions drivers/windows/dir_access_windows.cpp
Expand Up @@ -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"

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/windows/dir_access_windows.h
Expand Up @@ -84,6 +84,7 @@ class DirAccessWindows : public DirAccess {
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();
Expand Down
12 changes: 6 additions & 6 deletions editor/filesystem_dock.cpp
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions platform/macos/dir_access_macos.h
Expand Up @@ -49,6 +49,7 @@ class DirAccessMacOS : public DirAccessUnix {
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
Expand Down
17 changes: 17 additions & 0 deletions platform/macos/dir_access_macos.mm
Expand Up @@ -30,6 +30,8 @@

#include "dir_access_macos.h"

#include "core/config/project_settings.h"

#if defined(UNIX_ENABLED)

#include <errno.h>
Expand Down Expand Up @@ -78,4 +80,19 @@
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 changes: 2 additions & 0 deletions platform/windows/detect.py
Expand Up @@ -419,6 +419,7 @@ def configure_msvc(env, vcvars_msvc_config):
"dwmapi",
"dwrite",
"wbemuuid",
"ntdll",
]

if env.debug_features:
Expand Down Expand Up @@ -610,6 +611,7 @@ def configure_mingw(env):
"dwmapi",
"dwrite",
"wbemuuid",
"ntdll",
]
)

Expand Down