| 613 | } |
| 614 | |
| 615 | static int toml_write_atomic(const char *path, const char *old_data, size_t old_len, |
| 616 | const char *new_data, size_t new_len, |
| 617 | const toml_file_snapshot_t *snapshot) { |
| 618 | if (old_len > TOML_EDIT_MAX_BYTES || new_len > TOML_EDIT_MAX_BYTES) { |
| 619 | return TOML_EDIT_ERR; |
| 620 | } |
| 621 | if (old_len == new_len && (old_len == 0 || memcmp(old_data, new_data, old_len) == 0)) { |
| 622 | return TOML_EDIT_OK; |
| 623 | } |
| 624 | size_t path_len = strlen(path); |
| 625 | static const char suffix[] = ".XXXXXX"; |
| 626 | if (path_len > SIZE_MAX - sizeof(suffix)) { |
| 627 | return TOML_EDIT_ERR; |
| 628 | } |
| 629 | char *temp_path = (char *)malloc(path_len + sizeof(suffix)); |
| 630 | if (!temp_path) { |
| 631 | return TOML_EDIT_ERR; |
| 632 | } |
| 633 | memcpy(temp_path, path, path_len); |
| 634 | memcpy(temp_path + path_len, suffix, sizeof(suffix)); |
| 635 | |
| 636 | int fd = cbm_mkstemp(temp_path); |
| 637 | if (fd < 0) { |
| 638 | free(temp_path); |
| 639 | return TOML_EDIT_ERR; |
| 640 | } |
| 641 | FILE *file = toml_fdopen(fd, "wb"); |
| 642 | if (!file) { |
| 643 | (void)toml_close(fd); |
| 644 | (void)cbm_unlink(temp_path); |
| 645 | free(temp_path); |
| 646 | return TOML_EDIT_ERR; |
| 647 | } |
| 648 | |
| 649 | int failed = new_len != 0 && fwrite(new_data, 1, new_len, file) != new_len; |
| 650 | if (!failed && fflush(file) != 0) { |
| 651 | failed = 1; |
| 652 | } |
| 653 | #ifndef _WIN32 |
| 654 | if (!failed && snapshot->exists && |
| 655 | fchown(cbm_fileno(file), snapshot->owner, snapshot->group) != 0) { |
| 656 | failed = 1; |
| 657 | } |
| 658 | mode_t mode = snapshot->exists ? snapshot->mode & 0777U : 0600U; |
| 659 | if (!failed && fchmod(cbm_fileno(file), mode) != 0) { |
| 660 | failed = 1; |
| 661 | } |
| 662 | #endif |
| 663 | if (!failed && TOML_SYNC(cbm_fileno(file)) != 0) { |
| 664 | failed = 1; |
| 665 | } |
| 666 | if (fclose(file) != 0) { |
| 667 | failed = 1; |
| 668 | } |
| 669 | if (failed) { |
| 670 | (void)cbm_unlink(temp_path); |
| 671 | free(temp_path); |
| 672 | return TOML_EDIT_ERR; |
no test coverage detected