/* SPDX-License-Identifier: BSD-2-Clause */ /* * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "fstest.h" #include "fs_config.h" #include const char rtems_test_name[] = "FSRDWR " FILESYSTEM; static const mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; static const char databuf [] = "Happy days are here again. Happy days are here again.1Happy " "days are here again.2Happy days are here again.3Happy days are here again." "4Happy days are here again.5Happy days are here again.6Happy days are here " "again.7Happy days are here again."; static const size_t len = sizeof (databuf) - 1; static void test_case_enter (const char *wd) { int status; printf ("test case: %s\n", wd); status = mkdir (wd, mode); rtems_test_assert (status == 0); status = chdir (wd); rtems_test_assert (status == 0); } static void test_case_leave (void) { int status; status = chdir (".."); rtems_test_assert (status == 0); } static void read_write_test (void) { int fd; int status; char *name01 = "name01"; char *name02 = "name02"; struct stat statbuf; char *readbuf; off_t pos = 0; int n; test_case_enter (__func__); /* * Create an empty file */ fd = open (name01, O_CREAT | O_WRONLY, mode); status = close (fd); rtems_test_assert (status == 0); /* * Verify the empty file */ status = stat (name01, &statbuf); rtems_test_assert (status == 0); rtems_test_assert (S_ISREG (statbuf.st_mode)); rtems_test_assert (statbuf.st_size == 0); /* * Write data to the empty file */ fd = open (name01, O_WRONLY); rtems_test_assert (fd >= 0); n = write (fd, databuf, len); rtems_test_assert (n == len); status = close (fd); rtems_test_assert (status == 0); status = stat (name01, &statbuf); rtems_test_assert (status == 0); rtems_test_assert (S_ISREG (statbuf.st_mode)); rtems_test_assert (statbuf.st_size == len); /* * Read the data from the file */ readbuf = (char *) malloc (len + 1); rtems_test_assert (readbuf); fd = open (name01, O_RDONLY); rtems_test_assert (fd >= 0); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); status = close (fd); rtems_test_assert (status == 0); /* * Open the file using O_APPEND and write the data */ memset (readbuf, 0, len + 1); fd = open (name01, O_WRONLY | O_APPEND); n = write (fd, databuf, len); rtems_test_assert (n == len); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == 2 * len); pos = lseek (fd, 0, SEEK_SET); rtems_test_assert (pos == 0); n = write (fd, databuf, len); rtems_test_assert (n == len); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == 3 * len); status = close (fd); rtems_test_assert (status == 0); /* * Read the data and verify it */ fd = open (name01, O_RDONLY); rtems_test_assert (fd >= 0); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); status = close (fd); rtems_test_assert (status == 0); /* * Open the file using O_RDWR */ memset (readbuf, 0, len + 1); fd = open (name01, O_RDWR); n = write (fd, databuf, len); rtems_test_assert (n == len); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == len); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == 2 * len); status = close (fd); rtems_test_assert (status == 0); /* * Open the file using O_TRUNC */ fd = open (name01, O_WRONLY | O_TRUNC); status = close (fd); rtems_test_assert (status == 0); /* * Verify if the length is zero */ status = stat (name01, &statbuf); rtems_test_assert (status == 0); rtems_test_assert (S_ISREG (statbuf.st_mode)); rtems_test_assert (statbuf.st_size == 0); /* * Open a directory */ status = mkdir (name02, mode); rtems_test_assert (status == 0); fd = open (name02, O_RDONLY); rtems_test_assert (fd >= 0); status = close (fd); rtems_test_assert (status == 0); free (readbuf); test_case_leave (); } static void truncate_test03 (void) { int fd; int status; char *name01 = "name01"; struct stat statbuf; char data; int n; int i; char *readbuf; off_t good_size = 100; test_case_enter (__func__); /* * Create an empty file */ fd = creat (name01, mode); status = close (fd); rtems_test_assert (status == 0); /* * Truncate it to a valid size */ status = truncate (name01, good_size); rtems_test_assert (status == 0); /* * Verify the size and the data */ status = stat (name01, &statbuf); rtems_test_assert (status == 0); rtems_test_assert (good_size == statbuf.st_size); fd = open (name01, O_RDONLY); while ((n = read (fd, &data, 1)) > 0) { rtems_test_assert (data == 0); } status = close (fd); rtems_test_assert (status == 0); /* * Fill a file with data */ fd = open (name01, O_WRONLY); rtems_test_assert (fd >= 0); n = write (fd, databuf, len); rtems_test_assert (n == len); status = close (fd); rtems_test_assert (status == 0); /* * Truncate it to the half size */ status = truncate (name01, len / 2); rtems_test_assert (status == 0); status = truncate (name01, len); rtems_test_assert (status == 0); /* * verify the data */ readbuf = (char *) malloc (len / 2); rtems_test_assert (readbuf); fd = open (name01, O_RDONLY); rtems_test_assert (fd >= 0); n = read (fd, readbuf, len / 2); rtems_test_assert (n == len / 2); rtems_test_assert (!strncmp (databuf, readbuf, len / 2)); n = read (fd, readbuf, len / 2); rtems_test_assert (n == len / 2); for (i = 0; i < len / 2; i++) { rtems_test_assert (readbuf[i] == 0); } status = close (fd); rtems_test_assert (status == 0); /* * Go back to parent directory */ status = chdir (".."); rtems_test_assert (status == 0); free(readbuf); } static void lseek_test (void) { int fd; int status; const char *name01 = "test_name01"; struct stat statbuf; ssize_t n; int i; off_t pos; ssize_t total_written = 0; char *readbuf; test_case_enter (__func__); /* * Create a file and fill with the data. */ puts ("Create a new file"); fd = creat (name01, mode); rtems_test_assert (fd >= 0); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == 0); pos = lseek (fd, 0, SEEK_END); rtems_test_assert (pos == 0); pos = lseek (fd, 0, SEEK_SET); rtems_test_assert (pos == 0); printf ("Writing %zd bytes to file\n", len * 10); for (i = 0; i < 10; i++) { n = write (fd, databuf, len); rtems_test_assert (n == (ssize_t) len); total_written += n; } printf ("Successfully wrote %zd\n", total_written); /* * Check the current position */ puts ("Check the current position"); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == total_written); pos = lseek (fd, 0, SEEK_END); rtems_test_assert (pos == total_written); /* * ftruncate shall not change the posistion */ status = ftruncate (fd, total_written + 1); rtems_test_assert (status == 0); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == total_written); pos = lseek (fd, 0, SEEK_END); printf ("%jd\n", (intmax_t) pos); rtems_test_assert (pos == total_written + 1); status = ftruncate (fd, total_written); rtems_test_assert (status == 0); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == total_written + 1); /* * Check the file size */ status = fstat (fd, &statbuf); rtems_test_assert (status == 0); rtems_test_assert (statbuf.st_size == total_written); status = ftruncate (fd, total_written); rtems_test_assert (status == 0); status = close (fd); rtems_test_assert (status == 0); /* * Open the file with O_RDONLY and check the lseek */ readbuf = (char *) malloc (len); fd = open (name01, O_RDONLY); pos = lseek (fd, len, SEEK_CUR); rtems_test_assert (pos == len); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); pos = lseek (fd, len, SEEK_CUR); rtems_test_assert (pos == 3 * len); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); pos = lseek (fd, -(off_t) len, SEEK_CUR); rtems_test_assert (pos == 3 * len); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); pos = lseek (fd, 4 * len, SEEK_SET); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); pos = lseek (fd, 10, SEEK_SET); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (strncmp (databuf, readbuf, len) != 0); pos = lseek (fd, -(off_t) len, SEEK_END); n = read (fd, readbuf, 2 * len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); status = close (fd); rtems_test_assert (status == 0); /* * Open the file withe O_RDWR and check the lseek */ fd = open (name01, O_RDWR); pos = lseek (fd, len, SEEK_CUR); rtems_test_assert (pos == len); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); pos = lseek (fd, len, SEEK_CUR); rtems_test_assert (pos == 3 * len); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); pos = lseek (fd, -(off_t) len, SEEK_CUR); rtems_test_assert (pos == 3 * len); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); pos = lseek (fd, 4 * len, SEEK_SET); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); /* * Go to the wrong position, so the data is not the same */ pos = lseek (fd, 10, SEEK_SET); n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (strncmp (databuf, readbuf, len) != 0); /* * Use SEEK_END */ pos = lseek (fd, -(off_t) len, SEEK_END); n = read (fd, readbuf, 2 * len); rtems_test_assert (n == len); rtems_test_assert (!strncmp (databuf, readbuf, len)); memset (readbuf, 0, len); /* * Write the zero to the end of file. */ pos = lseek (fd, -(off_t) len, SEEK_END); rtems_test_assert (pos == (off_t) total_written - (off_t) len); n = write (fd, readbuf, len); rtems_test_assert (n == len); /* * Verify it */ pos = lseek (fd, (off_t) total_written - (off_t) len, SEEK_SET); n = read (fd, readbuf, len); rtems_test_assert (n == len); for (i = 0; i < n; i++) { rtems_test_assert (readbuf[i] == 0); } /* * Write the zero to the beginning of file. */ pos = lseek (fd, -(off_t) total_written, SEEK_END); rtems_test_assert (pos == 0); n = write (fd, readbuf, len); rtems_test_assert (n == len); /* * Verify it */ pos = lseek (fd, 0, SEEK_SET); n = read (fd, readbuf, len); rtems_test_assert (n == len); for (i = 0; i < n; i++) { rtems_test_assert (readbuf[i] == 0); } n = read (fd, readbuf, len); rtems_test_assert (n == len); rtems_test_assert (strncmp (databuf, readbuf, len) == 0); /* * Call ftruncate to decrease the file and the position not change */ status = ftruncate (fd, len); rtems_test_assert (status == 0); pos = lseek (fd, 0, SEEK_CUR); rtems_test_assert (pos == len * 2); status = close (fd); rtems_test_assert (status == 0); test_case_leave (); free(readbuf); } static void truncate_to_zero (void) { int fd; ssize_t n; int status; off_t pos; test_case_enter (__func__); fd = creat ("file", mode); rtems_test_assert (fd >= 0); n = write (fd, databuf, len); rtems_test_assert (n == (ssize_t) len); pos = lseek (fd, 0, SEEK_END); rtems_test_assert (pos == len); status = ftruncate (fd, 0); rtems_test_assert (status == 0); pos = lseek (fd, 0, SEEK_END); rtems_test_assert (pos == 0); status = close (fd); rtems_test_assert (status == 0); test_case_leave (); } static void random_fill (char *dst, size_t n) { static uint32_t u = 0x12345678; uint32_t v = u; uint32_t w = u; size_t i = 0; int j = 0; while (i < n) { if (j == 0) { v *= 1664525; v += 1013904223; w = v; } else { w >>= 8; } dst [i] = (char) w; ++i; j = (j + 1) % 4; } u = v; } static void block_rw_lseek (int fd, size_t pos) { off_t actual; actual = lseek (fd, pos, SEEK_SET); rtems_test_assert (actual == pos); } static void block_rw_write (int fd, char *out, size_t pos, size_t size) { ssize_t n; random_fill (out + pos, size); block_rw_lseek (fd, pos); n = write (fd, out + pos, size); rtems_test_assert (n == (ssize_t) size); } static void block_rw_write_cont (int fd, char *out, size_t *pos, size_t size) { ssize_t n; random_fill (out + *pos, size); n = write (fd, out + *pos, size); rtems_test_assert (n == (ssize_t) size); *pos += size; } static void block_rw_check (int fd, const char *out, char *in, size_t size) { ssize_t n; off_t file_size; file_size = lseek (fd, 0, SEEK_END); rtems_test_assert (file_size == size); block_rw_lseek (fd, 0); n = read (fd, in, size); rtems_test_assert (n == (ssize_t) size); rtems_test_assert (memcmp (out, in, size) == 0); } static void block_rw_prepare (const char *t, int fd, char *out, size_t size) { int status; printf ("test case: %s\n", t); memset (out, 0, size); status = ftruncate (fd, 0); rtems_test_assert (status == 0); block_rw_lseek (fd, 0); } static void block_rw_case_0 (int fd, size_t block_size, char *out, char *in) { const size_t size = 3 * block_size + 1; block_rw_prepare (__func__, fd, out, size); block_rw_write (fd, out, 0, size); block_rw_check (fd, out, in, size); } static void block_rw_case_1 (int fd, size_t block_size, char *out, char *in) { const size_t size = 2 * block_size; block_rw_prepare (__func__, fd, out, size); block_rw_write (fd, out, block_size, block_size); block_rw_check (fd, out, in, size); } static void block_rw_case_2 (int fd, size_t block_size, char *out, char *in) { const size_t size = (5 * block_size) / 2; block_rw_prepare (__func__, fd, out, size); block_rw_write (fd, out, (3 * block_size) / 2, block_size); block_rw_check (fd, out, in, size); } static void block_rw_case_3 (int fd, size_t block_size, char *out, char *in) { const size_t size = 2 * block_size; block_rw_prepare (__func__, fd, out, size); block_rw_write (fd, out, block_size, block_size / 3); block_rw_write (fd, out, 2 * block_size - block_size / 3, block_size / 3); block_rw_check (fd, out, in, size); } static void block_rw_case_4 (int fd, size_t block_size, char *out, char *in) { const size_t size = 3 * block_size + 1; size_t pos = 0; block_rw_prepare (__func__, fd, out, size); block_rw_write_cont (fd, out, &pos, block_size); block_rw_write_cont (fd, out, &pos, block_size / 2); block_rw_write_cont (fd, out, &pos, block_size); block_rw_write_cont (fd, out, &pos, block_size / 2); block_rw_write_cont (fd, out, &pos, 1); block_rw_check (fd, out, in, size); } static void block_read_and_write (void) { int fd; struct stat st; int status; size_t block_size; size_t size; char *out; char *in; test_case_enter (__func__); fd = open ("file", O_RDWR | O_CREAT | O_TRUNC, mode); rtems_test_assert (fd >= 0); status = fstat (fd, &st); rtems_test_assert (status == 0); block_size = st.st_blksize; size = 3 * block_size + 1; out = malloc (size); rtems_test_assert (out != NULL); in = malloc (size); rtems_test_assert (in != NULL); block_rw_case_0 (fd, block_size, out, in); block_rw_case_1 (fd, block_size, out, in); block_rw_case_2 (fd, block_size, out, in); block_rw_case_3 (fd, block_size, out, in); block_rw_case_4 (fd, block_size, out, in); status = close (fd); rtems_test_assert (status == 0); free (out); free (in); test_case_leave (); } static void write_until_no_space_is_left (void) { static const char file [] = "zero"; int fd; struct stat st; int status; blksize_t block_size; char *out; ssize_t chunk_size; ssize_t written; off_t total; /* Use the root directory to account for some FAT12 or FAT16 specialities */ printf ("test case: %s\n", __func__); fd = open (file, O_RDWR | O_CREAT | O_TRUNC, mode); rtems_test_assert (fd >= 0); status = fstat (fd, &st); rtems_test_assert (status == 0); rtems_test_assert (st.st_size == 0); rtems_test_assert (st.st_blksize > 0); block_size = st.st_blksize; out = calloc (1, block_size); rtems_test_assert (out != NULL); total = 0; chunk_size = block_size / 2; do { errno = 0; written = write (fd, out, chunk_size); if (written > 0) { total += written; } chunk_size = block_size; } while (written > 0); rtems_test_assert (written == -1); rtems_test_assert (errno == ENOSPC || errno == EFBIG); status = close (fd); rtems_test_assert (status == 0); /* Do not use fstat() to do the path evaluation again */ status = lstat (file, &st); rtems_test_assert (status == 0); rtems_test_assert (st.st_size == total); free (out); } void test (void) { read_write_test (); lseek_test (); truncate_test03 (); truncate_to_zero (); block_read_and_write (); write_until_no_space_is_left (); }