|
|
#include "../../unity/unity.h" |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <errno.h> |
|
|
#include <unistd.h> |
|
|
#include <sys/types.h> |
|
|
#include <sys/stat.h> |
|
|
#include <fcntl.h> |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void write_exact(int fd, const void *buf, size_t len) |
|
|
{ |
|
|
const char *p = (const char *)buf; |
|
|
size_t remaining = len; |
|
|
while (remaining > 0) { |
|
|
ssize_t w = write(fd, p, remaining); |
|
|
TEST_ASSERT_MESSAGE(w >= 0, "write() failed during test setup"); |
|
|
if (w == 0) { |
|
|
TEST_FAIL_MESSAGE("write() returned 0 unexpectedly"); |
|
|
} |
|
|
p += w; |
|
|
remaining -= (size_t)w; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void test_iftruncate_shrink_file(void) |
|
|
{ |
|
|
FILE *fp = tmpfile(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(fp, "tmpfile() failed"); |
|
|
int fd = fileno(fp); |
|
|
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "fileno() failed"); |
|
|
|
|
|
|
|
|
char buf[1000]; |
|
|
memset(buf, 'A', sizeof buf); |
|
|
write_exact(fd, buf, sizeof buf); |
|
|
|
|
|
|
|
|
errno = 0; |
|
|
int rc = iftruncate(fd, (off_t)100); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, "iftruncate should succeed when shrinking"); |
|
|
|
|
|
struct stat st; |
|
|
int s = fstat(fd, &st); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, s, "fstat failed after shrinking"); |
|
|
TEST_ASSERT_EQUAL_INT64_MESSAGE((long long)100, (long long)st.st_size, "File size after shrink is incorrect"); |
|
|
|
|
|
|
|
|
fclose(fp); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_iftruncate_extend_file_zero_filled(void) |
|
|
{ |
|
|
FILE *fp = tmpfile(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(fp, "tmpfile() failed"); |
|
|
int fd = fileno(fp); |
|
|
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "fileno() failed"); |
|
|
|
|
|
|
|
|
struct stat st0; |
|
|
TEST_ASSERT_EQUAL_INT(0, fstat(fd, &st0)); |
|
|
|
|
|
|
|
|
errno = 0; |
|
|
int rc = iftruncate(fd, (off_t)4096); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, "iftruncate should succeed when extending"); |
|
|
|
|
|
struct stat st; |
|
|
int s = fstat(fd, &st); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, s, "fstat failed after extending"); |
|
|
TEST_ASSERT_EQUAL_INT64_MESSAGE((long long)4096, (long long)st.st_size, "File size after extend is incorrect"); |
|
|
|
|
|
|
|
|
off_t r = lseek(fd, (off_t)4095, SEEK_SET); |
|
|
TEST_ASSERT_TRUE_MESSAGE(r == (off_t)4095, "lseek to last byte failed"); |
|
|
unsigned char c = 0xFF; |
|
|
ssize_t rr = read(fd, &c, 1); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(1, rr, "read of last byte failed"); |
|
|
TEST_ASSERT_EQUAL_UINT8_MESSAGE(0, c, "Extended area is not zero-filled"); |
|
|
|
|
|
|
|
|
fclose(fp); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_iftruncate_invalid_fd(void) |
|
|
{ |
|
|
errno = 0; |
|
|
int rc = iftruncate(-1, (off_t)123); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(-1, rc, "iftruncate should fail for invalid fd"); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(EBADF, errno, "errno should be EBADF for invalid fd"); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_iftruncate_negative_length(void) |
|
|
{ |
|
|
FILE *fp = tmpfile(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(fp, "tmpfile() failed"); |
|
|
int fd = fileno(fp); |
|
|
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "fileno() failed"); |
|
|
|
|
|
errno = 0; |
|
|
int rc = iftruncate(fd, (off_t)-1); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(-1, rc, "iftruncate should fail for negative length"); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(EINVAL, errno, "errno should be EINVAL for negative length"); |
|
|
|
|
|
fclose(fp); |
|
|
} |
|
|
|
|
|
int main(void) |
|
|
{ |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_iftruncate_shrink_file); |
|
|
RUN_TEST(test_iftruncate_extend_file_zero_filled); |
|
|
RUN_TEST(test_iftruncate_invalid_fd); |
|
|
RUN_TEST(test_iftruncate_negative_length); |
|
|
return UNITY_END(); |
|
|
} |