| 1560 | #endif |
| 1561 | |
| 1562 | static int jl_replace_atomic(const char *temp_path, const char *path, bool destination_exists) { |
| 1563 | #ifdef _WIN32 |
| 1564 | wchar_t *wide_temp = cbm_utf8_to_wide(temp_path); |
| 1565 | wchar_t *wide_path = cbm_utf8_to_wide(path); |
| 1566 | if (!wide_temp || !wide_path) { |
| 1567 | free(wide_temp); |
| 1568 | free(wide_path); |
| 1569 | return -1; |
| 1570 | } |
| 1571 | /* ReplaceFileW retains the destination's ACL and other mergeable metadata; |
| 1572 | * refusing merge errors is safer than silently dropping that metadata. */ |
| 1573 | BOOL replaced = destination_exists ? ReplaceFileW(wide_path, wide_temp, NULL, |
| 1574 | REPLACEFILE_WRITE_THROUGH, NULL, NULL) |
| 1575 | : MoveFileExW(wide_temp, wide_path, MOVEFILE_WRITE_THROUGH); |
| 1576 | free(wide_temp); |
| 1577 | free(wide_path); |
| 1578 | return replaced ? 0 : -1; |
| 1579 | #else |
| 1580 | if (!destination_exists) { |
| 1581 | if (link(temp_path, path) != 0) { |
| 1582 | return -1; |
| 1583 | } |
| 1584 | if (cbm_unlink(temp_path) != 0) { |
| 1585 | return -1; |
| 1586 | } |
| 1587 | return jl_sync_parent_directory(path); |
| 1588 | } |
| 1589 | if (rename(temp_path, path) != 0) { |
| 1590 | return -1; |
| 1591 | } |
| 1592 | return jl_sync_parent_directory(path); |
| 1593 | #endif |
| 1594 | } |
| 1595 | |
| 1596 | static int jl_write_atomic(const char *path, const char *content, size_t length, |
| 1597 | const char *expected_content, size_t expected_length, |
no test coverage detected