141a3b124SEnji Cooper /*- 241a3b124SEnji Cooper Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org> 341a3b124SEnji Cooper 441a3b124SEnji Cooper Redistribution and use in source and binary forms, with or without 541a3b124SEnji Cooper modification, are permitted provided that the following conditions 641a3b124SEnji Cooper are met: 741a3b124SEnji Cooper 1. Redistributions of source code must retain the above copyright 841a3b124SEnji Cooper notice, this list of conditions and the following disclaimer. 941a3b124SEnji Cooper 2. Redistributions in binary form must reproduce the above copyright 1041a3b124SEnji Cooper notice, this list of conditions and the following disclaimer in the 1141a3b124SEnji Cooper documentation and/or other materials provided with the distribution. 1241a3b124SEnji Cooper 1341a3b124SEnji Cooper THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1441a3b124SEnji Cooper ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1541a3b124SEnji Cooper IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1641a3b124SEnji Cooper ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 1741a3b124SEnji Cooper FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1841a3b124SEnji Cooper DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1941a3b124SEnji Cooper OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2041a3b124SEnji Cooper HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2141a3b124SEnji Cooper LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2241a3b124SEnji Cooper OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2341a3b124SEnji Cooper SUCH DAMAGE. 2441a3b124SEnji Cooper */ 2541a3b124SEnji Cooper 2641a3b124SEnji Cooper /* 2741a3b124SEnji Cooper * Test basic FILE * functions (fread, fwrite, fseek, fclose) against 2841a3b124SEnji Cooper * a FILE * retrieved using fmemopen() 2941a3b124SEnji Cooper */ 3041a3b124SEnji Cooper 3141a3b124SEnji Cooper #include <sys/cdefs.h> 3241a3b124SEnji Cooper __FBSDID("$FreeBSD$"); 3341a3b124SEnji Cooper 3441a3b124SEnji Cooper #include <errno.h> 3541a3b124SEnji Cooper #include <stdio.h> 3641a3b124SEnji Cooper #include <string.h> 3741a3b124SEnji Cooper #include <strings.h> 38*1ee02192SEnji Cooper 3941a3b124SEnji Cooper #include <atf-c.h> 4041a3b124SEnji Cooper 4141a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_preexisting); 4241a3b124SEnji Cooper ATF_TC_BODY(test_preexisting, tc) 4341a3b124SEnji Cooper { 44*1ee02192SEnji Cooper /* Use a pre-existing buffer. */ 4541a3b124SEnji Cooper char buf[512]; 4641a3b124SEnji Cooper char buf2[512]; 4741a3b124SEnji Cooper char str[] = "Test writing some stuff"; 4841a3b124SEnji Cooper char str2[] = "AAAAAAAAA"; 4941a3b124SEnji Cooper char str3[] = "AAAA writing some stuff"; 5041a3b124SEnji Cooper FILE *fp; 5141a3b124SEnji Cooper size_t nofw, nofr; 5241a3b124SEnji Cooper int rc; 5341a3b124SEnji Cooper 5441a3b124SEnji Cooper /* Open a FILE * using fmemopen. */ 5541a3b124SEnji Cooper fp = fmemopen(buf, sizeof(buf), "w"); 5641a3b124SEnji Cooper ATF_REQUIRE(fp != NULL); 5741a3b124SEnji Cooper 5841a3b124SEnji Cooper /* Write to the buffer. */ 5941a3b124SEnji Cooper nofw = fwrite(str, 1, sizeof(str), fp); 6041a3b124SEnji Cooper ATF_REQUIRE(nofw == sizeof(str)); 6141a3b124SEnji Cooper 6241a3b124SEnji Cooper /* Close the FILE *. */ 6341a3b124SEnji Cooper rc = fclose(fp); 6441a3b124SEnji Cooper ATF_REQUIRE(rc == 0); 6541a3b124SEnji Cooper 6641a3b124SEnji Cooper /* Re-open the FILE * to read back the data. */ 6741a3b124SEnji Cooper fp = fmemopen(buf, sizeof(buf), "r"); 6841a3b124SEnji Cooper ATF_REQUIRE(fp != NULL); 6941a3b124SEnji Cooper 7041a3b124SEnji Cooper /* Read from the buffer. */ 7141a3b124SEnji Cooper bzero(buf2, sizeof(buf2)); 7241a3b124SEnji Cooper nofr = fread(buf2, 1, sizeof(buf2), fp); 7341a3b124SEnji Cooper ATF_REQUIRE(nofr == sizeof(buf2)); 7441a3b124SEnji Cooper 7541a3b124SEnji Cooper /* 7641a3b124SEnji Cooper * Since a write on a FILE * retrieved by fmemopen 7741a3b124SEnji Cooper * will add a '\0' (if there's space), we can check 7841a3b124SEnji Cooper * the strings for equality. 7941a3b124SEnji Cooper */ 8041a3b124SEnji Cooper ATF_REQUIRE(strcmp(str, buf2) == 0); 8141a3b124SEnji Cooper 8241a3b124SEnji Cooper /* Close the FILE *. */ 8341a3b124SEnji Cooper rc = fclose(fp); 8441a3b124SEnji Cooper ATF_REQUIRE(rc == 0); 8541a3b124SEnji Cooper 8641a3b124SEnji Cooper /* Now open a FILE * on the first 4 bytes of the string. */ 8741a3b124SEnji Cooper fp = fmemopen(str, 4, "w"); 8841a3b124SEnji Cooper ATF_REQUIRE(fp != NULL); 8941a3b124SEnji Cooper 9041a3b124SEnji Cooper /* 9141a3b124SEnji Cooper * Try to write more bytes than we shoud, we'll get a short count (4). 9241a3b124SEnji Cooper */ 9341a3b124SEnji Cooper nofw = fwrite(str2, 1, sizeof(str2), fp); 9441a3b124SEnji Cooper ATF_REQUIRE(nofw == 4); 9541a3b124SEnji Cooper 9641a3b124SEnji Cooper /* Close the FILE *. */ 9741a3b124SEnji Cooper rc = fclose(fp); 98b95523e8SXin LI ATF_REQUIRE(rc == 0); 9941a3b124SEnji Cooper 10041a3b124SEnji Cooper /* Check that the string was not modified after the first 4 bytes. */ 10141a3b124SEnji Cooper ATF_REQUIRE(strcmp(str, str3) == 0); 10241a3b124SEnji Cooper } 10341a3b124SEnji Cooper 10441a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_autoalloc); 10541a3b124SEnji Cooper ATF_TC_BODY(test_autoalloc, tc) 10641a3b124SEnji Cooper { 107*1ee02192SEnji Cooper /* Let fmemopen allocate the buffer. */ 10841a3b124SEnji Cooper char str[] = "A quick test"; 10941a3b124SEnji Cooper FILE *fp; 11041a3b124SEnji Cooper long pos; 11141a3b124SEnji Cooper size_t nofw, nofr, i; 11241a3b124SEnji Cooper int rc; 11341a3b124SEnji Cooper 11441a3b124SEnji Cooper /* Open a FILE * using fmemopen. */ 11541a3b124SEnji Cooper fp = fmemopen(NULL, 512, "w+"); 11641a3b124SEnji Cooper ATF_REQUIRE(fp != NULL); 11741a3b124SEnji Cooper 11841a3b124SEnji Cooper /* fill the buffer */ 11941a3b124SEnji Cooper for (i = 0; i < 512; i++) { 12041a3b124SEnji Cooper nofw = fwrite("a", 1, 1, fp); 12141a3b124SEnji Cooper ATF_REQUIRE(nofw == 1); 12241a3b124SEnji Cooper } 12341a3b124SEnji Cooper 12441a3b124SEnji Cooper /* Get the current position into the stream. */ 12541a3b124SEnji Cooper pos = ftell(fp); 12641a3b124SEnji Cooper ATF_REQUIRE(pos == 512); 12741a3b124SEnji Cooper 128*1ee02192SEnji Cooper /* Try to write past the end, we should get a short object count (0) */ 12941a3b124SEnji Cooper nofw = fwrite("a", 1, 1, fp); 13041a3b124SEnji Cooper ATF_REQUIRE(nofw == 0); 13141a3b124SEnji Cooper 13241a3b124SEnji Cooper /* Close the FILE *. */ 13341a3b124SEnji Cooper rc = fclose(fp); 13441a3b124SEnji Cooper ATF_REQUIRE(rc == 0); 13541a3b124SEnji Cooper 13641a3b124SEnji Cooper /* Open a FILE * using a wrong mode */ 13741a3b124SEnji Cooper fp = fmemopen(NULL, 512, "r"); 13841a3b124SEnji Cooper ATF_REQUIRE(fp == NULL); 13941a3b124SEnji Cooper 14041a3b124SEnji Cooper fp = fmemopen(NULL, 512, "w"); 14141a3b124SEnji Cooper ATF_REQUIRE(fp == NULL); 14241a3b124SEnji Cooper } 14341a3b124SEnji Cooper 14441a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_data_length); 14541a3b124SEnji Cooper ATF_TC_BODY(test_data_length, tc) 14641a3b124SEnji Cooper { 14741a3b124SEnji Cooper /* 14841a3b124SEnji Cooper * Here we test that a read operation doesn't go past the end of the 14941a3b124SEnji Cooper * data actually written, and that a SEEK_END seeks from the end of the 15041a3b124SEnji Cooper * data, not of the whole buffer. 15141a3b124SEnji Cooper */ 15241a3b124SEnji Cooper FILE *fp; 15341a3b124SEnji Cooper char buf[512] = {'\0'}; 15441a3b124SEnji Cooper char str[] = "Test data length. "; 15541a3b124SEnji Cooper char str2[] = "Do we have two sentences?"; 15641a3b124SEnji Cooper char str3[sizeof(str) + sizeof(str2) -1]; 15741a3b124SEnji Cooper long pos; 15841a3b124SEnji Cooper size_t nofw, nofr; 15941a3b124SEnji Cooper int rc; 16041a3b124SEnji Cooper 16141a3b124SEnji Cooper /* Open a FILE * for updating our buffer. */ 16241a3b124SEnji Cooper fp = fmemopen(buf, sizeof(buf), "w+"); 16341a3b124SEnji Cooper ATF_REQUIRE(fp != NULL); 16441a3b124SEnji Cooper 16541a3b124SEnji Cooper /* Write our string into the buffer. */ 16641a3b124SEnji Cooper nofw = fwrite(str, 1, sizeof(str), fp); 16741a3b124SEnji Cooper ATF_REQUIRE(nofw == sizeof(str)); 16841a3b124SEnji Cooper 169*1ee02192SEnji Cooper /* Now seek to the end and check that ftell gives us sizeof(str). */ 17041a3b124SEnji Cooper rc = fseek(fp, 0, SEEK_END); 17141a3b124SEnji Cooper ATF_REQUIRE(rc == 0); 17241a3b124SEnji Cooper pos = ftell(fp); 17341a3b124SEnji Cooper ATF_REQUIRE(pos == sizeof(str)); 17441a3b124SEnji Cooper 17541a3b124SEnji Cooper /* Close the FILE *. */ 17641a3b124SEnji Cooper rc = fclose(fp); 17741a3b124SEnji Cooper ATF_REQUIRE(rc == 0); 17841a3b124SEnji Cooper 17941a3b124SEnji Cooper /* Reopen the buffer for appending. */ 18041a3b124SEnji Cooper fp = fmemopen(buf, sizeof(buf), "a+"); 18141a3b124SEnji Cooper ATF_REQUIRE(fp != NULL); 18241a3b124SEnji Cooper 18341a3b124SEnji Cooper /* We should now be writing after the first string. */ 18441a3b124SEnji Cooper nofw = fwrite(str2, 1, sizeof(str2), fp); 18541a3b124SEnji Cooper ATF_REQUIRE(nofw == sizeof(str2)); 18641a3b124SEnji Cooper 18741a3b124SEnji Cooper /* Rewind the FILE *. */ 18841a3b124SEnji Cooper rc = fseek(fp, 0, SEEK_SET); 18941a3b124SEnji Cooper ATF_REQUIRE(rc == 0); 19041a3b124SEnji Cooper 19141a3b124SEnji Cooper /* Make sure we're at the beginning. */ 19241a3b124SEnji Cooper pos = ftell(fp); 19341a3b124SEnji Cooper ATF_REQUIRE(pos == 0); 19441a3b124SEnji Cooper 19541a3b124SEnji Cooper /* Read the whole buffer. */ 19641a3b124SEnji Cooper nofr = fread(str3, 1, sizeof(buf), fp); 19741a3b124SEnji Cooper ATF_REQUIRE(nofr == sizeof(str3)); 19841a3b124SEnji Cooper 19941a3b124SEnji Cooper /* Make sure the two strings are there. */ 20041a3b124SEnji Cooper ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0); 20141a3b124SEnji Cooper ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0); 20241a3b124SEnji Cooper 20341a3b124SEnji Cooper /* Close the FILE *. */ 20441a3b124SEnji Cooper rc = fclose(fp); 20541a3b124SEnji Cooper ATF_REQUIRE(rc == 0); 20641a3b124SEnji Cooper } 20741a3b124SEnji Cooper 20841a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_binary); 20941a3b124SEnji Cooper ATF_TC_BODY(test_binary, tc) 21041a3b124SEnji Cooper { 21141a3b124SEnji Cooper /* 21241a3b124SEnji Cooper * Make sure that NULL bytes are never appended when opening a buffer 21341a3b124SEnji Cooper * in binary mode. 21441a3b124SEnji Cooper */ 21541a3b124SEnji Cooper 21641a3b124SEnji Cooper FILE *fp; 21741a3b124SEnji Cooper char buf[20]; 21841a3b124SEnji Cooper char str[] = "Test"; 21941a3b124SEnji Cooper size_t nofw; 22041a3b124SEnji Cooper int rc, i; 22141a3b124SEnji Cooper 22241a3b124SEnji Cooper /* Pre-fill the buffer. */ 22341a3b124SEnji Cooper memset(buf, 'A', sizeof(buf)); 22441a3b124SEnji Cooper 22541a3b124SEnji Cooper /* Open a FILE * in binary mode. */ 22641a3b124SEnji Cooper fp = fmemopen(buf, sizeof(buf), "w+b"); 22741a3b124SEnji Cooper ATF_REQUIRE(fp != NULL); 22841a3b124SEnji Cooper 22941a3b124SEnji Cooper /* Write some data into it. */ 23041a3b124SEnji Cooper nofw = fwrite(str, 1, strlen(str), fp); 23141a3b124SEnji Cooper ATF_REQUIRE(nofw == strlen(str)); 23241a3b124SEnji Cooper 23341a3b124SEnji Cooper /* Make sure that the buffer doesn't contain any NULL bytes. */ 23441a3b124SEnji Cooper for (i = 0; i < sizeof(buf); i++) 23541a3b124SEnji Cooper ATF_REQUIRE(buf[i] != '\0'); 23641a3b124SEnji Cooper 23741a3b124SEnji Cooper /* Close the FILE *. */ 23841a3b124SEnji Cooper rc = fclose(fp); 23941a3b124SEnji Cooper ATF_REQUIRE(rc == 0); 24041a3b124SEnji Cooper } 24141a3b124SEnji Cooper 24241a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_append_binary_pos); 24341a3b124SEnji Cooper ATF_TC_BODY(test_append_binary_pos, tc) 24441a3b124SEnji Cooper { 24541a3b124SEnji Cooper /* 24641a3b124SEnji Cooper * For compatibility with other implementations (glibc), we set the 24741a3b124SEnji Cooper * position to 0 when opening an automatically allocated binary stream 24841a3b124SEnji Cooper * for appending. 24941a3b124SEnji Cooper */ 25041a3b124SEnji Cooper 25141a3b124SEnji Cooper FILE *fp; 25241a3b124SEnji Cooper 25341a3b124SEnji Cooper fp = fmemopen(NULL, 16, "ab+"); 25441a3b124SEnji Cooper ATF_REQUIRE(ftell(fp) == 0L); 25541a3b124SEnji Cooper fclose(fp); 25641a3b124SEnji Cooper 257*1ee02192SEnji Cooper /* Make sure that a pre-allocated buffer behaves correctly. */ 25841a3b124SEnji Cooper char buf[] = "Hello"; 25941a3b124SEnji Cooper fp = fmemopen(buf, sizeof(buf), "ab+"); 26041a3b124SEnji Cooper ATF_REQUIRE(ftell(fp) == strlen(buf)); 26141a3b124SEnji Cooper fclose(fp); 26241a3b124SEnji Cooper } 26341a3b124SEnji Cooper 26441a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_size_0); 26541a3b124SEnji Cooper ATF_TC_BODY(test_size_0, tc) 26641a3b124SEnji Cooper { 267*1ee02192SEnji Cooper /* POSIX mandates that we return EINVAL if size is 0. */ 26841a3b124SEnji Cooper 26941a3b124SEnji Cooper FILE *fp; 27041a3b124SEnji Cooper 27141a3b124SEnji Cooper fp = fmemopen(NULL, 0, "r+"); 27241a3b124SEnji Cooper ATF_REQUIRE(fp == NULL); 27341a3b124SEnji Cooper ATF_REQUIRE(errno == EINVAL); 27441a3b124SEnji Cooper } 27541a3b124SEnji Cooper 27641a3b124SEnji Cooper ATF_TP_ADD_TCS(tp) 27741a3b124SEnji Cooper { 27841a3b124SEnji Cooper 27941a3b124SEnji Cooper ATF_TP_ADD_TC(tp, test_autoalloc); 28041a3b124SEnji Cooper ATF_TP_ADD_TC(tp, test_preexisting); 28141a3b124SEnji Cooper ATF_TP_ADD_TC(tp, test_data_length); 28241a3b124SEnji Cooper ATF_TP_ADD_TC(tp, test_binary); 28341a3b124SEnji Cooper ATF_TP_ADD_TC(tp, test_append_binary_pos); 28441a3b124SEnji Cooper ATF_TP_ADD_TC(tp, test_size_0); 28541a3b124SEnji Cooper 28641a3b124SEnji Cooper return (atf_no_error()); 28741a3b124SEnji Cooper } 288