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 41246206Sgahrtest_preexisting() 42246120Sgahr{ 43246120Sgahr /* 44246148Sgahr * 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 56246148Sgahr /* Open a FILE * using fmemopen. */ 57246206Sgahr fp = fmemopen(buf, sizeof(buf), "w"); 58246206Sgahr assert(fp != NULL); 59246120Sgahr 60246148Sgahr /* Write to the buffer. */ 61246206Sgahr nofw = fwrite(str, 1, sizeof(str), fp); 62246206Sgahr assert(nofw == sizeof(str)); 63246120Sgahr 64246148Sgahr /* Close the FILE *. */ 65246206Sgahr rc = fclose(fp); 66246206Sgahr assert(rc == 0); 67246120Sgahr 68246148Sgahr /* Re-open the FILE * to read back the data. */ 69246206Sgahr fp = fmemopen(buf, sizeof(buf), "r"); 70246206Sgahr assert(fp != NULL); 71246120Sgahr 72246148Sgahr /* Read from the buffer. */ 73246206Sgahr bzero(buf2, sizeof(buf2)); 74246206Sgahr nofr = fread(buf2, 1, sizeof(buf2), fp); 75246206Sgahr assert(nofr == sizeof(buf2)); 76246120Sgahr 77246148Sgahr /* 78246148Sgahr * Since a write on a FILE * retrieved by fmemopen 79246120Sgahr * will add a '\0' (if there's space), we can check 80246148Sgahr * the strings for equality. 81246148Sgahr */ 82246206Sgahr assert(strcmp(str, buf2) == 0); 83246120Sgahr 84246148Sgahr /* Close the FILE *. */ 85246206Sgahr rc = fclose(fp); 86246206Sgahr assert(rc == 0); 87246120Sgahr 88246148Sgahr /* Now open a FILE * on the first 4 bytes of the string. */ 89246206Sgahr fp = fmemopen(str, 4, "w"); 90246206Sgahr assert(fp != NULL); 91246120Sgahr 92246148Sgahr /* 93246148Sgahr * Try to write more bytes than we shoud, we'll get a short count (4). 94246148Sgahr */ 95246206Sgahr nofw = fwrite(str2, 1, sizeof(str2), fp); 96246206Sgahr assert(nofw == 4); 97246120Sgahr 98246148Sgahr /* Close the FILE *. */ 99246206Sgahr rc = fclose(fp); 100246120Sgahr 101246148Sgahr /* Check that the string was not modified after the first 4 bytes. */ 102246206Sgahr assert(strcmp(str, str3) == 0); 103246120Sgahr} 104246120Sgahr 105246120Sgahrvoid 106246206Sgahrtest_autoalloc() 107246120Sgahr{ 108246120Sgahr /* 109246148Sgahr * 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 118246148Sgahr /* Open a FILE * using fmemopen. */ 119246206Sgahr fp = fmemopen(NULL, 512, "w+"); 120246206Sgahr assert(fp != NULL); 121246120Sgahr 122246120Sgahr /* fill the buffer */ 123246120Sgahr for (i = 0; i < 512; i++) { 124246206Sgahr nofw = fwrite("a", 1, 1, fp); 125246206Sgahr assert(nofw == 1); 126246120Sgahr } 127246120Sgahr 128246148Sgahr /* Get the current position into the stream. */ 129246206Sgahr pos = ftell(fp); 130246206Sgahr assert(pos == 512); 131246120Sgahr 132246148Sgahr /* 133246148Sgahr * Try to write past the end, we should get a short object count (0) 134246148Sgahr */ 135246206Sgahr nofw = fwrite("a", 1, 1, fp); 136246206Sgahr assert(nofw == 0); 137246120Sgahr 138246148Sgahr /* Close the FILE *. */ 139246206Sgahr rc = fclose(fp); 140246206Sgahr assert(rc == 0); 141246120Sgahr} 142246120Sgahr 143246148Sgahrvoid 144246206Sgahrtest_data_length() 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+"); 162246206Sgahr assert(fp != NULL); 163246148Sgahr 164246148Sgahr /* Write our string into the buffer. */ 165246206Sgahr nofw = fwrite(str, 1, sizeof(str), fp); 166246206Sgahr assert(nofw == sizeof(str)); 167246148Sgahr 168246148Sgahr /* 169246148Sgahr * Now seek to the end and check that ftell 170246148Sgahr * gives us sizeof(str). 171246148Sgahr */ 172246206Sgahr rc = fseek(fp, 0, SEEK_END); 173246206Sgahr assert(rc == 0); 174246206Sgahr pos = ftell(fp); 175246206Sgahr assert(pos == sizeof(str)); 176246148Sgahr 177246148Sgahr /* Close the FILE *. */ 178246206Sgahr rc = fclose(fp); 179246206Sgahr assert(rc == 0); 180246148Sgahr 181246148Sgahr /* Reopen the buffer for appending. */ 182246206Sgahr fp = fmemopen(buf, sizeof(buf), "a+"); 183246206Sgahr assert(fp != NULL); 184246148Sgahr 185246148Sgahr /* We should now be writing after the first string. */ 186246206Sgahr nofw = fwrite(str2, 1, sizeof(str2), fp); 187246206Sgahr assert(nofw == sizeof(str2)); 188246148Sgahr 189246148Sgahr /* Rewind the FILE *. */ 190246206Sgahr rc = fseek(fp, 0, SEEK_SET); 191246206Sgahr assert(rc == 0); 192246148Sgahr 193246148Sgahr /* Make sure we're at the beginning. */ 194246206Sgahr pos = ftell(fp); 195246206Sgahr assert(pos == 0); 196246148Sgahr 197246148Sgahr /* Read the whole buffer. */ 198246206Sgahr nofr = fread(str3, 1, sizeof(buf), fp); 199246206Sgahr assert(nofr == sizeof(str3)); 200246148Sgahr 201246148Sgahr /* Make sure the two strings are there. */ 202246206Sgahr assert(strncmp(str3, str, sizeof(str) - 1) == 0); 203246206Sgahr assert(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0); 204246148Sgahr 205246148Sgahr /* Close the FILE *. */ 206246206Sgahr rc = fclose(fp); 207246206Sgahr assert(rc == 0); 208246148Sgahr} 209246148Sgahr 210246148Sgahrvoid 211246206Sgahrtest_binary() 212246148Sgahr{ 213246148Sgahr /* 214246148Sgahr * Make sure that NULL bytes are never appended when opening a buffer 215246148Sgahr * in binary mode. 216246148Sgahr */ 217246148Sgahr 218246148Sgahr FILE *fp; 219246148Sgahr char buf[20]; 220246148Sgahr char str[] = "Test"; 221246148Sgahr size_t nofw; 222246148Sgahr int rc, i; 223246148Sgahr 224246148Sgahr /* Pre-fill the buffer. */ 225246206Sgahr memset(buf, 'A', sizeof(buf)); 226246148Sgahr 227246148Sgahr /* Open a FILE * in binary mode. */ 228246206Sgahr fp = fmemopen(buf, sizeof(buf), "w+b"); 229246206Sgahr assert(fp != NULL); 230246148Sgahr 231246148Sgahr /* Write some data into it. */ 232246206Sgahr nofw = fwrite(str, 1, strlen(str), fp); 233246206Sgahr assert(nofw == strlen(str)); 234246148Sgahr 235246148Sgahr /* Make sure that the buffer doesn't contain any NULL bytes. */ 236246148Sgahr for (i = 0; i < sizeof(buf); i++) 237246206Sgahr assert(buf[i] != '\0'); 238246148Sgahr 239246148Sgahr /* Close the FILE *. */ 240246206Sgahr rc = fclose(fp); 241246206Sgahr assert(rc == 0); 242246148Sgahr} 243246148Sgahr 244246120Sgahrint 245246206Sgahrmain(void) 246246120Sgahr{ 247246206Sgahr test_autoalloc(); 248246206Sgahr test_preexisting(); 249246206Sgahr test_data_length(); 250246206Sgahr test_binary(); 251246120Sgahr return (0); 252246120Sgahr} 253