Write buffer to file atomically (write to tmp, rename). Returns 0 on success. */
| 158 | |
| 159 | /* Write buffer to file atomically (write to tmp, rename). Returns 0 on success. */ |
| 160 | static int write_file_atomic(const char *path, const char *data, size_t len, |
| 161 | artifact_file_error_t *out_err) { |
| 162 | file_error_clear(out_err); |
| 163 | |
| 164 | char tmp[CBM_SZ_4K]; |
| 165 | int n = snprintf(tmp, sizeof(tmp), "%s.tmp", path); |
| 166 | if (n < 0 || (size_t)n >= sizeof(tmp)) { |
| 167 | file_error_set(out_err, "path_too_long", 0); |
| 168 | return CBM_NOT_FOUND; |
| 169 | } |
| 170 | |
| 171 | FILE *fp = fopen(tmp, "wb"); |
| 172 | if (!fp) { |
| 173 | file_error_set(out_err, "open_temp", errno); |
| 174 | return CBM_NOT_FOUND; |
| 175 | } |
| 176 | |
| 177 | size_t wr = fwrite(data, ART_NUL, len, fp); |
| 178 | if (wr != len) { |
| 179 | int saved_errno = ferror(fp) ? errno : 0; |
| 180 | (void)fclose(fp); |
| 181 | cbm_unlink(tmp); |
| 182 | file_error_set(out_err, "write_temp", saved_errno); |
| 183 | return CBM_NOT_FOUND; |
| 184 | } |
| 185 | |
| 186 | if (fclose(fp) != 0) { |
| 187 | int saved_errno = errno; |
| 188 | cbm_unlink(tmp); |
| 189 | file_error_set(out_err, "close_temp", saved_errno); |
| 190 | return CBM_NOT_FOUND; |
| 191 | } |
| 192 | |
| 193 | #ifdef _WIN32 |
| 194 | /* MoveFileEx replace approach suggested by @Ayush7Ranjan in #492. */ |
| 195 | if (!MoveFileExA(tmp, path, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { |
| 196 | DWORD saved_error = GetLastError(); |
| 197 | cbm_unlink(tmp); |
| 198 | file_error_set(out_err, "rename_temp", (int)saved_error); |
| 199 | return CBM_NOT_FOUND; |
| 200 | } |
| 201 | #else |
| 202 | if (rename(tmp, path) != 0) { |
| 203 | int saved_errno = errno; |
| 204 | cbm_unlink(tmp); |
| 205 | file_error_set(out_err, "rename_temp", saved_errno); |
| 206 | return CBM_NOT_FOUND; |
| 207 | } |
| 208 | #endif |
| 209 | return 0; |
| 210 | } |
| 211 | |
| 212 | #ifdef _WIN32 |
| 213 | #define ARTIFACT_NULL_DEV "NUL" |
no test coverage detected