| 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, |
| 1598 | const jl_file_snapshot_t *expected_snapshot) { |
| 1599 | if (jl_ensure_parent(path) != 0) { |
| 1600 | return -1; |
| 1601 | } |
| 1602 | size_t path_length = strlen(path); |
| 1603 | enum { TEMP_SUFFIX_SPACE = 80 }; |
| 1604 | if (path_length > SIZE_MAX - TEMP_SUFFIX_SPACE) { |
| 1605 | return -1; |
| 1606 | } |
| 1607 | size_t temp_capacity = path_length + TEMP_SUFFIX_SPACE; |
| 1608 | char *temp_path = malloc(temp_capacity); |
| 1609 | if (!temp_path) { |
| 1610 | return -1; |
| 1611 | } |
| 1612 | |
| 1613 | FILE *file = NULL; |
| 1614 | for (unsigned attempt = 0; attempt < 64U; attempt++) { |
| 1615 | unsigned sequence = atomic_fetch_add_explicit(&jl_temp_sequence, 1U, memory_order_relaxed); |
| 1616 | int written = snprintf(temp_path, temp_capacity, "%s.cbm.tmp.%ld.%u", path, |
| 1617 | (long)JL_PROCESS_ID(), sequence); |
| 1618 | if (written < 0 || (size_t)written >= temp_capacity) { |
| 1619 | free(temp_path); |
| 1620 | return -1; |
| 1621 | } |
| 1622 | errno = 0; |
| 1623 | #ifdef _WIN32 |
| 1624 | file = cbm_fopen(temp_path, "wbx"); |
| 1625 | #else |
| 1626 | #ifndef O_NOFOLLOW |
| 1627 | free(temp_path); |
| 1628 | return -1; |
| 1629 | #else |
| 1630 | int flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW; |
| 1631 | #ifdef O_CLOEXEC |
| 1632 | flags |= O_CLOEXEC; |
| 1633 | #endif |
| 1634 | int descriptor = open(temp_path, flags, 0600); |
| 1635 | if (descriptor >= 0) { |
| 1636 | file = fdopen(descriptor, "wb"); |
| 1637 | if (!file) { |
| 1638 | int saved_error = errno; |
| 1639 | close(descriptor); |
| 1640 | (void)cbm_unlink(temp_path); |
| 1641 | errno = saved_error; |
| 1642 | } |
| 1643 | } |
| 1644 | #endif |
| 1645 | #endif |
| 1646 | if (file) { |
| 1647 | break; |
| 1648 | } |
| 1649 | if (errno != EEXIST) { |
| 1650 | free(temp_path); |
| 1651 | return -1; |
| 1652 | } |
| 1653 | } |
no test coverage detected