2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
29 #include "testutils.h"
30 #include "simpleprng.h"
32 static char *temp_filename = NULL;
35 * Macros for creating files with a particular structure
38 #define WRITE_HEADER(fd, version) do { \
41 snprintf(hdr, 28, "AMANDA ARCHIVE FORMAT %d", (version)); \
42 g_assert(full_write((fd), hdr, 28) == 28); \
45 #define WRITE_RECORD(fd, filenum, attrid, size, eoa, data) do { \
46 struct { uint16_t f; uint16_t a; uint32_t s; } rec; \
47 rec.f = htons((filenum)); \
48 rec.a = htons((attrid)); \
49 rec.s = htonl((size) | (eoa? 0x80000000 : 0)); \
50 g_assert(full_write((fd), &rec, sizeof(rec)) == sizeof(rec)); \
51 g_assert(full_write((fd), (data), (size)) == (size)); \
54 #define WRITE_RECORD_STR(fd, filenum, attrid, eoa, str) do { \
55 size_t len = strlen((str)); \
56 WRITE_RECORD((fd), (filenum), (attrid), len, (eoa), (str)); \
60 * Assertions for amanda_read_archive callbacks
76 gboolean multipart_ok;
79 gboolean should_ignore;
84 expected_step_t *steps;
88 #define EXPECT_START_FILE(filenum, data, datasize, should_ignore) \
89 { EXP_START_FILE, (filenum), 0, (data), (datasize), 0, 0, 0, (should_ignore), 0 }
91 #define EXPECT_START_FILE_STR(filenum, filename, should_ignore) \
92 { EXP_START_FILE, (filenum), 0, (filename), strlen((filename)), 0, 0, 0, (should_ignore), 1 }
94 #define EXPECT_ATTR_DATA(filenum, attrid, data, datasize, eoa, truncated) \
95 { EXP_ATTRDATA, (filenum), (attrid), (data), (datasize), 0, (eoa), (truncated), 0, 0 }
97 #define EXPECT_ATTR_DATA_MULTIPART(filenum, attrid, data, datasize, eoa, truncated) \
98 { EXP_ATTRDATA, (filenum), (attrid), (data), (datasize), 1, (eoa), (truncated), 0, 0 }
100 #define EXPECT_ATTR_DATA_STR(filenum, attrid, datastr, eoa, truncated) \
101 { EXP_ATTRDATA, (filenum), (attrid), (datastr), strlen((datastr)), 0, (eoa), (truncated), 0, 1 }
103 #define EXPECT_FINISH_FILE(filenum, truncated) \
104 { EXP_FINISH_FILE, (filenum), 0, 0, 0, 0, 0, (truncated), 0, 0 }
106 #define EXPECT_END() \
107 { EXP_END, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
109 #define EXPECT_FAILURE(fmt, ...) do { \
110 fprintf(stderr, fmt "\n", __VA_ARGS__); \
121 gpointer *file_data G_GNUC_UNUSED)
123 expected_state_t *state = user_data;
124 expected_step_t *step = state->steps + state->curstep;
126 tu_dbg("file_start_cb(NULL, %d, '%s', %zd, .., ..)\n",
127 (int)filenum, (char *)filename, filename_len);
129 if (step->kind != EXP_START_FILE)
130 EXPECT_FAILURE("step %d: unexpected new file with fileid %d",
131 state->curstep, (int)filenum);
133 if (step->filenum != filenum)
134 EXPECT_FAILURE("step %d: expected new file with filenum %d; got filenum %d",
135 state->curstep, (int)step->filenum, (int)filenum);
137 if (filename_len != step->datasize)
138 EXPECT_FAILURE("step %d: filename lengths do not match: got %zd, expected %zd",
139 state->curstep, filename_len, step->datasize);
141 if (memcmp(filename, step->data, filename_len)) {
143 EXPECT_FAILURE("step %d: new file's filename does not match: got '%*s', expected '%*s'",
144 state->curstep, (int)filename_len, (char *)filename,
145 (int)step->datasize, (char *)step->data);
147 EXPECT_FAILURE("step %d: new file's filename does not match",
152 *ignore = step->should_ignore;
162 gpointer *file_data G_GNUC_UNUSED,
165 expected_state_t *state = user_data;
166 expected_step_t *step = state->steps + state->curstep;
168 tu_dbg("file_finish_cb(NULL, %d, NULL, %d)\n",
169 (int)filenum, truncated);
171 if (step->kind != EXP_FINISH_FILE)
172 EXPECT_FAILURE("step %d: unexpected file finish with fileid %d",
173 state->curstep, (int)filenum);
175 if (step->truncated && !truncated)
176 EXPECT_FAILURE("step %d: file %d was unexpectedly not truncated",
177 state->curstep, (int)filenum);
179 if (step->truncated && !truncated)
180 EXPECT_FAILURE("step %d: file %d was unexpectedly truncated",
181 state->curstep, (int)filenum);
192 gpointer file_data G_GNUC_UNUSED,
194 gpointer attrid_data G_GNUC_UNUSED,
195 gpointer *attr_data G_GNUC_UNUSED,
201 expected_state_t *state = user_data;
202 expected_step_t *step = state->steps + state->curstep;
204 tu_dbg("file_finish_cb(NULL, %d, NULL, %d, %p, %zd, %d, %d)\n",
205 (int)filenum, (int)attrid, data, datasize, eoa, truncated);
207 if (step->kind != EXP_ATTRDATA)
208 EXPECT_FAILURE("step %d: unexpected attribute data with fileid %d, attrid %d",
209 state->curstep, (int)filenum, (int)attrid);
211 if (step->filenum != filenum)
212 EXPECT_FAILURE("step %d: expected attribute data with filenum %d; got filenum %d",
213 state->curstep, (int)step->filenum, (int)filenum);
215 if (step->attrid != attrid)
216 EXPECT_FAILURE("step %d: expected attribute data with attrid %d; got attrid %d",
217 state->curstep, (int)step->attrid, (int)attrid);
219 /* if we're accepting multiple fragments of the attribute here (due to internal
220 * buffering by the reader), then handle that specially */
221 if (step->multipart_ok && datasize < step->datasize) {
223 EXPECT_FAILURE("step %d: file %d attribute %d: early EOA in multipart attribute",
224 state->curstep, (int)filenum, (int)attrid);
226 if (memcmp(data, step->data, datasize)) {
227 EXPECT_FAILURE("step %d: attribute's data does not match",
230 step->data += datasize;
231 step->datasize -= datasize;
235 if (step->eoa && !eoa)
236 EXPECT_FAILURE("step %d: file %d attribute %d: expected EOA did not appear",
237 state->curstep, (int)filenum, (int)attrid);
239 if (!step->eoa && eoa)
240 EXPECT_FAILURE("step %d: file %d attribute %d: unexpected EOA",
241 state->curstep, (int)filenum, (int)attrid);
243 if (!step->truncated && truncated)
244 EXPECT_FAILURE("step %d: file %d attribute %d was unexpectedly truncated",
245 state->curstep, (int)filenum, (int)attrid);
247 if (step->truncated && !truncated)
248 EXPECT_FAILURE("step %d: file %d attribute %d was unexpectedly not truncated",
249 state->curstep, (int)filenum, (int)attrid);
251 if (datasize != step->datasize)
252 EXPECT_FAILURE("step %d: file %d attribute %d lengths do not match: "
253 "got %zd, expected %zd",
254 state->curstep, (int)filenum, (int)attrid,
255 datasize, step->datasize);
257 if (memcmp(data, step->data, datasize)) {
259 EXPECT_FAILURE("step %d: attribute's data does not match: got '%*s', expected '%*s'",
260 state->curstep, (int)datasize, (char *)data,
261 (int)step->datasize, (char *)step->data);
263 EXPECT_FAILURE("step %d: attribute's data does not match",
278 open_temp(gboolean write)
280 int fd = open(temp_filename, write? O_WRONLY|O_CREAT|O_TRUNC : O_RDONLY, 0777);
282 perror("open temporary file");
300 "'%s' set 'error' but did not indicate an error condition: %s (%s)\n",
301 fn, error->message, strerror(error->code));
304 "'%s' indicated an error condition but did not set 'error'.\n", fn);
307 "'%s' error: %s (%s)\n", fn, error->message, strerror(error->code));
312 #define check_gerror(ok, error, fn) check_gerror_((ok)!=0, (error), (fn))
315 check_gerror_matches_(
322 if (0 != strcmp(matches, error->message)) {
324 "%s produced error '%s' but expected '%s'\n",
325 fn, error->message, matches);
333 "'%s' correctly set 'error' but did not indicate an error condition: %s (%s)\n",
334 fn, error->message, strerror(error->code));
337 "'%s' correctly indicated an error condition but did not set 'error'.\n", fn);
342 #define check_gerror_matches(ok, error, match, fn) \
343 check_gerror_matches_((ok)!=0, (error), (match), (fn))
347 expected_step_t *steps,
348 amar_attr_handling_t *handling,
352 expected_state_t state = { steps, 0 };
353 GError *error = NULL;
356 ar = amar_new(fd, O_RDONLY, &error);
357 check_gerror(ar, error, "amar_new");
358 ok = amar_read(ar, &state, handling, file_start_cb, file_finish_cb, &error);
360 check_gerror(ok, error, "amar_read");
361 if (steps[state.curstep].kind != EXP_END)
362 EXPECT_FAILURE("Stopped reading early at step %d", state.curstep);
363 ok = amar_close(ar, &error);
364 check_gerror(ok, error, "amar_close");
369 expected_step_t *steps,
370 amar_attr_handling_t *handling)
375 try_reading_fd(steps, handling, fd);
380 try_reading_with_error(
381 expected_step_t *steps,
382 amar_attr_handling_t *handling,
386 expected_state_t state = { steps, 0 };
388 GError *error = NULL;
392 ar = amar_new(fd, O_RDONLY, &error);
393 check_gerror(ar, error, "amar_new");
394 ok = amar_read(ar, &state, handling, file_start_cb, file_finish_cb, &error);
395 check_gerror_matches(ok, error, message, "amar_read");
396 amar_close(ar, NULL);
401 * Test various valid inputs
405 test_simple_read(void)
411 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "/first/filename");
412 WRITE_RECORD_STR(fd, 1, 18, 1, "eighteen");
414 WRITE_RECORD_STR(fd, 1, 19, 0, "nine");
415 WRITE_RECORD_STR(fd, 1, 20, 0, "twen");
416 WRITE_RECORD_STR(fd, 1, 19, 1, "teen");
417 WRITE_RECORD_STR(fd, 1, 20, 1, "ty");
418 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, "");
422 amar_attr_handling_t handling[] = {
423 { 19, 256, frag_cb, NULL }, /* reassemble this attribute */
424 { 20, 0, frag_cb, NULL }, /* but pass along each fragment of this */
425 { 0, 256, frag_cb, NULL },
427 expected_step_t steps[] = {
428 EXPECT_START_FILE_STR(1, "/first/filename", 0),
429 EXPECT_ATTR_DATA_STR(1, 18, "eighteen", 1, 0),
430 EXPECT_ATTR_DATA_STR(1, 20, "twen", 0, 0),
431 EXPECT_ATTR_DATA_STR(1, 19, "nineteen", 1, 0),
432 EXPECT_ATTR_DATA_STR(1, 20, "ty", 1, 0),
433 EXPECT_FINISH_FILE(1, 0),
436 try_reading(steps, handling);
443 test_read_buffering(void)
449 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file1");
451 WRITE_RECORD_STR(fd, 2, AMAR_ATTR_FILENAME, 1, "file2");
452 WRITE_RECORD_STR(fd, 2, 19, 0, "1"); /* one byte at a time, for 12 bytes */
453 WRITE_RECORD_STR(fd, 2, 19, 0, "9");
454 WRITE_RECORD_STR(fd, 2, 21, 1, "012345678901234567890123456789"); /* thirty bytes exactly */
455 WRITE_RECORD_STR(fd, 2, 19, 0, "1");
456 WRITE_RECORD_STR(fd, 1, 18, 0, "ATTR");
457 WRITE_RECORD_STR(fd, 2, 19, 0, "9");
458 WRITE_RECORD_STR(fd, 2, 19, 0, "1");
459 WRITE_RECORD_STR(fd, 2, 19, 0, "9");
461 WRITE_RECORD_STR(fd, 1, 20, 0, "TWENTYTWE"); /* nine bytes, then three in the next frag */
462 WRITE_RECORD_STR(fd, 2, 19, 0, "1");
463 WRITE_RECORD_STR(fd, 1, 20, 1, "NTY");
464 WRITE_RECORD_STR(fd, 2, 19, 0, "9");
465 WRITE_RECORD_STR(fd, 1, 18, 0, "181818"); /* hit ten bytes exactly */
466 WRITE_RECORD_STR(fd, 2, 19, 0, "1");
467 WRITE_RECORD_STR(fd, 2, 19, 0, "9");
468 WRITE_RECORD_STR(fd, 1, 18, 0, "ATTR");
469 WRITE_RECORD_STR(fd, 1, 22, 0, "012345678"); /* nine bytes followed by 20 */
470 WRITE_RECORD_STR(fd, 1, 18, 1, "18");
471 WRITE_RECORD_STR(fd, 1, 22, 1, "01234567890123456789");
472 WRITE_RECORD_STR(fd, 2, 19, 0, "1");
473 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, "");
474 WRITE_RECORD_STR(fd, 2, 19, 1, "9");
475 WRITE_RECORD_STR(fd, 2, AMAR_ATTR_EOF, 1, "");
480 amar_attr_handling_t handling[] = {
481 { 0, 10, frag_cb, NULL }, /* reassemble all fragments in 10-byte chunks */
483 expected_step_t steps[] = {
484 EXPECT_START_FILE_STR(1, "file1", 0),
485 EXPECT_START_FILE_STR(2, "file2", 0),
486 EXPECT_ATTR_DATA_STR(2, 21, "012345678901234567890123456789", 1, 0),
487 EXPECT_ATTR_DATA_STR(1, 20, "TWENTYTWENTY", 1, 0),
488 EXPECT_ATTR_DATA_STR(1, 18, "ATTR181818", 0, 0),
489 EXPECT_ATTR_DATA_STR(2, 19, "1919191919", 0, 0),
490 EXPECT_ATTR_DATA_STR(1, 18, "ATTR18", 1, 0),
491 EXPECT_ATTR_DATA_STR(1, 22, "01234567801234567890123456789", 1, 0),
492 EXPECT_FINISH_FILE(1, 0),
493 EXPECT_ATTR_DATA_STR(2, 19, "19", 1, 0),
494 EXPECT_FINISH_FILE(2, 0),
497 try_reading(steps, handling);
504 test_missing_eoa(void)
510 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file1");
511 WRITE_RECORD_STR(fd, 1, 21, 0, "attribu"); /* note no EOA */
512 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, "");
517 amar_attr_handling_t handling[] = {
518 { 0, 1024, frag_cb, NULL },
520 expected_step_t steps[] = {
521 EXPECT_START_FILE_STR(1, "file1", 0),
522 EXPECT_ATTR_DATA_STR(1, 21, "attribu", 1, 1),
523 EXPECT_FINISH_FILE(1, 0),
526 try_reading(steps, handling);
539 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file1");
541 WRITE_RECORD_STR(fd, 2, AMAR_ATTR_FILENAME, 1, "file2");
542 WRITE_RECORD_STR(fd, 2, 20, 1, "attr20");
543 WRITE_RECORD_STR(fd, 1, 21, 0, "attr");
544 WRITE_RECORD_STR(fd, 1, 21, 1, "21");
546 WRITE_RECORD_STR(fd, 3, AMAR_ATTR_FILENAME, 1, "file3");
548 WRITE_RECORD_STR(fd, 4, AMAR_ATTR_FILENAME, 1, "file4");
549 WRITE_RECORD_STR(fd, 3, 22, 1, "attr22");
550 WRITE_RECORD_STR(fd, 4, 23, 1, "attr23");
551 WRITE_RECORD_STR(fd, 4, AMAR_ATTR_EOF, 1, "");
552 WRITE_RECORD_STR(fd, 3, AMAR_ATTR_EOF, 1, "");
553 WRITE_RECORD_STR(fd, 2, AMAR_ATTR_EOF, 1, "");
554 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, "");
559 amar_attr_handling_t handling[] = {
560 { 0, 10, frag_cb, NULL }, /* reassemble all fragments in 10-byte chunks */
562 expected_step_t steps[] = {
563 EXPECT_START_FILE_STR(1, "file1", 1),
564 EXPECT_START_FILE_STR(2, "file2", 0),
565 EXPECT_ATTR_DATA_STR(2, 20, "attr20", 1, 0),
566 EXPECT_START_FILE_STR(3, "file3", 1),
567 EXPECT_START_FILE_STR(4, "file4", 0),
568 EXPECT_ATTR_DATA_STR(4, 23, "attr23", 1, 0),
569 EXPECT_FINISH_FILE(4, 0),
570 EXPECT_FINISH_FILE(2, 0),
573 try_reading(steps, handling);
580 test_missing_eof(void)
586 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "file!");
587 WRITE_RECORD_STR(fd, 1, 20, 1, "attribute");
588 WRITE_RECORD_STR(fd, 1, 21, 0, "attribu"); /* note no EOA */
593 amar_attr_handling_t handling[] = {
594 { 0, 1024, frag_cb, NULL },
596 expected_step_t steps[] = {
597 EXPECT_START_FILE_STR(1, "file!", 0),
598 EXPECT_ATTR_DATA_STR(1, 20, "attribute", 1, 0),
599 EXPECT_ATTR_DATA_STR(1, 21, "attribu", 1, 1),
600 EXPECT_FINISH_FILE(1, 0),
603 try_reading(steps, handling);
610 test_extra_records(void)
616 WRITE_RECORD_STR(fd, 4, AMAR_ATTR_EOF, 1, "");
617 WRITE_RECORD_STR(fd, 5, 20, 1, "old attribute");
618 WRITE_RECORD_STR(fd, 6, AMAR_ATTR_FILENAME, 1, "file!");
619 WRITE_RECORD_STR(fd, 6, 21, 0, "attribu"); /* note no EOA */
620 WRITE_RECORD_STR(fd, 5, AMAR_ATTR_EOF, 1, "");
621 WRITE_RECORD_STR(fd, 6, 21, 1, "te");
622 WRITE_RECORD_STR(fd, 6, AMAR_ATTR_EOF, 1, "");
626 amar_attr_handling_t handling[] = {
627 { 0, 1024, frag_cb, NULL },
629 expected_step_t steps[] = {
630 EXPECT_START_FILE_STR(6, "file!", 0),
631 EXPECT_ATTR_DATA_STR(6, 21, "attribute", 1, 0),
632 EXPECT_FINISH_FILE(6, 0),
635 try_reading(steps, handling);
643 gpointer user_data G_GNUC_UNUSED,
644 uint16_t filenum G_GNUC_UNUSED,
645 gpointer file_data G_GNUC_UNUSED,
646 uint16_t attrid G_GNUC_UNUSED,
647 gpointer attrid_data G_GNUC_UNUSED,
648 gpointer *attr_data G_GNUC_UNUSED,
649 gpointer data G_GNUC_UNUSED,
650 gsize datasize G_GNUC_UNUSED,
651 gboolean eoa G_GNUC_UNUSED,
652 gboolean truncated G_GNUC_UNUSED)
658 test_early_exit(void)
664 WRITE_RECORD_STR(fd, 6, AMAR_ATTR_FILENAME, 1, "file!");
665 WRITE_RECORD_STR(fd, 6, 21, 1, "attribu");
666 WRITE_RECORD_STR(fd, 6, AMAR_ATTR_EOF, 1, "");
670 amar_attr_handling_t handling[] = {
671 { 0, 0, early_exit_frag_cb, NULL },
673 expected_step_t steps[] = {
674 EXPECT_START_FILE_STR(6, "file!", 0),
675 EXPECT_FINISH_FILE(6, 1),
678 try_reading(steps, handling);
685 * Test the write side, using round trips.
688 /* just try to execute most of the writing code */
690 test_writing_coverage(void)
697 size_t bigbuf_size = 1024*50+93;
698 simpleprng_state_t prng;
702 amar_file_t *af = NULL, *af2 = NULL;
703 amar_attr_t *at = NULL, *at2 = NULL;
704 GError *error = NULL;
707 /* set up some data buffers */
708 for (i = 0; i < sizeof(buf); i++) {
713 bigbuf = g_malloc(bigbuf_size);
714 simpleprng_seed(&prng, 0xfeaa);
715 simpleprng_fill_buffer(&prng, bigbuf, bigbuf_size);
717 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777);
719 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size);
724 arch = amar_new(fd, O_WRONLY, &error);
725 check_gerror(arch, error, "amar_new");
726 g_assert(arch != NULL);
728 af = amar_new_file(arch, "MyFile", 0, &posn, &error);
729 check_gerror(af, error, "amar_new_file");
730 tu_dbg("MyFile starts at 0x%x\n", (int)posn)
731 g_assert(af != NULL);
733 /* by character with EOA */
734 at = amar_new_attr(af, attrid++, &error);
735 check_gerror(at, error, "amar_new_attr");
736 g_assert(at != NULL);
737 ok = amar_attr_add_data_buffer(at, buf, sizeof(buf), 1, &error);
738 check_gerror(ok, error, "amar_attr_add_data_buffer");
739 ok = amar_attr_close(at, &error);
740 check_gerror(ok, error, "amar_attr_close");
742 /* by character without EOA */
743 at = amar_new_attr(af, attrid++, &error);
744 check_gerror(at, error, "amar_new_attr");
745 g_assert(at != NULL);
746 ok = amar_attr_add_data_buffer(at, buf2, sizeof(buf2), 0, &error);
747 check_gerror(ok, error, "amar_attr_add_data_buffer");
748 ok = amar_attr_close(at, &error);
749 check_gerror(ok, error, "amar_attr_close");
751 /* open up a new file, for fun */
752 af2 = amar_new_file(arch, "MyOtherFile", 0, &posn, &error);
753 check_gerror(af2, error, "amar_new_file");
754 tu_dbg("MyOtherFile starts at 0x%x\n", (int)posn)
756 /* by file descriptor, to the first file */
757 at = amar_new_attr(af, attrid++, &error);
758 check_gerror(at, error, "amar_new_attr");
759 fd2 = open("amar-test.big", O_RDONLY);
761 fdsize = amar_attr_add_data_fd(at, fd2, 0, &error);
762 check_gerror(fdsize != -1, error, "amar_attr_add_data_fd");
763 g_assert(fdsize > 0);
765 unlink("amar-test.big");
766 ok = amar_attr_close(at, &error);
767 check_gerror(ok, error, "amar_attr_close");
769 ok = amar_file_close(af, &error);
770 check_gerror(ok, error, "amar_file_close");
772 /* interlaeave two attributes */
773 at = amar_new_attr(af2, attrid++, &error);
774 check_gerror(at, error, "amar_new_attr");
775 at2 = amar_new_attr(af2, attrid++, &error);
776 check_gerror(at2, error, "amar_new_attr");
777 ok = amar_attr_add_data_buffer(at, buf, 72, 0, &error);
778 check_gerror(ok, error, "amar_attr_add_data_buffer");
779 ok = amar_attr_add_data_buffer(at2, buf2, 72, 0, &error);
780 check_gerror(ok, error, "amar_attr_add_data_buffer");
781 ok = amar_attr_add_data_buffer(at, buf, 13, 0, &error);
782 check_gerror(ok, error, "amar_attr_add_data_buffer");
783 ok = amar_attr_add_data_buffer(at2, buf2, 13, 1, &error);
784 check_gerror(ok, error, "amar_attr_add_data_buffer");
785 ok = amar_attr_close(at, &error);
786 check_gerror(ok, error, "amar_attr_close");
787 ok = amar_attr_close(at2, &error);
788 check_gerror(ok, error, "amar_attr_close");
790 ok = amar_file_close(af2, &error);
791 check_gerror(ok, error, "amar_file_close");
793 ok = amar_close(arch, &error);
794 check_gerror(ok, error, "amar_close");
798 amar_attr_handling_t handling[] = {
799 { 22, bigbuf_size+1, frag_cb, NULL }, /* buffer the big attr */
800 { 0, 0, frag_cb, NULL }, /* don't buffer other records */
802 expected_step_t steps[] = {
803 EXPECT_START_FILE_STR(1, "MyFile", 0),
804 EXPECT_ATTR_DATA_MULTIPART(1, 20, buf, sizeof(buf), 1, 0),
805 EXPECT_ATTR_DATA_MULTIPART(1, 21, buf2, sizeof(buf2), 0, 0),
806 EXPECT_ATTR_DATA_MULTIPART(1, 21, buf2, 0, 1, 0), /* trailing EOA */
807 EXPECT_START_FILE_STR(2, "MyOtherFile", 0),
808 EXPECT_ATTR_DATA(1, 22, bigbuf, bigbuf_size, 1, 0),
809 EXPECT_FINISH_FILE(1, 0),
810 EXPECT_ATTR_DATA_MULTIPART(2, 23, buf, 72, 0, 0),
811 EXPECT_ATTR_DATA_MULTIPART(2, 24, buf2, 72, 0, 0),
812 EXPECT_ATTR_DATA_MULTIPART(2, 23, buf+72, 13, 0, 0),
813 EXPECT_ATTR_DATA_MULTIPART(2, 24, buf2+72, 13, 1, 0),
814 EXPECT_ATTR_DATA_MULTIPART(2, 23, buf, 0, 1, 0),
815 EXPECT_FINISH_FILE(2, 0),
818 try_reading(steps, handling);
824 /* test big attributes */
831 const size_t max_record_data_size = 4*1024*1024;
832 size_t bigbuf_size = max_record_data_size + 1274; /* a record and a bit */
833 simpleprng_state_t prng;
836 amar_file_t *af = NULL;
837 amar_attr_t *at = NULL;
838 GError *error = NULL;
841 /* set up some data buffers */
842 bigbuf = g_malloc(bigbuf_size);
843 simpleprng_seed(&prng, 0xb001);
844 simpleprng_fill_buffer(&prng, bigbuf, bigbuf_size);
846 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777);
848 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size);
853 arch = amar_new(fd, O_WRONLY, &error);
854 check_gerror(arch, error, "amar_new");
856 af = amar_new_file(arch, "bigstuff", 0, NULL, &error);
857 check_gerror(af, error, "amar_new_file");
860 at = amar_new_attr(af, attrid++, &error);
861 check_gerror(at, error, "amar_new_attr");
862 ok = amar_attr_add_data_buffer(at, bigbuf, bigbuf_size, 1, &error);
863 check_gerror(ok, error, "amar_attr_add_data_buffer");
864 ok = amar_attr_close(at, &error);
865 check_gerror(ok, error, "amar_attr_close");
867 /* by file descriptor */
868 at = amar_new_attr(af, attrid++, &error);
869 check_gerror(at, error, "amar_new_attr");
870 fd2 = open("amar-test.big", O_RDONLY);
872 fdsize = amar_attr_add_data_fd(at, fd2, 1, &error);
873 check_gerror(fdsize != -1, error, "amar_attr_add_data_fd");
874 g_assert(fdsize > 0);
876 unlink("amar-test.big");
877 ok = amar_attr_close(at, &error);
878 check_gerror(ok, error, "amar_attr_close");
880 ok = amar_file_close(af, &error);
881 check_gerror(ok, error, "amar_file_close");
883 ok = amar_close(arch, &error);
884 check_gerror(ok, error, "amar_close");
888 amar_attr_handling_t handling[] = {
889 { 0, 0, frag_cb, NULL }, /* don't buffer records */
891 expected_step_t steps[] = {
892 EXPECT_START_FILE_STR(1, "bigstuff", 0),
893 EXPECT_ATTR_DATA_MULTIPART(1, 20, bigbuf, max_record_data_size, 0, 0),
894 EXPECT_ATTR_DATA_MULTIPART(1, 20, bigbuf+max_record_data_size, bigbuf_size-max_record_data_size, 1, 0),
895 EXPECT_ATTR_DATA_MULTIPART(1, 21, bigbuf, max_record_data_size, 0, 0),
896 EXPECT_ATTR_DATA_MULTIPART(1, 21, bigbuf+max_record_data_size, bigbuf_size-max_record_data_size, 1, 0),
897 EXPECT_FINISH_FILE(1, 0),
900 try_reading(steps, handling);
906 /* like test_big_attr, but using a pipe and ignoring one of the attrs in hopes
907 * of triggering an lseek(), which will fail on a pipe. */
915 const size_t max_record_data_size = 4*1024*1024;
916 size_t bigbuf_size = max_record_data_size + 1274; /* a record and a bit */
917 simpleprng_state_t prng;
920 amar_file_t *af = NULL;
921 amar_attr_t *at = NULL;
922 GError *error = NULL;
925 /* set up some data buffers */
926 bigbuf = g_malloc(bigbuf_size);
927 simpleprng_seed(&prng, 0xb001);
928 simpleprng_fill_buffer(&prng, bigbuf, bigbuf_size);
930 fd = open("amar-test.big", O_CREAT|O_WRONLY|O_TRUNC, 0777);
932 g_assert(full_write(fd, bigbuf, bigbuf_size) == bigbuf_size);
935 g_assert(pipe(p) >= 0);
940 arch = amar_new(p[1], O_WRONLY, &error);
941 check_gerror(arch, error, "amar_new");
942 g_assert(arch != NULL);
944 af = amar_new_file(arch, "bigstuff", 0, NULL, &error);
945 check_gerror(af, error, "amar_new_file");
948 at = amar_new_attr(af, attrid++, &error);
949 check_gerror(at, error, "amar_new_attr");
950 ok = amar_attr_add_data_buffer(at, bigbuf, bigbuf_size, 1, &error);
951 check_gerror(ok, error, "amar_attr_add_data_buffer");
952 ok = amar_attr_close(at, &error);
953 check_gerror(ok, error, "amar_attr_close");
955 /* by file descriptor */
956 at = amar_new_attr(af, attrid++, &error);
957 check_gerror(at, error, "amar_new_attr");
958 fd = open("amar-test.big", O_RDONLY);
960 fdsize = amar_attr_add_data_fd(at, fd, 1, &error);
961 check_gerror(fdsize != -1, error, "amar_attr_add_data_fd");
962 g_assert(fdsize > 0);
964 unlink("amar-test.big");
965 ok = amar_attr_close(at, &error);
966 check_gerror(ok, error, "amar_attr_close");
968 ok = amar_file_close(af, &error);
969 check_gerror(ok, error, "amar_file_close");
971 ok = amar_close(arch, &error);
972 check_gerror(ok, error, "amar_close");
980 default: { /* parent */
981 amar_attr_handling_t handling[] = {
982 { 20, 0, NULL, NULL }, /* ignore attr 20 */
983 { 0, 0, frag_cb, NULL }, /* don't buffer records */
985 expected_step_t steps[] = {
986 EXPECT_START_FILE_STR(1, "bigstuff", 0),
987 EXPECT_ATTR_DATA_MULTIPART(1, 21, bigbuf, max_record_data_size, 0, 0),
988 EXPECT_ATTR_DATA_MULTIPART(1, 21, bigbuf+max_record_data_size, bigbuf_size-max_record_data_size, 1, 0),
989 EXPECT_FINISH_FILE(1, 0),
994 try_reading_fd(steps, handling, p[0]);
997 if(WIFSIGNALED(status)) {
998 printf("child was terminated by signal %d\n", WTERMSIG(status));
1008 * Invalid inputs - test error returns
1012 test_no_header(void)
1017 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "/first/filename");
1021 amar_attr_handling_t handling[] = {
1022 { 0, 0, frag_cb, NULL },
1024 expected_step_t steps[] = {
1027 try_reading_with_error(steps, handling,
1028 "Archive read does not begin at a header record");
1035 test_invalid_eof(void)
1040 WRITE_HEADER(fd, 1);
1041 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_FILENAME, 1, "hi");
1042 WRITE_RECORD_STR(fd, 1, AMAR_ATTR_EOF, 1, "abc");
1046 amar_attr_handling_t handling[] = {
1047 { 0, 0, frag_cb, NULL },
1049 expected_step_t steps[] = {
1050 EXPECT_START_FILE_STR(1, "hi", 0),
1053 try_reading_with_error(steps, handling,
1054 "Archive contains an EOF record with nonzero size");
1061 test_header_vers(void)
1066 bzero(hdr, sizeof(hdr));
1067 strcpy(hdr, "AMANDA ARCHIVE FORMAT 2");
1070 if (full_write(fd, hdr, sizeof(hdr)) < sizeof(hdr)) {
1071 perror("full_write");
1077 amar_attr_handling_t handling[] = {
1078 { 0, 0, frag_cb, NULL },
1080 expected_step_t steps[] = {
1083 try_reading_with_error(steps, handling,
1084 "Archive version 2 is not supported");
1095 main(int argc, char **argv)
1098 char *cwd = g_get_current_dir();
1099 static TestUtilsTest tests[] = {
1100 TU_TEST(test_simple_read, 90),
1101 TU_TEST(test_read_buffering, 90),
1102 TU_TEST(test_missing_eoa, 90),
1103 TU_TEST(test_ignore, 90),
1104 TU_TEST(test_missing_eof, 90),
1105 TU_TEST(test_extra_records, 90),
1106 TU_TEST(test_early_exit, 90),
1107 TU_TEST(test_writing_coverage, 90),
1108 TU_TEST(test_big_attr, 90),
1109 TU_TEST(test_pipe, 90),
1110 TU_TEST(test_no_header, 90),
1111 TU_TEST(test_invalid_eof, 90),
1112 TU_TEST(test_header_vers, 90),
1116 temp_filename = vstralloc(cwd, "/amar-test.tmp", NULL);
1118 rv = testutils_run_tests(argc, argv, tests);
1119 unlink(temp_filename);