| 844 | } |
| 845 | |
| 846 | static int yaml_write_atomic(const char *path, const char *data, size_t len, |
| 847 | const char *expected_data, size_t expected_len, |
| 848 | const yaml_file_snapshot_t *expected_snapshot) { |
| 849 | size_t path_len = 0U; |
| 850 | if (yaml_bounded_strlen(path, YAML_OUTPUT_MAX, &path_len) != 0 || |
| 851 | path_len > SIZE_MAX - YAML_TMP_SUFFIX_MAX - YAML_UNIT) { |
| 852 | return YAML_ERROR; |
| 853 | } |
| 854 | size_t capacity = path_len + YAML_TMP_SUFFIX_MAX + YAML_UNIT; |
| 855 | char *temp_path = (char *)malloc(capacity); |
| 856 | if (!temp_path) { |
| 857 | return YAML_ERROR; |
| 858 | } |
| 859 | |
| 860 | FILE *file = NULL; |
| 861 | for (unsigned attempt = 0U; attempt < YAML_TMP_ATTEMPTS; attempt++) { |
| 862 | unsigned sequence = |
| 863 | atomic_fetch_add_explicit(&yaml_temp_sequence, YAML_UNIT, memory_order_relaxed); |
| 864 | int written = snprintf(temp_path, capacity, "%s.cbm-yaml-%ld-%u.tmp", path, |
| 865 | (long)YAML_PROCESS_ID(), sequence); |
| 866 | if (written < 0 || (size_t)written >= capacity) { |
| 867 | free(temp_path); |
| 868 | return YAML_ERROR; |
| 869 | } |
| 870 | errno = 0; |
| 871 | #ifdef _WIN32 |
| 872 | file = cbm_fopen(temp_path, "wbx"); |
| 873 | #else |
| 874 | int flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW; |
| 875 | #ifdef O_CLOEXEC |
| 876 | flags |= O_CLOEXEC; |
| 877 | #endif |
| 878 | int descriptor = open(temp_path, flags, YAML_NEW_FILE_MODE); |
| 879 | if (descriptor >= 0) { |
| 880 | file = fdopen(descriptor, "wb"); |
| 881 | if (!file) { |
| 882 | (void)close(descriptor); |
| 883 | (void)cbm_unlink(temp_path); |
| 884 | free(temp_path); |
| 885 | return YAML_ERROR; |
| 886 | } |
| 887 | } |
| 888 | #endif |
| 889 | if (file) { |
| 890 | break; |
| 891 | } |
| 892 | if (errno != EEXIST) { |
| 893 | free(temp_path); |
| 894 | return YAML_ERROR; |
| 895 | } |
| 896 | } |
| 897 | if (!file) { |
| 898 | free(temp_path); |
| 899 | return YAML_ERROR; |
| 900 | } |
| 901 | |
| 902 | bool failed = fwrite(data, YAML_UNIT, len, file) != len; |
| 903 | if (!failed && fflush(file) != 0) { |
no test coverage detected