| 589 | } |
| 590 | |
| 591 | static bool posix_log_append(const char *log_path, const char *record, size_t record_length, |
| 592 | size_t cap_bytes) { |
| 593 | posix_log_path_t path; |
| 594 | if (!posix_log_path_open(log_path, &path)) { |
| 595 | return false; |
| 596 | } |
| 597 | bool lock_created = false; |
| 598 | int lock_fd = posix_lock_file_open(&path, &lock_created); |
| 599 | if (lock_fd >= 0) { |
| 600 | conflict_log_test_hook(CBM_DAEMON_CONFLICT_LOG_BEFORE_SERIALIZATION_LOCK); |
| 601 | } |
| 602 | bool ok = lock_fd >= 0 && posix_lock_exclusive(lock_fd); |
| 603 | if (ok) { |
| 604 | conflict_log_test_hook(CBM_DAEMON_CONFLICT_LOG_AFTER_SERIALIZATION_LOCK); |
| 605 | } |
| 606 | struct stat status; |
| 607 | bool created = false; |
| 608 | int fd = ok ? posix_log_file_open(&path, &status, &created) : -1; |
| 609 | ok = ok && fd >= 0 && posix_log_refresh_locked(&path, fd, &status); |
| 610 | bool directory_changed = lock_created || created; |
| 611 | bool rotate = false; |
| 612 | if (ok && status.st_size > 0) { |
| 613 | uintmax_t size = (uintmax_t)status.st_size; |
| 614 | rotate = size > cap_bytes || record_length > cap_bytes - (size_t)size; |
| 615 | } |
| 616 | if (ok && rotate) { |
| 617 | ok = renameat(path.dir_fd, path.base, path.dir_fd, path.rotated) == 0; |
| 618 | ok = close(fd) == 0 && ok; |
| 619 | fd = -1; |
| 620 | directory_changed = directory_changed || ok; |
| 621 | if (ok) { |
| 622 | fd = posix_log_file_open(&path, &status, &created); |
| 623 | ok = fd >= 0 && posix_log_refresh_locked(&path, fd, &status); |
| 624 | directory_changed = directory_changed || created; |
| 625 | } |
| 626 | } |
| 627 | if (ok) { |
| 628 | char last = '\n'; |
| 629 | if (status.st_size > 0) { |
| 630 | ssize_t count; |
| 631 | do { |
| 632 | count = pread(fd, &last, 1, status.st_size - 1); |
| 633 | } while (count < 0 && errno == EINTR); |
| 634 | ok = count == 1 && last == '\n'; |
| 635 | } |
| 636 | if (ok) { |
| 637 | ok = posix_complete_write(fd, record, record_length, status.st_size); |
| 638 | } |
| 639 | } |
| 640 | if (fd >= 0) { |
| 641 | if (close(fd) != 0) { |
| 642 | ok = false; |
| 643 | } |
| 644 | } |
| 645 | if (lock_fd >= 0) { |
| 646 | (void)flock(lock_fd, LOCK_UN); |
| 647 | if (close(lock_fd) != 0) { |
| 648 | ok = false; |
no test coverage detected