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$"); 33246120Sgahr 34246120Sgahr#include <assert.h> 35246120Sgahr#include <errno.h> 36246120Sgahr#include <stdio.h> 37246120Sgahr#include <string.h> 38246120Sgahr#include <strings.h> 39246120Sgahr 40246120Sgahrvoid 41252343Sjhbtest_preexisting() 42246120Sgahr{ 43246120Sgahr /* 44252343Sjhb * Use a pre-existing buffer. 45246120Sgahr */ 46246120Sgahr 47246120Sgahr char buf[512]; 48246120Sgahr char buf2[512]; 49246120Sgahr char str[] = "Test writing some stuff"; 50246120Sgahr char str2[] = "AAAAAAAAA"; 51246120Sgahr char str3[] = "AAAA writing some stuff"; 52246120Sgahr FILE *fp; 53246120Sgahr size_t nofw, nofr; 54246120Sgahr int rc; 55246120Sgahr 56252343Sjhb /* Open a FILE * using fmemopen. */ 57252343Sjhb fp = fmemopen(buf, sizeof(buf), "w"); 58252343Sjhb assert(fp != NULL); 59246120Sgahr 60252343Sjhb /* Write to the buffer. */ 61252343Sjhb nofw = fwrite(str, 1, sizeof(str), fp); 62252343Sjhb assert(nofw == sizeof(str)); 63246120Sgahr 64252343Sjhb /* Close the FILE *. */ 65252343Sjhb rc = fclose(fp); 66252343Sjhb assert(rc == 0); 67246120Sgahr 68252343Sjhb /* Re-open the FILE * to read back the data. */ 69252343Sjhb fp = fmemopen(buf, sizeof(buf), "r"); 70252343Sjhb assert(fp != NULL); 71246120Sgahr 72252343Sjhb /* Read from the buffer. */ 73252343Sjhb bzero(buf2, sizeof(buf2)); 74252343Sjhb nofr = fread(buf2, 1, sizeof(buf2), fp); 75252343Sjhb assert(nofr == sizeof(buf2)); 76246120Sgahr 77252343Sjhb /* 78252343Sjhb * Since a write on a FILE * retrieved by fmemopen 79246120Sgahr * will add a '\0' (if there's space), we can check 80252343Sjhb * the strings for equality. 81252343Sjhb */ 82252343Sjhb assert(strcmp(str, buf2) == 0); 83246120Sgahr 84252343Sjhb /* Close the FILE *. */ 85252343Sjhb rc = fclose(fp); 86252343Sjhb assert(rc == 0); 87246120Sgahr 88252343Sjhb /* Now open a FILE * on the first 4 bytes of the string. */ 89252343Sjhb fp = fmemopen(str, 4, "w"); 90252343Sjhb assert(fp != NULL); 91246120Sgahr 92252343Sjhb /* 93252343Sjhb * Try to write more bytes than we shoud, we'll get a short count (4). 94252343Sjhb */ 95252343Sjhb nofw = fwrite(str2, 1, sizeof(str2), fp); 96252343Sjhb assert(nofw == 4); 97246120Sgahr 98252343Sjhb /* Close the FILE *. */ 99252343Sjhb rc = fclose(fp); 100246120Sgahr 101252343Sjhb /* Check that the string was not modified after the first 4 bytes. */ 102252343Sjhb assert(strcmp(str, str3) == 0); 103246120Sgahr} 104246120Sgahr 105246120Sgahrvoid 106252343Sjhbtest_autoalloc() 107246120Sgahr{ 108246120Sgahr /* 109252343Sjhb * Let fmemopen allocate the buffer. 110246120Sgahr */ 111246120Sgahr 112246120Sgahr char str[] = "A quick test"; 113246120Sgahr FILE *fp; 114246120Sgahr long pos; 115246120Sgahr size_t nofw, nofr, i; 116246120Sgahr int rc; 117246120Sgahr 118252343Sjhb /* Open a FILE * using fmemopen. */ 119252343Sjhb fp = fmemopen(NULL, 512, "w+"); 120252343Sjhb assert(fp != NULL); 121246120Sgahr 122246120Sgahr /* fill the buffer */ 123246120Sgahr for (i = 0; i < 512; i++) { 124252343Sjhb nofw = fwrite("a", 1, 1, fp); 125252343Sjhb assert(nofw == 1); 126246120Sgahr } 127246120Sgahr 128252343Sjhb /* Get the current position into the stream. */ 129252343Sjhb pos = ftell(fp); 130252343Sjhb assert(pos == 512); 131246120Sgahr 132252343Sjhb /* 133252343Sjhb * Try to write past the end, we should get a short object count (0) 134252343Sjhb */ 135252343Sjhb nofw = fwrite("a", 1, 1, fp); 136252343Sjhb assert(nofw == 0); 137246120Sgahr 138252343Sjhb /* Close the FILE *. */ 139252343Sjhb rc = fclose(fp); 140252343Sjhb assert(rc == 0); 141246120Sgahr} 142246120Sgahr 143252343Sjhbvoid 144252343Sjhbtest_data_length() 145252343Sjhb{ 146252343Sjhb /* 147252343Sjhb * Here we test that a read operation doesn't go past the end of the 148252343Sjhb * data actually written, and that a SEEK_END seeks from the end of the 149252343Sjhb * data, not of the whole buffer. 150252343Sjhb */ 151252343Sjhb FILE *fp; 152252343Sjhb char buf[512] = {'\0'}; 153252343Sjhb char str[] = "Test data length. "; 154252343Sjhb char str2[] = "Do we have two sentences?"; 155252343Sjhb char str3[sizeof(str) + sizeof(str2) -1]; 156252343Sjhb long pos; 157252343Sjhb size_t nofw, nofr; 158252343Sjhb int rc; 159252343Sjhb 160252343Sjhb /* Open a FILE * for updating our buffer. */ 161252343Sjhb fp = fmemopen(buf, sizeof(buf), "w+"); 162252343Sjhb assert(fp != NULL); 163252343Sjhb 164252343Sjhb /* Write our string into the buffer. */ 165252343Sjhb nofw = fwrite(str, 1, sizeof(str), fp); 166252343Sjhb assert(nofw == sizeof(str)); 167252343Sjhb 168252343Sjhb /* 169252343Sjhb * Now seek to the end and check that ftell 170252343Sjhb * gives us sizeof(str). 171252343Sjhb */ 172252343Sjhb rc = fseek(fp, 0, SEEK_END); 173252343Sjhb assert(rc == 0); 174252343Sjhb pos = ftell(fp); 175252343Sjhb assert(pos == sizeof(str)); 176252343Sjhb 177252343Sjhb /* Close the FILE *. */ 178252343Sjhb rc = fclose(fp); 179252343Sjhb assert(rc == 0); 180252343Sjhb 181252343Sjhb /* Reopen the buffer for appending. */ 182252343Sjhb fp = fmemopen(buf, sizeof(buf), "a+"); 183252343Sjhb assert(fp != NULL); 184252343Sjhb 185252343Sjhb /* We should now be writing after the first string. */ 186252343Sjhb nofw = fwrite(str2, 1, sizeof(str2), fp); 187252343Sjhb assert(nofw == sizeof(str2)); 188252343Sjhb 189252343Sjhb /* Rewind the FILE *. */ 190252343Sjhb rc = fseek(fp, 0, SEEK_SET); 191252343Sjhb assert(rc == 0); 192252343Sjhb 193252343Sjhb /* Make sure we're at the beginning. */ 194252343Sjhb pos = ftell(fp); 195252343Sjhb assert(pos == 0); 196252343Sjhb 197252343Sjhb /* Read the whole buffer. */ 198252343Sjhb nofr = fread(str3, 1, sizeof(buf), fp); 199252343Sjhb assert(nofr == sizeof(str3)); 200252343Sjhb 201252343Sjhb /* Make sure the two strings are there. */ 202252343Sjhb assert(strncmp(str3, str, sizeof(str) - 1) == 0); 203252343Sjhb assert(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0); 204252343Sjhb 205252343Sjhb /* Close the FILE *. */ 206252343Sjhb rc = fclose(fp); 207252343Sjhb assert(rc == 0); 208252343Sjhb} 209252343Sjhb 210252343Sjhbvoid 211252343Sjhbtest_binary() 212252343Sjhb{ 213252343Sjhb /* 214252343Sjhb * Make sure that NULL bytes are never appended when opening a buffer 215252343Sjhb * in binary mode. 216252343Sjhb */ 217252343Sjhb 218252343Sjhb FILE *fp; 219252343Sjhb char buf[20]; 220252343Sjhb char str[] = "Test"; 221252343Sjhb size_t nofw; 222252343Sjhb int rc, i; 223252343Sjhb 224252343Sjhb /* Pre-fill the buffer. */ 225252343Sjhb memset(buf, 'A', sizeof(buf)); 226252343Sjhb 227252343Sjhb /* Open a FILE * in binary mode. */ 228252343Sjhb fp = fmemopen(buf, sizeof(buf), "w+b"); 229252343Sjhb assert(fp != NULL); 230252343Sjhb 231252343Sjhb /* Write some data into it. */ 232252343Sjhb nofw = fwrite(str, 1, strlen(str), fp); 233252343Sjhb assert(nofw == strlen(str)); 234252343Sjhb 235252343Sjhb /* Make sure that the buffer doesn't contain any NULL bytes. */ 236252343Sjhb for (i = 0; i < sizeof(buf); i++) 237252343Sjhb assert(buf[i] != '\0'); 238252343Sjhb 239252343Sjhb /* Close the FILE *. */ 240252343Sjhb rc = fclose(fp); 241252343Sjhb assert(rc == 0); 242252343Sjhb} 243252343Sjhb 244246120Sgahrint 245252343Sjhbmain(void) 246246120Sgahr{ 247252343Sjhb test_autoalloc(); 248252343Sjhb test_preexisting(); 249252343Sjhb test_data_length(); 250252343Sjhb test_binary(); 251246120Sgahr return (0); 252246120Sgahr} 253