diffarch.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /* Diff files from a tar archive.
  2. Copyright (C) 1988, 1992, 1993 Free Software Foundation
  3. This file is part of GNU Tar.
  4. GNU Tar is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Tar is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Tar; see the file COPYING. If not, write to
  14. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  15. /*
  16. * Diff files from a tar archive.
  17. *
  18. * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
  19. */
  20. #include <stdio.h>
  21. #include <errno.h>
  22. #ifndef STDC_HEADERS
  23. extern int errno;
  24. #endif
  25. #include <sys/types.h>
  26. #ifdef BSD42
  27. #include <sys/file.h>
  28. #else
  29. #ifndef V7
  30. #include <fcntl.h>
  31. #endif
  32. #endif
  33. #ifdef HAVE_SYS_MTIO_H
  34. #include <sys/ioctl.h>
  35. #include <sys/mtio.h>
  36. #endif
  37. #include "tar.h"
  38. #include "port.h"
  39. #include "rmt.h"
  40. #ifndef S_ISLNK
  41. #define lstat stat
  42. #endif
  43. extern void *valloc ();
  44. extern union record *head; /* Points to current tape header */
  45. extern struct stat hstat; /* Stat struct corresponding */
  46. extern int head_standard; /* Tape header is in ANSI format */
  47. void decode_header ();
  48. void diff_sparse_files ();
  49. void fill_in_sparse_array ();
  50. void fl_read ();
  51. long from_oct ();
  52. int do_stat ();
  53. extern void print_header ();
  54. int read_header ();
  55. void saverec ();
  56. void sigh ();
  57. extern void skip_file ();
  58. extern void skip_extended_headers ();
  59. int wantbytes ();
  60. extern FILE *msg_file;
  61. int now_verifying = 0; /* Are we verifying at the moment? */
  62. int diff_fd; /* Descriptor of file we're diffing */
  63. char *diff_buf = 0; /* Pointer to area for reading
  64. file contents into */
  65. char *diff_dir; /* Directory contents for LF_DUMPDIR */
  66. int different = 0;
  67. /*struct sp_array *sparsearray;
  68. int sp_ar_size = 10;*/
  69. /*
  70. * Initialize for a diff operation
  71. */
  72. void
  73. diff_init ()
  74. {
  75. /*NOSTRICT*/
  76. diff_buf = (char *) valloc ((unsigned) blocksize);
  77. if (!diff_buf)
  78. {
  79. msg ("could not allocate memory for diff buffer of %d bytes",
  80. blocksize);
  81. exit (EX_ARGSBAD);
  82. }
  83. }
  84. /*
  85. * Diff a file against the archive.
  86. */
  87. void
  88. diff_archive ()
  89. {
  90. register char *data;
  91. int check, namelen;
  92. int err;
  93. long offset;
  94. struct stat filestat;
  95. int compare_chunk ();
  96. int compare_dir ();
  97. int no_op ();
  98. #ifndef __MSDOS__
  99. dev_t dev;
  100. ino_t ino;
  101. #endif
  102. char *get_dir_contents ();
  103. long from_oct ();
  104. errno = EPIPE; /* FIXME, remove perrors */
  105. saverec (&head); /* Make sure it sticks around */
  106. userec (head); /* And go past it in the archive */
  107. decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */
  108. /* Print the record from 'head' and 'hstat' */
  109. if (f_verbose)
  110. {
  111. if (now_verifying)
  112. fprintf (msg_file, "Verify ");
  113. print_header ();
  114. }
  115. switch (head->header.linkflag)
  116. {
  117. default:
  118. msg ("Unknown file type '%c' for %s, diffed as normal file",
  119. head->header.linkflag, current_file_name);
  120. /* FALL THRU */
  121. case LF_OLDNORMAL:
  122. case LF_NORMAL:
  123. case LF_SPARSE:
  124. case LF_CONTIG:
  125. /*
  126. * Appears to be a file.
  127. * See if it's really a directory.
  128. */
  129. namelen = strlen (current_file_name) - 1;
  130. if (current_file_name[namelen] == '/')
  131. goto really_dir;
  132. if (do_stat (&filestat))
  133. {
  134. if (head->header.isextended)
  135. skip_extended_headers ();
  136. skip_file ((long) hstat.st_size);
  137. different++;
  138. goto quit;
  139. }
  140. if (!S_ISREG (filestat.st_mode))
  141. {
  142. fprintf (msg_file, "%s: not a regular file\n",
  143. current_file_name);
  144. skip_file ((long) hstat.st_size);
  145. different++;
  146. goto quit;
  147. }
  148. filestat.st_mode &= 07777;
  149. if (filestat.st_mode != hstat.st_mode)
  150. sigh ("mode");
  151. if (filestat.st_uid != hstat.st_uid)
  152. sigh ("uid");
  153. if (filestat.st_gid != hstat.st_gid)
  154. sigh ("gid");
  155. if (filestat.st_mtime != hstat.st_mtime)
  156. sigh ("mod time");
  157. if (head->header.linkflag != LF_SPARSE &&
  158. filestat.st_size != hstat.st_size)
  159. {
  160. sigh ("size");
  161. skip_file ((long) hstat.st_size);
  162. goto quit;
  163. }
  164. diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
  165. if (diff_fd < 0 && !f_absolute_paths)
  166. {
  167. char tmpbuf[NAMSIZ + 2];
  168. tmpbuf[0] = '/';
  169. strcpy (&tmpbuf[1], current_file_name);
  170. diff_fd = open (tmpbuf, O_NDELAY | O_RDONLY);
  171. }
  172. if (diff_fd < 0)
  173. {
  174. msg_perror ("cannot open %s", current_file_name);
  175. if (head->header.isextended)
  176. skip_extended_headers ();
  177. skip_file ((long) hstat.st_size);
  178. different++;
  179. goto quit;
  180. }
  181. /*
  182. * Need to treat sparse files completely differently here.
  183. */
  184. if (head->header.linkflag == LF_SPARSE)
  185. diff_sparse_files (hstat.st_size);
  186. else
  187. wantbytes ((long) (hstat.st_size), compare_chunk);
  188. check = close (diff_fd);
  189. if (check < 0)
  190. msg_perror ("Error while closing %s", current_file_name);
  191. quit:
  192. break;
  193. #ifndef __MSDOS__
  194. case LF_LINK:
  195. if (do_stat (&filestat))
  196. break;
  197. dev = filestat.st_dev;
  198. ino = filestat.st_ino;
  199. err = stat (current_link_name, &filestat);
  200. if (err < 0)
  201. {
  202. if (errno == ENOENT)
  203. {
  204. fprintf (msg_file, "%s: does not exist\n", current_file_name);
  205. }
  206. else
  207. {
  208. msg_perror ("cannot stat file %s", current_file_name);
  209. }
  210. different++;
  211. break;
  212. }
  213. if (filestat.st_dev != dev || filestat.st_ino != ino)
  214. {
  215. fprintf (msg_file, "%s not linked to %s\n", current_file_name, current_link_name);
  216. break;
  217. }
  218. break;
  219. #endif
  220. #ifdef S_ISLNK
  221. case LF_SYMLINK:
  222. {
  223. char linkbuf[NAMSIZ + 3];
  224. check = readlink (current_file_name, linkbuf,
  225. (sizeof linkbuf) - 1);
  226. if (check < 0)
  227. {
  228. if (errno == ENOENT)
  229. {
  230. fprintf (msg_file,
  231. "%s: no such file or directory\n",
  232. current_file_name);
  233. }
  234. else
  235. {
  236. msg_perror ("cannot read link %s", current_file_name);
  237. }
  238. different++;
  239. break;
  240. }
  241. linkbuf[check] = '\0'; /* Null-terminate it */
  242. if (strncmp (current_link_name, linkbuf, check) != 0)
  243. {
  244. fprintf (msg_file, "%s: symlink differs\n",
  245. current_link_name);
  246. different++;
  247. }
  248. }
  249. break;
  250. #endif
  251. #ifdef S_IFCHR
  252. case LF_CHR:
  253. hstat.st_mode |= S_IFCHR;
  254. goto check_node;
  255. #endif
  256. #ifdef S_IFBLK
  257. /* If local system doesn't support block devices, use default case */
  258. case LF_BLK:
  259. hstat.st_mode |= S_IFBLK;
  260. goto check_node;
  261. #endif
  262. #ifdef S_ISFIFO
  263. /* If local system doesn't support FIFOs, use default case */
  264. case LF_FIFO:
  265. #ifdef S_IFIFO
  266. hstat.st_mode |= S_IFIFO;
  267. #endif
  268. hstat.st_rdev = 0; /* FIXME, do we need this? */
  269. goto check_node;
  270. #endif
  271. check_node:
  272. /* FIXME, deal with umask */
  273. if (do_stat (&filestat))
  274. break;
  275. if (hstat.st_rdev != filestat.st_rdev)
  276. {
  277. fprintf (msg_file, "%s: device numbers changed\n", current_file_name);
  278. different++;
  279. break;
  280. }
  281. #ifdef S_IFMT
  282. if (hstat.st_mode != filestat.st_mode)
  283. #else /* POSIX lossage */
  284. if ((hstat.st_mode & 07777) != (filestat.st_mode & 07777))
  285. #endif
  286. {
  287. fprintf (msg_file, "%s: mode or device-type changed\n", current_file_name);
  288. different++;
  289. break;
  290. }
  291. break;
  292. case LF_DUMPDIR:
  293. data = diff_dir = get_dir_contents (current_file_name, 0);
  294. if (data)
  295. {
  296. wantbytes ((long) (hstat.st_size), compare_dir);
  297. free (data);
  298. }
  299. else
  300. wantbytes ((long) (hstat.st_size), no_op);
  301. /* FALL THROUGH */
  302. case LF_DIR:
  303. /* Check for trailing / */
  304. namelen = strlen (current_file_name) - 1;
  305. really_dir:
  306. while (namelen && current_file_name[namelen] == '/')
  307. current_file_name[namelen--] = '\0'; /* Zap / */
  308. if (do_stat (&filestat))
  309. break;
  310. if (!S_ISDIR (filestat.st_mode))
  311. {
  312. fprintf (msg_file, "%s is no longer a directory\n", current_file_name);
  313. different++;
  314. break;
  315. }
  316. if ((filestat.st_mode & 07777) != (hstat.st_mode & 07777))
  317. sigh ("mode");
  318. break;
  319. case LF_VOLHDR:
  320. break;
  321. case LF_MULTIVOL:
  322. namelen = strlen (current_file_name) - 1;
  323. if (current_file_name[namelen] == '/')
  324. goto really_dir;
  325. if (do_stat (&filestat))
  326. break;
  327. if (!S_ISREG (filestat.st_mode))
  328. {
  329. fprintf (msg_file, "%s: not a regular file\n",
  330. current_file_name);
  331. skip_file ((long) hstat.st_size);
  332. different++;
  333. break;
  334. }
  335. filestat.st_mode &= 07777;
  336. offset = from_oct (1 + 12, head->header.offset);
  337. if (filestat.st_size != hstat.st_size + offset)
  338. {
  339. sigh ("size");
  340. skip_file ((long) hstat.st_size);
  341. different++;
  342. break;
  343. }
  344. diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
  345. if (diff_fd < 0)
  346. {
  347. msg_perror ("cannot open file %s", current_file_name);
  348. skip_file ((long) hstat.st_size);
  349. different++;
  350. break;
  351. }
  352. err = lseek (diff_fd, offset, 0);
  353. if (err != offset)
  354. {
  355. msg_perror ("cannot seek to %ld in file %s", offset, current_file_name);
  356. different++;
  357. break;
  358. }
  359. wantbytes ((long) (hstat.st_size), compare_chunk);
  360. check = close (diff_fd);
  361. if (check < 0)
  362. {
  363. msg_perror ("Error while closing %s", current_file_name);
  364. }
  365. break;
  366. }
  367. /* We don't need to save it any longer. */
  368. saverec ((union record **) 0);/* Unsave it */
  369. }
  370. int
  371. compare_chunk (bytes, buffer)
  372. long bytes;
  373. char *buffer;
  374. {
  375. int err;
  376. err = read (diff_fd, diff_buf, bytes);
  377. if (err != bytes)
  378. {
  379. if (err < 0)
  380. {
  381. msg_perror ("can't read %s", current_file_name);
  382. }
  383. else
  384. {
  385. fprintf (msg_file, "%s: could only read %d of %d bytes\n", current_file_name, err, bytes);
  386. }
  387. different++;
  388. return -1;
  389. }
  390. if (bcmp (buffer, diff_buf, bytes))
  391. {
  392. fprintf (msg_file, "%s: data differs\n", current_file_name);
  393. different++;
  394. return -1;
  395. }
  396. return 0;
  397. }
  398. int
  399. compare_dir (bytes, buffer)
  400. long bytes;
  401. char *buffer;
  402. {
  403. if (bcmp (buffer, diff_dir, bytes))
  404. {
  405. fprintf (msg_file, "%s: data differs\n", current_file_name);
  406. different++;
  407. return -1;
  408. }
  409. diff_dir += bytes;
  410. return 0;
  411. }
  412. /*
  413. * Sigh about something that differs.
  414. */
  415. void
  416. sigh (what)
  417. char *what;
  418. {
  419. fprintf (msg_file, "%s: %s differs\n",
  420. current_file_name, what);
  421. }
  422. void
  423. verify_volume ()
  424. {
  425. int status;
  426. #ifdef MTIOCTOP
  427. struct mtop t;
  428. int er;
  429. #endif
  430. if (!diff_buf)
  431. diff_init ();
  432. #ifdef MTIOCTOP
  433. t.mt_op = MTBSF;
  434. t.mt_count = 1;
  435. if ((er = rmtioctl (archive, MTIOCTOP, &t)) < 0)
  436. {
  437. if (errno != EIO || (er = rmtioctl (archive, MTIOCTOP, &t)) < 0)
  438. {
  439. #endif
  440. if (rmtlseek (archive, 0L, 0) != 0)
  441. {
  442. /* Lseek failed. Try a different method */
  443. msg_perror ("Couldn't rewind archive file for verify");
  444. return;
  445. }
  446. #ifdef MTIOCTOP
  447. }
  448. }
  449. #endif
  450. ar_reading = 1;
  451. now_verifying = 1;
  452. fl_read ();
  453. for (;;)
  454. {
  455. status = read_header ();
  456. if (status == 0)
  457. {
  458. unsigned n;
  459. n = 0;
  460. do
  461. {
  462. n++;
  463. status = read_header ();
  464. }
  465. while (status == 0);
  466. msg ("VERIFY FAILURE: %d invalid header%s detected!", n, n == 1 ? "" : "s");
  467. }
  468. if (status == 2 || status == EOF)
  469. break;
  470. diff_archive ();
  471. }
  472. ar_reading = 0;
  473. now_verifying = 0;
  474. }
  475. int
  476. do_stat (statp)
  477. struct stat *statp;
  478. {
  479. int err;
  480. err = f_follow_links ? stat (current_file_name, statp) : lstat (current_file_name, statp);
  481. if (err < 0)
  482. {
  483. if (errno == ENOENT)
  484. {
  485. fprintf (msg_file, "%s: does not exist\n", current_file_name);
  486. }
  487. else
  488. msg_perror ("can't stat file %s", current_file_name);
  489. /* skip_file((long)hstat.st_size);
  490. different++;*/
  491. return 1;
  492. }
  493. else
  494. return 0;
  495. }
  496. /*
  497. * JK
  498. * Diff'ing a sparse file with its counterpart on the tar file is a
  499. * bit of a different story than a normal file. First, we must know
  500. * what areas of the file to skip through, i.e., we need to contruct
  501. * a sparsearray, which will hold all the information we need. We must
  502. * compare small amounts of data at a time as we find it.
  503. */
  504. void
  505. diff_sparse_files (filesize)
  506. int filesize;
  507. {
  508. int sparse_ind = 0;
  509. char *buf;
  510. int buf_size = RECORDSIZE;
  511. union record *datarec;
  512. int err;
  513. long numbytes;
  514. /* int amt_read = 0;*/
  515. int size = filesize;
  516. buf = (char *) ck_malloc (buf_size * sizeof (char));
  517. fill_in_sparse_array ();
  518. while (size > 0)
  519. {
  520. datarec = findrec ();
  521. if (!sparsearray[sparse_ind].numbytes)
  522. break;
  523. /*
  524. * 'numbytes' is nicer to write than
  525. * 'sparsearray[sparse_ind].numbytes' all the time ...
  526. */
  527. numbytes = sparsearray[sparse_ind].numbytes;
  528. lseek (diff_fd, sparsearray[sparse_ind].offset, 0);
  529. /*
  530. * take care to not run out of room in our buffer
  531. */
  532. while (buf_size < numbytes)
  533. {
  534. buf = (char *) ck_realloc (buf, buf_size * 2 * sizeof (char));
  535. buf_size *= 2;
  536. }
  537. while (numbytes > RECORDSIZE)
  538. {
  539. if ((err = read (diff_fd, buf, RECORDSIZE)) != RECORDSIZE)
  540. {
  541. if (err < 0)
  542. msg_perror ("can't read %s", current_file_name);
  543. else
  544. fprintf (msg_file, "%s: could only read %d of %d bytes\n",
  545. current_file_name, err, numbytes);
  546. break;
  547. }
  548. if (bcmp (buf, datarec->charptr, RECORDSIZE))
  549. {
  550. different++;
  551. break;
  552. }
  553. numbytes -= err;
  554. size -= err;
  555. userec (datarec);
  556. datarec = findrec ();
  557. }
  558. if ((err = read (diff_fd, buf, numbytes)) != numbytes)
  559. {
  560. if (err < 0)
  561. msg_perror ("can't read %s", current_file_name);
  562. else
  563. fprintf (msg_file, "%s: could only read %d of %d bytes\n",
  564. current_file_name, err, numbytes);
  565. break;
  566. }
  567. if (bcmp (buf, datarec->charptr, numbytes))
  568. {
  569. different++;
  570. break;
  571. }
  572. /* amt_read += numbytes;
  573. if (amt_read >= RECORDSIZE) {
  574. amt_read = 0;
  575. userec(datarec);
  576. datarec = findrec();
  577. }*/
  578. userec (datarec);
  579. sparse_ind++;
  580. size -= numbytes;
  581. }
  582. /*
  583. * if the number of bytes read isn't the
  584. * number of bytes supposedly in the file,
  585. * they're different
  586. */
  587. /* if (amt_read != filesize)
  588. different++;*/
  589. userec (datarec);
  590. free (sparsearray);
  591. if (different)
  592. fprintf (msg_file, "%s: data differs\n", current_file_name);
  593. }
  594. /*
  595. * JK
  596. * This routine should be used more often than it is ... look into
  597. * that. Anyhow, what it does is translate the sparse information
  598. * on the header, and in any subsequent extended headers, into an
  599. * array of structures with true numbers, as opposed to character
  600. * strings. It simply makes our life much easier, doing so many
  601. * comparisong and such.
  602. */
  603. void
  604. fill_in_sparse_array ()
  605. {
  606. int ind;
  607. /*
  608. * allocate space for our scratch space; it's initially
  609. * 10 elements long, but can change in this routine if
  610. * necessary
  611. */
  612. sp_array_size = 10;
  613. sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
  614. /*
  615. * there are at most five of these structures in the header
  616. * itself; read these in first
  617. */
  618. for (ind = 0; ind < SPARSE_IN_HDR; ind++)
  619. {
  620. if (!head->header.sp[ind].numbytes)
  621. break;
  622. sparsearray[ind].offset =
  623. from_oct (1 + 12, head->header.sp[ind].offset);
  624. sparsearray[ind].numbytes =
  625. from_oct (1 + 12, head->header.sp[ind].numbytes);
  626. }
  627. /*
  628. * if the header's extended, we gotta read in exhdr's till
  629. * we're done
  630. */
  631. if (head->header.isextended)
  632. {
  633. /* how far into the sparsearray we are 'so far' */
  634. static int so_far_ind = SPARSE_IN_HDR;
  635. union record *exhdr;
  636. for (;;)
  637. {
  638. exhdr = findrec ();
  639. for (ind = 0; ind < SPARSE_EXT_HDR; ind++)
  640. {
  641. if (ind + so_far_ind > sp_array_size - 1)
  642. {
  643. /*
  644. * we just ran out of room in our
  645. * scratch area - realloc it
  646. */
  647. sparsearray = (struct sp_array *)
  648. ck_realloc (sparsearray,
  649. sp_array_size * 2 * sizeof (struct sp_array));
  650. sp_array_size *= 2;
  651. }
  652. /*
  653. * convert the character strings into longs
  654. */
  655. sparsearray[ind + so_far_ind].offset =
  656. from_oct (1 + 12, exhdr->ext_hdr.sp[ind].offset);
  657. sparsearray[ind + so_far_ind].numbytes =
  658. from_oct (1 + 12, exhdr->ext_hdr.sp[ind].numbytes);
  659. }
  660. /*
  661. * if this is the last extended header for this
  662. * file, we can stop
  663. */
  664. if (!exhdr->ext_hdr.isextended)
  665. break;
  666. else
  667. {
  668. so_far_ind += SPARSE_EXT_HDR;
  669. userec (exhdr);
  670. }
  671. }
  672. /* be sure to skip past the last one */
  673. userec (exhdr);
  674. }
  675. }