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.
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.
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.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
30 #include "testutils.h"
31 #include "simpleprng.h"
33 static char *temp_filename = NULL;
36 * Macros for creating files with a particular structure
39 #define WRITE_HEADER(fd, version) do { \
42 snprintf(hdr, 28, "AMANDA ARCHIVE FORMAT %d", (version)); \
43 g_assert(full_write((fd), hdr, 28) == 28); \
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)); \
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)); \
61 * Assertions for amanda_read_archive callbacks
77 gboolean multipart_ok;
80 gboolean should_ignore;
85 expected_step_t *steps;
89 #define EXPECT_START_FILE(filenum, data, datasize, should_ignore) \
90 { EXP_START_FILE, (filenum), 0, (data), (datasize), 0, 0, 0, (should_ignore), 0 }
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 }
95 #define EXPECT_ATTR_DATA(filenum, attrid, data, datasize, eoa, truncated) \
96 { EXP_ATTRDATA, (filenum), (attrid), (data), (datasize), 0, (eoa), (truncated), 0, 0 }
98 #define EXPECT_ATTR_DATA_MULTIPART(filenum, attrid, data, datasize, eoa, truncated) \
99 { EXP_ATTRDATA, (filenum), (attrid), (data), (datasize), 1, (eoa), (truncated), 0, 0 }
101 #define EXPECT_ATTR_DATA_STR(filenum, attrid, datastr, eoa, truncated) \
102 { EXP_ATTRDATA, (filenum), (attrid), (datastr), strlen((datastr)), 0, (eoa), (truncated), 0, 1 }
104 #define EXPECT_FINISH_FILE(filenum, truncated) \
105 { EXP_FINISH_FILE, (filenum), 0, 0, 0, 0, 0, (truncated), 0, 0 }
107 #define EXPECT_END() \
108 { EXP_END, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
110 #define EXPECT_FAILURE(fmt, ...) do { \
111 fprintf(stderr, fmt "\n", __VA_ARGS__); \
122 gpointer *file_data G_GNUC_UNUSED)
124 expected_state_t *state = user_data;
125 expected_step_t *step = state->steps + state->curstep;
127 tu_dbg("file_start_cb(NULL, %d, '%s', %zd, .., ..)\n",
128 (int)filenum, (char *)filename, filename_len);
130 if (step->kind != EXP_START_FILE)
131 EXPECT_FAILURE("step %d: unexpected new file with fileid %d",
132 state->curstep, (int)filenum);
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);
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);
142 if (memcmp(filename, step->data, filename_len)) {
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);
148 EXPECT_FAILURE("step %d: new file's filename does not match",
153 *ignore = step->should_ignore;
163 gpointer *file_data G_GNUC_UNUSED,
166 expected_state_t *state = user_data;
167 expected_step_t *step = state->steps + state->curstep;
169 tu_dbg("file_finish_cb(NULL, %d, NULL, %d)\n",
170 (int)filenum, truncated);
172 if (step->kind != EXP_FINISH_FILE)
173 EXPECT_FAILURE("step %d: unexpected file finish with fileid %d",
174 state->curstep, (int)filenum);
176 if (step->truncated && !truncated)
177 EXPECT_FAILURE("step %d: file %d was unexpectedly not truncated",
178 state->curstep, (int)filenum);
180 if (step->truncated && !truncated)
181 EXPECT_FAILURE("step %d: file %d was unexpectedly truncated",
182 state->curstep, (int)filenum);
193 gpointer file_data G_GNUC_UNUSED,
195 gpointer attrid_data G_GNUC_UNUSED,
196 gpointer *attr_data G_GNUC_UNUSED,
202 expected_state_t *state = user_data;
203 expected_step_t *step = state->steps + state->curstep;
205 tu_dbg("file_finish_cb(NULL, %d, NULL, %d, %p, %zd, %d, %d)\n",
206 (int)filenum, (int)attrid, data, datasize, eoa, truncated);
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);
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);
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);
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) {
224 EXPECT_FAILURE("step %d: file %d attribute %d: early EOA in multipart attribute",
225 state->curstep, (int)filenum, (int)attrid);
227 if (memcmp(data, step->data, datasize)) {
228 EXPECT_FAILURE("step %d: attribute's data does not match",
231 step->data += datasize;
232 step->datasize -= datasize;
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);
240 if (!step->eoa && eoa)
241 EXPECT_FAILURE("step %d: file %d attribute %d: unexpected EOA",
242 state->curstep, (int)filenum, (int)attrid);
244 if (!step->truncated && truncated)
245 EXPECT_FAILURE("step %d: file %d attribute %d was unexpectedly truncated",
246 state->curstep, (int)filenum, (int)attrid);
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);
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);
258 if (memcmp(data, step->data, datasize)) {
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);
264 EXPECT_FAILURE("step %d: attribute's data does not match",
279 open_temp(gboolean write)
281 int fd = open(temp_filename, write? O_WRONLY|O_CREAT|O_TRUNC : O_RDONLY, 0777);
283 perror("open temporary file");
301 "'%s' set 'error' but did not indicate an error condition: %s (%s)\n",
302 fn, error->message, strerror(error->code));
305 "'%s' indicated an error condition but did not set 'error'.\n", fn);
308 "'%s' error: %s (%s)\n", fn, error->message, strerror(error->code));
313 #define check_gerror(ok, error, fn) check_gerror_((ok)!=0, (error), (fn))
316 check_gerror_matches_(
323 if (0 != strcmp(matches, error->message)) {
325 "%s produced error '%s' but expected '%s'\n",
326 fn, error->message, matches);
334 "'%s' correctly set 'error' but did not indicate an error condition: %s (%s)\n",
335 fn, error->message, strerror(error->code));
338 "'%s' correctly indicated an error condition but did not set 'error'.\n", fn);
343 #define check_gerror_matches(ok, error, match, fn) \
344 check_gerror_matches_((ok)!=0, (error), (match), (fn))
348 expected_step_t *steps,
349 amar_attr_handling_t *handling,
353 expected_state_t state = { steps, 0 };
354 GError *error = NULL;
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);
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");
370 expected_step_t *steps,
371 amar_attr_handling_t *handling)
376 try_reading_fd(steps, handling, fd);
381 try_reading_with_error(
382 expected_step_t *steps,
383 amar_attr_handling_t *handling,
387 expected_state_t state = { steps, 0 };
389 GError *error = NULL;
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);
402 * Test various valid inputs
406 test_simple_read(void)
412 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "/first/filename");
413 WRITE_RECORD_STR(fd, 1, 18, 1, "eighteen");
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, "");
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 },
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),
437 try_reading(steps, handling);
444 test_read_buffering(void)
450 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file1");
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");
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, "");
481 amar_attr_handling_t handling[] = {
482 { 0, 10, frag_cb, NULL }, /* reassemble all fragments in 10-byte chunks */
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),
498 try_reading(steps, handling);
505 test_missing_eoa(void)
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, "");
518 amar_attr_handling_t handling[] = {
519 { 0, 1024, frag_cb, NULL },
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),
527 try_reading(steps, handling);
540 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file1");
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");
547 WRITE_RECORD_STR(fd, 3, AMAR_ATTR_FILENAME, 1, "file3");
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, "");
560 amar_attr_handling_t handling[] = {
561 { 0, 10, frag_cb, NULL }, /* reassemble all fragments in 10-byte chunks */
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),
574 try_reading(steps, handling);
581 test_missing_eof(void)
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 */
594 amar_attr_handling_t handling[] = {
595 { 0, 1024, frag_cb, NULL },
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),
604 try_reading(steps, handling);
611 test_extra_records(void)
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, "");
627 amar_attr_handling_t handling[] = {
628 { 0, 1024, frag_cb, NULL },
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),
636 try_reading(steps, handling);
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)
659 test_early_exit(void)
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, "");
671 amar_attr_handling_t handling[] = {
672 { 0, 0, early_exit_frag_cb, NULL },
674 expected_step_t steps[] = {
675 EXPECT_START_FILE_STR(6, "file!", 0),
676 EXPECT_FINISH_FILE(6, 1),
679 try_reading(steps, handling);
686 * Test the write side, using round trips.
689 /* just try to execute most of the writing code */
691 test_writing_coverage(void)
698 size_t bigbuf_size = 1024*50+93;
699 simpleprng_state_t prng;
703 amar_file_t *af = NULL, *af2 = NULL;
704 amar_attr_t *at = NULL, *at2 = NULL;
705 GError *error = NULL;
708 /* set up some data buffers */
709 for (i = 0; i < sizeof(buf); i++) {
714 bigbuf = g_malloc(bigbuf_size);
715 simpleprng_seed(&prng, 0xfeaa);
716 simpleprng_fill_buffer(&prng, bigbuf, bigbuf_size);
718 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777);
720 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size);
725 arch = amar_new(fd, O_WRONLY, &error);
726 check_gerror(arch, error, "amar_new");
727 g_assert(arch != NULL);
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);
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");
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");
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)
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);
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);
766 unlink("amar-test.big");
767 ok = amar_attr_close(at, &error);
768 check_gerror(ok, error, "amar_attr_close");
770 ok = amar_file_close(af, &error);
771 check_gerror(ok, error, "amar_file_close");
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");
791 ok = amar_file_close(af2, &error);
792 check_gerror(ok, error, "amar_file_close");
794 ok = amar_close(arch, &error);
795 check_gerror(ok, error, "amar_close");
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 */
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),
819 try_reading(steps, handling);
825 /* test big attributes */
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;
837 amar_file_t *af = NULL;
838 amar_attr_t *at = NULL;
839 GError *error = NULL;
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);
847 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777);
849 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size);
854 arch = amar_new(fd, O_WRONLY, &error);
855 check_gerror(arch, error, "amar_new");
857 af = amar_new_file(arch, "bigstuff", 0, NULL, &error);
858 check_gerror(af, error, "amar_new_file");
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");
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);
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);
877 unlink("amar-test.big");
878 ok = amar_attr_close(at, &error);
879 check_gerror(ok, error, "amar_attr_close");
881 ok = amar_file_close(af, &error);
882 check_gerror(ok, error, "amar_file_close");
884 ok = amar_close(arch, &error);
885 check_gerror(ok, error, "amar_close");
889 amar_attr_handling_t handling[] = {
890 { 0, 0, frag_cb, NULL }, /* don't buffer records */
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),
901 try_reading(steps, handling);
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. */
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;
921 amar_file_t *af = NULL;
922 amar_attr_t *at = NULL;
923 GError *error = NULL;
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);
931 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777);
933 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size);
936 g_assert(pipe(p) >= 0);
941 arch = amar_new(p[1], O_WRONLY, &error);
942 check_gerror(arch, error, "amar_new");
943 g_assert(arch != NULL);
945 af = amar_new_file(arch, "bigstuff", 0, NULL, &error);
946 check_gerror(af, error, "amar_new_file");
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");
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);
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);
965 unlink("amar-test.big");
966 ok = amar_attr_close(at, &error);
967 check_gerror(ok, error, "amar_attr_close");
969 ok = amar_file_close(af, &error);
970 check_gerror(ok, error, "amar_file_close");
972 ok = amar_close(arch, &error);
973 check_gerror(ok, error, "amar_close");
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 */
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),
995 try_reading_fd(steps, handling, p[0]);
998 if(WIFSIGNALED(status)) {
999 printf("child was terminated by signal %d\n", WTERMSIG(status));
1009 * Invalid inputs - test error returns
1013 test_no_header(void)
1018 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "/first/filename");
1022 amar_attr_handling_t handling[] = {
1023 { 0, 0, frag_cb, NULL },
1025 expected_step_t steps[] = {
1028 try_reading_with_error(steps, handling,
1029 "Archive read does not begin at a header record");
1036 test_invalid_eof(void)
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");
1047 amar_attr_handling_t handling[] = {
1048 { 0, 0, frag_cb, NULL },
1050 expected_step_t steps[] = {
1051 EXPECT_START_FILE_STR(1, "hi", 0),
1054 try_reading_with_error(steps, handling,
1055 "Archive contains an EOF record with nonzero size");
1062 test_header_vers(void)
1067 bzero(hdr, sizeof(hdr));
1068 strcpy(hdr, "AMANDA ARCHIVE FORMAT 2");
1071 if (full_write(fd, hdr, sizeof(hdr)) < sizeof(hdr)) {
1072 perror("full_write");
1078 amar_attr_handling_t handling[] = {
1079 { 0, 0, frag_cb, NULL },
1081 expected_step_t steps[] = {
1084 try_reading_with_error(steps, handling,
1085 "Archive version 2 is not supported");
1096 main(int argc, char **argv)
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),
1117 temp_filename = vstralloc(cwd, "/amar-test.tmp", NULL);
1119 rv = testutils_run_tests(argc, argv, tests);
1120 unlink(temp_filename);