Skip to content

Commit 3207014

Browse files
committed
Merge pull request godotengine#91100 from bruvzg/x_finks
Add symlink API support for Windows, expose symlink methods.
2 parents 339cb0e + fc948e8 commit 3207014

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

core/io/dir_access.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,10 @@ void DirAccess::_bind_methods() {
582582
ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove);
583583
ClassDB::bind_static_method("DirAccess", D_METHOD("remove_absolute", "path"), &DirAccess::remove_absolute);
584584

585+
ClassDB::bind_method(D_METHOD("is_link", "path"), &DirAccess::is_link);
586+
ClassDB::bind_method(D_METHOD("read_link", "path"), &DirAccess::read_link);
587+
ClassDB::bind_method(D_METHOD("create_link", "source", "target"), &DirAccess::create_link);
588+
585589
ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational);
586590
ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational);
587591
ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);

doc/classes/DirAccess.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@
9494
Static version of [method copy]. Supports only absolute paths.
9595
</description>
9696
</method>
97+
<method name="create_link">
98+
<return type="int" enum="Error" />
99+
<param index="0" name="source" type="String" />
100+
<param index="1" name="target" type="String" />
101+
<description>
102+
Creates symbolic link between files or folders.
103+
[b]Note:[/b] On Windows, this method works only if the application is running with elevated privileges or Developer Mode is enabled.
104+
[b]Note:[/b] This method is implemented on macOS, Linux, and Windows.
105+
</description>
106+
</method>
97107
<method name="current_is_dir" qualifiers="const">
98108
<return type="bool" />
99109
<description>
@@ -212,6 +222,14 @@
212222
[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].
213223
</description>
214224
</method>
225+
<method name="is_link">
226+
<return type="bool" />
227+
<param index="0" name="path" type="String" />
228+
<description>
229+
Returns [code]true[/code] if the file or directory is a symbolic link, directory junction, or other reparse point.
230+
[b]Note:[/b] This method is implemented on macOS, Linux, and Windows.
231+
</description>
232+
</method>
215233
<method name="list_dir_begin">
216234
<return type="int" enum="Error" />
217235
<description>
@@ -264,6 +282,14 @@
264282
Returns [code]null[/code] if opening the directory failed. You can use [method get_open_error] to check the error that occurred.
265283
</description>
266284
</method>
285+
<method name="read_link">
286+
<return type="String" />
287+
<param index="0" name="path" type="String" />
288+
<description>
289+
Returns target of the symbolic link.
290+
[b]Note:[/b] This method is implemented on macOS, Linux, and Windows.
291+
</description>
292+
</method>
267293
<method name="remove">
268294
<return type="int" enum="Error" />
269295
<param index="0" name="path" type="String" />

drivers/windows/dir_access_windows.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,66 @@ bool DirAccessWindows::is_case_sensitive(const String &p_path) const {
396396
}
397397
}
398398

399+
bool DirAccessWindows::is_link(String p_file) {
400+
String f = p_file;
401+
402+
if (!f.is_absolute_path()) {
403+
f = get_current_dir().path_join(f);
404+
}
405+
f = fix_path(f);
406+
407+
DWORD attr = GetFileAttributesW((LPCWSTR)(f.utf16().get_data()));
408+
if (attr == INVALID_FILE_ATTRIBUTES) {
409+
return false;
410+
}
411+
412+
return (attr & FILE_ATTRIBUTE_REPARSE_POINT);
413+
}
414+
415+
String DirAccessWindows::read_link(String p_file) {
416+
String f = p_file;
417+
418+
if (!f.is_absolute_path()) {
419+
f = get_current_dir().path_join(f);
420+
}
421+
f = fix_path(f);
422+
423+
HANDLE hfile = CreateFileW((LPCWSTR)(f.utf16().get_data()), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
424+
if (hfile == INVALID_HANDLE_VALUE) {
425+
return f;
426+
}
427+
428+
DWORD ret = GetFinalPathNameByHandleW(hfile, nullptr, 0, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED);
429+
if (ret == 0) {
430+
return f;
431+
}
432+
Char16String cs;
433+
cs.resize(ret + 1);
434+
GetFinalPathNameByHandleW(hfile, (LPWSTR)cs.ptrw(), ret, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED);
435+
CloseHandle(hfile);
436+
437+
return String::utf16((const char16_t *)cs.ptr(), ret).trim_prefix(R"(\\?\)");
438+
}
439+
440+
Error DirAccessWindows::create_link(String p_source, String p_target) {
441+
if (p_target.is_relative_path()) {
442+
p_target = get_current_dir().path_join(p_target);
443+
}
444+
445+
p_source = fix_path(p_source);
446+
p_target = fix_path(p_target);
447+
448+
DWORD file_attr = GetFileAttributesW((LPCWSTR)(p_source.utf16().get_data()));
449+
bool is_dir = (file_attr & FILE_ATTRIBUTE_DIRECTORY);
450+
451+
DWORD flags = ((is_dir) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
452+
if (CreateSymbolicLinkW((LPCWSTR)p_target.utf16().get_data(), (LPCWSTR)p_source.utf16().get_data(), flags) != 0) {
453+
return OK;
454+
} else {
455+
return FAILED;
456+
}
457+
}
458+
399459
DirAccessWindows::DirAccessWindows() {
400460
p = memnew(DirAccessWindowsPrivate);
401461
p->h = INVALID_HANDLE_VALUE;

drivers/windows/dir_access_windows.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ class DirAccessWindows : public DirAccess {
7777
virtual Error rename(String p_path, String p_new_path) override;
7878
virtual Error remove(String p_path) override;
7979

80-
virtual bool is_link(String p_file) override { return false; };
81-
virtual String read_link(String p_file) override { return p_file; };
82-
virtual Error create_link(String p_source, String p_target) override { return FAILED; };
80+
virtual bool is_link(String p_file) override;
81+
virtual String read_link(String p_file) override;
82+
virtual Error create_link(String p_source, String p_target) override;
8383

8484
uint64_t get_space_left() override;
8585

0 commit comments

Comments
 (0)