| | #include "../../unity/unity.h" |
| | #include <stdio.h> |
| | #include <stdlib.h> |
| | #include <string.h> |
| | #include <errno.h> |
| | #include <fcntl.h> |
| | #include <unistd.h> |
| | #include <sys/stat.h> |
| | #include <sys/types.h> |
| |
|
| | |
| | |
| | |
| |
|
| | static void remove_file_if_exists(const char *path) |
| | { |
| | if (path && *path) |
| | unlink(path); |
| | } |
| |
|
| | static void rmdir_if_exists(const char *path) |
| | { |
| | if (path && *path) |
| | rmdir(path); |
| | } |
| |
|
| | static int write_all(int fd, const void *buf, size_t len) |
| | { |
| | const char *p = (const char *)buf; |
| | while (len > 0) |
| | { |
| | ssize_t n = write(fd, p, len); |
| | if (n < 0) |
| | { |
| | if (errno == EINTR) |
| | continue; |
| | return -1; |
| | } |
| | if (n == 0) |
| | return -1; |
| | p += n; |
| | len -= (size_t)n; |
| | } |
| | return 0; |
| | } |
| |
|
| | static int read_all(int fd, void *buf, size_t len) |
| | { |
| | char *p = (char *)buf; |
| | size_t got = 0; |
| | while (got < len) |
| | { |
| | ssize_t n = read(fd, p + got, len - got); |
| | if (n < 0) |
| | { |
| | if (errno == EINTR) |
| | continue; |
| | return -1; |
| | } |
| | if (n == 0) |
| | break; |
| | got += (size_t)n; |
| | } |
| | return (int)got; |
| | } |
| |
|
| | |
| | extern int status_level; |
| |
|
| | |
| | |
| | extern sig_atomic_t volatile info_signal_count; |
| | extern sig_atomic_t volatile interrupt_signal; |
| |
|
| | void setUp(void) { |
| | |
| | status_level = 1; |
| | info_signal_count = 0; |
| | interrupt_signal = 0; |
| | } |
| |
|
| | void tearDown(void) { |
| | |
| | status_level = 3; |
| | info_signal_count = 0; |
| | interrupt_signal = 0; |
| | } |
| |
|
| | |
| | static char *make_temp_file(char *out_template) |
| | { |
| | int fd = mkstemp(out_template); |
| | if (fd < 0) |
| | return NULL; |
| | close(fd); |
| | return out_template; |
| | } |
| |
|
| | |
| | static char *make_temp_dir(char *out_template) |
| | { |
| | char *p = mkdtemp(out_template); |
| | return p; |
| | } |
| |
|
| | |
| | void test_ifd_reopen_success_reopens_fd(void) |
| | { |
| | char tmpl[] = "/tmp/dd_ifd_reopen_file_XXXXXX"; |
| | char *path = make_temp_file(tmpl); |
| | TEST_ASSERT_MESSAGE(path != NULL, "mkstemp failed to create temp file"); |
| |
|
| | int dupfd = dup(STDERR_FILENO); |
| | TEST_ASSERT_MESSAGE(dupfd >= 0, "dup failed"); |
| |
|
| | errno = 0; |
| | int ret = ifd_reopen(dupfd, path, O_WRONLY | O_CREAT | O_TRUNC, 0600); |
| | TEST_ASSERT_EQUAL_MESSAGE(0, ret, "ifd_reopen should succeed"); |
| |
|
| | const char payload[] = "hello world"; |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(0, write_all(dupfd, payload, sizeof(payload)), "write_all failed"); |
| | close(dupfd); |
| |
|
| | int rfd = open(path, O_RDONLY); |
| | TEST_ASSERT_MESSAGE(rfd >= 0, "open for readback failed"); |
| | char buf[sizeof(payload)] = {0}; |
| | int n = read_all(rfd, buf, sizeof(buf)); |
| | close(rfd); |
| |
|
| | TEST_ASSERT_EQUAL_INT((int)sizeof(payload), n); |
| | TEST_ASSERT_EQUAL_UINT8_ARRAY(payload, buf, sizeof(payload)); |
| |
|
| | remove_file_if_exists(path); |
| | } |
| |
|
| | |
| | void test_ifd_reopen_failure_returns_error(void) |
| | { |
| | char dtmpl[] = "/tmp/dd_ifd_reopen_dir_XXXXXX"; |
| | char *dirpath = make_temp_dir(dtmpl); |
| | TEST_ASSERT_MESSAGE(dirpath != NULL, "mkdtemp failed to create temp dir"); |
| |
|
| | int dupfd = dup(STDERR_FILENO); |
| | TEST_ASSERT_MESSAGE(dupfd >= 0, "dup failed"); |
| |
|
| | errno = 0; |
| | int ret = ifd_reopen(dupfd, dirpath, O_WRONLY, 0); |
| | TEST_ASSERT_TRUE_MESSAGE(ret < 0, "ifd_reopen should fail for directory with O_WRONLY"); |
| |
|
| | |
| |
|
| | close(dupfd); |
| | rmdir_if_exists(dirpath); |
| | } |
| |
|
| | |
| | void test_ifd_reopen_processes_pending_infosignal(void) |
| | { |
| | |
| | info_signal_count = 1; |
| | status_level = 1; |
| |
|
| | char tmpl[] = "/tmp/dd_ifd_reopen_file_XXXXXX"; |
| | char *path = make_temp_file(tmpl); |
| | TEST_ASSERT_MESSAGE(path != NULL, "mkstemp failed to create temp file"); |
| |
|
| | int dupfd = dup(STDERR_FILENO); |
| | TEST_ASSERT_MESSAGE(dupfd >= 0, "dup failed"); |
| |
|
| | errno = 0; |
| | int ret = ifd_reopen(dupfd, path, O_WRONLY | O_CREAT | O_TRUNC, 0600); |
| | TEST_ASSERT_EQUAL_MESSAGE(0, ret, "ifd_reopen should succeed"); |
| |
|
| | |
| | TEST_ASSERT_EQUAL_INT_MESSAGE(0, (int)info_signal_count, "info_signal_count should be 0 after ifd_reopen"); |
| |
|
| | close(dupfd); |
| | remove_file_if_exists(path); |
| | } |
| |
|
| | int main(void) |
| | { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_ifd_reopen_success_reopens_fd); |
| | RUN_TEST(test_ifd_reopen_failure_returns_error); |
| | RUN_TEST(test_ifd_reopen_processes_pending_infosignal); |
| | return UNITY_END(); |
| | } |