1 | /**************************************************************************/ |
2 | /* dir_access.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "dir_access.h" |
32 | |
33 | #include "core/config/project_settings.h" |
34 | #include "core/io/file_access.h" |
35 | #include "core/os/memory.h" |
36 | #include "core/os/os.h" |
37 | #include "core/templates/local_vector.h" |
38 | |
39 | thread_local Error DirAccess::last_dir_open_error = OK; |
40 | |
41 | String DirAccess::_get_root_path() const { |
42 | switch (_access_type) { |
43 | case ACCESS_RESOURCES: |
44 | return ProjectSettings::get_singleton()->get_resource_path(); |
45 | case ACCESS_USERDATA: |
46 | return OS::get_singleton()->get_user_data_dir(); |
47 | default: |
48 | return "" ; |
49 | } |
50 | } |
51 | |
52 | String DirAccess::_get_root_string() const { |
53 | switch (_access_type) { |
54 | case ACCESS_RESOURCES: |
55 | return "res://" ; |
56 | case ACCESS_USERDATA: |
57 | return "user://" ; |
58 | default: |
59 | return "" ; |
60 | } |
61 | } |
62 | |
63 | int DirAccess::get_current_drive() { |
64 | String path = get_current_dir().to_lower(); |
65 | for (int i = 0; i < get_drive_count(); i++) { |
66 | String d = get_drive(i).to_lower(); |
67 | if (path.begins_with(d)) { |
68 | return i; |
69 | } |
70 | } |
71 | |
72 | return 0; |
73 | } |
74 | |
75 | bool DirAccess::drives_are_shortcuts() { |
76 | return false; |
77 | } |
78 | |
79 | static Error _erase_recursive(DirAccess *da) { |
80 | List<String> dirs; |
81 | List<String> files; |
82 | |
83 | da->list_dir_begin(); |
84 | String n = da->get_next(); |
85 | while (!n.is_empty()) { |
86 | if (n != "." && n != ".." ) { |
87 | if (da->current_is_dir()) { |
88 | dirs.push_back(n); |
89 | } else { |
90 | files.push_back(n); |
91 | } |
92 | } |
93 | |
94 | n = da->get_next(); |
95 | } |
96 | |
97 | da->list_dir_end(); |
98 | |
99 | for (const String &E : dirs) { |
100 | Error err = da->change_dir(E); |
101 | if (err == OK) { |
102 | err = _erase_recursive(da); |
103 | if (err) { |
104 | da->change_dir(".." ); |
105 | return err; |
106 | } |
107 | err = da->change_dir(".." ); |
108 | if (err) { |
109 | return err; |
110 | } |
111 | err = da->remove(da->get_current_dir().path_join(E)); |
112 | if (err) { |
113 | return err; |
114 | } |
115 | } else { |
116 | return err; |
117 | } |
118 | } |
119 | |
120 | for (const String &E : files) { |
121 | Error err = da->remove(da->get_current_dir().path_join(E)); |
122 | if (err) { |
123 | return err; |
124 | } |
125 | } |
126 | |
127 | return OK; |
128 | } |
129 | |
130 | Error DirAccess::erase_contents_recursive() { |
131 | return _erase_recursive(this); |
132 | } |
133 | |
134 | Error DirAccess::make_dir_recursive(String p_dir) { |
135 | if (p_dir.length() < 1) { |
136 | return OK; |
137 | } |
138 | |
139 | String full_dir; |
140 | |
141 | if (p_dir.is_relative_path()) { |
142 | //append current |
143 | full_dir = get_current_dir().path_join(p_dir); |
144 | |
145 | } else { |
146 | full_dir = p_dir; |
147 | } |
148 | |
149 | full_dir = full_dir.replace("\\" , "/" ); |
150 | |
151 | String base; |
152 | |
153 | if (full_dir.begins_with("res://" )) { |
154 | base = "res://" ; |
155 | } else if (full_dir.begins_with("user://" )) { |
156 | base = "user://" ; |
157 | } else if (full_dir.is_network_share_path()) { |
158 | int pos = full_dir.find("/" , 2); |
159 | ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER); |
160 | pos = full_dir.find("/" , pos + 1); |
161 | ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER); |
162 | base = full_dir.substr(0, pos + 1); |
163 | } else if (full_dir.begins_with("/" )) { |
164 | base = "/" ; |
165 | } else if (full_dir.contains(":/" )) { |
166 | base = full_dir.substr(0, full_dir.find(":/" ) + 2); |
167 | } else { |
168 | ERR_FAIL_V(ERR_INVALID_PARAMETER); |
169 | } |
170 | |
171 | full_dir = full_dir.replace_first(base, "" ).simplify_path(); |
172 | |
173 | Vector<String> subdirs = full_dir.split("/" ); |
174 | |
175 | String curpath = base; |
176 | for (int i = 0; i < subdirs.size(); i++) { |
177 | curpath = curpath.path_join(subdirs[i]); |
178 | Error err = make_dir(curpath); |
179 | if (err != OK && err != ERR_ALREADY_EXISTS) { |
180 | ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath); |
181 | } |
182 | } |
183 | |
184 | return OK; |
185 | } |
186 | |
187 | DirAccess::AccessType DirAccess::get_access_type() const { |
188 | return _access_type; |
189 | } |
190 | |
191 | String DirAccess::fix_path(String p_path) const { |
192 | switch (_access_type) { |
193 | case ACCESS_RESOURCES: { |
194 | if (ProjectSettings::get_singleton()) { |
195 | if (p_path.begins_with("res://" )) { |
196 | String resource_path = ProjectSettings::get_singleton()->get_resource_path(); |
197 | if (!resource_path.is_empty()) { |
198 | return p_path.replace_first("res:/" , resource_path); |
199 | } |
200 | return p_path.replace_first("res://" , "" ); |
201 | } |
202 | } |
203 | |
204 | } break; |
205 | case ACCESS_USERDATA: { |
206 | if (p_path.begins_with("user://" )) { |
207 | String data_dir = OS::get_singleton()->get_user_data_dir(); |
208 | if (!data_dir.is_empty()) { |
209 | return p_path.replace_first("user:/" , data_dir); |
210 | } |
211 | return p_path.replace_first("user://" , "" ); |
212 | } |
213 | |
214 | } break; |
215 | case ACCESS_FILESYSTEM: { |
216 | return p_path; |
217 | } break; |
218 | case ACCESS_MAX: |
219 | break; // Can't happen, but silences warning |
220 | } |
221 | |
222 | return p_path; |
223 | } |
224 | |
225 | DirAccess::CreateFunc DirAccess::create_func[ACCESS_MAX] = { nullptr, nullptr, nullptr }; |
226 | |
227 | Ref<DirAccess> DirAccess::create_for_path(const String &p_path) { |
228 | Ref<DirAccess> da; |
229 | if (p_path.begins_with("res://" )) { |
230 | da = create(ACCESS_RESOURCES); |
231 | } else if (p_path.begins_with("user://" )) { |
232 | da = create(ACCESS_USERDATA); |
233 | } else { |
234 | da = create(ACCESS_FILESYSTEM); |
235 | } |
236 | |
237 | return da; |
238 | } |
239 | |
240 | Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) { |
241 | Ref<DirAccess> da = create_for_path(p_path); |
242 | ERR_FAIL_COND_V_MSG(da.is_null(), nullptr, "Cannot create DirAccess for path '" + p_path + "'." ); |
243 | Error err = da->change_dir(p_path); |
244 | if (r_error) { |
245 | *r_error = err; |
246 | } |
247 | if (err != OK) { |
248 | return nullptr; |
249 | } |
250 | |
251 | return da; |
252 | } |
253 | |
254 | Ref<DirAccess> DirAccess::_open(const String &p_path) { |
255 | Error err = OK; |
256 | Ref<DirAccess> da = open(p_path, &err); |
257 | last_dir_open_error = err; |
258 | if (err) { |
259 | return Ref<DirAccess>(); |
260 | } |
261 | return da; |
262 | } |
263 | |
264 | int DirAccess::_get_drive_count() { |
265 | Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); |
266 | return d->get_drive_count(); |
267 | } |
268 | |
269 | String DirAccess::get_drive_name(int p_idx) { |
270 | Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); |
271 | return d->get_drive(p_idx); |
272 | } |
273 | |
274 | Error DirAccess::make_dir_absolute(const String &p_dir) { |
275 | Ref<DirAccess> d = DirAccess::create_for_path(p_dir); |
276 | return d->make_dir(p_dir); |
277 | } |
278 | |
279 | Error DirAccess::make_dir_recursive_absolute(const String &p_dir) { |
280 | Ref<DirAccess> d = DirAccess::create_for_path(p_dir); |
281 | return d->make_dir_recursive(p_dir); |
282 | } |
283 | |
284 | bool DirAccess::dir_exists_absolute(const String &p_dir) { |
285 | Ref<DirAccess> d = DirAccess::create_for_path(p_dir); |
286 | return d->dir_exists(p_dir); |
287 | } |
288 | |
289 | Error DirAccess::copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags) { |
290 | Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); |
291 | // Support copying from res:// to user:// etc. |
292 | String from = ProjectSettings::get_singleton()->globalize_path(p_from); |
293 | String to = ProjectSettings::get_singleton()->globalize_path(p_to); |
294 | return d->copy(from, to, p_chmod_flags); |
295 | } |
296 | |
297 | Error DirAccess::rename_absolute(const String &p_from, const String &p_to) { |
298 | Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); |
299 | String from = ProjectSettings::get_singleton()->globalize_path(p_from); |
300 | String to = ProjectSettings::get_singleton()->globalize_path(p_to); |
301 | return d->rename(from, to); |
302 | } |
303 | |
304 | Error DirAccess::remove_absolute(const String &p_path) { |
305 | Ref<DirAccess> d = DirAccess::create_for_path(p_path); |
306 | return d->remove(p_path); |
307 | } |
308 | |
309 | Ref<DirAccess> DirAccess::create(AccessType p_access) { |
310 | Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr; |
311 | if (da.is_valid()) { |
312 | da->_access_type = p_access; |
313 | |
314 | // for ACCESS_RESOURCES and ACCESS_FILESYSTEM, current_dir already defaults to where game was started |
315 | // in case current directory is force changed elsewhere for ACCESS_RESOURCES |
316 | if (p_access == ACCESS_RESOURCES) { |
317 | da->change_dir("res://" ); |
318 | } else if (p_access == ACCESS_USERDATA) { |
319 | da->change_dir("user://" ); |
320 | } |
321 | } |
322 | |
323 | return da; |
324 | } |
325 | |
326 | Error DirAccess::get_open_error() { |
327 | return last_dir_open_error; |
328 | } |
329 | |
330 | String DirAccess::get_full_path(const String &p_path, AccessType p_access) { |
331 | Ref<DirAccess> d = DirAccess::create(p_access); |
332 | if (d.is_null()) { |
333 | return p_path; |
334 | } |
335 | |
336 | d->change_dir(p_path); |
337 | String full = d->get_current_dir(); |
338 | return full; |
339 | } |
340 | |
341 | Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { |
342 | //printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data()); |
343 | Error err; |
344 | { |
345 | Ref<FileAccess> fsrc = FileAccess::open(p_from, FileAccess::READ, &err); |
346 | ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_from); |
347 | |
348 | Ref<FileAccess> fdst = FileAccess::open(p_to, FileAccess::WRITE, &err); |
349 | ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_to); |
350 | |
351 | const size_t copy_buffer_limit = 65536; // 64 KB |
352 | |
353 | fsrc->seek_end(0); |
354 | uint64_t size = fsrc->get_position(); |
355 | fsrc->seek(0); |
356 | err = OK; |
357 | size_t buffer_size = MIN(size * sizeof(uint8_t), copy_buffer_limit); |
358 | LocalVector<uint8_t> buffer; |
359 | buffer.resize(buffer_size); |
360 | while (size > 0) { |
361 | if (fsrc->get_error() != OK) { |
362 | err = fsrc->get_error(); |
363 | break; |
364 | } |
365 | if (fdst->get_error() != OK) { |
366 | err = fdst->get_error(); |
367 | break; |
368 | } |
369 | |
370 | int bytes_read = fsrc->get_buffer(buffer.ptr(), buffer_size); |
371 | if (bytes_read <= 0) { |
372 | err = FAILED; |
373 | break; |
374 | } |
375 | fdst->store_buffer(buffer.ptr(), bytes_read); |
376 | |
377 | size -= bytes_read; |
378 | } |
379 | } |
380 | |
381 | if (err == OK && p_chmod_flags != -1) { |
382 | err = FileAccess::set_unix_permissions(p_to, p_chmod_flags); |
383 | // If running on a platform with no chmod support (i.e., Windows), don't fail |
384 | if (err == ERR_UNAVAILABLE) { |
385 | err = OK; |
386 | } |
387 | } |
388 | |
389 | return err; |
390 | } |
391 | |
392 | // Changes dir for the current scope, returning back to the original dir |
393 | // when scope exits |
394 | class DirChanger { |
395 | DirAccess *da; |
396 | String original_dir; |
397 | |
398 | public: |
399 | DirChanger(DirAccess *p_da, String p_dir) : |
400 | da(p_da), |
401 | original_dir(p_da->get_current_dir()) { |
402 | p_da->change_dir(p_dir); |
403 | } |
404 | |
405 | ~DirChanger() { |
406 | da->change_dir(original_dir); |
407 | } |
408 | }; |
409 | |
410 | Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) { |
411 | List<String> dirs; |
412 | |
413 | String curdir = get_current_dir(); |
414 | list_dir_begin(); |
415 | String n = get_next(); |
416 | while (!n.is_empty()) { |
417 | if (n != "." && n != ".." ) { |
418 | if (p_copy_links && is_link(get_current_dir().path_join(n))) { |
419 | create_link(read_link(get_current_dir().path_join(n)), p_to + n); |
420 | } else if (current_is_dir()) { |
421 | dirs.push_back(n); |
422 | } else { |
423 | const String &rel_path = n; |
424 | if (!n.is_relative_path()) { |
425 | list_dir_end(); |
426 | return ERR_BUG; |
427 | } |
428 | Error err = copy(get_current_dir().path_join(n), p_to + rel_path, p_chmod_flags); |
429 | if (err) { |
430 | list_dir_end(); |
431 | return err; |
432 | } |
433 | } |
434 | } |
435 | |
436 | n = get_next(); |
437 | } |
438 | |
439 | list_dir_end(); |
440 | |
441 | for (const String &rel_path : dirs) { |
442 | String target_dir = p_to + rel_path; |
443 | if (!p_target_da->dir_exists(target_dir)) { |
444 | Error err = p_target_da->make_dir(target_dir); |
445 | ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + target_dir + "'." ); |
446 | } |
447 | |
448 | Error err = change_dir(rel_path); |
449 | ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + rel_path + "'." ); |
450 | |
451 | err = _copy_dir(p_target_da, p_to + rel_path + "/" , p_chmod_flags, p_copy_links); |
452 | if (err) { |
453 | change_dir(".." ); |
454 | ERR_FAIL_V_MSG(err, "Failed to copy recursively." ); |
455 | } |
456 | err = change_dir(".." ); |
457 | ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to go back." ); |
458 | } |
459 | |
460 | return OK; |
461 | } |
462 | |
463 | Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_copy_links) { |
464 | ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist." ); |
465 | |
466 | Ref<DirAccess> target_da = DirAccess::create_for_path(p_to); |
467 | ERR_FAIL_COND_V_MSG(target_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'." ); |
468 | |
469 | if (!target_da->dir_exists(p_to)) { |
470 | Error err = target_da->make_dir_recursive(p_to); |
471 | ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + p_to + "'." ); |
472 | } |
473 | |
474 | if (!p_to.ends_with("/" )) { |
475 | p_to = p_to + "/" ; |
476 | } |
477 | |
478 | DirChanger dir_changer(this, p_from); |
479 | Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links); |
480 | |
481 | return err; |
482 | } |
483 | |
484 | bool DirAccess::exists(String p_dir) { |
485 | Ref<DirAccess> da = DirAccess::create_for_path(p_dir); |
486 | return da->change_dir(p_dir) == OK; |
487 | } |
488 | |
489 | PackedStringArray DirAccess::get_files() { |
490 | return _get_contents(false); |
491 | } |
492 | |
493 | PackedStringArray DirAccess::get_files_at(const String &p_path) { |
494 | Ref<DirAccess> da = DirAccess::open(p_path); |
495 | ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\"." , p_path)); |
496 | return da->get_files(); |
497 | } |
498 | |
499 | PackedStringArray DirAccess::get_directories() { |
500 | return _get_contents(true); |
501 | } |
502 | |
503 | PackedStringArray DirAccess::get_directories_at(const String &p_path) { |
504 | Ref<DirAccess> da = DirAccess::open(p_path); |
505 | ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\"." , p_path)); |
506 | return da->get_directories(); |
507 | } |
508 | |
509 | PackedStringArray DirAccess::_get_contents(bool p_directories) { |
510 | PackedStringArray ret; |
511 | |
512 | list_dir_begin(); |
513 | String s = _get_next(); |
514 | while (!s.is_empty()) { |
515 | if (current_is_dir() == p_directories) { |
516 | ret.append(s); |
517 | } |
518 | s = _get_next(); |
519 | } |
520 | |
521 | ret.sort(); |
522 | return ret; |
523 | } |
524 | |
525 | String DirAccess::_get_next() { |
526 | String next = get_next(); |
527 | while (!next.is_empty() && ((!include_navigational && (next == "." || next == ".." )) || (!include_hidden && current_is_hidden()))) { |
528 | next = get_next(); |
529 | } |
530 | return next; |
531 | } |
532 | |
533 | void DirAccess::set_include_navigational(bool p_enable) { |
534 | include_navigational = p_enable; |
535 | } |
536 | |
537 | bool DirAccess::get_include_navigational() const { |
538 | return include_navigational; |
539 | } |
540 | |
541 | void DirAccess::set_include_hidden(bool p_enable) { |
542 | include_hidden = p_enable; |
543 | } |
544 | |
545 | bool DirAccess::get_include_hidden() const { |
546 | return include_hidden; |
547 | } |
548 | |
549 | void DirAccess::_bind_methods() { |
550 | ClassDB::bind_static_method("DirAccess" , D_METHOD("open" , "path" ), &DirAccess::_open); |
551 | ClassDB::bind_static_method("DirAccess" , D_METHOD("get_open_error" ), &DirAccess::get_open_error); |
552 | |
553 | ClassDB::bind_method(D_METHOD("list_dir_begin" ), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false)); |
554 | ClassDB::bind_method(D_METHOD("get_next" ), &DirAccess::_get_next); |
555 | ClassDB::bind_method(D_METHOD("current_is_dir" ), &DirAccess::current_is_dir); |
556 | ClassDB::bind_method(D_METHOD("list_dir_end" ), &DirAccess::list_dir_end); |
557 | ClassDB::bind_method(D_METHOD("get_files" ), &DirAccess::get_files); |
558 | ClassDB::bind_static_method("DirAccess" , D_METHOD("get_files_at" , "path" ), &DirAccess::get_files_at); |
559 | ClassDB::bind_method(D_METHOD("get_directories" ), &DirAccess::get_directories); |
560 | ClassDB::bind_static_method("DirAccess" , D_METHOD("get_directories_at" , "path" ), &DirAccess::get_directories_at); |
561 | ClassDB::bind_static_method("DirAccess" , D_METHOD("get_drive_count" ), &DirAccess::_get_drive_count); |
562 | ClassDB::bind_static_method("DirAccess" , D_METHOD("get_drive_name" , "idx" ), &DirAccess::get_drive_name); |
563 | ClassDB::bind_method(D_METHOD("get_current_drive" ), &DirAccess::get_current_drive); |
564 | ClassDB::bind_method(D_METHOD("change_dir" , "to_dir" ), &DirAccess::change_dir); |
565 | ClassDB::bind_method(D_METHOD("get_current_dir" , "include_drive" ), &DirAccess::get_current_dir, DEFVAL(true)); |
566 | ClassDB::bind_method(D_METHOD("make_dir" , "path" ), &DirAccess::make_dir); |
567 | ClassDB::bind_static_method("DirAccess" , D_METHOD("make_dir_absolute" , "path" ), &DirAccess::make_dir_absolute); |
568 | ClassDB::bind_method(D_METHOD("make_dir_recursive" , "path" ), &DirAccess::make_dir_recursive); |
569 | ClassDB::bind_static_method("DirAccess" , D_METHOD("make_dir_recursive_absolute" , "path" ), &DirAccess::make_dir_recursive_absolute); |
570 | ClassDB::bind_method(D_METHOD("file_exists" , "path" ), &DirAccess::file_exists); |
571 | ClassDB::bind_method(D_METHOD("dir_exists" , "path" ), &DirAccess::dir_exists); |
572 | ClassDB::bind_static_method("DirAccess" , D_METHOD("dir_exists_absolute" , "path" ), &DirAccess::dir_exists_absolute); |
573 | ClassDB::bind_method(D_METHOD("get_space_left" ), &DirAccess::get_space_left); |
574 | ClassDB::bind_method(D_METHOD("copy" , "from" , "to" , "chmod_flags" ), &DirAccess::copy, DEFVAL(-1)); |
575 | ClassDB::bind_static_method("DirAccess" , D_METHOD("copy_absolute" , "from" , "to" , "chmod_flags" ), &DirAccess::copy_absolute, DEFVAL(-1)); |
576 | ClassDB::bind_method(D_METHOD("rename" , "from" , "to" ), &DirAccess::rename); |
577 | ClassDB::bind_static_method("DirAccess" , D_METHOD("rename_absolute" , "from" , "to" ), &DirAccess::rename_absolute); |
578 | ClassDB::bind_method(D_METHOD("remove" , "path" ), &DirAccess::remove); |
579 | ClassDB::bind_static_method("DirAccess" , D_METHOD("remove_absolute" , "path" ), &DirAccess::remove_absolute); |
580 | |
581 | ClassDB::bind_method(D_METHOD("set_include_navigational" , "enable" ), &DirAccess::set_include_navigational); |
582 | ClassDB::bind_method(D_METHOD("get_include_navigational" ), &DirAccess::get_include_navigational); |
583 | ClassDB::bind_method(D_METHOD("set_include_hidden" , "enable" ), &DirAccess::set_include_hidden); |
584 | ClassDB::bind_method(D_METHOD("get_include_hidden" ), &DirAccess::get_include_hidden); |
585 | |
586 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational" ), "set_include_navigational" , "get_include_navigational" ); |
587 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden" ), "set_include_hidden" , "get_include_hidden" ); |
588 | } |
589 | |