/amar-src/amar-test.c
C | 1122 lines | 897 code | 160 blank | 65 comment | 72 complexity | 46f9b0299c4ac63363aea0ee598b80b1 MD5 | raw file
1/* 2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver 3 * Copyright (c) 1991-1998 University of Maryland at College Park 4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved. 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that 10 * copyright notice and this permission notice appear in supporting 11 * documentation, and that the name of U.M. not be used in advertising or 12 * publicity pertaining to distribution of the software without specific, 13 * written prior permission. U.M. makes no representations about the 14 * suitability of this software for any purpose. It is provided "as is" 15 * without express or implied warranty. 16 * 17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 * 24 * Authors: the Amanda Development Team. Its members are listed in a 25 * file named AUTHORS, in the root directory of this distribution. 26 */ 27 28#include "amanda.h" 29#include "amar.h" 30#include "testutils.h" 31#include "simpleprng.h" 32 33static char *temp_filename = NULL; 34 35/**** 36 * Macros for creating files with a particular structure 37 */ 38 39#define WRITE_HEADER(fd, version) do { \ 40 char hdr[28]; \ 41 bzero(hdr, 28); \ 42 snprintf(hdr, 28, "AMANDA ARCHIVE FORMAT %d", (version)); \ 43 g_assert(full_write((fd), hdr, 28) == 28); \ 44} while(0); 45 46#define WRITE_RECORD(fd, filenum, attrid, size, eoa, data) do { \ 47 struct { uint16_t f; uint16_t a; uint32_t s; } rec; \ 48 rec.f = htons((filenum)); \ 49 rec.a = htons((attrid)); \ 50 rec.s = htonl((size) | (eoa? 0x80000000 : 0)); \ 51 g_assert(full_write((fd), &rec, sizeof(rec)) == sizeof(rec)); \ 52 g_assert(full_write((fd), (data), (size)) == (size)); \ 53} while(0); 54 55#define WRITE_RECORD_STR(fd, filenum, attrid, eoa, str) do { \ 56 size_t len = strlen((str)); \ 57 WRITE_RECORD((fd), (filenum), (attrid), len, (eoa), (str)); \ 58} while(0); 59 60/**** 61 * Assertions for amanda_read_archive callbacks 62 */ 63 64typedef enum { 65 EXP_END, 66 EXP_START_FILE, 67 EXP_ATTRDATA, 68 EXP_FINISH_FILE, 69} expected_kind_t; 70 71typedef struct { 72 expected_kind_t kind; 73 uint16_t filenum; 74 uint16_t attrid; 75 char *data; 76 size_t datasize; 77 gboolean multipart_ok; 78 gboolean eoa; 79 gboolean truncated; 80 gboolean should_ignore; 81 gboolean isstr; 82} expected_step_t; 83 84typedef struct { 85 expected_step_t *steps; 86 int curstep; 87} expected_state_t; 88 89#define EXPECT_START_FILE(filenum, data, datasize, should_ignore) \ 90 { EXP_START_FILE, (filenum), 0, (data), (datasize), 0, 0, 0, (should_ignore), 0 } 91 92#define EXPECT_START_FILE_STR(filenum, filename, should_ignore) \ 93 { EXP_START_FILE, (filenum), 0, (filename), strlen((filename)), 0, 0, 0, (should_ignore), 1 } 94 95#define EXPECT_ATTR_DATA(filenum, attrid, data, datasize, eoa, truncated) \ 96 { EXP_ATTRDATA, (filenum), (attrid), (data), (datasize), 0, (eoa), (truncated), 0, 0 } 97 98#define EXPECT_ATTR_DATA_MULTIPART(filenum, attrid, data, datasize, eoa, truncated) \ 99 { EXP_ATTRDATA, (filenum), (attrid), (data), (datasize), 1, (eoa), (truncated), 0, 0 } 100 101#define EXPECT_ATTR_DATA_STR(filenum, attrid, datastr, eoa, truncated) \ 102 { EXP_ATTRDATA, (filenum), (attrid), (datastr), strlen((datastr)), 0, (eoa), (truncated), 0, 1 } 103 104#define EXPECT_FINISH_FILE(filenum, truncated) \ 105 { EXP_FINISH_FILE, (filenum), 0, 0, 0, 0, 0, (truncated), 0, 0 } 106 107#define EXPECT_END() \ 108 { EXP_END, 0, 0, 0, 0, 0, 0, 0, 0, 0 } 109 110#define EXPECT_FAILURE(fmt, ...) do { \ 111 fprintf(stderr, fmt "\n", __VA_ARGS__); \ 112 exit(1); \ 113} while(0) 114 115static gboolean 116file_start_cb( 117 gpointer user_data, 118 uint16_t filenum, 119 gpointer filename, 120 gsize filename_len, 121 gboolean *ignore, 122 gpointer *file_data G_GNUC_UNUSED) 123{ 124 expected_state_t *state = user_data; 125 expected_step_t *step = state->steps + state->curstep; 126 127 tu_dbg("file_start_cb(NULL, %d, '%s', %zd, .., ..)\n", 128 (int)filenum, (char *)filename, filename_len); 129 130 if (step->kind != EXP_START_FILE) 131 EXPECT_FAILURE("step %d: unexpected new file with fileid %d", 132 state->curstep, (int)filenum); 133 134 if (step->filenum != filenum) 135 EXPECT_FAILURE("step %d: expected new file with filenum %d; got filenum %d", 136 state->curstep, (int)step->filenum, (int)filenum); 137 138 if (filename_len != step->datasize) 139 EXPECT_FAILURE("step %d: filename lengths do not match: got %zd, expected %zd", 140 state->curstep, filename_len, step->datasize); 141 142 if (memcmp(filename, step->data, filename_len)) { 143 if (step->isstr) { 144 EXPECT_FAILURE("step %d: new file's filename does not match: got '%*s', expected '%*s'", 145 state->curstep, (int)filename_len, (char *)filename, 146 (int)step->datasize, (char *)step->data); 147 } else { 148 EXPECT_FAILURE("step %d: new file's filename does not match", 149 state->curstep); 150 } 151 } 152 153 *ignore = step->should_ignore; 154 state->curstep++; 155 156 return TRUE; 157} 158 159static gboolean 160file_finish_cb( 161 gpointer user_data, 162 uint16_t filenum, 163 gpointer *file_data G_GNUC_UNUSED, 164 gboolean truncated) 165{ 166 expected_state_t *state = user_data; 167 expected_step_t *step = state->steps + state->curstep; 168 169 tu_dbg("file_finish_cb(NULL, %d, NULL, %d)\n", 170 (int)filenum, truncated); 171 172 if (step->kind != EXP_FINISH_FILE) 173 EXPECT_FAILURE("step %d: unexpected file finish with fileid %d", 174 state->curstep, (int)filenum); 175 176 if (step->truncated && !truncated) 177 EXPECT_FAILURE("step %d: file %d was unexpectedly not truncated", 178 state->curstep, (int)filenum); 179 180 if (step->truncated && !truncated) 181 EXPECT_FAILURE("step %d: file %d was unexpectedly truncated", 182 state->curstep, (int)filenum); 183 184 state->curstep++; 185 186 return TRUE; 187} 188 189static gboolean 190frag_cb( 191 gpointer user_data, 192 uint16_t filenum, 193 gpointer file_data G_GNUC_UNUSED, 194 uint16_t attrid, 195 gpointer attrid_data G_GNUC_UNUSED, 196 gpointer *attr_data G_GNUC_UNUSED, 197 gpointer data, 198 gsize datasize, 199 gboolean eoa, 200 gboolean truncated) 201{ 202 expected_state_t *state = user_data; 203 expected_step_t *step = state->steps + state->curstep; 204 205 tu_dbg("file_finish_cb(NULL, %d, NULL, %d, %p, %zd, %d, %d)\n", 206 (int)filenum, (int)attrid, data, datasize, eoa, truncated); 207 208 if (step->kind != EXP_ATTRDATA) 209 EXPECT_FAILURE("step %d: unexpected attribute data with fileid %d, attrid %d", 210 state->curstep, (int)filenum, (int)attrid); 211 212 if (step->filenum != filenum) 213 EXPECT_FAILURE("step %d: expected attribute data with filenum %d; got filenum %d", 214 state->curstep, (int)step->filenum, (int)filenum); 215 216 if (step->attrid != attrid) 217 EXPECT_FAILURE("step %d: expected attribute data with attrid %d; got attrid %d", 218 state->curstep, (int)step->attrid, (int)attrid); 219 220 /* if we're accepting multiple fragments of the attribute here (due to internal 221 * buffering by the reader), then handle that specially */ 222 if (step->multipart_ok && datasize < step->datasize) { 223 if (eoa) 224 EXPECT_FAILURE("step %d: file %d attribute %d: early EOA in multipart attribute", 225 state->curstep, (int)filenum, (int)attrid); 226 227 if (memcmp(data, step->data, datasize)) { 228 EXPECT_FAILURE("step %d: attribute's data does not match", 229 state->curstep); 230 } 231 step->data += datasize; 232 step->datasize -= datasize; 233 return TRUE; 234 } 235 236 if (step->eoa && !eoa) 237 EXPECT_FAILURE("step %d: file %d attribute %d: expected EOA did not appear", 238 state->curstep, (int)filenum, (int)attrid); 239 240 if (!step->eoa && eoa) 241 EXPECT_FAILURE("step %d: file %d attribute %d: unexpected EOA", 242 state->curstep, (int)filenum, (int)attrid); 243 244 if (!step->truncated && truncated) 245 EXPECT_FAILURE("step %d: file %d attribute %d was unexpectedly truncated", 246 state->curstep, (int)filenum, (int)attrid); 247 248 if (step->truncated && !truncated) 249 EXPECT_FAILURE("step %d: file %d attribute %d was unexpectedly not truncated", 250 state->curstep, (int)filenum, (int)attrid); 251 252 if (datasize != step->datasize) 253 EXPECT_FAILURE("step %d: file %d attribute %d lengths do not match: " 254 "got %zd, expected %zd", 255 state->curstep, (int)filenum, (int)attrid, 256 datasize, step->datasize); 257 258 if (memcmp(data, step->data, datasize)) { 259 if (step->isstr) { 260 EXPECT_FAILURE("step %d: attribute's data does not match: got '%*s', expected '%*s'", 261 state->curstep, (int)datasize, (char *)data, 262 (int)step->datasize, (char *)step->data); 263 } else { 264 EXPECT_FAILURE("step %d: attribute's data does not match", 265 state->curstep); 266 } 267 } 268 269 state->curstep++; 270 271 return TRUE; 272} 273 274/**** 275 * Utilities 276 */ 277 278static int 279open_temp(gboolean write) 280{ 281 int fd = open(temp_filename, write? O_WRONLY|O_CREAT|O_TRUNC : O_RDONLY, 0777); 282 if (fd < 0) { 283 perror("open temporary file"); 284 exit(1); 285 } 286 287 return fd; 288} 289 290static void 291check_gerror_( 292 gboolean ok, 293 GError *error, 294 const char *fn) 295{ 296 if (ok && !error) 297 return; 298 299 if (ok) 300 EXPECT_FAILURE( 301 "'%s' set 'error' but did not indicate an error condition: %s (%s)\n", 302 fn, error->message, strerror(error->code)); 303 else if (!error) 304 EXPECT_FAILURE( 305 "'%s' indicated an error condition but did not set 'error'.\n", fn); 306 else 307 EXPECT_FAILURE( 308 "'%s' error: %s (%s)\n", fn, error->message, strerror(error->code)); 309 310 exit(1); 311} 312 313#define check_gerror(ok, error, fn) check_gerror_((ok)!=0, (error), (fn)) 314 315static void 316check_gerror_matches_( 317 gboolean ok, 318 GError *error, 319 const char *matches, 320 const char *fn) 321{ 322 if (!ok && error) { 323 if (0 != strcmp(matches, error->message)) { 324 EXPECT_FAILURE( 325 "%s produced error '%s' but expected '%s'\n", 326 fn, error->message, matches); 327 exit(1); 328 } 329 return; 330 } 331 332 if (ok) 333 EXPECT_FAILURE( 334 "'%s' correctly set 'error' but did not indicate an error condition: %s (%s)\n", 335 fn, error->message, strerror(error->code)); 336 else /* (!error) */ 337 EXPECT_FAILURE( 338 "'%s' correctly indicated an error condition but did not set 'error'.\n", fn); 339 340 exit(1); 341} 342 343#define check_gerror_matches(ok, error, match, fn) \ 344 check_gerror_matches_((ok)!=0, (error), (match), (fn)) 345 346static void 347try_reading_fd( 348 expected_step_t *steps, 349 amar_attr_handling_t *handling, 350 int fd) 351{ 352 amar_t *ar; 353 expected_state_t state = { steps, 0 }; 354 GError *error = NULL; 355 gboolean ok; 356 357 ar = amar_new(fd, O_RDONLY, &error); 358 check_gerror(ar, error, "amar_new"); 359 ok = amar_read(ar, &state, handling, file_start_cb, file_finish_cb, &error); 360 if (ok || error) 361 check_gerror(ok, error, "amar_read"); 362 if (steps[state.curstep].kind != EXP_END) 363 EXPECT_FAILURE("Stopped reading early at step %d", state.curstep); 364 ok = amar_close(ar, &error); 365 check_gerror(ok, error, "amar_close"); 366} 367 368static void 369try_reading( 370 expected_step_t *steps, 371 amar_attr_handling_t *handling) 372{ 373 int fd; 374 375 fd = open_temp(0); 376 try_reading_fd(steps, handling, fd); 377 close(fd); 378} 379 380static void 381try_reading_with_error( 382 expected_step_t *steps, 383 amar_attr_handling_t *handling, 384 const char *message) 385{ 386 amar_t *ar; 387 expected_state_t state = { steps, 0 }; 388 int fd; 389 GError *error = NULL; 390 gboolean ok; 391 392 fd = open_temp(0); 393 ar = amar_new(fd, O_RDONLY, &error); 394 check_gerror(ar, error, "amar_new"); 395 ok = amar_read(ar, &state, handling, file_start_cb, file_finish_cb, &error); 396 check_gerror_matches(ok, error, message, "amar_read"); 397 amar_close(ar, NULL); 398 close(fd); 399} 400 401/**** 402 * Test various valid inputs 403 */ 404 405static int 406test_simple_read(void) 407{ 408 int fd; 409 410 fd = open_temp(1); 411 WRITE_HEADER(fd, 1); 412 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "/first/filename"); 413 WRITE_RECORD_STR(fd, 1, 18, 1, "eighteen"); 414 WRITE_HEADER(fd, 1); 415 WRITE_RECORD_STR(fd, 1, 19, 0, "nine"); 416 WRITE_RECORD_STR(fd, 1, 20, 0, "twen"); 417 WRITE_RECORD_STR(fd, 1, 19, 1, "teen"); 418 WRITE_RECORD_STR(fd, 1, 20, 1, "ty"); 419 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, ""); 420 close(fd); 421 422 { 423 amar_attr_handling_t handling[] = { 424 { 19, 256, frag_cb, NULL }, /* reassemble this attribute */ 425 { 20, 0, frag_cb, NULL }, /* but pass along each fragment of this */ 426 { 0, 256, frag_cb, NULL }, 427 }; 428 expected_step_t steps[] = { 429 EXPECT_START_FILE_STR(1, "/first/filename", 0), 430 EXPECT_ATTR_DATA_STR(1, 18, "eighteen", 1, 0), 431 EXPECT_ATTR_DATA_STR(1, 20, "twen", 0, 0), 432 EXPECT_ATTR_DATA_STR(1, 19, "nineteen", 1, 0), 433 EXPECT_ATTR_DATA_STR(1, 20, "ty", 1, 0), 434 EXPECT_FINISH_FILE(1, 0), 435 EXPECT_END(), 436 }; 437 try_reading(steps, handling); 438 } 439 440 return 1; 441} 442 443static int 444test_read_buffering(void) 445{ 446 int fd; 447 448 fd = open_temp(1); 449 WRITE_HEADER(fd, 1); 450 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file1"); 451 WRITE_HEADER(fd, 1); 452 WRITE_RECORD_STR(fd, 2, AMAR_ATTR_FILENAME, 1, "file2"); 453 WRITE_RECORD_STR(fd, 2, 19, 0, "1"); /* one byte at a time, for 12 bytes */ 454 WRITE_RECORD_STR(fd, 2, 19, 0, "9"); 455 WRITE_RECORD_STR(fd, 2, 21, 1, "012345678901234567890123456789"); /* thirty bytes exactly */ 456 WRITE_RECORD_STR(fd, 2, 19, 0, "1"); 457 WRITE_RECORD_STR(fd, 1, 18, 0, "ATTR"); 458 WRITE_RECORD_STR(fd, 2, 19, 0, "9"); 459 WRITE_RECORD_STR(fd, 2, 19, 0, "1"); 460 WRITE_RECORD_STR(fd, 2, 19, 0, "9"); 461 WRITE_HEADER(fd, 1); 462 WRITE_RECORD_STR(fd, 1, 20, 0, "TWENTYTWE"); /* nine bytes, then three in the next frag */ 463 WRITE_RECORD_STR(fd, 2, 19, 0, "1"); 464 WRITE_RECORD_STR(fd, 1, 20, 1, "NTY"); 465 WRITE_RECORD_STR(fd, 2, 19, 0, "9"); 466 WRITE_RECORD_STR(fd, 1, 18, 0, "181818"); /* hit ten bytes exactly */ 467 WRITE_RECORD_STR(fd, 2, 19, 0, "1"); 468 WRITE_RECORD_STR(fd, 2, 19, 0, "9"); 469 WRITE_RECORD_STR(fd, 1, 18, 0, "ATTR"); 470 WRITE_RECORD_STR(fd, 1, 22, 0, "012345678"); /* nine bytes followed by 20 */ 471 WRITE_RECORD_STR(fd, 1, 18, 1, "18"); 472 WRITE_RECORD_STR(fd, 1, 22, 1, "01234567890123456789"); 473 WRITE_RECORD_STR(fd, 2, 19, 0, "1"); 474 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, ""); 475 WRITE_RECORD_STR(fd, 2, 19, 1, "9"); 476 WRITE_RECORD_STR(fd, 2, AMAR_ATTR_EOF, 1, ""); 477 478 close(fd); 479 480 { 481 amar_attr_handling_t handling[] = { 482 { 0, 10, frag_cb, NULL }, /* reassemble all fragments in 10-byte chunks */ 483 }; 484 expected_step_t steps[] = { 485 EXPECT_START_FILE_STR(1, "file1", 0), 486 EXPECT_START_FILE_STR(2, "file2", 0), 487 EXPECT_ATTR_DATA_STR(2, 21, "012345678901234567890123456789", 1, 0), 488 EXPECT_ATTR_DATA_STR(1, 20, "TWENTYTWENTY", 1, 0), 489 EXPECT_ATTR_DATA_STR(1, 18, "ATTR181818", 0, 0), 490 EXPECT_ATTR_DATA_STR(2, 19, "1919191919", 0, 0), 491 EXPECT_ATTR_DATA_STR(1, 18, "ATTR18", 1, 0), 492 EXPECT_ATTR_DATA_STR(1, 22, "01234567801234567890123456789", 1, 0), 493 EXPECT_FINISH_FILE(1, 0), 494 EXPECT_ATTR_DATA_STR(2, 19, "19", 1, 0), 495 EXPECT_FINISH_FILE(2, 0), 496 EXPECT_END(), 497 }; 498 try_reading(steps, handling); 499 } 500 501 return 1; 502} 503 504static int 505test_missing_eoa(void) 506{ 507 int fd; 508 509 fd = open_temp(1); 510 WRITE_HEADER(fd, 1); 511 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file1"); 512 WRITE_RECORD_STR(fd, 1, 21, 0, "attribu"); /* note no EOA */ 513 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, ""); 514 515 close(fd); 516 517 { 518 amar_attr_handling_t handling[] = { 519 { 0, 1024, frag_cb, NULL }, 520 }; 521 expected_step_t steps[] = { 522 EXPECT_START_FILE_STR(1, "file1", 0), 523 EXPECT_ATTR_DATA_STR(1, 21, "attribu", 1, 1), 524 EXPECT_FINISH_FILE(1, 0), 525 EXPECT_END(), 526 }; 527 try_reading(steps, handling); 528 } 529 530 return 1; 531} 532 533static int 534test_ignore(void) 535{ 536 int fd; 537 538 fd = open_temp(1); 539 WRITE_HEADER(fd, 1); 540 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file1"); 541 WRITE_HEADER(fd, 1); 542 WRITE_RECORD_STR(fd, 2, AMAR_ATTR_FILENAME, 1, "file2"); 543 WRITE_RECORD_STR(fd, 2, 20, 1, "attr20"); 544 WRITE_RECORD_STR(fd, 1, 21, 0, "attr"); 545 WRITE_RECORD_STR(fd, 1, 21, 1, "21"); 546 WRITE_HEADER(fd, 1); 547 WRITE_RECORD_STR(fd, 3, AMAR_ATTR_FILENAME, 1, "file3"); 548 WRITE_HEADER(fd, 1); 549 WRITE_RECORD_STR(fd, 4, AMAR_ATTR_FILENAME, 1, "file4"); 550 WRITE_RECORD_STR(fd, 3, 22, 1, "attr22"); 551 WRITE_RECORD_STR(fd, 4, 23, 1, "attr23"); 552 WRITE_RECORD_STR(fd, 4, AMAR_ATTR_EOF, 1, ""); 553 WRITE_RECORD_STR(fd, 3, AMAR_ATTR_EOF, 1, ""); 554 WRITE_RECORD_STR(fd, 2, AMAR_ATTR_EOF, 1, ""); 555 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, ""); 556 557 close(fd); 558 559 { 560 amar_attr_handling_t handling[] = { 561 { 0, 10, frag_cb, NULL }, /* reassemble all fragments in 10-byte chunks */ 562 }; 563 expected_step_t steps[] = { 564 EXPECT_START_FILE_STR(1, "file1", 1), 565 EXPECT_START_FILE_STR(2, "file2", 0), 566 EXPECT_ATTR_DATA_STR(2, 20, "attr20", 1, 0), 567 EXPECT_START_FILE_STR(3, "file3", 1), 568 EXPECT_START_FILE_STR(4, "file4", 0), 569 EXPECT_ATTR_DATA_STR(4, 23, "attr23", 1, 0), 570 EXPECT_FINISH_FILE(4, 0), 571 EXPECT_FINISH_FILE(2, 0), 572 EXPECT_END(), 573 }; 574 try_reading(steps, handling); 575 } 576 577 return 1; 578} 579 580static int 581test_missing_eof(void) 582{ 583 int fd; 584 585 fd = open_temp(1); 586 WRITE_HEADER(fd, 1); 587 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file!"); 588 WRITE_RECORD_STR(fd, 1, 20, 1, "attribute"); 589 WRITE_RECORD_STR(fd, 1, 21, 0, "attribu"); /* note no EOA */ 590 591 close(fd); 592 593 { 594 amar_attr_handling_t handling[] = { 595 { 0, 1024, frag_cb, NULL }, 596 }; 597 expected_step_t steps[] = { 598 EXPECT_START_FILE_STR(1, "file!", 0), 599 EXPECT_ATTR_DATA_STR(1, 20, "attribute", 1, 0), 600 EXPECT_ATTR_DATA_STR(1, 21, "attribu", 1, 1), 601 EXPECT_FINISH_FILE(1, 0), 602 EXPECT_END(), 603 }; 604 try_reading(steps, handling); 605 } 606 607 return 1; 608} 609 610static int 611test_extra_records(void) 612{ 613 int fd; 614 615 fd = open_temp(1); 616 WRITE_HEADER(fd, 1); 617 WRITE_RECORD_STR(fd, 4, AMAR_ATTR_EOF, 1, ""); 618 WRITE_RECORD_STR(fd, 5, 20, 1, "old attribute"); 619 WRITE_RECORD_STR(fd, 6, AMAR_ATTR_FILENAME, 1, "file!"); 620 WRITE_RECORD_STR(fd, 6, 21, 0, "attribu"); /* note no EOA */ 621 WRITE_RECORD_STR(fd, 5, AMAR_ATTR_EOF, 1, ""); 622 WRITE_RECORD_STR(fd, 6, 21, 1, "te"); 623 WRITE_RECORD_STR(fd, 6, AMAR_ATTR_EOF, 1, ""); 624 close(fd); 625 626 { 627 amar_attr_handling_t handling[] = { 628 { 0, 1024, frag_cb, NULL }, 629 }; 630 expected_step_t steps[] = { 631 EXPECT_START_FILE_STR(6, "file!", 0), 632 EXPECT_ATTR_DATA_STR(6, 21, "attribute", 1, 0), 633 EXPECT_FINISH_FILE(6, 0), 634 EXPECT_END(), 635 }; 636 try_reading(steps, handling); 637 } 638 639 return 1; 640} 641 642static gboolean 643early_exit_frag_cb( 644 gpointer user_data G_GNUC_UNUSED, 645 uint16_t filenum G_GNUC_UNUSED, 646 gpointer file_data G_GNUC_UNUSED, 647 uint16_t attrid G_GNUC_UNUSED, 648 gpointer attrid_data G_GNUC_UNUSED, 649 gpointer *attr_data G_GNUC_UNUSED, 650 gpointer data G_GNUC_UNUSED, 651 gsize datasize G_GNUC_UNUSED, 652 gboolean eoa G_GNUC_UNUSED, 653 gboolean truncated G_GNUC_UNUSED) 654{ 655 return FALSE; 656} 657 658static int 659test_early_exit(void) 660{ 661 int fd; 662 663 fd = open_temp(1); 664 WRITE_HEADER(fd, 1); 665 WRITE_RECORD_STR(fd, 6, AMAR_ATTR_FILENAME, 1, "file!"); 666 WRITE_RECORD_STR(fd, 6, 21, 1, "attribu"); 667 WRITE_RECORD_STR(fd, 6, AMAR_ATTR_EOF, 1, ""); 668 close(fd); 669 670 { 671 amar_attr_handling_t handling[] = { 672 { 0, 0, early_exit_frag_cb, NULL }, 673 }; 674 expected_step_t steps[] = { 675 EXPECT_START_FILE_STR(6, "file!", 0), 676 EXPECT_FINISH_FILE(6, 1), 677 EXPECT_END(), 678 }; 679 try_reading(steps, handling); 680 } 681 682 return 1; 683} 684 685/**** 686 * Test the write side, using round trips. 687 */ 688 689/* just try to execute most of the writing code */ 690static int 691test_writing_coverage(void) 692{ 693 int fd, fd2; 694 off_t posn, fdsize; 695 char buf[16300]; 696 char buf2[16300]; 697 char *bigbuf; 698 size_t bigbuf_size = 1024*50+93; 699 simpleprng_state_t prng; 700 gsize i; 701 guint16 attrid = 20; 702 amar_t *arch = NULL; 703 amar_file_t *af = NULL, *af2 = NULL; 704 amar_attr_t *at = NULL, *at2 = NULL; 705 GError *error = NULL; 706 gboolean ok; 707 708 /* set up some data buffers */ 709 for (i = 0; i < sizeof(buf); i++) { 710 buf[i] = 0xfe; 711 buf2[i] = 0xaa; 712 } 713 714 bigbuf = g_malloc(bigbuf_size); 715 simpleprng_seed(&prng, 0xfeaa); 716 simpleprng_fill_buffer(&prng, bigbuf, bigbuf_size); 717 718 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777); 719 g_assert(fd >= 0); 720 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size); 721 close(fd); 722 723 fd = open_temp(1); 724 725 arch = amar_new(fd, O_WRONLY, &error); 726 check_gerror(arch, error, "amar_new"); 727 g_assert(arch != NULL); 728 729 af = amar_new_file(arch, "MyFile", 0, &posn, &error); 730 check_gerror(af, error, "amar_new_file"); 731 tu_dbg("MyFile starts at 0x%x\n", (int)posn) 732 g_assert(af != NULL); 733 734 /* by character with EOA */ 735 at = amar_new_attr(af, attrid++, &error); 736 check_gerror(at, error, "amar_new_attr"); 737 g_assert(at != NULL); 738 ok = amar_attr_add_data_buffer(at, buf, sizeof(buf), 1, &error); 739 check_gerror(ok, error, "amar_attr_add_data_buffer"); 740 ok = amar_attr_close(at, &error); 741 check_gerror(ok, error, "amar_attr_close"); 742 743 /* by character without EOA */ 744 at = amar_new_attr(af, attrid++, &error); 745 check_gerror(at, error, "amar_new_attr"); 746 g_assert(at != NULL); 747 ok = amar_attr_add_data_buffer(at, buf2, sizeof(buf2), 0, &error); 748 check_gerror(ok, error, "amar_attr_add_data_buffer"); 749 ok = amar_attr_close(at, &error); 750 check_gerror(ok, error, "amar_attr_close"); 751 752 /* open up a new file, for fun */ 753 af2 = amar_new_file(arch, "MyOtherFile", 0, &posn, &error); 754 check_gerror(af2, error, "amar_new_file"); 755 tu_dbg("MyOtherFile starts at 0x%x\n", (int)posn) 756 757 /* by file descriptor, to the first file */ 758 at = amar_new_attr(af, attrid++, &error); 759 check_gerror(at, error, "amar_new_attr"); 760 fd2 = open("amar-test.big", O_RDONLY); 761 g_assert(fd2 >= 0); 762 fdsize = amar_attr_add_data_fd(at, fd2, 0, &error); 763 check_gerror(fdsize != -1, error, "amar_attr_add_data_fd"); 764 g_assert(fdsize > 0); 765 close(fd2); 766 unlink("amar-test.big"); 767 ok = amar_attr_close(at, &error); 768 check_gerror(ok, error, "amar_attr_close"); 769 770 ok = amar_file_close(af, &error); 771 check_gerror(ok, error, "amar_file_close"); 772 773 /* interlaeave two attributes */ 774 at = amar_new_attr(af2, attrid++, &error); 775 check_gerror(at, error, "amar_new_attr"); 776 at2 = amar_new_attr(af2, attrid++, &error); 777 check_gerror(at2, error, "amar_new_attr"); 778 ok = amar_attr_add_data_buffer(at, buf, 72, 0, &error); 779 check_gerror(ok, error, "amar_attr_add_data_buffer"); 780 ok = amar_attr_add_data_buffer(at2, buf2, 72, 0, &error); 781 check_gerror(ok, error, "amar_attr_add_data_buffer"); 782 ok = amar_attr_add_data_buffer(at, buf, 13, 0, &error); 783 check_gerror(ok, error, "amar_attr_add_data_buffer"); 784 ok = amar_attr_add_data_buffer(at2, buf2, 13, 1, &error); 785 check_gerror(ok, error, "amar_attr_add_data_buffer"); 786 ok = amar_attr_close(at, &error); 787 check_gerror(ok, error, "amar_attr_close"); 788 ok = amar_attr_close(at2, &error); 789 check_gerror(ok, error, "amar_attr_close"); 790 791 ok = amar_file_close(af2, &error); 792 check_gerror(ok, error, "amar_file_close"); 793 794 ok = amar_close(arch, &error); 795 check_gerror(ok, error, "amar_close"); 796 close(fd); 797 798 { 799 amar_attr_handling_t handling[] = { 800 { 22, bigbuf_size+1, frag_cb, NULL }, /* buffer the big attr */ 801 { 0, 0, frag_cb, NULL }, /* don't buffer other records */ 802 }; 803 expected_step_t steps[] = { 804 EXPECT_START_FILE_STR(1, "MyFile", 0), 805 EXPECT_ATTR_DATA_MULTIPART(1, 20, buf, sizeof(buf), 1, 0), 806 EXPECT_ATTR_DATA_MULTIPART(1, 21, buf2, sizeof(buf2), 0, 0), 807 EXPECT_ATTR_DATA_MULTIPART(1, 21, buf2, 0, 1, 0), /* trailing EOA */ 808 EXPECT_START_FILE_STR(2, "MyOtherFile", 0), 809 EXPECT_ATTR_DATA(1, 22, bigbuf, bigbuf_size, 1, 0), 810 EXPECT_FINISH_FILE(1, 0), 811 EXPECT_ATTR_DATA_MULTIPART(2, 23, buf, 72, 0, 0), 812 EXPECT_ATTR_DATA_MULTIPART(2, 24, buf2, 72, 0, 0), 813 EXPECT_ATTR_DATA_MULTIPART(2, 23, buf+72, 13, 0, 0), 814 EXPECT_ATTR_DATA_MULTIPART(2, 24, buf2+72, 13, 1, 0), 815 EXPECT_ATTR_DATA_MULTIPART(2, 23, buf, 0, 1, 0), 816 EXPECT_FINISH_FILE(2, 0), 817 EXPECT_END(), 818 }; 819 try_reading(steps, handling); 820 } 821 822 return 1; 823} 824 825/* test big attributes */ 826static int 827test_big_attr(void) 828{ 829 int fd, fd2; 830 off_t fdsize; 831 char *bigbuf; 832 const size_t max_record_data_size = 4*1024*1024; 833 size_t bigbuf_size = max_record_data_size + 1274; /* a record and a bit */ 834 simpleprng_state_t prng; 835 guint16 attrid = 20; 836 amar_t *arch = NULL; 837 amar_file_t *af = NULL; 838 amar_attr_t *at = NULL; 839 GError *error = NULL; 840 gboolean ok; 841 842 /* set up some data buffers */ 843 bigbuf = g_malloc(bigbuf_size); 844 simpleprng_seed(&prng, 0xb001); 845 simpleprng_fill_buffer(&prng, bigbuf, bigbuf_size); 846 847 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777); 848 g_assert(fd >= 0); 849 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size); 850 close(fd); 851 852 fd = open_temp(1); 853 854 arch = amar_new(fd, O_WRONLY, &error); 855 check_gerror(arch, error, "amar_new"); 856 857 af = amar_new_file(arch, "bigstuff", 0, NULL, &error); 858 check_gerror(af, error, "amar_new_file"); 859 860 /* by character */ 861 at = amar_new_attr(af, attrid++, &error); 862 check_gerror(at, error, "amar_new_attr"); 863 ok = amar_attr_add_data_buffer(at, bigbuf, bigbuf_size, 1, &error); 864 check_gerror(ok, error, "amar_attr_add_data_buffer"); 865 ok = amar_attr_close(at, &error); 866 check_gerror(ok, error, "amar_attr_close"); 867 868 /* by file descriptor */ 869 at = amar_new_attr(af, attrid++, &error); 870 check_gerror(at, error, "amar_new_attr"); 871 fd2 = open("amar-test.big", O_RDONLY); 872 g_assert(fd2 >= 0); 873 fdsize = amar_attr_add_data_fd(at, fd2, 1, &error); 874 check_gerror(fdsize != -1, error, "amar_attr_add_data_fd"); 875 g_assert(fdsize > 0); 876 close(fd2); 877 unlink("amar-test.big"); 878 ok = amar_attr_close(at, &error); 879 check_gerror(ok, error, "amar_attr_close"); 880 881 ok = amar_file_close(af, &error); 882 check_gerror(ok, error, "amar_file_close"); 883 884 ok = amar_close(arch, &error); 885 check_gerror(ok, error, "amar_close"); 886 close(fd); 887 888 { 889 amar_attr_handling_t handling[] = { 890 { 0, 0, frag_cb, NULL }, /* don't buffer records */ 891 }; 892 expected_step_t steps[] = { 893 EXPECT_START_FILE_STR(1, "bigstuff", 0), 894 EXPECT_ATTR_DATA_MULTIPART(1, 20, bigbuf, max_record_data_size, 0, 0), 895 EXPECT_ATTR_DATA_MULTIPART(1, 20, bigbuf+max_record_data_size, bigbuf_size-max_record_data_size, 1, 0), 896 EXPECT_ATTR_DATA_MULTIPART(1, 21, bigbuf, max_record_data_size, 0, 0), 897 EXPECT_ATTR_DATA_MULTIPART(1, 21, bigbuf+max_record_data_size, bigbuf_size-max_record_data_size, 1, 0), 898 EXPECT_FINISH_FILE(1, 0), 899 EXPECT_END(), 900 }; 901 try_reading(steps, handling); 902 } 903 904 return 1; 905} 906 907/* like test_big_attr, but using a pipe and ignoring one of the attrs in hopes 908 * of triggering an lseek(), which will fail on a pipe. */ 909static int 910test_pipe(void) 911{ 912 int fd; 913 int p[2]; 914 off_t fdsize; 915 char *bigbuf; 916 const size_t max_record_data_size = 4*1024*1024; 917 size_t bigbuf_size = max_record_data_size + 1274; /* a record and a bit */ 918 simpleprng_state_t prng; 919 guint16 attrid = 20; 920 amar_t *arch = NULL; 921 amar_file_t *af = NULL; 922 amar_attr_t *at = NULL; 923 GError *error = NULL; 924 gboolean ok; 925 926 /* set up some data buffers */ 927 bigbuf = g_malloc(bigbuf_size); 928 simpleprng_seed(&prng, 0xb001); 929 simpleprng_fill_buffer(&prng, bigbuf, bigbuf_size); 930 931 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777); 932 g_assert(fd >= 0); 933 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size); 934 close(fd); 935 936 g_assert(pipe(p) >= 0); 937 938 switch (fork()) { 939 case 0: /* child */ 940 close(p[0]); 941 arch = amar_new(p[1], O_WRONLY, &error); 942 check_gerror(arch, error, "amar_new"); 943 g_assert(arch != NULL); 944 945 af = amar_new_file(arch, "bigstuff", 0, NULL, &error); 946 check_gerror(af, error, "amar_new_file"); 947 948 /* by character */ 949 at = amar_new_attr(af, attrid++, &error); 950 check_gerror(at, error, "amar_new_attr"); 951 ok = amar_attr_add_data_buffer(at, bigbuf, bigbuf_size, 1, &error); 952 check_gerror(ok, error, "amar_attr_add_data_buffer"); 953 ok = amar_attr_close(at, &error); 954 check_gerror(ok, error, "amar_attr_close"); 955 956 /* by file descriptor */ 957 at = amar_new_attr(af, attrid++, &error); 958 check_gerror(at, error, "amar_new_attr"); 959 fd = open("amar-test.big", O_RDONLY); 960 g_assert(fd >= 0); 961 fdsize = amar_attr_add_data_fd(at, fd, 1, &error); 962 check_gerror(fdsize != -1, error, "amar_attr_add_data_fd"); 963 g_assert(fdsize > 0); 964 close(fd); 965 unlink("amar-test.big"); 966 ok = amar_attr_close(at, &error); 967 check_gerror(ok, error, "amar_attr_close"); 968 969 ok = amar_file_close(af, &error); 970 check_gerror(ok, error, "amar_file_close"); 971 972 ok = amar_close(arch, &error); 973 check_gerror(ok, error, "amar_close"); 974 close(p[1]); 975 exit(0); 976 977 case -1: 978 perror("fork"); 979 exit(1); 980 981 default: { /* parent */ 982 amar_attr_handling_t handling[] = { 983 { 20, 0, NULL, NULL }, /* ignore attr 20 */ 984 { 0, 0, frag_cb, NULL }, /* don't buffer records */ 985 }; 986 expected_step_t steps[] = { 987 EXPECT_START_FILE_STR(1, "bigstuff", 0), 988 EXPECT_ATTR_DATA_MULTIPART(1, 21, bigbuf, max_record_data_size, 0, 0), 989 EXPECT_ATTR_DATA_MULTIPART(1, 21, bigbuf+max_record_data_size, bigbuf_size-max_record_data_size, 1, 0), 990 EXPECT_FINISH_FILE(1, 0), 991 EXPECT_END(), 992 }; 993 int status; 994 close(p[1]); 995 try_reading_fd(steps, handling, p[0]); 996 close(p[0]); 997 wait(&status); 998 if(WIFSIGNALED(status)) { 999 printf("child was terminated by signal %d\n", WTERMSIG(status)); 1000 exit(1); 1001 } 1002 } 1003 } 1004 1005 return 1; 1006} 1007 1008/**** 1009 * Invalid inputs - test error returns 1010 */ 1011 1012static int 1013test_no_header(void) 1014{ 1015 int fd; 1016 1017 fd = open_temp(1); 1018 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "/first/filename"); 1019 close(fd); 1020 1021 { 1022 amar_attr_handling_t handling[] = { 1023 { 0, 0, frag_cb, NULL }, 1024 }; 1025 expected_step_t steps[] = { 1026 EXPECT_END(), 1027 }; 1028 try_reading_with_error(steps, handling, 1029 "Archive read does not begin at a header record"); 1030 } 1031 1032 return 1; 1033} 1034 1035static int 1036test_invalid_eof(void) 1037{ 1038 int fd; 1039 1040 fd = open_temp(1); 1041 WRITE_HEADER(fd, 1); 1042 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "hi"); 1043 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, "abc"); 1044 close(fd); 1045 1046 { 1047 amar_attr_handling_t handling[] = { 1048 { 0, 0, frag_cb, NULL }, 1049 }; 1050 expected_step_t steps[] = { 1051 EXPECT_START_FILE_STR(1, "hi", 0), 1052 EXPECT_END(), 1053 }; 1054 try_reading_with_error(steps, handling, 1055 "Archive contains an EOF record with nonzero size"); 1056 } 1057 1058 return 1; 1059} 1060 1061static int 1062test_header_vers(void) 1063{ 1064 int fd; 1065 char hdr[32]; 1066 1067 bzero(hdr, sizeof(hdr)); 1068 strcpy(hdr, "AMANDA ARCHIVE FORMAT 2"); 1069 1070 fd = open_temp(1); 1071 if (full_write(fd, hdr, sizeof(hdr)) < sizeof(hdr)) { 1072 perror("full_write"); 1073 exit(1); 1074 } 1075 close(fd); 1076 1077 { 1078 amar_attr_handling_t handling[] = { 1079 { 0, 0, frag_cb, NULL }, 1080 }; 1081 expected_step_t steps[] = { 1082 EXPECT_END(), 1083 }; 1084 try_reading_with_error(steps, handling, 1085 "Archive version 2 is not supported"); 1086 } 1087 1088 return 1; 1089} 1090 1091/**** 1092 * Driver 1093 */ 1094 1095int 1096main(int argc, char **argv) 1097{ 1098 int rv; 1099 char *cwd = g_get_current_dir(); 1100 static TestUtilsTest tests[] = { 1101 TU_TEST(test_simple_read, 90), 1102 TU_TEST(test_read_buffering, 90), 1103 TU_TEST(test_missing_eoa, 90), 1104 TU_TEST(test_ignore, 90), 1105 TU_TEST(test_missing_eof, 90), 1106 TU_TEST(test_extra_records, 90), 1107 TU_TEST(test_early_exit, 90), 1108 TU_TEST(test_writing_coverage, 90), 1109 TU_TEST(test_big_attr, 90), 1110 TU_TEST(test_pipe, 90), 1111 TU_TEST(test_no_header, 90), 1112 TU_TEST(test_invalid_eof, 90), 1113 TU_TEST(test_header_vers, 90), 1114 TU_END() 1115 }; 1116 1117 temp_filename = vstralloc(cwd, "/amar-test.tmp", NULL); 1118 1119 rv = testutils_run_tests(argc, argv, tests); 1120 unlink(temp_filename); 1121 return rv; 1122}