#include #include #include #include #include #include #include #include #include #include #include #define ARCH64 ((sizeof(long)) > 4) #define ARCH32 ((sizeof(long)) == 4) char *testfile = "testlen.dat"; int testfd; volatile int sigxfsz; void try(const char *what, int err) { if (!err) return; fprintf (stderr, "Unexpected result %d. %s: %s\n", err, what, strerror(errno)); exit(1); } void compare(const char *what, int error, int result) { if (!error && !result) return; if (error && result && error == errno) return; if (result && !error) fprintf (stderr, "%s: unexpected failure, %s\n", what, strerror(errno)); else if (result) fprintf (stderr, "%s: wrong failure, %s (expected %s)\n", what, strerror(errno), strerror(error)); else fprintf (stderr, "%s: unexpected success\n", what); exit(1); } void check_signal(const char *what, int expected) { if (expected == sigxfsz) return; if (expected) fprintf (stderr, "%s: expected signal missing,\n", what); else fprintf (stderr, "%s: unexpected signal\n", what); exit(1); } void handle_sigxfsz(int n) { sigxfsz = 1; signal (SIGXFSZ, handle_sigxfsz); } void create_file(void) { testfd = open(testfile, O_CREAT|O_TRUNC|O_RDWR, 0666); try ("open(O_CREAT)", testfd < 0); } void set_length(long length, int error, int expect_signal) { sigxfsz = 0; compare ("ftruncate", error, ftruncate(testfd, length) != 0); check_signal ("ftruncate", expect_signal); } void test_seek(long where, long expected, int error) { errno = 0; try ("lseek", expected != lseek(testfd, where, SEEK_SET)); compare ("lseek", errno, error); } void write_file(long where, long how_much, long expected, int error, int expect_signal) { char *buffer = alloca(how_much); errno = 0; sigxfsz = 0; try ("lseek", where != lseek(testfd, where, SEEK_SET)); try ("write", expected != write(testfd, buffer, how_much)); compare ("write", errno, error); assert (expect_signal == sigxfsz); } /* * Set the max-file-length resource limit. */ void set_maxfile (int max) { struct rlimit rlimit; if (max) rlimit.rlim_cur = max; else rlimit.rlim_cur = RLIM_INFINITY; rlimit.rlim_max = RLIM_INFINITY; try ("setrlimit", setrlimit(RLIMIT_FSIZE, &rlimit)); } int main() { long max_filesize; long soft_limit = 1000000; signal (SIGXFSZ, handle_sigxfsz); /* First set of tests. Check out the handling of the filesystem * offset maximum. */ if (ARCH32) max_filesize = 0x7FFFFFFFL; else { long ind_entries; struct statfs statbuf; try ("statfs", statfs (".", &statbuf)); /* We know about ext2 internals here... */ ind_entries = statbuf.f_bsize / 4; max_filesize = statbuf.f_bsize * (12L + ind_entries + ind_entries * ind_entries + ind_entries * ind_entries * ind_entries) - 1; } printf ("Using a maximum file size of %ld %ld\n", max_filesize); /* Creating a file and extending to 0 should be a noop. */ create_file(); set_length(0, 0, 0); printf ("truncate to 0: PASSED\n"); /* Creating a file and extending to maxlen should be fine. */ create_file(); set_length(max_filesize, 0, 0); printf ("truncate to %ld: PASSED\n", max_filesize); /* Creating a file 1 beyond maxlen should fail with EINVAL (-ve) * on ARCH32, and EFBIG (it's still +ve) on ARCH64. */ create_file(); if (ARCH32) set_length(max_filesize+1, EINVAL, 0); else set_length(max_filesize+1, EFBIG, 0); printf ("truncate to %ld: PASSED\n", max_filesize + 1); /* Creating a file with -ve size should fail with EINVAL. */ create_file(); set_length(-1, EINVAL, 0); printf ("truncate to -1: PASSED\n"); /* * Now test out writes near the limit boundaries. */ /* Just test that simple writes work. */ create_file(); set_length(1000, 0, 0); write_file(1000, 1000, 1000, 0, 0); printf ("simple write: PASSED\n"); /* Test writes just below maxlen */ create_file(); set_length(max_filesize - 1000, 0, 0); write_file(max_filesize - 1000, 1000, 1000, 0, 0); printf ("write (max_filesize-1000, 1000): PASSED\n"); /* Test overwrites just below maxlen */ create_file(); set_length(max_filesize, 0, 0); write_file(max_filesize - 1000, 1000, 1000, 0, 0); printf ("overwrite (max_filesize-1000, 1000): PASSED\n"); /* Test writes passing maxlen */ create_file(); set_length(max_filesize - 1000, 0, 0); write_file(max_filesize - 1000, 1001, 1000, 0, 0); write_file(max_filesize, 1, -1, EFBIG, 0); printf ("write (max_filesize-1000, 1001): PASSED\n"); /* Test writes at maxlen */ create_file(); write_file(max_filesize, 1000, -1, EFBIG, 0); printf ("write (max_filesize, 1000): PASSED\n"); /* Test writes beyond maxlen */ create_file(); test_seek(max_filesize+1000, -1, EINVAL); printf ("seek (max_filesize+1000): PASSED\n"); /* * Set up a filesize resource limit and repeat the tests. * Truncate first: */ set_maxfile(soft_limit); printf ("Established soft file size limit.\n"); /* Creating a file and extending to 0 should be a noop. */ create_file(); set_length(0, 0, 0); printf ("truncate to 0: PASSED\n"); /* Creating a file and extending to the soft limit should be fine. */ create_file(); set_length(soft_limit, 0, 0); printf ("truncate to soft_limit: PASSED\n"); /* Creating a file 1 beyond the soft limit should fail with * EFBIG and SIGXFSZ. */ create_file(); set_length(soft_limit+1, EFBIG, 1); printf ("truncate to soft_limit+1: PASSED\n"); /* Creating a file with -ve size should fail with EINVAL. */ create_file(); set_length(-1, EINVAL, 0); printf ("truncate to -1: PASSED\n"); /* * Now the write tests again. */ /* Just test that simple writes work. */ create_file(); set_length(1000, 0, 0); write_file(1000, 1000, 1000, 0, 0); printf ("simple write: PASSED\n"); /* Test writes just below soft_limit */ create_file(); set_length(soft_limit - 1000, 0, 0); write_file(soft_limit - 1000, 1000, 1000, 0, 0); printf ("write (soft_limit-1000, 1000): PASSED\n"); /* Test overwrites just below soft_limit */ create_file(); set_length(soft_limit, 0, 0); write_file(soft_limit - 1000, 1000, 1000, 0, 0); printf ("overwrite (soft_limit-1000, 1000): PASSED\n"); /* Test writes passing soft_limit */ create_file(); set_length(soft_limit - 1000, 0, 0); write_file(soft_limit - 1000, 1001, 1000, 0, 0); write_file(soft_limit, 1, -1, EFBIG, 1); printf ("write (soft_limit-1000, 1001): PASSED\n"); /* Test writes at soft_limit */ create_file(); write_file(soft_limit, 1000, -1, EFBIG, 1); printf ("write (soft_limit, 1000): PASSED\n"); /* Test writes beyond soft_limit */ create_file(); test_seek(soft_limit+1000, soft_limit+1000, 0); write_file(soft_limit+1000, 1000, -1, EFBIG, 1); printf ("seek (soft_limit+1000): PASSED\n"); return 0; }