PageRenderTime 51ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/amar-src/amar-test.c

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