home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gtak212.zip / 1.10 / diffarch.c < prev    next >
C/C++ Source or Header  |  1993-01-14  |  23KB  |  905 lines

  1. /*****************************************************************************
  2.  * $Id: diffarch.c,v 1.7 1993/01/14 21:50:37 ak Exp $
  3.  *****************************************************************************
  4.  * $Log: diffarch.c,v $
  5.  * Revision 1.7  1993/01/14  21:50:37  ak
  6.  * EMX 0.8f fixes and enhancements by Kai Uwe Rommel.
  7.  *
  8.  * Revision 1.6  1993/01/12  18:24:55  ak
  9.  * setnbuf for TTY output only.
  10.  *
  11.  * Revision 1.5  1993/01/10  11:54:43  ak
  12.  * diff_init sets output stream to non-buffered.
  13.  *
  14.  * Revision 1.4  1992/12/19  22:22:24  ak
  15.  * Eberhard Mattes: Trapped when ea_load returned NULL.
  16.  *
  17.  * Revision 1.3  1992/09/12  15:57:23  ak
  18.  * - Usenet patches for GNU TAR 1.10
  19.  * - Bugfixes and patches of Kai Uwe Rommel:
  20.  *         filename conversion for FAT
  21.  *         EMX 0.8e
  22.  *         -0..1 alias for a: b:
  23.  *         -2..7 alias for +++TAPE$x
  24.  *
  25.  * Revision 1.2  1992/09/02  20:07:55  ak
  26.  * Version AK200
  27.  * - Tape access
  28.  * - Quick file access
  29.  * - OS/2 extended attributes
  30.  * - Some OS/2 fixes
  31.  * - Some fixes of Kai Uwe Rommel
  32.  *
  33.  * Revision 1.1.1.1  1992/09/02  19:21:14  ak
  34.  * Original GNU Tar 1.10 with some filenames changed for FAT compatibility.
  35.  *
  36.  * Revision 1.1  1992/09/02  19:21:12  ak
  37.  * Initial revision
  38.  *
  39.  *****************************************************************************/
  40.  
  41. static char *rcsid = "$Id: diffarch.c,v 1.7 1993/01/14 21:50:37 ak Exp $";
  42.  
  43. /*
  44.  * Modified by Andreas Kaiser July 92.
  45.  * See CHANGES.AK for info.
  46.  */
  47.  
  48. /* Modified so that the verify option works even if some filenames got
  49.    mangled because of excessive length.  Note that this also required
  50.    adding an inverse_find_mangled operation to mangle.c.  While I was
  51.    at it I also fixed the handling of absolute pathnames and also
  52.    three buggy error messages in the handling of links that used the wrong
  53.    names.  I didn't make the verification of mangled names or absolute
  54.    pathnames work for dump directories.
  55.      -Max Hailperin <max@nic.gac.edu> 8/1/91 */
  56.  
  57. /* Further modified so that diff won't complain about uid or gid differing
  58.    if the numerically stored id matches, even if the name doesn't tally.
  59.    This prevents error messages verifying an archive with files owned by
  60.    non-existant users or groups.
  61.      -Max Hailperin <max@nic.gac.edu> 8/2/91 */
  62.  
  63. /* Fixed two bugs in the changes of 8/1/91.
  64.     1) For some reason linkabspath was one byte two small, even though
  65.        abspath was right.
  66.     2) The filename and linkname variables were initialized to point into
  67.        a header record in the buffer which might go away in the course of
  68.        diffing the file contents, leading to garbage filenames in data
  69.        differs error message.  The saverec mechamism only protects head,
  70.        not other pointers into that record.
  71.    -Max Hailperin <max@nic.gac.edu> 8/11/91 */
  72.  
  73. /* Diff files from a tar archive.
  74.    Copyright (C) 1988 Free Software Foundation
  75.  
  76. This file is part of GNU Tar.
  77.  
  78. GNU Tar is free software; you can redistribute it and/or modify
  79. it under the terms of the GNU General Public License as published by
  80. the Free Software Foundation; either version 1, or (at your option)
  81. any later version.
  82.  
  83. GNU Tar is distributed in the hope that it will be useful,
  84. but WITHOUT ANY WARRANTY; without even the implied warranty of
  85. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  86. GNU General Public License for more details.
  87.  
  88. You should have received a copy of the GNU General Public License
  89. along with GNU Tar; see the file COPYING.  If not, write to
  90. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  91.  
  92. /*
  93.  * Diff files from a tar archive.
  94.  *
  95.  * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
  96.  *
  97.  * @(#) diffarch.c 1.10 87/11/11 - gnu
  98.  */
  99.  
  100. #include <stdio.h>
  101. #include <errno.h>
  102. #include <sys/types.h>
  103. #include <sys/stat.h>
  104.  
  105. #ifndef V7
  106. #include <fcntl.h>
  107. #endif
  108.  
  109. #ifdef BSD42
  110. #include <sys/file.h>
  111. #endif
  112.  
  113. #ifndef MSDOS
  114. #include <sys/ioctl.h>
  115. #if !defined(USG) || defined(HAVE_MTIO)
  116. #include <sys/mtio.h>
  117. #endif
  118. #endif
  119.  
  120. #ifdef USG
  121. #include <fcntl.h>
  122. #endif
  123.  
  124. /* Some systems don't have these #define's -- we fake it here. */
  125. #ifndef O_RDONLY
  126. #define    O_RDONLY    0
  127. #endif
  128. #ifndef    O_NDELAY
  129. #define    O_NDELAY    0
  130. #endif
  131.  
  132. /*
  133.  * Most people don't have a #define for this.
  134.  */
  135. #ifndef    O_BINARY
  136. #define    O_BINARY    0
  137. #endif
  138.  
  139. #ifndef S_IFLNK
  140. #define lstat stat
  141. #endif
  142.  
  143. extern int errno;            /* From libc.a */
  144. extern char *valloc();            /* From libc.a */
  145.  
  146. #include "tar.h"
  147. #include "port.h"
  148. #include "rmt.h"
  149.  
  150. extern union record *head;        /* Points to current tape header */
  151. extern struct stat hstat;        /* Stat struct corresponding */
  152. extern int head_standard;        /* Tape header is in ANSI format */
  153.  
  154. extern void print_header();
  155. extern void skip_file();
  156. extern void skip_extended_headers();
  157.  
  158. extern FILE *msg_file;
  159.  
  160. int now_verifying = 0;        /* Are we verifying at the moment? */
  161.  
  162. char    *diff_name;        /* head->header.name */
  163.  
  164. int    diff_fd;        /* Descriptor of file we're diffing */
  165.  
  166. char    *diff_buf = 0;        /* Pointer to area for reading
  167.                        file contents into */
  168.  
  169. char    *diff_dir;        /* Directory contents for LF_DUMPDIR */
  170.  
  171. #ifdef OS2
  172. char *eaptr;            /* EA pointer */
  173. #endif
  174.  
  175. int different = 0;
  176.  
  177. #define FILENAME (filename?filename:head->header.name)
  178. #define LINKNAME (linkname?linkname:head->header.linkname)
  179.  
  180. static char *filename, *linkname; /* NULL means as in header */
  181. extern char *inverse_find_mangled();
  182. static char abspath[FILENAME_MAX+2] = "/", linkabspath[FILENAME_MAX+2] = "/";
  183.  
  184. /*struct sp_array *sparsearray;
  185. int         sp_ar_size = 10;*/
  186. /*
  187.  * Initialize for a diff operation
  188.  */
  189. diff_init()
  190. {
  191.  
  192.     /*NOSTRICT*/
  193.     diff_buf = (char *) valloc((unsigned)blocksize);
  194.     if (!diff_buf) {
  195.         msg("could not allocate memory for diff buffer of %d bytes",
  196.             blocksize);
  197.         exit(EX_ARGSBAD);
  198.     }
  199.     if (isatty(fileno(msg_file)))
  200.         setvbuf(msg_file, NULL, _IONBF, 0);
  201. }
  202.  
  203. /*
  204.  * Diff a file against the archive.
  205.  */
  206. void
  207. diff_archive()
  208. {
  209.     register char *data;
  210.     int check, namelen;
  211.     int err;
  212.     long offset;
  213.     struct stat filestat;
  214.     int compare_chunk();
  215.     int compare_dir();
  216. #ifdef OS2
  217.     int compare_eattr();
  218. #endif
  219.     int no_op();
  220. #ifndef MSDOS
  221.     dev_t    dev;
  222.     ino_t    ino;
  223. #endif
  224.     char *get_dir_contents();
  225.     long from_oct();
  226.     long lseek();
  227.         char *new_name;
  228.         long numerical_uid, numerical_gid;
  229.  
  230.     errno = EPIPE;            /* FIXME, remove perrors */
  231.  
  232.     saverec(&head);            /* Make sure it sticks around */
  233.     userec(head);            /* And go past it in the archive */
  234.     decode_header(head, &hstat, &head_standard, 1);    /* Snarf fields */
  235.     numerical_uid = from_oct(8,  head->header.uid);
  236.     numerical_gid = from_oct(8,  head->header.gid);
  237.  
  238.         filename = NULL;
  239.         linkname = NULL;
  240.  
  241.     /* Print the record from 'head' and 'hstat' */
  242.     if (f_verbose) {
  243.         if(now_verifying)
  244.             fprintf(msg_file,"Verify ");
  245.         print_header();
  246.     }
  247.  
  248.     diff_name = head->header.name;
  249.     switch (head->header.linkflag) {
  250.  
  251.     default:
  252.         msg("Unknown file type '%c' for %s, diffed as normal file",
  253.             head->header.linkflag, FILENAME);
  254.  
  255.         /* FALL THRU */
  256.  
  257.     case LF_OLDNORMAL:
  258.     case LF_NORMAL:
  259.     case LF_SPARSE:
  260.     case LF_CONTIG:
  261.         /*
  262.          * Appears to be a file.
  263.          * See if it's really a directory.
  264.          */
  265.         namelen = strlen(FILENAME)-1;
  266.         if (FILENAME[namelen] == '/')
  267.             goto really_dir;
  268.  
  269.         
  270.         if(do_stat(&filestat)) {
  271.             if (head->header.isextended)
  272.                 skip_extended_headers();
  273.             skip_file((long)hstat.st_size);
  274.             different++;
  275.             goto quit;
  276.         }
  277.  
  278.         if ((filestat.st_mode & S_IFMT) != S_IFREG) {
  279.             fprintf(msg_file, "%s: not a regular file\n",
  280.                 FILENAME);
  281.             skip_file((long)hstat.st_size);
  282.             different++;
  283.             goto quit;
  284.         }
  285.  
  286.         filestat.st_mode &= ~S_IFMT;
  287.         if (filestat.st_mode != hstat.st_mode)
  288.             sigh("mode");
  289. #ifndef OS2
  290.         if (filestat.st_uid  != hstat.st_uid &&
  291.                     filestat.st_uid  != numerical_uid)
  292.             sigh("uid");
  293.         if (filestat.st_gid  != hstat.st_gid &&
  294.                     filestat.st_gid  != numerical_gid)
  295.             sigh("gid");
  296. #endif
  297.         if (filestat.st_mtime != hstat.st_mtime)
  298.             sigh("mod time");
  299.         if (head->header.linkflag != LF_SPARSE &&
  300.                 filestat.st_size != hstat.st_size) {
  301.             sigh("size");
  302.             skip_file((long)hstat.st_size);
  303.             goto quit;
  304.         }
  305.  
  306.         diff_fd = open(FILENAME, O_NDELAY|O_RDONLY|O_BINARY);
  307.  
  308.         if (diff_fd < 0) {
  309.             msg_perror("cannot open %s",FILENAME);
  310.             if (head->header.isextended)
  311.                 skip_extended_headers();
  312.             skip_file((long)hstat.st_size);
  313.             different++;
  314.             goto quit;
  315.         }
  316.         /*
  317.          * Need to treat sparse files completely differently here.
  318.          */
  319.         if (head->header.linkflag == LF_SPARSE)
  320.             diff_sparse_files(hstat.st_size);
  321.         else 
  322.             wantbytes((long)(hstat.st_size),compare_chunk);
  323.  
  324.         check = close(diff_fd);
  325.         if (check < 0)
  326.             msg_perror("Error while closing %s",FILENAME);
  327.  
  328.     quit:
  329.         break;
  330.  
  331.         case LF_NAMES:
  332.                 skip_file((long)hstat.st_size);
  333.                 break;
  334.  
  335. #ifndef MSDOS
  336.     case LF_LINK:
  337.         if(do_stat(&filestat))
  338.             break;
  339.         dev = filestat.st_dev;
  340.         ino = filestat.st_ino;
  341.               retry_linkstat:
  342.         err = stat(LINKNAME, &filestat);
  343.         if (err < 0) {
  344.             if (errno==ENOENT) {
  345.                           if(now_verifying &&
  346.                              (new_name = inverse_find_mangled(LINKNAME))
  347.                              != NULL){
  348.                             linkname = new_name;
  349.                             goto retry_linkstat;
  350.                           }
  351.                           else if(!f_absolute_paths && *LINKNAME != '/'){
  352.                             strcpy(linkabspath+1,LINKNAME);
  353.                             linkname = linkabspath;
  354.                             goto retry_linkstat;
  355.                           }
  356.                           else{
  357.                             if(!f_absolute_paths && linkname != NULL &&
  358.                                *linkname == '/')
  359.                               linkname++;
  360.                             fprintf(msg_file, "%s: does not exist\n",LINKNAME);
  361.                           }
  362.             } else {
  363.                 msg_perror("cannot stat file %s",LINKNAME);
  364.             }
  365.             different++;
  366.             break;
  367.         }
  368.         if(filestat.st_dev!=dev || filestat.st_ino!=ino) {
  369.             fprintf(msg_file, "%s not linked to %s\n",FILENAME,LINKNAME);
  370.             break;
  371.         }
  372.         break;
  373. #endif
  374.  
  375. #ifdef S_IFLNK
  376.     case LF_SYMLINK:
  377.     {
  378.         char linkbuf[FILENAME_MAX+1];
  379.               retry_readlink:
  380.         check = readlink(FILENAME, linkbuf,
  381.                  (sizeof linkbuf)-1);
  382.         
  383.         if (check < 0) {
  384.             if (errno == ENOENT) {
  385.                           if(now_verifying &&
  386.                              (new_name = inverse_find_mangled(FILENAME))
  387.                              != NULL){
  388.                             filename = new_name;
  389.                             goto retry_readlink;
  390.                           }
  391.                           else if(!f_absolute_paths && *FILENAME != '/'){
  392.                             strcpy(abspath+1, FILENAME);
  393.                             filename = abspath;
  394.                             goto retry_readlink;
  395.                           }
  396.                           else{
  397.                             if(!f_absolute_paths && filename != NULL &&
  398.                                *filename == '/')
  399.                               filename++;
  400.                 fprintf(msg_file,
  401.                     "%s: no such file or directory\n",
  402.                     FILENAME);
  403.                           }
  404.             } else {
  405.                 msg_perror("cannot read link %s",FILENAME);
  406.             }
  407.             different++;
  408.             break;
  409.         }
  410.  
  411.         linkbuf[check] = '\0';    /* Null-terminate it */
  412.               retry_symlink_check:
  413.         if (strncmp(LINKNAME, linkbuf, check) != 0) {
  414.                   if(now_verifying &&
  415.                      (new_name = inverse_find_mangled(LINKNAME)) != NULL){
  416.                     linkname = new_name;
  417.                     goto retry_symlink_check;
  418.                   }
  419.                   else if(!f_absolute_paths && *LINKNAME != '/'){
  420.                     strcpy(linkabspath+1, LINKNAME);
  421.                     linkname = linkabspath;
  422.                     goto retry_symlink_check;
  423.                   }
  424.                   else{
  425.                     if(!f_absolute_paths && linkname != NULL &&
  426.                        *linkname == '/')
  427.                       linkname++;
  428.             fprintf(msg_file, "%s: symlink differs\n",
  429.                 FILENAME);
  430.             different++;
  431.         }
  432.     }
  433.     }
  434.         break;
  435. #endif
  436.  
  437.     case LF_CHR:
  438.         hstat.st_mode |= S_IFCHR;
  439.         goto check_node;
  440.  
  441. #ifdef S_IFBLK
  442.     /* If local system doesn't support block devices, use default case */
  443.     case LF_BLK:
  444.         hstat.st_mode |= S_IFBLK;
  445.         goto check_node;
  446. #endif
  447.  
  448. #ifdef S_IFIFO
  449.     /* If local system doesn't support FIFOs, use default case */
  450.     case LF_FIFO:
  451.         hstat.st_mode |= S_IFIFO;
  452.         hstat.st_rdev = 0;        /* FIXME, do we need this? */
  453.         goto check_node;
  454. #endif
  455.  
  456.     check_node:
  457.         /* FIXME, deal with umask */
  458.         if(do_stat(&filestat))
  459.             break;
  460.         if(hstat.st_rdev != filestat.st_rdev) {
  461.             fprintf(msg_file, "%s: device numbers changed\n", FILENAME);
  462.             different++;
  463.             break;
  464.         }
  465.         if(hstat.st_mode != filestat.st_mode) {
  466.             fprintf(msg_file, "%s: mode or device-type changed\n", FILENAME);
  467.             different++;
  468.             break;
  469.         }
  470.         break;
  471.  
  472.     case LF_DUMPDIR:
  473.         data=diff_dir=get_dir_contents(FILENAME,0);
  474.         if(data != NULL && *data) {
  475.         wantbytes((long)(hstat.st_size),compare_dir);
  476.         free(data);
  477.         }
  478.         else wantbytes((long)(hstat.st_size),no_op);
  479.         /* FALL THROUGH */
  480.  
  481.     case LF_DIR:
  482.         /* Check for trailing / */
  483.         namelen = strlen(FILENAME)-1;
  484.     really_dir:
  485.         while (namelen && FILENAME[namelen] == '/')
  486.             FILENAME[namelen--] = '\0';    /* Zap / */
  487.  
  488.         if(do_stat(&filestat))
  489.             break;
  490.         if((filestat.st_mode&S_IFMT)!=S_IFDIR) {
  491.             fprintf(msg_file, "%s is no longer a directory\n",FILENAME);
  492.             different++;
  493.             break;
  494.         }
  495.         if((filestat.st_mode&~S_IFMT) != hstat.st_mode)
  496.             sigh("mode");
  497.         break;
  498.  
  499.     case LF_VOLHDR:
  500.         break;
  501.  
  502.     case LF_MULTIVOL:
  503.         namelen = strlen(FILENAME)-1;
  504.         if (FILENAME[namelen] == '/')
  505.             goto really_dir;
  506.  
  507.         if(do_stat(&filestat))
  508.             break;
  509.  
  510.         if ((filestat.st_mode & S_IFMT) != S_IFREG) {
  511.             fprintf(msg_file, "%s: not a regular file\n",
  512.                 FILENAME);
  513.             skip_file((long)hstat.st_size);
  514.             different++;
  515.             break;
  516.         }
  517.  
  518.         filestat.st_mode &= ~S_IFMT;
  519.         offset = from_oct(1+12, head->header.offset);
  520.         if (filestat.st_size != hstat.st_size + offset) {
  521.             sigh("size");
  522.             skip_file((long)hstat.st_size);
  523.             different++;
  524.             break;
  525.         }
  526.  
  527.         diff_fd = open(FILENAME, O_NDELAY|O_RDONLY|O_BINARY);
  528.  
  529.         if (diff_fd < 0) {
  530.                         msg_perror("cannot open file %s",FILENAME);
  531.             skip_file((long)hstat.st_size);
  532.             different++;
  533.             break;
  534.         }
  535.         err = lseek(diff_fd, offset, 0);
  536.         if(err!=offset) {
  537.             msg_perror("cannot seek to %ld in file %s",offset,FILENAME);
  538.             different++;
  539.             break;
  540.         }
  541.  
  542.         wantbytes((long)(hstat.st_size),compare_chunk);
  543.  
  544.         check = close(diff_fd);
  545.         if (check < 0) {
  546.             msg_perror("Error while closing %s",FILENAME);
  547.         }
  548.         break;
  549.  
  550. #ifdef OS2
  551.     case LF_EATTR:
  552.         if (eabuf)
  553.             ea_free(eabuf);
  554.         eabuf = ea_load(diff_name);
  555.         if (hstat.st_size != (eabuf ? EALength(eabuf) : 0)) {
  556.             sigh("EA size");
  557.             goto quit;
  558.         }
  559.         if (hstat.st_size != 0) {
  560.             eaptr = (char _far *)eabuf;
  561.             wantbytes((long)(hstat.st_size),compare_eattr);
  562.         }
  563.         break;
  564. #endif
  565.     }
  566.  
  567.     /* We don't need to save it any longer. */
  568.     saverec((union record **) 0);    /* Unsave it */
  569. }
  570.  
  571. int
  572. compare_chunk(bytes,buffer)
  573. long bytes;
  574. char *buffer;
  575. {
  576.     int err;
  577.  
  578.     err=read(diff_fd,diff_buf,bytes);
  579.     if(err!=bytes) {
  580.         if(err<0) {
  581.             msg_perror("can't read %s",FILENAME);
  582.         } else {
  583.             fprintf(msg_file,"%s: could only read %d of %d bytes\n",FILENAME,err,bytes);
  584.         }
  585.         different++;
  586.         return -1;
  587.     }
  588.     if(bcmp(buffer,diff_buf,bytes)) {
  589.         fprintf(msg_file, "%s: data differs\n",FILENAME);
  590.         different++;
  591.         return -1;
  592.     }
  593.     return 0;
  594. }
  595.  
  596. int
  597. compare_dir(bytes,buffer)
  598. long bytes;
  599. char *buffer;
  600. {
  601.     if(bcmp(buffer,diff_dir,bytes)) {
  602.         fprintf(msg_file, "%s: data differs\n",FILENAME);
  603.         different++;
  604.         return -1;
  605.     }
  606.     diff_dir+=bytes;
  607.     return 0;
  608. }
  609.  
  610. int
  611. compare_eattr(bytes,buffer)
  612. int bytes;
  613. char *buffer;
  614. {
  615. #ifdef OS2
  616.     int err = bcmp(buffer, eaptr, bytes);
  617.     eaptr += bytes;
  618.     if (err) {
  619.         fprintf(msg_file, "%s: EA data differs\n",head->header.name);
  620.         different++;
  621.         return -1;
  622.     }
  623. #endif
  624.     return 0;
  625. }
  626.  
  627. /*
  628.  * Sigh about something that differs.
  629.  */
  630. sigh(what)
  631.     char *what;
  632. {
  633.  
  634.     fprintf(msg_file, "%s: %s differs\n",
  635.         FILENAME, what);
  636. }
  637.  
  638. verify_volume()
  639. {
  640.     int status;
  641. #ifdef MTIOCTOP
  642.     struct mtop t;
  643.     int er;
  644. #endif
  645.  
  646.     if(!diff_buf)
  647.         diff_init();
  648. #ifdef MTIOCTOP
  649.     t.mt_op = MTBSF;
  650.     t.mt_count = 1;
  651.     if((er=rmtioctl(archive,MTIOCTOP,&t))<0) {
  652.         if(errno!=EIO || (er=rmtioctl(archive,MTIOCTOP,&t))<0) {
  653. #endif
  654.             if(rmtlseek(archive,0L,0)!=0) {
  655.                 /* Lseek failed.  Try a different method */
  656.                 msg_perror("Couldn't rewind archive file for verify");
  657.                 return;
  658.             }
  659. #ifdef MTIOCTOP
  660.         }
  661.     }
  662. #endif
  663.     ar_reading=1;
  664.     now_verifying = 1;
  665.     fl_read();
  666.     for(;;) {
  667.         status = read_header();
  668.         if(status==0) {
  669.             unsigned n;
  670.  
  671.             n=0;
  672.             do {
  673.                 n++;
  674.                 status=read_header();
  675.             } while(status==0);
  676.             msg("VERIFY FAILURE: %d invalid header%s detected!",n,n==1?"":"s");
  677.         }
  678.         if(status==2 || status==EOF)
  679.             break;
  680.         diff_archive();
  681.     }
  682.     ar_reading=0;
  683.     now_verifying = 0;
  684.  
  685. }
  686.  
  687. int do_stat(statp)
  688. struct stat *statp;
  689. {
  690.     int err;
  691.         char *new_name;
  692.  
  693.       retry:
  694.     err = f_follow_links ? stat(FILENAME, statp) : lstat(FILENAME, statp);
  695.     if (err < 0) {
  696.         if (errno==ENOENT) {
  697.                   if(now_verifying &&
  698.                      (new_name = inverse_find_mangled(FILENAME)) != NULL){
  699.                     filename = new_name;
  700.                     goto retry;
  701.                   }
  702.                   else if(!f_absolute_paths && *FILENAME != '/'){
  703.                     strcpy(abspath+1, FILENAME);
  704.                     filename = abspath;
  705.                     goto retry;
  706.                   }
  707.                   else{
  708.                     if(!f_absolute_paths && filename != NULL &&
  709.                        *filename == '/')
  710.                       filename++;
  711.                     fprintf(msg_file, "%s: does not exist\n",FILENAME);
  712.                   }
  713.         } else
  714.             msg_perror("can't stat file %s",FILENAME);
  715. /*        skip_file((long)hstat.st_size);
  716.         different++;*/
  717.         return 1;
  718.     }
  719. #ifdef MSDOS
  720.     get_fileattr(diff_name, statp);
  721. #endif
  722.     return 0;
  723. }
  724.  
  725. /*
  726.  * JK
  727.  * Diff'ing a sparse file with its counterpart on the tar file is a 
  728.  * bit of a different story than a normal file.  First, we must know
  729.  * what areas of the file to skip through, i.e., we need to contruct
  730.  * a sparsearray, which will hold all the information we need.  We must
  731.  * compare small amounts of data at a time as we find it.  
  732.  */
  733.  
  734. diff_sparse_files(filesize)
  735. int    filesize;
  736.  
  737. {
  738.     int        sparse_ind = 0;
  739.     char        *buf;
  740.     int        buf_size = RECORDSIZE;
  741.     union record     *datarec;    
  742.     int        err;
  743.     long        numbytes;
  744.     int        amt_read = 0;
  745.     int        size = filesize;
  746.  
  747.     buf = (char *) malloc(buf_size * sizeof (char));
  748.     
  749.     fill_in_sparse_array();
  750.     
  751.  
  752.     while (size > 0) {
  753.         datarec = findrec();
  754.         if (!sparsearray[sparse_ind].numbytes)
  755.             break;
  756.  
  757.         /*
  758.          * 'numbytes' is nicer to write than
  759.          * 'sparsearray[sparse_ind].numbytes' all the time ...
  760.          */
  761.         numbytes = sparsearray[sparse_ind].numbytes;
  762.         
  763.         lseek(diff_fd, sparsearray[sparse_ind].offset, 0);
  764.         /*
  765.          * take care to not run out of room in our buffer
  766.          */
  767.         while (buf_size < numbytes) {
  768.             buf = (char *) realloc(buf, buf_size * 2 * sizeof(char));
  769.             buf_size *= 2;
  770.         }
  771.         while (numbytes > RECORDSIZE) {
  772.             if ((err = read(diff_fd, buf, RECORDSIZE)) != RECORDSIZE) {
  773.                  if (err < 0) 
  774.                     msg_perror("can't read %s", FILENAME);
  775.                 else
  776.                     fprintf(msg_file, "%s: could only read %d of %d bytes\n", 
  777.                         err, numbytes);
  778.                 break;
  779.             }
  780.             if (bcmp(buf, datarec->charptr, RECORDSIZE)) {
  781.                 different++;
  782.                 break;
  783.             }
  784.             numbytes -= err;
  785.             size -= err;
  786.             userec(datarec);
  787.             datarec = findrec();
  788.         }
  789.         if ((err = read(diff_fd, buf, numbytes)) != numbytes) {
  790.              if (err < 0) 
  791.                 msg_perror("can't read %s", FILENAME);
  792.             else
  793.                 fprintf(msg_file, "%s: could only read %d of %d bytes\n", 
  794.                         err, numbytes);
  795.             break;
  796.         }
  797.  
  798.         if (bcmp(buf, datarec->charptr, numbytes)) {
  799.             different++;
  800.             break;
  801.         }
  802. /*        amt_read += numbytes;
  803.         if (amt_read >= RECORDSIZE) {
  804.             amt_read = 0;
  805.             userec(datarec);
  806.             datarec = findrec();
  807.         }*/
  808.         userec(datarec);
  809.         sparse_ind++;
  810.         size -= numbytes;
  811.     }
  812.     /* 
  813.      * if the number of bytes read isn't the
  814.      * number of bytes supposedly in the file,
  815.      * they're different
  816.      */
  817. /*    if (amt_read != filesize)
  818.         different++;*/
  819.     userec(datarec);
  820.     free(sparsearray);
  821.     if (different)
  822.         fprintf(msg_file, "%s: data differs\n", FILENAME);
  823.  
  824. }
  825.  
  826. /*
  827.  * JK
  828.  * This routine should be used more often than it is ... look into
  829.  * that.  Anyhow, what it does is translate the sparse information
  830.  * on the header, and in any subsequent extended headers, into an
  831.  * array of structures with true numbers, as opposed to character
  832.  * strings.  It simply makes our life much easier, doing so many
  833.  * comparisong and such.
  834.  */
  835. fill_in_sparse_array()
  836. {
  837.     int     ind;
  838.     long from_oct();
  839.  
  840.     /*
  841.      * allocate space for our scratch space; it's initially
  842.      * 10 elements long, but can change in this routine if
  843.      * necessary
  844.      */
  845.     sp_array_size = 10;
  846.     sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
  847.  
  848.     /*
  849.      * there are at most five of these structures in the header
  850.      * itself; read these in first
  851.      */
  852.     for (ind = 0; ind < SPARSE_IN_HDR; ind++) {
  853.         if (!head->header.sp[ind].numbytes)
  854.             break;
  855.         sparsearray[ind].offset =
  856.             from_oct(1+12, head->header.sp[ind].offset);
  857.         sparsearray[ind].numbytes =
  858.             from_oct(1+12, head->header.sp[ind].numbytes);
  859.     }
  860.     /*
  861.      * if the header's extended, we gotta read in exhdr's till
  862.      * we're done
  863.      */
  864.     if (head->header.isextended) {
  865.          /* how far into the sparsearray we are 'so far' */
  866.         static int so_far_ind = SPARSE_IN_HDR;    
  867.         union record *exhdr;
  868.            
  869.         for (;;) {
  870.         exhdr = findrec();
  871.         for (ind = 0; ind < SPARSE_EXT_HDR; ind++) {
  872.             if (ind+so_far_ind > sp_array_size-1) {
  873.                 /*
  874.                   * we just ran out of room in our
  875.                  *  scratch area - realloc it
  876.                   */
  877.                 sparsearray = (struct sp_array *)
  878.                     realloc(sparsearray, 
  879.                         sp_array_size*2*sizeof(struct sp_array));
  880.                 sp_array_size *= 2;
  881.             }
  882.             /*
  883.              * convert the character strings into longs
  884.              */
  885.             sparsearray[ind+so_far_ind].offset = 
  886.                 from_oct(1+12, exhdr->ext_hdr.sp[ind].offset);
  887.             sparsearray[ind+so_far_ind].numbytes =
  888.                 from_oct(1+12, exhdr->ext_hdr.sp[ind].numbytes);
  889.         }
  890.         /* 
  891.          * if this is the last extended header for this
  892.          * file, we can stop
  893.          */
  894.         if (!exhdr->ext_hdr.isextended)
  895.             break;
  896.         else {
  897.             so_far_ind += SPARSE_EXT_HDR;
  898.             userec(exhdr);
  899.         }
  900.         }
  901.         /* be sure to skip past the last one  */
  902.         userec(exhdr);
  903.     }
  904. }
  905.