home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / fixcpio / fixcpio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-03-01  |  9.1 KB  |  403 lines

  1.  
  2. /*
  3. **  fixcpio.c -- fix troubled cpio archive by skipping trashed members.
  4. **
  5. **  Dave Brower, 12/13/86
  6. **  {sun, amdahl, mtxinu}!rtech!daveb
  7. **
  8. **  Usage:  fixcpio [ infile [ outfile ] ]
  9. **
  10. **  Writes a cpio -c archive to outfile (or stdout) from the infile (stdin).
  11. **  ("-" may be used as the stdin/stdout filename.)
  12. **
  13. **  Skips over junk members.  This is how to recover when you've lost
  14. **  floppy 9 of a 30 disk backup.  Eliminates "Out of phase -- get help"
  15. */
  16.  
  17. # include <stdio.h>
  18.  
  19. /* size blocks to write */
  20.  
  21. # define BLKSIZ    512
  22.  
  23. /* Maximum reasonable pathname in a header record */
  24.  
  25. # define MAXPATH 128
  26.  
  27. typedef struct
  28. {
  29.     /* these are ints for scanf's benefit. */
  30.     int        h_magic,
  31.             h_dev,
  32.             h_ino,
  33.             h_mode,
  34.         h_uid,
  35.         h_gid,
  36.             h_nlink,
  37.             h_rdev;
  38.     long    h_longtime;
  39.     int        h_namesize;
  40.     long    h_longfile;
  41. } CHARHDR;
  42.  
  43. typedef struct
  44. {
  45.     CHARHDR    h;
  46.     char     h_name[ MAXPATH ];
  47. } CHARREC;
  48.  
  49. CHARREC CRec = { 0 };            /* Character header */
  50. char Trailer[] = "TRAILER!!!";        /* Magic string */
  51. char Tmpfile[] = "/tmp/fixcpioXXXXXX";    /* temp file template */
  52. int Debug;                /* Debugging? */
  53.  
  54. void outerr();                /* error writing output file */
  55. void tmperr();                /* error writing temp file */
  56. void writeerr();            /* error writing file */
  57. int fprintf();                /* libc defined, -1 on error */
  58.  
  59. /*
  60. ** main() -- fix a cpio archive with "Out of phase -- get help" problems.
  61. */
  62. main(argc, argv)
  63. int argc;
  64. char **argv;
  65. {
  66.     register int last;            /* last char processed */
  67.     register int this;            /* current chars */
  68.     register int nmagic;        /* "07"s in magic "070707" seen */
  69.  
  70.     register FILE *ifp = stdin;        /* input stream */
  71.     register FILE *ofp = stdout;    /* output stream */
  72.     register FILE *tfp = NULL;        /* temp file */
  73.  
  74.     int done = 0;            /* all done flag */
  75.     long nbytes = 0;            /* count of bytes written */
  76.  
  77.     char buf[ 512 ];            /* holds a trailer. */
  78.  
  79.     char *getenv();            /* libc defined */
  80.     FILE *efopen();            /* fopen, fatal on error */
  81.     FILE *getmember();            /* stash a member in a temp file */
  82.     long putmember();            /* write temp file */
  83.  
  84.     /* Set "secret" debugging flag */
  85.     Debug = getenv("FIXCPIO") != NULL;
  86.  
  87.     if( argc > 3 )
  88.     {
  89.         fprintf(stderr, "Usage: fixcpio [ infile [ outfile ] ]\n");
  90.     return( 1 );
  91.     }
  92.  
  93.     if( --argc > 0 && strcmp( *++argv, "-" ) )
  94.     ifp = efopen( *argv, "r" );
  95.  
  96.     if( --argc > 0 && strcmp( *++argv, "-" ) )
  97.         ofp = efopen( *argv, "w" );
  98.  
  99.     /*
  100.     ** Process chars of input.  When you see a magic number, try
  101.     ** to accumulate the archive member on a temp file.  Write out
  102.     ** good members as they are validated, skipping trouble makers.
  103.     */
  104.     for ( nmagic = last = this = 0 ; !done ; last = this )
  105.     {
  106.     switch( this = getc( ifp ) )
  107.     {
  108.     case '0':
  109.  
  110.         /* maybe a header, no special action */
  111.         break;
  112.  
  113.     case '7':
  114.  
  115.         /* Maintain count of special "07" pairs */
  116.         nmagic = last == '0' ? nmagic + 1 : 0;
  117.  
  118.         /* It's a magic number, try to process as a header */
  119.         if( nmagic == 3 )
  120.         {
  121.         nmagic = 0;
  122.  
  123.         /* stashed entry is good, write it */
  124.         if( tfp )
  125.             nbytes += putmember( tfp, ofp );
  126.  
  127.         /* stash this possible entry into tfp, get CRec */
  128.         tfp = getmember( ifp );
  129.         }
  130.         break;
  131.  
  132.     case EOF:
  133.  
  134.         done = 1;
  135.         /* Fall into... */
  136.  
  137.     default:
  138.  
  139.         /* Any existing entry is garbage... */
  140.         nmagic = 0;
  141.         if( tfp )
  142.         {
  143.         if( !strcmp( CRec.h_name, Trailer ) )
  144.             done = 1;
  145.         else
  146.             fprintf(stderr, "Skipping bad member \"%s\"\n",
  147.                 CRec.h_name );
  148.         (void)fclose( tfp );
  149.         tfp = NULL;
  150.         }
  151.         break;
  152.     } /* switch */
  153.     } /* for */
  154.  
  155.     /* flush pending good member */
  156.     if( tfp )
  157.     {
  158.         nbytes += putmember( tfp, ofp );
  159.     tfp = NULL;
  160.     }
  161.  
  162.     /* Write a trailer -- remember to terminate the name string! */
  163.     (void)sprintf( buf,    "070707%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o%s",
  164.     0, 0, 0, 0, 0, 0, 0, 0, sizeof(Trailer) + 1, 0, Trailer );
  165.     if( fprintf(ofp, "%s", buf) < 0  || putc( 0, ofp ) < 0 )
  166.         outerr();
  167.     nbytes += strlen( buf ) + 1;
  168.  
  169.     /* round output to an even block */
  170.     nbytes = BLKSIZ - (nbytes % BLKSIZ);
  171.     while( nbytes-- )
  172.         if( putc( 0, ofp ) < 0 )
  173.         outerr();
  174.  
  175.     if( fclose( ofp ) < 0 )
  176.         outerr();
  177.     return( 0 );
  178. }
  179.  
  180. /*
  181. ** getmember() -- save an archive member to a temp file
  182. **
  183. ** When positioned after the magic number in a cpio file on ifp,
  184. ** copy the member to a temp file, and return it's fp.  The temp file
  185. ** contains a complete member (including magic number) and is positioned
  186. ** for catting directly to the real output file.
  187. **
  188. ** If there are problems getting the member, return NULL.
  189. */
  190. FILE *
  191. getmember( ifp )
  192. register FILE *ifp;
  193. {
  194.     register int c;            /* character of the member name */
  195.     register int nr;            /* number read or scanned */
  196.     register FILE *ofp;            /* temp file */
  197.     long len;                /* actual member length */
  198.  
  199.     char name[ sizeof(Tmpfile) + 1 ];    /* name of the temp file */
  200.  
  201.     /* number of chars to read for a -c header */
  202. #   define NCREAD    ( (8 * 6) + (2 * 11) )
  203.  
  204.     char buf[ NCREAD + 1 ];        /* raw header */
  205.  
  206.     char *mktemp();            /* libc, make temp file name */
  207.     char *strcpy();            /* libc, copy string */
  208.     long ncat();            /* cat file to a length */
  209.  
  210.     if( NCREAD != ( nr = fread( buf, 1, NCREAD, ifp ) ) )
  211.     {
  212.     fprintf(stderr, "Couldn't read header:  Wanted %d, got %d\n",
  213.         NCREAD, nr);
  214.     return (NULL);
  215.     }
  216.  
  217.     if( Debug )
  218.     {
  219.     fprintf(stderr,
  220.     "dev  |ino  |mode |uid  |gid  |nlink|rdev |longtime  |nsize|longfile\n" );
  221.     fprintf(stderr, "%s\n", buf );
  222.  
  223.     }
  224.  
  225.     if( 10 != ( nr = sscanf( buf, "%6o%6o%6o%6o%6o%6o%6o%11o%6o%11o",
  226.             &CRec.h.h_dev,  &CRec.h.h_ino,  &CRec.h.h_mode,
  227.             &CRec.h.h_uid,  &CRec.h.h_gid,  &CRec.h.h_nlink,
  228.             &CRec.h.h_rdev, &CRec.h.h_longtime,
  229.             &CRec.h.h_namesize , &CRec.h.h_longfile ) ) )
  230.     {
  231.     fprintf(stderr, "Couldn't scan header:  Wanted 10, got %d\n", nr);
  232.     return (NULL);
  233.     }
  234.  
  235.     if( Debug )
  236.     {
  237.      fprintf(stderr, "dev 0%o ino 0%o mode 0%o uid %d gid %d\n",
  238.         CRec.h.h_dev, CRec.h.h_ino, CRec.h.h_mode,
  239.         CRec.h.h_uid, CRec.h.h_gid );
  240.      fprintf(stderr,
  241.         "nlink %d rdev 0%o longtime 0%o namesize %d longfile 0%o\n",
  242.         CRec.h.h_nlink, CRec.h.h_rdev, CRec.h.h_longtime,
  243.         CRec.h.h_namesize, CRec.h.h_longfile );
  244.     }
  245.  
  246.     /* Ridiculous name size?  probably trashed entry */
  247.     if( !CRec.h.h_namesize || CRec.h.h_namesize > sizeof( CRec.h_name ) )
  248.     {
  249.     fprintf(stderr, "Bad namesize %d\n", CRec.h.h_namesize );
  250.         return (NULL);
  251.     }
  252.  
  253.     /* Get the name */
  254.     nr = 0;
  255.     while( nr < CRec.h.h_namesize && ( c = getc( ifp ) ) != EOF )
  256.         CRec.h_name[ nr++ ] = c;
  257.  
  258.     if( c == EOF )
  259.     {
  260.     fprintf(stderr, "Unexpected EOF reading name in header\n");
  261.         return (NULL);
  262.     }
  263.  
  264.     if( Debug )
  265.     fprintf(stderr, "name \"%s\"\n", CRec.h_name );
  266.  
  267.     /* create a new temp file, and mark it for delete on close */
  268.     (void)strcpy( name, mktemp( Tmpfile ) );
  269.     ofp = efopen( name, "w+" );
  270.     (void)unlink( name );
  271.  
  272.     /* Write a header */
  273.     fprintf( ofp, "070707%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o",
  274.                 CRec.h.h_dev,  CRec.h.h_ino,  CRec.h.h_mode,
  275.             CRec.h.h_uid,  CRec.h.h_gid,  CRec.h.h_nlink,
  276.             CRec.h.h_rdev,  CRec.h.h_longtime,
  277.             CRec.h.h_namesize, CRec.h.h_longfile ) ;
  278.  
  279.     for( nr = 0; nr < CRec.h.h_namesize ; )
  280.         putc( CRec.h_name[ nr++ ], ofp );
  281.  
  282.     /* now copy the file body */
  283.     if( CRec.h.h_longfile != (len = ncat( CRec.h.h_longfile, ifp, ofp ) ) )
  284.     {
  285.     fprintf(stderr, "Bad member length:  Should be %ld, was %ld\n",
  286.         CRec.h.h_longfile, len );
  287.     (void)fclose( ofp );
  288.     return( NULL );
  289.     }
  290.  
  291.     if( fseek( ofp, 0L, 0 ) < 0L )
  292.         tmperr();
  293.     return( ofp );
  294.  
  295. }
  296.  
  297. /*
  298. ** putmember() -- Write member, close input and return bytes written
  299. */
  300. long
  301. putmember( ifp, ofp )
  302. register FILE * ifp;
  303. register FILE * ofp;
  304. {
  305.     register long n;
  306.     long cat();
  307.  
  308.     fprintf(stderr, "%s\n", CRec.h_name );
  309.     n = cat( ifp, ofp );
  310.     (void)fclose( ifp );
  311.     return ( n );
  312. }
  313.  
  314.  
  315.  
  316. /*
  317. ** cat() -- copy one stream to another, returning n bytes copied
  318. */
  319. long
  320. cat( ifp, ofp )
  321. register FILE *ifp;
  322. register FILE *ofp;
  323. {
  324.     register int c;
  325.     register int n;
  326.  
  327.     for( n = 0 ; ( c = getc( ifp ) ) != EOF ; n++ )
  328.         if( putc( c, ofp ) < 0 )
  329.         outerr();
  330.  
  331.     return ( n );
  332. }
  333.  
  334. /*
  335. ** ncat() -- copy up to n bytes from one stream to another, return actual
  336. */
  337. long
  338. ncat( in, ifp, ofp )
  339. register long in;
  340. register FILE *ifp;
  341. register FILE *ofp;
  342. {
  343.     register int c;
  344.     register long on;
  345.  
  346.     for( on = 0; in-- && ( c = getc( ifp ) ) != EOF ; on++ )
  347.         if( putc( c, ofp ) < 0 )
  348.         tmperr();
  349.  
  350.     return ( on );
  351. }
  352.  
  353. /*
  354. ** efopen() -- fopen() that fatals on error
  355. */
  356. FILE *
  357. efopen( file, mode )
  358. char *file;
  359. char *mode;
  360. {
  361.     FILE * fp;
  362.  
  363.     if( NULL == (fp = fopen( file, mode ) ) )
  364.     {
  365.     fprintf(stderr, "Can't open \"%s\" mode \"%s\"\n", file, mode );
  366.     perror("efopen");
  367.     exit( 1 );
  368.     }
  369.     return( fp );
  370. }
  371.  
  372. /*
  373. ** outerr() -- handle error writing output file
  374. */
  375. void
  376. outerr()
  377. {
  378.     writeerr( "output" );
  379. }
  380.  
  381. /*
  382. ** tmperr() -- handle error writing temp file
  383. */
  384. void
  385. tmperr()
  386. {
  387.     writeerr( "temp" );
  388. }
  389.  
  390. /*
  391. ** writeerr() -- handle write errors, gracelessly.
  392. */
  393. void
  394. writeerr( what )
  395. char *what;
  396. {
  397.     fprintf(stderr, "\007Error writing %s file", what );
  398.     perror("");
  399.  
  400. }
  401.  
  402. /* end of fixcpio.c */
  403.