home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / PAX20.ZIP / PAX.C < prev    next >
C/C++ Source or Header  |  1990-11-12  |  17KB  |  659 lines

  1. /* $Source: /u/mark/src/pax/RCS/pax.c,v $
  2.  *
  3.  * $Revision: 2.0.0.4 $
  4.  *
  5.  * DESCRIPTION
  6.  *
  7.  *    Pax is the archiver described in IEEE P1003.2.  It is an archiver
  8.  *    which understands both tar and cpio archives and has a new interface.
  9.  *
  10.  * SYNOPSIS
  11.  *
  12.  *    pax -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
  13.  *    pax -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
  14.  *    pax -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]...]
  15.  *           [-t device][-x format][pathname...]
  16.  *    pax -r -w [-ilmopuvy][-s replstr][pathname...] directory
  17.  *
  18.  * DESCRIPTION
  19.  *
  20.  *     PAX - POSIX conforming tar and cpio archive handler.  This
  21.  *    program implements POSIX conformant versions of tar, cpio and pax
  22.  *    archive handlers for UNIX.  These handlers have defined befined
  23.  *    by the IEEE P1003.2 commitee.
  24.  *
  25.  * COMPILATION
  26.  *
  27.  *    A number of different compile time configuration options are
  28.  *    available, please see the Makefile and config.h for more details.
  29.  *
  30.  * AUTHOR
  31.  *
  32.  *     Mark H. Colburn, Open Systems Architects, Inc. (mark@minnetech.mn.org)
  33.  *
  34.  * COPYRIGHT
  35.  *
  36.  *    Copyright (c) 1989 Mark H. Colburn.  All rights reserved.
  37.  *
  38.  *    Redistribution and use in source and binary forms are permitted
  39.  *    provided that the above copyright notice and this paragraph are
  40.  *    duplicated in all such forms and that any documentation,
  41.  *    advertising materials, and other materials related to such
  42.  *    distribution and use acknowledge that the software was developed
  43.  *    by Mark H. Colburn.
  44.  *
  45.  *    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  46.  *    IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  47.  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  48.  *
  49.  * $Log:    pax.c,v $
  50.  * Revision 2.0.0.4  89/10/13  02:35:35  mark
  51.  * Beta Test Freeze
  52.  *
  53.  */
  54.  
  55. #ifndef lint
  56. static char        *ident = "$Id: pax.c,v 2.0.0.4 89/10/13 02:35:35 mark Exp Locker: mark $";
  57. static char        *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
  58. #endif /* ! lint */
  59.  
  60.  
  61. /* Headers */
  62.  
  63. #define NO_EXTERN
  64. #include "pax.h"
  65.  
  66.  
  67. /* Globally Available Identifiers */
  68.  
  69. char               *ar_file;        /* File containing name of archive */
  70. char               *bufend;        /* End of data within archive buffer */
  71. char               *bufstart;        /* Archive buffer */
  72. char               *bufidx;        /* Archive buffer index */
  73. char               *myname;        /* name of executable (argv[0]) */
  74. char              **n_argv;        /* Argv used by name routines */
  75. int                 n_argc;        /* Argc used by name routines */
  76. int                 archivefd;        /* Archive file descriptor */
  77. int                 blocking;        /* Size of each block, in records */
  78. GIDTYPE             gid;        /* Group ID */
  79. int                 head_standard;    /* true if archive is POSIX format */
  80. int                 ar_interface;    /* defines interface we are using */
  81. int                 ar_format;        /* defines current archve format */
  82. int                 mask;        /* File creation mask */
  83. int                 ttyf;        /* For interactive queries */
  84. UIDTYPE             uid;        /* User ID */
  85. int                 names_from_stdin;    /* names for files are from stdin */
  86. OFFSET              total;        /* Total number of bytes transferred */
  87. short               f_access_time;    /* Reset access times of input files */
  88. short               areof;        /* End of input volume reached */
  89. short               f_dir_create;    /* Create missing directories */
  90. short               f_append;        /* Add named files to end of archive */
  91. short               f_create;        /* create a new archive */
  92. short               f_extract;        /* Extract named files from archive */
  93. short               f_follow_links;    /* follow symbolic links */
  94. short               f_interactive;    /* Interactivly extract files */
  95. short               f_unresolved;    /* Report on unresolved links */
  96. short               f_list;        /* List files on the archive */
  97. short               f_modified;        /* Don't restore modification times */
  98. short               f_verbose;        /* Turn on verbose mode */
  99. short               f_link;        /* link files where possible */
  100. short               f_owner;        /* extract files as the user */
  101. short               f_pass;        /* pass files between directories */
  102. short               f_newer;        /* append files to archive if newer */
  103. short               f_disposition;    /* ask for file disposition */
  104. short               f_reverse_match;    /* Reverse sense of pattern match */
  105. short               f_mtime;        /* Retain file modification time */
  106. short               f_unconditional;    /* Copy unconditionally */
  107. short               tar_interface = 0;    /* using the tar interface */
  108. short               cpio_interface = 0;    /* using the cpio interface */
  109. short               pax_interface = 0;    /* using the pax interface */
  110. time_t              now = 0;        /* Current time */
  111. uint                arvolume;        /* Volume number */
  112. uint                blocksize = BLOCKSIZE;    /* Archive block size */
  113. FILE               *msgfile;        /* message outpu file stdout/stderr */
  114. Replstr            *rplhead = (Replstr *) NULL;    /* head of replstr list */
  115. Replstr            *rpltail;        /* pointer to tail of replstr list */
  116.  
  117.  
  118. /* Function Prototypes */
  119.  
  120. #ifdef __STDC__
  121.  
  122. static void        usage(void);
  123. static OFFSET       pax_optsize(char *);
  124.  
  125. #else /* !__STDC__ */
  126.  
  127. static void         usage();
  128. static OFFSET       pax_optsize();
  129.  
  130. #endif /* __STDC__ */
  131.  
  132.  
  133. /* main - main routine for handling all archive formats.
  134.  *
  135.  * DESCRIPTION
  136.  *
  137.  *     Set up globals and call the proper interface as specified by the user.
  138.  *
  139.  * PARAMETERS
  140.  *
  141.  *    int argc    - count of user supplied arguments
  142.  *    char **argv    - user supplied arguments
  143.  *
  144.  * RETURNS
  145.  *
  146.  *    Returns an exit code of 0 to the parent process.
  147.  */
  148.  
  149. #ifdef __STDC__
  150.  
  151. int
  152. main(int argc, char **argv)
  153.  
  154. #else
  155.  
  156. int
  157. main(argc, argv)
  158.     int                 argc;
  159.     char              **argv;
  160.  
  161. #endif
  162. {
  163. #ifdef MSDOS
  164.     char            *tmp;
  165. #endif /* MSDOS */
  166.  
  167.     DBUG_ENTER("main");
  168.     DBUG_PROCESS(argv[0]);
  169.  
  170. #ifdef MSDOS
  171.     _fmode = O_BINARY;
  172.     setmode(fileno(stdin), O_BINARY);
  173.     setmode(fileno(stdout), O_BINARY);
  174.     /* strip the pathname off of the name of the executable */
  175. #ifdef DIO
  176.     dio_str(argv[0]);
  177. #endif
  178.     if ((myname = strrchr(argv[0], '/')) != (char *)NULL) {
  179.      myname++;
  180.     } else if ((myname = strrchr(argv[0], '\\')) != (char *)NULL) {
  181.     myname++;
  182.     } else {
  183.     myname = argv[0];
  184.     }
  185.     if ((tmp = strrchr(myname, '.')) != (char *) NULL) {
  186.     *tmp = '\0';
  187.     }
  188. #else /* !MSDOS */
  189.     /* strip the pathname off of the name of the executable */
  190.     if ((myname = rindex(argv[0], '/')) != (char *) NULL) {
  191.     myname++;
  192.     } else {
  193.     myname = argv[0];
  194.     }
  195. #endif /* MSDOS */
  196.  
  197.     /* set up for collecting other command line arguments */
  198.     name_init(argc, argv);
  199.  
  200.     /* get all our necessary information */
  201.     mask = umask(0);
  202.     uid = getuid();
  203.     gid = getgid();
  204.     now = time((time_t *) 0);
  205.  
  206.     /* open terminal for interactive queries */
  207.     ttyf = open_tty();
  208.  
  209.     if (stricmp(myname, "tar") == 0) {
  210.     tar_interface = 1;
  211.     do_tar(argc, argv);
  212.     } else if (stricmp(myname, "cpio") == 0) {
  213.     cpio_interface = 1;
  214.     do_cpio(argc, argv);
  215.     } else {
  216.     pax_interface = 1;
  217.     do_pax(argc, argv);
  218.     }
  219.     exit(0);
  220.     /* NOTREACHED */
  221. }
  222.  
  223.  
  224. /* do_pax - provide a PAX conformant user interface for archive handling
  225.  *
  226.  * DESCRIPTION
  227.  *
  228.  *    Process the command line parameters given, doing some minimal sanity
  229.  *    checking, and then launch the specified archiving functions.
  230.  *
  231.  * PARAMETERS
  232.  *
  233.  *    int ac        - A count of arguments in av.  Should be passed argc
  234.  *              from main
  235.  *    char **av        - A pointer to an argument list.  Should be passed
  236.  *              argv from main
  237.  *
  238.  * RETURNS
  239.  *
  240.  *    Normally returns 0.  If an error occurs, -1 is returned
  241.  *    and state is set to reflect the error.
  242.  *
  243.  */
  244.  
  245. #ifdef __STDC__
  246.  
  247. int
  248. do_pax(int ac, char **av)
  249.  
  250. #else
  251.  
  252. int
  253. do_pax(ac, av)
  254.     int                 ac;    /* argument counter */
  255.     char              **av;    /* arguments */
  256.  
  257. #endif
  258. {
  259.     int                 c;
  260.     char               *dirname;
  261.     Stat                st;
  262.  
  263.     DBUG_ENTER("do_pax");
  264.     /* default input/output file for PAX is STDIN/STDOUT */
  265.     ar_file = "-";
  266.  
  267.     /*
  268.      * set up the flags to reflect the default pax inteface.  Unfortunately
  269.      * the pax interface has several options which are completely opposite of
  270.      * the tar and/or cpio interfaces...
  271.      */
  272.     f_unconditional = 1;
  273.     f_mtime = 1;
  274.     f_dir_create = 1;
  275.     f_list = 1;
  276.     blocksize = 0;
  277.     blocking = 0;
  278.     ar_interface = PAX;
  279.     ar_format = TAR;        /* default interface if none given for -w */
  280.     msgfile = stdout;
  281.  
  282.     while ((c = getopt(ac, av, "#:ab:cdf:ilmoprs:t:uvwx:y")) != EOF) {
  283.     switch (c) {
  284.  
  285.     case '#':
  286.         DBUG_PUSH(optarg);
  287.         break;
  288.  
  289.     case 'a':
  290.         f_append = 1;
  291.         f_list = 0;
  292.         break;
  293.  
  294.     case 'b':
  295.         if ((blocksize = pax_optsize(optarg)) == 0) {
  296.         fatal("Bad block size");
  297.         }
  298.         break;
  299.  
  300.     case 'c':
  301.         f_reverse_match = 1;
  302.         break;
  303.  
  304.     case 'd':
  305.         f_dir_create = 0;
  306.         break;
  307.  
  308.     case 'f':
  309.         if (blocksize == 0) {
  310.         blocking = 1;
  311.         blocksize = 1 * BLOCKSIZE;
  312.         }
  313.         ar_file = optarg;
  314.         break;
  315.  
  316.     case 'i':
  317.         f_interactive = 1;
  318.         break;
  319.  
  320.     case 'l':
  321.         f_link = 1;
  322.         break;
  323.  
  324.     case 'm':
  325.         f_mtime = 0;
  326.         break;
  327.  
  328.     case 'o':
  329.         f_owner = 1;
  330.         break;
  331.  
  332.     case 'p':
  333.         f_access_time = 1;
  334.         break;
  335.  
  336.     case 'r':
  337.         if (f_create) {
  338.         f_create = 0;
  339.         f_pass = 1;
  340.         } else {
  341.         f_list = 0;
  342.         f_extract = 1;
  343.         }
  344.         msgfile = stderr;
  345.         break;
  346.  
  347.     case 's':
  348.         add_replstr(optarg);
  349.         break;
  350.  
  351.     case 't':
  352.         if (blocksize == 0) {
  353.         blocking = 1;
  354.         blocksize = 10 * BLOCKSIZE;
  355.         }
  356.         ar_file = optarg;
  357.         break;
  358.  
  359.     case 'u':
  360.         f_unconditional = 1;
  361.         break;
  362.  
  363.     case 'v':
  364.         f_verbose = 1;
  365.         break;
  366.  
  367.     case 'w':
  368.         if (f_extract) {
  369.         f_extract = 0;
  370.         f_pass = 1;
  371.         } else {
  372.         f_list = 0;
  373.         f_create = 1;
  374.         }
  375.         msgfile = stderr;
  376.         break;
  377.  
  378.     case 'x':
  379.             if (stricmp(optarg, "ustar") == 0) {
  380.         ar_format = TAR;
  381.             } else if (stricmp(optarg, "cpio") == 0) {
  382.         ar_format = CPIO;
  383.         } else {
  384.         usage();
  385.         }
  386.         break;
  387.  
  388.     case 'y':
  389.         f_disposition = 1;
  390.         break;
  391.  
  392.     default:
  393.         usage();
  394.     }
  395.     }
  396.  
  397.     if ( strcmp(ar_file, "-") == 0
  398.          && isatty(fileno(stdin))
  399.          && isatty(fileno(stdout)) )
  400.       usage();
  401.  
  402. #ifdef MSDOS
  403.     setmode(fileno(msgfile), O_TEXT);
  404. #endif /* MSDOS */
  405.  
  406.     if (blocksize == 0) {
  407.     blocking = 1;
  408.     blocksize = blocking * BLOCKSIZE;
  409.     }
  410.     buf_allocate((OFFSET) blocksize);
  411.  
  412.     if (f_extract || f_list) {
  413.     open_archive(AR_READ);
  414.     get_archive_type();
  415.     read_archive();
  416.     } else if (f_create) {
  417.     if (optind >= n_argc) {
  418.         names_from_stdin++;    /* args from stdin */
  419.     }
  420.  
  421. #ifdef MSDOS
  422.         if (names_from_stdin) {
  423.             setmode(fileno(stdin), O_TEXT);
  424.     }
  425. #endif /* MSDOS */
  426.  
  427.     open_archive(AR_WRITE);
  428.     create_archive();
  429.     } else if (f_append) {
  430.     open_archive(AR_APPEND);
  431.     get_archive_type();
  432.     append_archive();
  433.     } else if (f_pass && optind < n_argc) {
  434.     dirname = n_argv[--n_argc];
  435.     if (LSTAT(dirname, &st) < 0) {
  436.         fatal(strerror());
  437.     }
  438.     if ((st.sb_mode & S_IFMT) != S_IFDIR) {
  439.         fatal("Not a directory");
  440.     }
  441.     if (optind >= n_argc) {
  442.         names_from_stdin++;    /* args from stdin */
  443.     }
  444.  
  445. #ifdef MSDOS
  446.         if (names_from_stdin) {
  447.             setmode(fileno(stdin), O_TEXT);
  448.     }
  449. #endif /* MSDOS */
  450.  
  451.     pass(dirname);
  452.     } else {
  453.     usage();
  454.     }
  455.  
  456.     DBUG_RETURN(0);
  457. }
  458.  
  459.  
  460. /* get_archive_type - determine input archive type from archive header
  461.  *
  462.  * DESCRIPTION
  463.  *
  464.  *     reads the first block of the archive and determines the archive
  465.  *    type from the data.  If the archive type cannot be determined,
  466.  *    processing stops, and a 1 is returned to the caller.  If verbose
  467.  *    mode is on, then the archive type will be printed on the standard
  468.  *    error device as it is determined.
  469.  *
  470.  * FIXME
  471.  *
  472.  *    be able to understand TAR and CPIO magic numbers
  473.  */
  474.  
  475. #ifdef __STDC__
  476.  
  477. void
  478. get_archive_type(void)
  479.  
  480. #else
  481.  
  482. void
  483. get_archive_type()
  484.  
  485. #endif
  486. {
  487.     DBUG_ENTER("get_archive_type");
  488.     if (ar_read() != 0) {
  489.     fatal("Unable to determine archive type.");
  490.     }
  491.     if (strncmp(bufstart, "070707", 6) == 0) {
  492.     ar_format = CPIO;
  493.     if (f_verbose) {
  494.         fputs("CPIO format archive\n", stderr);
  495.     }
  496.     } else if ((((bufstart[0]&0x0FF)<<8) | (bufstart[1]&0x0FF)) == 070707) {
  497.         /* big-endian (not byte swapped, might be word swapped) */
  498.     ar_format = CPIO;
  499.     if (f_verbose) {
  500.         fputs("CPIO format archive\n", stderr);
  501.     }
  502.     } else if ((((bufstart[1]&0x0FF)<<8) | (bufstart[0]&0x0FF)) == 070707) {
  503.         /* big-endian (not byte swapped, might be word swapped) */
  504.     ar_format = CPIO;
  505.     if (f_verbose) {
  506.         fputs("CPIO format archive\n", stderr);
  507.     }
  508.     } else if (strncmp(&bufstart[257], "ustar", 5) == 0) {
  509.     ar_format = TAR;
  510.     if (f_verbose) {
  511.         fputs("USTAR format archive\n", stderr);
  512.     }
  513.     } else {
  514.     ar_format = TAR;
  515.     if (f_verbose) {
  516.         fputs("USTAR format archive assumed\n", stderr);
  517.     }
  518.     }
  519.     DBUG_VOID_RETURN;
  520. }
  521.  
  522.  
  523. /* pax_optsize - interpret a size argument
  524.  *
  525.  * DESCRIPTION
  526.  *
  527.  *     Recognizes suffixes for blocks (512-bytes), k-bytes and megabytes.
  528.  *     Also handles simple expressions containing '+' for addition.
  529.  *
  530.  * PARAMETERS
  531.  *
  532.  *    char     *str    - A pointer to the string to interpret
  533.  *
  534.  * RETURNS
  535.  *
  536.  *    Normally returns the value represented by the expression in the
  537.  *    the string.
  538.  *
  539.  * ERRORS
  540.  *
  541.  *    If the string cannot be interpretted, the program will fail, since
  542.  *    the buffering will be incorrect.
  543.  *
  544.  */
  545.  
  546. #ifdef __STDC__
  547.  
  548. static OFFSET
  549. pax_optsize(char *str)
  550.  
  551. #else
  552.  
  553. static OFFSET
  554. pax_optsize(str)
  555.     char               *str;    /* pointer to string to interpret */
  556.  
  557. #endif
  558. {
  559.     char               *idx;
  560.     OFFSET              number;    /* temporary storage for current number */
  561.     OFFSET              result;    /* cumulative total to be returned to caller */
  562.  
  563.     DBUG_ENTER("pax_optsize");
  564.     result = 0;
  565.     idx = str;
  566.     for (;;) {
  567.     number = 0;
  568.     while (*idx >= '0' && *idx <= '9')
  569.         number = number * 10 + *idx++ - '0';
  570.     switch (*idx++) {
  571.  
  572.     case 'b':
  573.         result += number * 512L;
  574.         continue;
  575.  
  576.     case 'k':
  577.         result += number * 1024L;
  578.         continue;
  579.  
  580.     case 'm':
  581.         result += number * 1024L * 1024L;
  582.         continue;
  583.  
  584.     case '+':
  585.         result += number;
  586.         continue;
  587.  
  588.     case '\0':
  589.         result += number;
  590.         break;
  591.  
  592.     default:
  593.         break;
  594.     }
  595.     break;
  596.     }
  597.     if (*--idx) {
  598.     fatal("Unrecognizable value");
  599.     }
  600.     DBUG_RETURN(result);
  601. }
  602.  
  603.  
  604. /* usage - print a helpful message and exit
  605.  *
  606.  * DESCRIPTION
  607.  *
  608.  *    Usage prints out the usage message for the PAX interface and then
  609.  *    exits with a non-zero termination status.  This is used when a user
  610.  *    has provided non-existant or incompatible command line arguments.
  611.  *
  612.  * RETURNS
  613.  *
  614.  *    Returns an exit status of 1 to the parent process.
  615.  *
  616.  */
  617.  
  618. #ifdef __STDC__
  619.  
  620. static void
  621. usage(void)
  622.  
  623. #else
  624.  
  625. static void
  626. usage()
  627.  
  628. #endif
  629. {
  630.     DBUG_ENTER("usage");
  631. #ifdef MSDOS
  632.     printf("\r\nPAX version 2.0 - POSIX conforming tar and cpio archiver for DOS and OS/2\r\n");
  633.  
  634.     printf("\r\nUsage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\r\n", myname);
  635.     printf("       %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\r\n", myname);
  636.     printf("       %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\r\n"
  637.            "              [-t device] [-x format] [pathname...]\r\n", myname);
  638.     printf("       %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\r\n", myname);
  639.  
  640.     printf("\r\nRename PAX.EXE to TAR.EXE or CPIO.EXE to get the TAR or CPIO user interface.\r\n");
  641.  
  642. #ifdef DISKACC
  643.     printf("\r\nUse the option -t with the special device names 0: and 1: to access Unix floppy"
  644.            "\r\ndisks with tar or cpio archives. The disk type is automatically detected.\r\n");
  645. #endif
  646. #else
  647.     fprintf(stderr, "Usage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
  648.         myname);
  649.     fprintf(stderr, "       %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
  650.         myname);
  651.     fprintf(stderr, "       %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\n"
  652.                     "              [-t device] [-x format] [pathname...]\n",
  653.         myname);
  654.     fprintf(stderr, "       %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\n",
  655.             myname);
  656. #endif
  657.     exit(1);
  658. }
  659.