1246120Sgahr/*- 2246120SgahrCopyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org> 3246120Sgahr 4246120SgahrRedistribution and use in source and binary forms, with or without 5246120Sgahrmodification, are permitted provided that the following conditions 6246120Sgahrare met: 7246120Sgahr1. Redistributions of source code must retain the above copyright 8246120Sgahr notice, this list of conditions and the following disclaimer. 9246120Sgahr2. Redistributions in binary form must reproduce the above copyright 10246120Sgahr notice, this list of conditions and the following disclaimer in the 11246120Sgahr documentation and/or other materials provided with the distribution. 12246120Sgahr 13246120SgahrTHIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14246120SgahrANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15246120SgahrIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16246120SgahrARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17246120SgahrFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18246120SgahrDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19246120SgahrOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20246120SgahrHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21246120SgahrLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22246120SgahrOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23246120SgahrSUCH DAMAGE. 24246120Sgahr*/ 25246120Sgahr 26246120Sgahr/* 27246120Sgahr * Test basic FILE * functions (fread, fwrite, fseek, fclose) against 28246120Sgahr * a FILE * retrieved using fmemopen() 29246120Sgahr */ 30246120Sgahr 31246120Sgahr#include <sys/cdefs.h> 32246120Sgahr__FBSDID("$FreeBSD: releng/11.0/lib/libc/tests/stdio/fmemopen2_test.c 298311 2016-04-19 23:59:10Z ngie $"); 33246120Sgahr 34246120Sgahr#include <errno.h> 35246120Sgahr#include <stdio.h> 36246120Sgahr#include <string.h> 37246120Sgahr#include <strings.h> 38290537Sngie 39274592Sngie#include <atf-c.h> 40246120Sgahr 41274592SngieATF_TC_WITHOUT_HEAD(test_preexisting); 42274592SngieATF_TC_BODY(test_preexisting, tc) 43246120Sgahr{ 44290537Sngie /* Use a pre-existing buffer. */ 45246120Sgahr char buf[512]; 46246120Sgahr char buf2[512]; 47246120Sgahr char str[] = "Test writing some stuff"; 48246120Sgahr char str2[] = "AAAAAAAAA"; 49246120Sgahr char str3[] = "AAAA writing some stuff"; 50246120Sgahr FILE *fp; 51246120Sgahr size_t nofw, nofr; 52246120Sgahr int rc; 53246120Sgahr 54246148Sgahr /* Open a FILE * using fmemopen. */ 55246206Sgahr fp = fmemopen(buf, sizeof(buf), "w"); 56274592Sngie ATF_REQUIRE(fp != NULL); 57246120Sgahr 58246148Sgahr /* Write to the buffer. */ 59246206Sgahr nofw = fwrite(str, 1, sizeof(str), fp); 60274592Sngie ATF_REQUIRE(nofw == sizeof(str)); 61246120Sgahr 62246148Sgahr /* Close the FILE *. */ 63246206Sgahr rc = fclose(fp); 64274592Sngie ATF_REQUIRE(rc == 0); 65246120Sgahr 66246148Sgahr /* Re-open the FILE * to read back the data. */ 67246206Sgahr fp = fmemopen(buf, sizeof(buf), "r"); 68274592Sngie ATF_REQUIRE(fp != NULL); 69246120Sgahr 70246148Sgahr /* Read from the buffer. */ 71246206Sgahr bzero(buf2, sizeof(buf2)); 72246206Sgahr nofr = fread(buf2, 1, sizeof(buf2), fp); 73274592Sngie ATF_REQUIRE(nofr == sizeof(buf2)); 74246120Sgahr 75290537Sngie /* 76246148Sgahr * Since a write on a FILE * retrieved by fmemopen 77246120Sgahr * will add a '\0' (if there's space), we can check 78246148Sgahr * the strings for equality. 79246148Sgahr */ 80274592Sngie ATF_REQUIRE(strcmp(str, buf2) == 0); 81246120Sgahr 82246148Sgahr /* Close the FILE *. */ 83246206Sgahr rc = fclose(fp); 84274592Sngie ATF_REQUIRE(rc == 0); 85246120Sgahr 86246148Sgahr /* Now open a FILE * on the first 4 bytes of the string. */ 87246206Sgahr fp = fmemopen(str, 4, "w"); 88274592Sngie ATF_REQUIRE(fp != NULL); 89246120Sgahr 90246148Sgahr /* 91246148Sgahr * Try to write more bytes than we shoud, we'll get a short count (4). 92246148Sgahr */ 93246206Sgahr nofw = fwrite(str2, 1, sizeof(str2), fp); 94274592Sngie ATF_REQUIRE(nofw == 4); 95246120Sgahr 96246148Sgahr /* Close the FILE *. */ 97246206Sgahr rc = fclose(fp); 98288382Sdelphij ATF_REQUIRE(rc == 0); 99246120Sgahr 100246148Sgahr /* Check that the string was not modified after the first 4 bytes. */ 101274592Sngie ATF_REQUIRE(strcmp(str, str3) == 0); 102246120Sgahr} 103246120Sgahr 104274592SngieATF_TC_WITHOUT_HEAD(test_autoalloc); 105274592SngieATF_TC_BODY(test_autoalloc, tc) 106246120Sgahr{ 107290537Sngie /* Let fmemopen allocate the buffer. */ 108246120Sgahr FILE *fp; 109246120Sgahr long pos; 110290860Sbapt size_t nofw, i; 111246120Sgahr int rc; 112246120Sgahr 113246148Sgahr /* Open a FILE * using fmemopen. */ 114246206Sgahr fp = fmemopen(NULL, 512, "w+"); 115274592Sngie ATF_REQUIRE(fp != NULL); 116246120Sgahr 117246120Sgahr /* fill the buffer */ 118246120Sgahr for (i = 0; i < 512; i++) { 119246206Sgahr nofw = fwrite("a", 1, 1, fp); 120274592Sngie ATF_REQUIRE(nofw == 1); 121246120Sgahr } 122246120Sgahr 123246148Sgahr /* Get the current position into the stream. */ 124246206Sgahr pos = ftell(fp); 125274592Sngie ATF_REQUIRE(pos == 512); 126246120Sgahr 127290537Sngie /* Try to write past the end, we should get a short object count (0) */ 128246206Sgahr nofw = fwrite("a", 1, 1, fp); 129274592Sngie ATF_REQUIRE(nofw == 0); 130246120Sgahr 131246148Sgahr /* Close the FILE *. */ 132246206Sgahr rc = fclose(fp); 133274592Sngie ATF_REQUIRE(rc == 0); 134266971Sgahr 135266971Sgahr /* Open a FILE * using a wrong mode */ 136266971Sgahr fp = fmemopen(NULL, 512, "r"); 137274592Sngie ATF_REQUIRE(fp == NULL); 138266971Sgahr 139266971Sgahr fp = fmemopen(NULL, 512, "w"); 140274592Sngie ATF_REQUIRE(fp == NULL); 141246120Sgahr} 142246120Sgahr 143274592SngieATF_TC_WITHOUT_HEAD(test_data_length); 144274592SngieATF_TC_BODY(test_data_length, tc) 145246148Sgahr{ 146246148Sgahr /* 147246148Sgahr * Here we test that a read operation doesn't go past the end of the 148246148Sgahr * data actually written, and that a SEEK_END seeks from the end of the 149246148Sgahr * data, not of the whole buffer. 150246148Sgahr */ 151246148Sgahr FILE *fp; 152246148Sgahr char buf[512] = {'\0'}; 153246148Sgahr char str[] = "Test data length. "; 154246148Sgahr char str2[] = "Do we have two sentences?"; 155246148Sgahr char str3[sizeof(str) + sizeof(str2) -1]; 156246148Sgahr long pos; 157246148Sgahr size_t nofw, nofr; 158246148Sgahr int rc; 159246148Sgahr 160246148Sgahr /* Open a FILE * for updating our buffer. */ 161246206Sgahr fp = fmemopen(buf, sizeof(buf), "w+"); 162274592Sngie ATF_REQUIRE(fp != NULL); 163246148Sgahr 164246148Sgahr /* Write our string into the buffer. */ 165246206Sgahr nofw = fwrite(str, 1, sizeof(str), fp); 166274592Sngie ATF_REQUIRE(nofw == sizeof(str)); 167246148Sgahr 168290537Sngie /* Now seek to the end and check that ftell gives us sizeof(str). */ 169246206Sgahr rc = fseek(fp, 0, SEEK_END); 170274592Sngie ATF_REQUIRE(rc == 0); 171246206Sgahr pos = ftell(fp); 172274592Sngie ATF_REQUIRE(pos == sizeof(str)); 173246148Sgahr 174246148Sgahr /* Close the FILE *. */ 175246206Sgahr rc = fclose(fp); 176274592Sngie ATF_REQUIRE(rc == 0); 177246148Sgahr 178246148Sgahr /* Reopen the buffer for appending. */ 179246206Sgahr fp = fmemopen(buf, sizeof(buf), "a+"); 180274592Sngie ATF_REQUIRE(fp != NULL); 181246148Sgahr 182246148Sgahr /* We should now be writing after the first string. */ 183246206Sgahr nofw = fwrite(str2, 1, sizeof(str2), fp); 184274592Sngie ATF_REQUIRE(nofw == sizeof(str2)); 185246148Sgahr 186246148Sgahr /* Rewind the FILE *. */ 187246206Sgahr rc = fseek(fp, 0, SEEK_SET); 188274592Sngie ATF_REQUIRE(rc == 0); 189246148Sgahr 190246148Sgahr /* Make sure we're at the beginning. */ 191246206Sgahr pos = ftell(fp); 192274592Sngie ATF_REQUIRE(pos == 0); 193246148Sgahr 194246148Sgahr /* Read the whole buffer. */ 195246206Sgahr nofr = fread(str3, 1, sizeof(buf), fp); 196274592Sngie ATF_REQUIRE(nofr == sizeof(str3)); 197246148Sgahr 198246148Sgahr /* Make sure the two strings are there. */ 199274592Sngie ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0); 200274592Sngie ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0); 201246148Sgahr 202246148Sgahr /* Close the FILE *. */ 203246206Sgahr rc = fclose(fp); 204274592Sngie ATF_REQUIRE(rc == 0); 205246148Sgahr} 206246148Sgahr 207274592SngieATF_TC_WITHOUT_HEAD(test_binary); 208274592SngieATF_TC_BODY(test_binary, tc) 209246148Sgahr{ 210246148Sgahr /* 211246148Sgahr * Make sure that NULL bytes are never appended when opening a buffer 212246148Sgahr * in binary mode. 213246148Sgahr */ 214246148Sgahr 215246148Sgahr FILE *fp; 216246148Sgahr char buf[20]; 217246148Sgahr char str[] = "Test"; 218246148Sgahr size_t nofw; 219246148Sgahr int rc, i; 220246148Sgahr 221246148Sgahr /* Pre-fill the buffer. */ 222246206Sgahr memset(buf, 'A', sizeof(buf)); 223246148Sgahr 224246148Sgahr /* Open a FILE * in binary mode. */ 225246206Sgahr fp = fmemopen(buf, sizeof(buf), "w+b"); 226274592Sngie ATF_REQUIRE(fp != NULL); 227246148Sgahr 228246148Sgahr /* Write some data into it. */ 229246206Sgahr nofw = fwrite(str, 1, strlen(str), fp); 230274592Sngie ATF_REQUIRE(nofw == strlen(str)); 231246148Sgahr 232246148Sgahr /* Make sure that the buffer doesn't contain any NULL bytes. */ 233246148Sgahr for (i = 0; i < sizeof(buf); i++) 234274592Sngie ATF_REQUIRE(buf[i] != '\0'); 235246148Sgahr 236246148Sgahr /* Close the FILE *. */ 237246206Sgahr rc = fclose(fp); 238274592Sngie ATF_REQUIRE(rc == 0); 239246148Sgahr} 240246148Sgahr 241274592SngieATF_TC_WITHOUT_HEAD(test_append_binary_pos); 242274592SngieATF_TC_BODY(test_append_binary_pos, tc) 243266971Sgahr{ 244266971Sgahr /* 245266971Sgahr * For compatibility with other implementations (glibc), we set the 246266971Sgahr * position to 0 when opening an automatically allocated binary stream 247266971Sgahr * for appending. 248266971Sgahr */ 249266971Sgahr 250266971Sgahr FILE *fp; 251266971Sgahr 252266971Sgahr fp = fmemopen(NULL, 16, "ab+"); 253298311Sngie ATF_REQUIRE(fp != NULL); 254274592Sngie ATF_REQUIRE(ftell(fp) == 0L); 255266971Sgahr fclose(fp); 256266971Sgahr 257290537Sngie /* Make sure that a pre-allocated buffer behaves correctly. */ 258266971Sgahr char buf[] = "Hello"; 259266971Sgahr fp = fmemopen(buf, sizeof(buf), "ab+"); 260298311Sngie ATF_REQUIRE(fp != NULL); 261274592Sngie ATF_REQUIRE(ftell(fp) == strlen(buf)); 262266971Sgahr fclose(fp); 263266971Sgahr} 264266971Sgahr 265274592SngieATF_TC_WITHOUT_HEAD(test_size_0); 266274592SngieATF_TC_BODY(test_size_0, tc) 267266971Sgahr{ 268290537Sngie /* POSIX mandates that we return EINVAL if size is 0. */ 269266971Sgahr 270266971Sgahr FILE *fp; 271266971Sgahr 272266971Sgahr fp = fmemopen(NULL, 0, "r+"); 273274592Sngie ATF_REQUIRE(fp == NULL); 274274592Sngie ATF_REQUIRE(errno == EINVAL); 275266971Sgahr} 276266971Sgahr 277274592SngieATF_TP_ADD_TCS(tp) 278246120Sgahr{ 279274592Sngie 280274592Sngie ATF_TP_ADD_TC(tp, test_autoalloc); 281274592Sngie ATF_TP_ADD_TC(tp, test_preexisting); 282274592Sngie ATF_TP_ADD_TC(tp, test_data_length); 283274592Sngie ATF_TP_ADD_TC(tp, test_binary); 284274592Sngie ATF_TP_ADD_TC(tp, test_append_binary_pos); 285274592Sngie ATF_TP_ADD_TC(tp, test_size_0); 286274592Sngie 287274592Sngie return (atf_no_error()); 288246120Sgahr} 289