| 936 | } |
| 937 | |
| 938 | static bool windows_log_append(const char *log_path, const char *record, size_t record_length, |
| 939 | size_t cap_bytes) { |
| 940 | windows_log_path_t path; |
| 941 | if (!windows_log_path_open(log_path, &path)) { |
| 942 | return false; |
| 943 | } |
| 944 | bool prepared = windows_private_file_prepare(path.storage, path.lock_base); |
| 945 | HANDLE lock = prepared ? windows_lock_open(path.lock) : INVALID_HANDLE_VALUE; |
| 946 | if (lock != INVALID_HANDLE_VALUE) { |
| 947 | conflict_log_test_hook(CBM_DAEMON_CONFLICT_LOG_BEFORE_SERIALIZATION_LOCK); |
| 948 | } |
| 949 | OVERLAPPED lock_range; |
| 950 | bool lock_acquired = lock != INVALID_HANDLE_VALUE && windows_lock_exclusive(lock, &lock_range); |
| 951 | if (lock_acquired) { |
| 952 | conflict_log_test_hook(CBM_DAEMON_CONFLICT_LOG_AFTER_SERIALIZATION_LOCK); |
| 953 | } |
| 954 | |
| 955 | LARGE_INTEGER size; |
| 956 | bool ok = lock_acquired && windows_private_file_prepare(path.storage, path.base); |
| 957 | HANDLE file = ok ? windows_log_open(path.wide, &size) : INVALID_HANDLE_VALUE; |
| 958 | ok = ok && file != INVALID_HANDLE_VALUE; |
| 959 | bool rotate = false; |
| 960 | if (ok && size.QuadPart > 0) { |
| 961 | uint64_t current = (uint64_t)size.QuadPart; |
| 962 | rotate = current > cap_bytes || record_length > cap_bytes - (size_t)current; |
| 963 | } |
| 964 | if (ok && rotate) { |
| 965 | (void)CloseHandle(file); |
| 966 | file = INVALID_HANDLE_VALUE; |
| 967 | DWORD rotated_attributes = GetFileAttributesW(path.rotated); |
| 968 | if (rotated_attributes != INVALID_FILE_ATTRIBUTES && |
| 969 | (rotated_attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) != 0) { |
| 970 | ok = false; |
| 971 | } |
| 972 | if (ok) { |
| 973 | ok = MoveFileExW(path.wide, path.rotated, |
| 974 | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) != 0; |
| 975 | } |
| 976 | if (ok) { |
| 977 | ok = windows_private_file_prepare(path.storage, path.base); |
| 978 | } |
| 979 | if (ok) { |
| 980 | file = windows_log_open(path.wide, &size); |
| 981 | ok = file != INVALID_HANDLE_VALUE; |
| 982 | } |
| 983 | } |
| 984 | if (ok && size.QuadPart > 0) { |
| 985 | LARGE_INTEGER offset = {.QuadPart = size.QuadPart - 1}; |
| 986 | char last = '\0'; |
| 987 | DWORD count = 0; |
| 988 | ok = SetFilePointerEx(file, offset, NULL, FILE_BEGIN) != 0 && |
| 989 | ReadFile(file, &last, 1, &count, NULL) != 0 && count == 1 && last == '\n'; |
| 990 | } |
| 991 | if (ok) { |
| 992 | ok = windows_complete_write(file, record, record_length, size); |
| 993 | } |
| 994 | if (file != INVALID_HANDLE_VALUE) { |
| 995 | if (!CloseHandle(file)) { |
no test coverage detected