|
38 | 38 | #include "core/io/file_access_pack.h"
|
39 | 39 | #include "core/io/marshalls.h"
|
40 | 40 | #include "core/os/os.h"
|
| 41 | +#include "core/os/time.h" |
41 | 42 |
|
42 | 43 | FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = {};
|
43 | 44 |
|
@@ -84,6 +85,79 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
|
84 | 85 | return ret;
|
85 | 86 | }
|
86 | 87 |
|
| 88 | +Ref<FileAccess> FileAccess::create_temp(int p_mode_flags, const String &p_prefix, const String &p_extension, bool p_keep, Error *r_error) { |
| 89 | + const String ERROR_COMMON_PREFIX = "Error while creating temporary file"; |
| 90 | + |
| 91 | + if (!p_prefix.is_valid_filename()) { |
| 92 | + *r_error = ERR_FILE_BAD_PATH; |
| 93 | + ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: "%s" is not a valid prefix.)", ERROR_COMMON_PREFIX, p_prefix)); |
| 94 | + } |
| 95 | + |
| 96 | + if (!p_extension.is_valid_filename()) { |
| 97 | + *r_error = ERR_FILE_BAD_PATH; |
| 98 | + ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: "%s" is not a valid extension.)", ERROR_COMMON_PREFIX, p_extension)); |
| 99 | + } |
| 100 | + |
| 101 | + const String TEMP_DIR = OS::get_singleton()->get_temp_path(); |
| 102 | + String extension = p_extension.trim_prefix("."); |
| 103 | + |
| 104 | + uint32_t suffix_i = 0; |
| 105 | + String path; |
| 106 | + while (true) { |
| 107 | + String datetime = Time::get_singleton()->get_datetime_string_from_system().replace("-", "").replace("T", "").replace(":", ""); |
| 108 | + datetime += itos(Time::get_singleton()->get_ticks_usec()); |
| 109 | + String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : ""); |
| 110 | + path = TEMP_DIR.path_join((p_prefix.is_empty() ? "" : p_prefix + "-") + suffix + (extension.is_empty() ? "" : "." + extension)); |
| 111 | + if (!DirAccess::exists(path)) { |
| 112 | + break; |
| 113 | + } |
| 114 | + suffix_i += 1; |
| 115 | + } |
| 116 | + |
| 117 | + Error err; |
| 118 | + { |
| 119 | + // Create file first with WRITE mode. |
| 120 | + // Otherwise, it would fail to open with a READ mode. |
| 121 | + Ref<FileAccess> ret = FileAccess::open(path, FileAccess::ModeFlags::WRITE, &err); |
| 122 | + if (err != OK) { |
| 123 | + *r_error = err; |
| 124 | + ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: could not create "%s".)", ERROR_COMMON_PREFIX, path)); |
| 125 | + } |
| 126 | + ret->flush(); |
| 127 | + } |
| 128 | + |
| 129 | + // Open then the temp file with the correct mode flag. |
| 130 | + Ref<FileAccess> ret = FileAccess::open(path, p_mode_flags, &err); |
| 131 | + if (err != OK) { |
| 132 | + *r_error = err; |
| 133 | + ERR_FAIL_V_MSG(Ref<FileAccess>(), vformat(R"(%s: could not open "%s".)", ERROR_COMMON_PREFIX, path)); |
| 134 | + } |
| 135 | + if (ret.is_valid()) { |
| 136 | + ret->_is_temp_file = true; |
| 137 | + ret->_temp_keep_after_use = p_keep; |
| 138 | + ret->_temp_path = ret->get_path_absolute(); |
| 139 | + } |
| 140 | + |
| 141 | + *r_error = OK; |
| 142 | + return ret; |
| 143 | +} |
| 144 | + |
| 145 | +Ref<FileAccess> FileAccess::_create_temp(int p_mode_flags, const String &p_prefix, const String &p_extension, bool p_keep) { |
| 146 | + return create_temp(p_mode_flags, p_prefix, p_extension, p_keep, &last_file_open_error); |
| 147 | +} |
| 148 | + |
| 149 | +void FileAccess::_delete_temp() { |
| 150 | + if (!_is_temp_file || _temp_keep_after_use) { |
| 151 | + return; |
| 152 | + } |
| 153 | + |
| 154 | + if (!FileAccess::exists(_temp_path)) { |
| 155 | + return; |
| 156 | + } |
| 157 | + |
| 158 | + DirAccess::remove_absolute(_temp_path); |
| 159 | +} |
| 160 | + |
87 | 161 | Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
|
88 | 162 | return open_internal(p_path, p_mode_flags);
|
89 | 163 | }
|
@@ -823,6 +897,7 @@ void FileAccess::_bind_methods() {
|
823 | 897 | ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
|
824 | 898 | ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
|
825 | 899 | ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
|
| 900 | + ClassDB::bind_static_method("FileAccess", D_METHOD("create_temp", "mode_flags", "prefix", "extension", "keep"), &FileAccess::_create_temp, DEFVAL(""), DEFVAL(""), DEFVAL(false)); |
826 | 901 |
|
827 | 902 | ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes);
|
828 | 903 | ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string);
|
@@ -912,3 +987,7 @@ void FileAccess::_bind_methods() {
|
912 | 987 | BIND_BITFIELD_FLAG(UNIX_SET_GROUP_ID);
|
913 | 988 | BIND_BITFIELD_FLAG(UNIX_RESTRICTED_DELETE);
|
914 | 989 | }
|
| 990 | + |
| 991 | +FileAccess::~FileAccess() { |
| 992 | + _delete_temp(); |
| 993 | +} |
0 commit comments