1 /*- 2 Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org> 3 4 Redistribution and use in source and binary forms, with or without 5 modification, are permitted provided that the following conditions 6 are met: 7 1. Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 2. Redistributions in binary form must reproduce the above copyright 10 notice, this list of conditions and the following disclaimer in the 11 documentation and/or other materials provided with the distribution. 12 13 THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 SUCH DAMAGE. 24 */ 25 26 /* 27 * Test basic FILE * functions (fread, fwrite, fseek, fclose) against 28 * a FILE * retrieved using fmemopen() 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <errno.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <atf-c.h> 39 40 ATF_TC_WITHOUT_HEAD(test_preexisting); 41 ATF_TC_BODY(test_preexisting, tc) 42 { 43 /* 44 * Use a pre-existing buffer. 45 */ 46 47 char buf[512]; 48 char buf2[512]; 49 char str[] = "Test writing some stuff"; 50 char str2[] = "AAAAAAAAA"; 51 char str3[] = "AAAA writing some stuff"; 52 FILE *fp; 53 size_t nofw, nofr; 54 int rc; 55 56 /* Open a FILE * using fmemopen. */ 57 fp = fmemopen(buf, sizeof(buf), "w"); 58 ATF_REQUIRE(fp != NULL); 59 60 /* Write to the buffer. */ 61 nofw = fwrite(str, 1, sizeof(str), fp); 62 ATF_REQUIRE(nofw == sizeof(str)); 63 64 /* Close the FILE *. */ 65 rc = fclose(fp); 66 ATF_REQUIRE(rc == 0); 67 68 /* Re-open the FILE * to read back the data. */ 69 fp = fmemopen(buf, sizeof(buf), "r"); 70 ATF_REQUIRE(fp != NULL); 71 72 /* Read from the buffer. */ 73 bzero(buf2, sizeof(buf2)); 74 nofr = fread(buf2, 1, sizeof(buf2), fp); 75 ATF_REQUIRE(nofr == sizeof(buf2)); 76 77 /* 78 * Since a write on a FILE * retrieved by fmemopen 79 * will add a '\0' (if there's space), we can check 80 * the strings for equality. 81 */ 82 ATF_REQUIRE(strcmp(str, buf2) == 0); 83 84 /* Close the FILE *. */ 85 rc = fclose(fp); 86 ATF_REQUIRE(rc == 0); 87 88 /* Now open a FILE * on the first 4 bytes of the string. */ 89 fp = fmemopen(str, 4, "w"); 90 ATF_REQUIRE(fp != NULL); 91 92 /* 93 * Try to write more bytes than we shoud, we'll get a short count (4). 94 */ 95 nofw = fwrite(str2, 1, sizeof(str2), fp); 96 ATF_REQUIRE(nofw == 4); 97 98 /* Close the FILE *. */ 99 rc = fclose(fp); 100 ATF_REQUIRE(rc == 0); 101 102 /* Check that the string was not modified after the first 4 bytes. */ 103 ATF_REQUIRE(strcmp(str, str3) == 0); 104 } 105 106 ATF_TC_WITHOUT_HEAD(test_autoalloc); 107 ATF_TC_BODY(test_autoalloc, tc) 108 { 109 /* 110 * Let fmemopen allocate the buffer. 111 */ 112 113 char str[] = "A quick test"; 114 FILE *fp; 115 long pos; 116 size_t nofw, nofr, i; 117 int rc; 118 119 /* Open a FILE * using fmemopen. */ 120 fp = fmemopen(NULL, 512, "w+"); 121 ATF_REQUIRE(fp != NULL); 122 123 /* fill the buffer */ 124 for (i = 0; i < 512; i++) { 125 nofw = fwrite("a", 1, 1, fp); 126 ATF_REQUIRE(nofw == 1); 127 } 128 129 /* Get the current position into the stream. */ 130 pos = ftell(fp); 131 ATF_REQUIRE(pos == 512); 132 133 /* 134 * Try to write past the end, we should get a short object count (0) 135 */ 136 nofw = fwrite("a", 1, 1, fp); 137 ATF_REQUIRE(nofw == 0); 138 139 /* Close the FILE *. */ 140 rc = fclose(fp); 141 ATF_REQUIRE(rc == 0); 142 143 /* Open a FILE * using a wrong mode */ 144 fp = fmemopen(NULL, 512, "r"); 145 ATF_REQUIRE(fp == NULL); 146 147 fp = fmemopen(NULL, 512, "w"); 148 ATF_REQUIRE(fp == NULL); 149 } 150 151 ATF_TC_WITHOUT_HEAD(test_data_length); 152 ATF_TC_BODY(test_data_length, tc) 153 { 154 /* 155 * Here we test that a read operation doesn't go past the end of the 156 * data actually written, and that a SEEK_END seeks from the end of the 157 * data, not of the whole buffer. 158 */ 159 FILE *fp; 160 char buf[512] = {'\0'}; 161 char str[] = "Test data length. "; 162 char str2[] = "Do we have two sentences?"; 163 char str3[sizeof(str) + sizeof(str2) -1]; 164 long pos; 165 size_t nofw, nofr; 166 int rc; 167 168 /* Open a FILE * for updating our buffer. */ 169 fp = fmemopen(buf, sizeof(buf), "w+"); 170 ATF_REQUIRE(fp != NULL); 171 172 /* Write our string into the buffer. */ 173 nofw = fwrite(str, 1, sizeof(str), fp); 174 ATF_REQUIRE(nofw == sizeof(str)); 175 176 /* 177 * Now seek to the end and check that ftell 178 * gives us sizeof(str). 179 */ 180 rc = fseek(fp, 0, SEEK_END); 181 ATF_REQUIRE(rc == 0); 182 pos = ftell(fp); 183 ATF_REQUIRE(pos == sizeof(str)); 184 185 /* Close the FILE *. */ 186 rc = fclose(fp); 187 ATF_REQUIRE(rc == 0); 188 189 /* Reopen the buffer for appending. */ 190 fp = fmemopen(buf, sizeof(buf), "a+"); 191 ATF_REQUIRE(fp != NULL); 192 193 /* We should now be writing after the first string. */ 194 nofw = fwrite(str2, 1, sizeof(str2), fp); 195 ATF_REQUIRE(nofw == sizeof(str2)); 196 197 /* Rewind the FILE *. */ 198 rc = fseek(fp, 0, SEEK_SET); 199 ATF_REQUIRE(rc == 0); 200 201 /* Make sure we're at the beginning. */ 202 pos = ftell(fp); 203 ATF_REQUIRE(pos == 0); 204 205 /* Read the whole buffer. */ 206 nofr = fread(str3, 1, sizeof(buf), fp); 207 ATF_REQUIRE(nofr == sizeof(str3)); 208 209 /* Make sure the two strings are there. */ 210 ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0); 211 ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0); 212 213 /* Close the FILE *. */ 214 rc = fclose(fp); 215 ATF_REQUIRE(rc == 0); 216 } 217 218 ATF_TC_WITHOUT_HEAD(test_binary); 219 ATF_TC_BODY(test_binary, tc) 220 { 221 /* 222 * Make sure that NULL bytes are never appended when opening a buffer 223 * in binary mode. 224 */ 225 226 FILE *fp; 227 char buf[20]; 228 char str[] = "Test"; 229 size_t nofw; 230 int rc, i; 231 232 /* Pre-fill the buffer. */ 233 memset(buf, 'A', sizeof(buf)); 234 235 /* Open a FILE * in binary mode. */ 236 fp = fmemopen(buf, sizeof(buf), "w+b"); 237 ATF_REQUIRE(fp != NULL); 238 239 /* Write some data into it. */ 240 nofw = fwrite(str, 1, strlen(str), fp); 241 ATF_REQUIRE(nofw == strlen(str)); 242 243 /* Make sure that the buffer doesn't contain any NULL bytes. */ 244 for (i = 0; i < sizeof(buf); i++) 245 ATF_REQUIRE(buf[i] != '\0'); 246 247 /* Close the FILE *. */ 248 rc = fclose(fp); 249 ATF_REQUIRE(rc == 0); 250 } 251 252 ATF_TC_WITHOUT_HEAD(test_append_binary_pos); 253 ATF_TC_BODY(test_append_binary_pos, tc) 254 { 255 /* 256 * For compatibility with other implementations (glibc), we set the 257 * position to 0 when opening an automatically allocated binary stream 258 * for appending. 259 */ 260 261 FILE *fp; 262 263 fp = fmemopen(NULL, 16, "ab+"); 264 ATF_REQUIRE(ftell(fp) == 0L); 265 fclose(fp); 266 267 /* 268 * Make sure that a pre-allocated buffer behaves correctly. 269 */ 270 char buf[] = "Hello"; 271 fp = fmemopen(buf, sizeof(buf), "ab+"); 272 ATF_REQUIRE(ftell(fp) == strlen(buf)); 273 fclose(fp); 274 } 275 276 ATF_TC_WITHOUT_HEAD(test_size_0); 277 ATF_TC_BODY(test_size_0, tc) 278 { 279 /* 280 * POSIX mandates that we return EINVAL if size is 0. 281 */ 282 283 FILE *fp; 284 285 fp = fmemopen(NULL, 0, "r+"); 286 ATF_REQUIRE(fp == NULL); 287 ATF_REQUIRE(errno == EINVAL); 288 } 289 290 ATF_TP_ADD_TCS(tp) 291 { 292 293 ATF_TP_ADD_TC(tp, test_autoalloc); 294 ATF_TP_ADD_TC(tp, test_preexisting); 295 ATF_TP_ADD_TC(tp, test_data_length); 296 ATF_TP_ADD_TC(tp, test_binary); 297 ATF_TP_ADD_TC(tp, test_append_binary_pos); 298 ATF_TP_ADD_TC(tp, test_size_0); 299 300 return (atf_no_error()); 301 } 302