| 128 | */ |
| 129 | |
| 130 | static int Sys_Save(lua_State* L) |
| 131 | { |
| 132 | size_t filename_len = 0; |
| 133 | const char* filename = luaL_checklstring(L, 1, &filename_len); |
| 134 | |
| 135 | if (filename_len >= DMPATH_MAX_PATH) |
| 136 | { |
| 137 | return luaL_error(L, "Could not write to the file %s. Path too long.", filename); |
| 138 | } |
| 139 | |
| 140 | luaL_checktype(L, 2, LUA_TTABLE); |
| 141 | |
| 142 | char tmp_filename[DMPATH_MAX_PATH]; |
| 143 | // The counter and hash are there to make the files unique enough to avoid that the user |
| 144 | // accidentally writes to it. |
| 145 | static int save_counter = 0; |
| 146 | uint32_t hash = dmHashString32(filename); |
| 147 | int res = dmSnPrintf(tmp_filename, sizeof(tmp_filename), "%s.defoldtmp_%x_%d", filename, hash, save_counter++); |
| 148 | if (res == -1) |
| 149 | { |
| 150 | return luaL_error(L, "Could not write to the file %s. Path too long.", filename); |
| 151 | } |
| 152 | |
| 153 | uint32_t table_size = CheckTableSize(L, 2); |
| 154 | |
| 155 | char* buffer = Sys_SetupTableSerializationBuffer(table_size); |
| 156 | if (!buffer) |
| 157 | { |
| 158 | return luaL_error(L, "Could not allocate %d bytes for table serialization.", table_size); |
| 159 | } |
| 160 | uint32_t n_used = CheckTable(L, buffer, table_size, 2); |
| 161 | |
| 162 | #if !defined(__EMSCRIPTEN__) |
| 163 | FILE* file = fopen(tmp_filename, "wb"); |
| 164 | if (!file) |
| 165 | { |
| 166 | Sys_FreeTableSerializationBuffer(buffer); |
| 167 | |
| 168 | #if defined(DM_NO_ERRNO) |
| 169 | return luaL_error(L, "Could not open the file %s", tmp_filename); |
| 170 | #else |
| 171 | char errmsg[128] = {}; |
| 172 | dmStrError(errmsg, sizeof(errmsg), errno); |
| 173 | return luaL_error(L, "Could not open the file %s, reason: %s.", tmp_filename, errmsg); |
| 174 | #endif |
| 175 | } |
| 176 | |
| 177 | bool result = fwrite(buffer, 1, n_used, file) == n_used; |
| 178 | result = (fclose(file) == 0) && result; |
| 179 | Sys_FreeTableSerializationBuffer(buffer); |
| 180 | |
| 181 | if (!result) |
| 182 | { |
| 183 | dmSys::Unlink(tmp_filename); |
| 184 | |
| 185 | #if defined(DM_NO_ERRNO) |
| 186 | return luaL_error(L, "Could not write to the file %s.", filename); |
| 187 | #else |
nothing calls this directly
no test coverage detected