static void test_bigfprintf(abts_case *tc, void *data) { apr_file_t *f; const char *fname = "data/testbigfprintf.dat"; char *to_write; int i; apr_file_remove(fname, p); APR_ASSERT_SUCCESS(tc, "open test file", apr_file_open(&f, fname, APR_CREATE|APR_WRITE, APR_UREAD|APR_UWRITE, p)); to_write = malloc(HUGE_STRING_LEN + 3); for (i = 0; i < HUGE_STRING_LEN + 1; ++i) to_write[i] = 'A' + i%26; strcpy(to_write + HUGE_STRING_LEN, "42"); i = apr_file_printf(f, "%s", to_write); ABTS_INT_EQUAL(tc, HUGE_STRING_LEN + 2, i); apr_file_close(f); file_contents_equal(tc, fname, to_write, HUGE_STRING_LEN + 2); free(to_write); }
static void test_writev_full(abts_case *tc, void *data) { apr_file_t *f; apr_size_t nbytes; struct iovec vec[5]; const char *fname = "data/testwritev_full.txt"; APR_ASSERT_SUCCESS(tc, "open file for writing", apr_file_open(&f, fname, APR_WRITE|APR_CREATE|APR_TRUNCATE, APR_OS_DEFAULT, p)); vec[0].iov_base = LINE1; vec[0].iov_len = strlen(LINE1); vec[1].iov_base = LINE2; vec[1].iov_len = strlen(LINE2); vec[2].iov_base = LINE1; vec[2].iov_len = strlen(LINE1); vec[3].iov_base = LINE1; vec[3].iov_len = strlen(LINE1); vec[4].iov_base = LINE2; vec[4].iov_len = strlen(LINE2); APR_ASSERT_SUCCESS(tc, "writev_full of size 5 to file", apr_file_writev_full(f, vec, 5, &nbytes)); ABTS_INT_EQUAL(tc, strlen(LINE1)*3 + strlen(LINE2)*2, nbytes); APR_ASSERT_SUCCESS(tc, "close for writing", apr_file_close(f)); file_contents_equal(tc, fname, LINE1 LINE2 LINE1 LINE1 LINE2, strlen(LINE1)*3 + strlen(LINE2)*2); }
static void test_writev_buffered(abts_case *tc, void *data) { apr_file_t *f; apr_size_t nbytes; struct iovec vec[2]; const char *fname = "data/testwritev_buffered.dat"; APR_ASSERT_SUCCESS(tc, "open file for writing", apr_file_open(&f, fname, APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BUFFERED, APR_OS_DEFAULT, p)); nbytes = strlen(TESTSTR); APR_ASSERT_SUCCESS(tc, "buffered write", apr_file_write(f, TESTSTR, &nbytes)); vec[0].iov_base = LINE1; vec[0].iov_len = strlen(LINE1); vec[1].iov_base = LINE2; vec[1].iov_len = strlen(LINE2); APR_ASSERT_SUCCESS(tc, "writev of size 2 to file", apr_file_writev(f, vec, 2, &nbytes)); APR_ASSERT_SUCCESS(tc, "close for writing", apr_file_close(f)); file_contents_equal(tc, fname, TESTSTR LINE1 LINE2, strlen(TESTSTR) + strlen(LINE1) + strlen(LINE2)); }
static void test_writev_buffered(CuTest *tc) { apr_status_t rv; apr_file_t *f; apr_size_t nbytes; struct iovec vec[2]; const char *fname = "data/testwritev_buffered.dat"; rv = apr_file_open(&f, fname, APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BUFFERED, APR_OS_DEFAULT, p); CuAssertIntEquals(tc, APR_SUCCESS, rv); nbytes = strlen(TESTSTR); rv = apr_file_write(f, TESTSTR, &nbytes); CuAssertIntEquals(tc, APR_SUCCESS, rv); vec[0].iov_base = LINE1; vec[0].iov_len = strlen(LINE1); vec[1].iov_base = LINE2; vec[1].iov_len = strlen(LINE2); rv = apr_file_writev(f, vec, 2, &nbytes); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_file_close(f); CuAssertIntEquals(tc, APR_SUCCESS, rv); file_contents_equal(tc, fname, TESTSTR LINE1 LINE2, strlen(TESTSTR) + strlen(LINE1) + strlen(LINE2)); }
static void test_puts(abts_case *tc, void *data) { apr_file_t *f; const char *fname = "data/testputs.txt"; APR_ASSERT_SUCCESS(tc, "open file for writing", apr_file_open(&f, fname, APR_WRITE|APR_CREATE|APR_TRUNCATE, APR_OS_DEFAULT, p)); APR_ASSERT_SUCCESS(tc, "write line to file", apr_file_puts(LINE1, f)); APR_ASSERT_SUCCESS(tc, "write second line to file", apr_file_puts(LINE2, f)); APR_ASSERT_SUCCESS(tc, "close for writing", apr_file_close(f)); file_contents_equal(tc, fname, LINE1 LINE2, strlen(LINE1 LINE2)); }
static void test_writev_buffered_seek(CuTest *tc) { apr_file_t *f; apr_status_t rv; apr_off_t off = 0; struct iovec vec[3]; apr_size_t nbytes = strlen(TESTSTR); char *str = apr_pcalloc(p, nbytes+1); const char *fname = "data/testwritev_buffered.dat"; rv = apr_file_open(&f, fname, APR_WRITE | APR_READ | APR_BUFFERED, APR_OS_DEFAULT, p); rv = apr_file_read(f, str, &nbytes); CuAssertIntEquals(tc, APR_SUCCESS, rv); CuAssertStrEquals(tc, TESTSTR, str); rv = apr_file_seek(f, APR_SET, &off); CuAssertIntEquals(tc, APR_SUCCESS, rv); vec[0].iov_base = LINE1; vec[0].iov_len = strlen(LINE1); vec[1].iov_base = LINE2; vec[1].iov_len = strlen(LINE2); vec[2].iov_base = TESTSTR; vec[2].iov_len = strlen(TESTSTR); rv = apr_file_writev(f, vec, 3, &nbytes); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_file_close(f); CuAssertIntEquals(tc, APR_SUCCESS, rv); file_contents_equal(tc, fname, LINE1 LINE2 TESTSTR, strlen(LINE1) + strlen(LINE2) + strlen(TESTSTR)); rv = apr_file_remove(fname, p); CuAssertIntEquals(tc, APR_SUCCESS, rv); }
static void test_writev_buffered_seek(abts_case *tc, void *data) { apr_file_t *f; apr_status_t rv; apr_off_t off = 0; struct iovec vec[3]; apr_size_t nbytes = strlen(TESTSTR); char *str = apr_pcalloc(p, nbytes+1); const char *fname = "data/testwritev_buffered.dat"; APR_ASSERT_SUCCESS(tc, "open file for writing", apr_file_open(&f, fname, APR_FOPEN_WRITE | APR_FOPEN_READ | APR_FOPEN_BUFFERED, APR_OS_DEFAULT, p)); rv = apr_file_read(f, str, &nbytes); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_STR_EQUAL(tc, TESTSTR, str); APR_ASSERT_SUCCESS(tc, "buffered seek", apr_file_seek(f, APR_SET, &off)); vec[0].iov_base = LINE1; vec[0].iov_len = strlen(LINE1); vec[1].iov_base = LINE2; vec[1].iov_len = strlen(LINE2); vec[2].iov_base = TESTSTR; vec[2].iov_len = strlen(TESTSTR); APR_ASSERT_SUCCESS(tc, "writev of size 2 to file", apr_file_writev(f, vec, 3, &nbytes)); APR_ASSERT_SUCCESS(tc, "close for writing", apr_file_close(f)); file_contents_equal(tc, fname, LINE1 LINE2 TESTSTR, strlen(LINE1) + strlen(LINE2) + strlen(TESTSTR)); APR_ASSERT_SUCCESS(tc, "remove file", apr_file_remove(fname, p)); }
static int sis_try_deduplicate(const char *rootdir, const char *fname) { const char *p, *hash, *hashdir, *path, *hashes_dir, *hashes_path; struct stat st; ino_t inode; int ret; /* fname should be in <hash>-<guid> format */ p = strchr(fname, '-'); i_assert(p != NULL); hash = t_strdup_until(fname, p); hashdir = sis_get_dir(rootdir, hash); path = t_strdup_printf("%s/%s", hashdir, fname); hashes_dir = t_strconcat(hashdir, "/", HASH_DIR_NAME, NULL); hashes_path = t_strconcat(hashes_dir, "/", hash, NULL); if (link(path, hashes_path) == 0) { /* first file with this hash. we're done */ return 0; } if (errno == ENOENT) { /* either path was already deleted or hashes dir doesn't exist */ if (mkdir(hashes_dir, 0700) < 0) { if (errno == EEXIST) return 0; i_error("mkdir(%s) failed: %m", hashes_dir); return -1; } /* try again */ if (link(path, hashes_path) == 0 || errno == ENOENT) return 0; } if (errno != EEXIST) { i_error("link(%s, %s) failed: %m", path, hashes_path); return -1; } /* need to do a byte-by-byte comparison. but check first if someone else already had deduplicated the file. */ if (stat(path, &st) < 0) { if (errno == ENOENT) { /* just got deleted */ return 0; } i_error("stat(%s) failed: %m", path); return -1; } if (st.st_nlink > 1) { /* already deduplicated */ return 0; } ret = file_contents_equal(path, hashes_path, &inode); if (ret < 0) { if (errno == ENOENT) { /* either path or hashes_path was deleted. */ return sis_try_deduplicate(rootdir, fname); } return -1; } if (ret > 0) { /* equal, replace with hard link */ ret = hardlink_replace(hashes_path, path, inode); if (ret > 0) return 0; else if (ret < 0) return -1; /* too many hard links or inode changed */ } /* replace hashes link with this */ return hardlink_replace(path, hashes_path, st.st_ino) < 0 ? -1 : 0; }