Skip to content

Commit d5cea9b

Browse files
committed
Implement DirAccess.is_equivalent method.
1 parent 6b5b84c commit d5cea9b

File tree

7 files changed

+67
-0
lines changed

7 files changed

+67
-0
lines changed

core/io/dir_access.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,10 @@ bool DirAccess::is_case_sensitive(const String &p_path) const {
626626
return true;
627627
}
628628

629+
bool DirAccess::is_equivalent(const String &p_path_a, const String &p_path_b) const {
630+
return p_path_a == p_path_b;
631+
}
632+
629633
void DirAccess::_bind_methods() {
630634
ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
631635
ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
@@ -671,6 +675,7 @@ void DirAccess::_bind_methods() {
671675
ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
672676

673677
ClassDB::bind_method(D_METHOD("is_case_sensitive", "path"), &DirAccess::is_case_sensitive);
678+
ClassDB::bind_method(D_METHOD("is_equivalent", "path_a", "path_b"), &DirAccess::is_equivalent);
674679

675680
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
676681
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");

core/io/dir_access.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ class DirAccess : public RefCounted {
168168

169169
virtual bool is_case_sensitive(const String &p_path) const;
170170
virtual bool is_bundle(const String &p_file) const { return false; }
171+
virtual bool is_equivalent(const String &p_path_a, const String &p_path_b) const;
171172

172173
public:
173174
DirAccess() {}

doc/classes/DirAccess.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,14 @@
248248
[b]Note:[/b] This method is implemented on macOS, Linux (for EXT4 and F2FS filesystems only) and Windows. On other platforms, it always returns [code]true[/code].
249249
</description>
250250
</method>
251+
<method name="is_equivalent" qualifiers="const">
252+
<return type="bool" />
253+
<param index="0" name="path_a" type="String" />
254+
<param index="1" name="path_b" type="String" />
255+
<description>
256+
Returns [code]true[/code] if paths [param path_a] and [param path_b] resolve to the same file system object. Returns [code]false[/code] otherwise, even if the files are bit-for-bit identical (e.g., identical copies of the file that are not symbolic links).
257+
</description>
258+
</method>
251259
<method name="is_link">
252260
<return type="bool" />
253261
<param index="0" name="path" type="String" />

drivers/unix/dir_access_unix.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <stdlib.h>
4444
#include <string.h>
4545
#include <sys/ioctl.h>
46+
#include <sys/stat.h>
4647
#include <sys/statvfs.h>
4748

4849
#ifdef HAVE_MNTENT
@@ -544,6 +545,24 @@ bool DirAccessUnix::is_case_sensitive(const String &p_path) const {
544545
return true;
545546
}
546547

548+
bool DirAccessUnix::is_equivalent(const String &p_path_a, const String &p_path_b) const {
549+
String f1 = fix_path(p_path_a);
550+
struct stat st1 = {};
551+
int err = stat(f1.utf8().get_data(), &st1);
552+
if (err) {
553+
return DirAccess::is_equivalent(p_path_a, p_path_b);
554+
}
555+
556+
String f2 = fix_path(p_path_b);
557+
struct stat st2 = {};
558+
err = stat(f2.utf8().get_data(), &st2);
559+
if (err) {
560+
return DirAccess::is_equivalent(p_path_a, p_path_b);
561+
}
562+
563+
return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino);
564+
}
565+
547566
DirAccessUnix::DirAccessUnix() {
548567
dir_stream = nullptr;
549568
_cisdir = false;

drivers/unix/dir_access_unix.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class DirAccessUnix : public DirAccess {
8585
virtual Error create_link(String p_source, String p_target) override;
8686

8787
virtual bool is_case_sensitive(const String &p_path) const override;
88+
virtual bool is_equivalent(const String &p_path_a, const String &p_path_b) const override;
8889

8990
virtual uint64_t get_space_left() override;
9091

drivers/windows/dir_access_windows.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,38 @@ bool DirAccessWindows::is_case_sensitive(const String &p_path) const {
391391
}
392392
}
393393

394+
typedef struct {
395+
ULONGLONG LowPart;
396+
ULONGLONG HighPart;
397+
} GD_FILE_ID_128;
398+
399+
typedef struct {
400+
ULONGLONG VolumeSerialNumber;
401+
GD_FILE_ID_128 FileId;
402+
} GD_FILE_ID_INFO;
403+
404+
bool DirAccessWindows::is_equivalent(const String &p_path_a, const String &p_path_b) const {
405+
String f1 = fix_path(p_path_a);
406+
GD_FILE_ID_INFO st1;
407+
HANDLE h1 = ::CreateFileW((LPCWSTR)(f1.utf16().get_data()), FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
408+
if (h1 == INVALID_HANDLE_VALUE) {
409+
return DirAccess::is_equivalent(p_path_a, p_path_b);
410+
}
411+
::GetFileInformationByHandleEx(h1, (FILE_INFO_BY_HANDLE_CLASS)0x12 /*FileIdInfo*/, &st1, sizeof(st1));
412+
::CloseHandle(h1);
413+
414+
String f2 = fix_path(p_path_b);
415+
GD_FILE_ID_INFO st2;
416+
HANDLE h2 = ::CreateFileW((LPCWSTR)(f2.utf16().get_data()), FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
417+
if (h2 == INVALID_HANDLE_VALUE) {
418+
return DirAccess::is_equivalent(p_path_a, p_path_b);
419+
}
420+
::GetFileInformationByHandleEx(h2, (FILE_INFO_BY_HANDLE_CLASS)0x12 /*FileIdInfo*/, &st2, sizeof(st2));
421+
::CloseHandle(h2);
422+
423+
return (st1.VolumeSerialNumber == st2.VolumeSerialNumber) && (st1.FileId.LowPart == st2.FileId.LowPart) && (st1.FileId.HighPart == st2.FileId.HighPart);
424+
}
425+
394426
bool DirAccessWindows::is_link(String p_file) {
395427
String f = fix_path(p_file);
396428

drivers/windows/dir_access_windows.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class DirAccessWindows : public DirAccess {
8484

8585
virtual String get_filesystem_type() const override;
8686
virtual bool is_case_sensitive(const String &p_path) const override;
87+
virtual bool is_equivalent(const String &p_path_a, const String &p_path_b) const override;
8788

8889
DirAccessWindows();
8990
~DirAccessWindows();

0 commit comments

Comments
 (0)