home *** CD-ROM | disk | FTP | other *** search
/ Mega Top 1 / os2_top1.zip / os2_top1 / APPS / ARCH / PAX20-2 / PAX.C < prev    next >
C/C++ Source or Header  |  1993-12-24  |  17KB  |  663 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 PC
  164.     char            *tmp;
  165. #endif /* PC */
  166.  
  167. #ifdef __EMX__
  168.     _response(&argc, &argv);
  169.     _wildcard(&argc, &argv);
  170. #endif
  171.  
  172.     DBUG_ENTER("main");
  173.     DBUG_PROCESS(argv[0]);
  174.  
  175. #ifdef PC
  176.     setmode(fileno(stdin), O_BINARY);
  177.     setmode(fileno(stdout), O_BINARY);
  178.     /* strip the pathname off of the name of the executable */
  179. #ifdef DIO
  180.     dio_str(argv[0]);
  181. #endif
  182.     if ((myname = strrchr(argv[0], '/')) != (char *)NULL) {
  183.      myname++;
  184.     } else if ((myname = strrchr(argv[0], '\\')) != (char *)NULL) {
  185.     myname++;
  186.     } else {
  187.     myname = argv[0];
  188.     }
  189.     if ((tmp = strrchr(myname, '.')) != (char *) NULL) {
  190.     *tmp = '\0';
  191.     }
  192. #else /* !PC */
  193.     /* strip the pathname off of the name of the executable */
  194.     if ((myname = rindex(argv[0], '/')) != (char *) NULL) {
  195.     myname++;
  196.     } else {
  197.     myname = argv[0];
  198.     }
  199. #endif /* PC */
  200.  
  201.     /* set up for collecting other command line arguments */
  202.     name_init(argc, argv);
  203.  
  204.     /* get all our necessary information */
  205.     mask = umask(0);
  206.     uid = getuid();
  207.     gid = getgid();
  208.     now = time((time_t *) 0);
  209.  
  210.     /* open terminal for interactive queries */
  211.     ttyf = open_tty();
  212.  
  213.     if (stricmp(myname, "tar") == 0) {
  214.     tar_interface = 1;
  215.     do_tar(argc, argv);
  216.     } else if (stricmp(myname, "cpio") == 0) {
  217.     cpio_interface = 1;
  218.     do_cpio(argc, argv);
  219.     } else {
  220.     pax_interface = 1;
  221.     do_pax(argc, argv);
  222.     }
  223.     exit(0);
  224.     /* NOTREACHED */
  225. }
  226.  
  227.  
  228. /* do_pax - provide a PAX conformant user interface for archive handling
  229.  *
  230.  * DESCRIPTION
  231.  *
  232.  *    Process the command line parameters given, doing some minimal sanity
  233.  *    checking, and then launch the specified archiving functions.
  234.  *
  235.  * PARAMETERS
  236.  *
  237.  *    int ac        - A count of arguments in av.  Should be passed argc
  238.  *              from main
  239.  *    char **av        - A pointer to an argument list.  Should be passed
  240.  *              argv from main
  241.  *
  242.  * RETURNS
  243.  *
  244.  *    Normally returns 0.  If an error occurs, -1 is returned
  245.  *    and state is set to reflect the error.
  246.  *
  247.  */
  248.  
  249. #ifdef __STDC__
  250.  
  251. int
  252. do_pax(int ac, char **av)
  253.  
  254. #else
  255.  
  256. int
  257. do_pax(ac, av)
  258.     int                 ac;    /* argument counter */
  259.     char              **av;    /* arguments */
  260.  
  261. #endif
  262. {
  263.     int                 c;
  264.     char               *dirname;
  265.     Stat                st;
  266.  
  267.     DBUG_ENTER("do_pax");
  268.     /* default input/output file for PAX is STDIN/STDOUT */
  269.     ar_file = "-";
  270.  
  271.     /*
  272.      * set up the flags to reflect the default pax inteface.  Unfortunately
  273.      * the pax interface has several options which are completely opposite of
  274.      * the tar and/or cpio interfaces...
  275.      */
  276.     f_unconditional = 1;
  277.     f_mtime = 1;
  278.     f_dir_create = 1;
  279.     f_list = 1;
  280.     blocksize = 0;
  281.     blocking = 0;
  282.     ar_interface = PAX;
  283.     ar_format = TAR;        /* default interface if none given for -w */
  284.     msgfile = stdout;
  285.  
  286.     while ((c = getopt(ac, av, "#:ab:cdf:ilmoprs:t:uvwx:y")) != EOF) {
  287.     switch (c) {
  288.  
  289.     case '#':
  290.         DBUG_PUSH(optarg);
  291.         break;
  292.  
  293.     case 'a':
  294.         f_append = 1;
  295.         f_list = 0;
  296.         break;
  297.  
  298.     case 'b':
  299.         if ((blocksize = pax_optsize(optarg)) == 0) {
  300.         fatal("Bad block size");
  301.         }
  302.         break;
  303.  
  304.     case 'c':
  305.         f_reverse_match = 1;
  306.         break;
  307.  
  308.     case 'd':
  309.         f_dir_create = 0;
  310.         break;
  311.  
  312.     case 'f':
  313.         if (blocksize == 0) {
  314.         blocking = 1;
  315.         blocksize = 1 * BLOCKSIZE;
  316.         }
  317.         ar_file = optarg;
  318.         break;
  319.  
  320.     case 'i':
  321.         f_interactive = 1;
  322.         break;
  323.  
  324.     case 'l':
  325.         f_link = 1;
  326.         break;
  327.  
  328.     case 'm':
  329.         f_mtime = 0;
  330.         break;
  331.  
  332.     case 'o':
  333.         f_owner = 1;
  334.         break;
  335.  
  336.     case 'p':
  337.         f_access_time = 1;
  338.         break;
  339.  
  340.     case 'r':
  341.         if (f_create) {
  342.         f_create = 0;
  343.         f_pass = 1;
  344.         } else {
  345.         f_list = 0;
  346.         f_extract = 1;
  347.         }
  348.         msgfile = stderr;
  349.         break;
  350.  
  351.     case 's':
  352.         add_replstr(optarg);
  353.         break;
  354.  
  355.     case 't':
  356.         if (blocksize == 0) {
  357.         blocking = 1;
  358.         blocksize = 10 * BLOCKSIZE;
  359.         }
  360.         ar_file = optarg;
  361.         break;
  362.  
  363.     case 'u':
  364.         f_unconditional = 1;
  365.         break;
  366.  
  367.     case 'v':
  368.         f_verbose = 1;
  369.         break;
  370.  
  371.     case 'w':
  372.         if (f_extract) {
  373.         f_extract = 0;
  374.         f_pass = 1;
  375.         } else {
  376.         f_list = 0;
  377.         f_create = 1;
  378.         }
  379.         msgfile = stderr;
  380.         break;
  381.  
  382.     case 'x':
  383.             if (stricmp(optarg, "ustar") == 0) {
  384.         ar_format = TAR;
  385.             } else if (stricmp(optarg, "cpio") == 0) {
  386.         ar_format = CPIO;
  387.         } else {
  388.         usage();
  389.         }
  390.         break;
  391.  
  392.     case 'y':
  393.         f_disposition = 1;
  394.         break;
  395.  
  396.     default:
  397.         usage();
  398.     }
  399.     }
  400.  
  401.     if ( strcmp(ar_file, "-") == 0
  402.          && isatty(fileno(stdin))
  403.          && isatty(fileno(stdout)) )
  404.       usage();
  405.  
  406. #ifdef PC
  407.     setmode(fileno(msgfile), O_TEXT);
  408. #endif /* PC */
  409.  
  410.     if (blocksize == 0) {
  411.     blocking = 1;
  412.     blocksize = blocking * BLOCKSIZE;
  413.     }
  414.     buf_allocate((OFFSET) blocksize);
  415.  
  416.     if (f_extract || f_list) {
  417.     open_archive(AR_READ);
  418.     get_archive_type();
  419.     read_archive();
  420.     } else if (f_create) {
  421.     if (optind >= n_argc) {
  422.         names_from_stdin++;    /* args from stdin */
  423.     }
  424.  
  425. #ifdef PC
  426.         if (names_from_stdin) {
  427.             setmode(fileno(stdin), O_TEXT);
  428.     }
  429. #endif /* PC */
  430.  
  431.     open_archive(AR_WRITE);
  432.     create_archive();
  433.     } else if (f_append) {
  434.     open_archive(AR_APPEND);
  435.     get_archive_type();
  436.     append_archive();
  437.     } else if (f_pass && optind < n_argc) {
  438.     dirname = n_argv[--n_argc];
  439.     if (LSTAT(dirname, &st) < 0) {
  440.         fatal(strerror());
  441.     }
  442.     if ((st.sb_mode & S_IFMT) != S_IFDIR) {
  443.         fatal("Not a directory");
  444.     }
  445.     if (optind >= n_argc) {
  446.         names_from_stdin++;    /* args from stdin */
  447.     }
  448.  
  449. #ifdef PC
  450.         if (names_from_stdin) {
  451.             setmode(fileno(stdin), O_TEXT);
  452.     }
  453. #endif /* PC */
  454.  
  455.     pass(dirname);
  456.     } else {
  457.     usage();
  458.     }
  459.  
  460.     DBUG_RETURN(0);
  461. }
  462.  
  463.  
  464. /* get_archive_type - determine input archive type from archive header
  465.  *
  466.  * DESCRIPTION
  467.  *
  468.  *     reads the first block of the archive and determines the archive
  469.  *    type from the data.  If the archive type cannot be determined,
  470.  *    processing stops, and a 1 is returned to the caller.  If verbose
  471.  *    mode is on, then the archive type will be printed on the standard
  472.  *    error device as it is determined.
  473.  *
  474.  * FIXME
  475.  *
  476.  *    be able to understand TAR and CPIO magic numbers
  477.  */
  478.  
  479. #ifdef __STDC__
  480.  
  481. void
  482. get_archive_type(void)
  483.  
  484. #else
  485.  
  486. void
  487. get_archive_type()
  488.  
  489. #endif
  490. {
  491.     DBUG_ENTER("get_archive_type");
  492.     if (ar_read() != 0) {
  493.     fatal("Unable to determine archive type.");
  494.     }
  495.     if (strncmp(bufstart, "070707", 6) == 0) {
  496.     ar_format = CPIO;
  497.     if (f_verbose) {
  498.         fputs("CPIO format archive\n", stderr);
  499.     }
  500.     } else if ((((bufstart[0]&0x0FF)<<8) | (bufstart[1]&0x0FF)) == 070707) {
  501.         /* big-endian (not byte swapped, might be word swapped) */
  502.     ar_format = CPIO;
  503.     if (f_verbose) {
  504.         fputs("CPIO format archive\n", stderr);
  505.     }
  506.     } else if ((((bufstart[1]&0x0FF)<<8) | (bufstart[0]&0x0FF)) == 070707) {
  507.         /* big-endian (not byte swapped, might be word swapped) */
  508.     ar_format = CPIO;
  509.     if (f_verbose) {
  510.         fputs("CPIO format archive\n", stderr);
  511.     }
  512.     } else if (strncmp(&bufstart[257], "ustar", 5) == 0) {
  513.     ar_format = TAR;
  514.     if (f_verbose) {
  515.         fputs("USTAR format archive\n", stderr);
  516.     }
  517.     } else {
  518.     ar_format = TAR;
  519.     if (f_verbose) {
  520.         fputs("USTAR format archive assumed\n", stderr);
  521.     }
  522.     }
  523.     DBUG_VOID_RETURN;
  524. }
  525.  
  526.  
  527. /* pax_optsize - interpret a size argument
  528.  *
  529.  * DESCRIPTION
  530.  *
  531.  *     Recognizes suffixes for blocks (512-bytes), k-bytes and megabytes.
  532.  *     Also handles simple expressions containing '+' for addition.
  533.  *
  534.  * PARAMETERS
  535.  *
  536.  *    char     *str    - A pointer to the string to interpret
  537.  *
  538.  * RETURNS
  539.  *
  540.  *    Normally returns the value represented by the expression in the
  541.  *    the string.
  542.  *
  543.  * ERRORS
  544.  *
  545.  *    If the string cannot be interpretted, the program will fail, since
  546.  *    the buffering will be incorrect.
  547.  *
  548.  */
  549.  
  550. #ifdef __STDC__
  551.  
  552. static OFFSET
  553. pax_optsize(char *str)
  554.  
  555. #else
  556.  
  557. static OFFSET
  558. pax_optsize(str)
  559.     char               *str;    /* pointer to string to interpret */
  560.  
  561. #endif
  562. {
  563.     char               *idx;
  564.     OFFSET              number;    /* temporary storage for current number */
  565.     OFFSET              result;    /* cumulative total to be returned to caller */
  566.  
  567.     DBUG_ENTER("pax_optsize");
  568.     result = 0;
  569.     idx = str;
  570.     for (;;) {
  571.     number = 0;
  572.     while (*idx >= '0' && *idx <= '9')
  573.         number = number * 10 + *idx++ - '0';
  574.     switch (*idx++) {
  575.  
  576.     case 'b':
  577.         result += number * 512L;
  578.         continue;
  579.  
  580.     case 'k':
  581.         result += number * 1024L;
  582.         continue;
  583.  
  584.     case 'm':
  585.         result += number * 1024L * 1024L;
  586.         continue;
  587.  
  588.     case '+':
  589.         result += number;
  590.         continue;
  591.  
  592.     case '\0':
  593.         result += number;
  594.         break;
  595.  
  596.     default:
  597.         break;
  598.     }
  599.     break;
  600.     }
  601.     if (*--idx) {
  602.     fatal("Unrecognizable value");
  603.     }
  604.     DBUG_RETURN(result);
  605. }
  606.  
  607.  
  608. /* usage - print a helpful message and exit
  609.  *
  610.  * DESCRIPTION
  611.  *
  612.  *    Usage prints out the usage message for the PAX interface and then
  613.  *    exits with a non-zero termination status.  This is used when a user
  614.  *    has provided non-existant or incompatible command line arguments.
  615.  *
  616.  * RETURNS
  617.  *
  618.  *    Returns an exit status of 1 to the parent process.
  619.  *
  620.  */
  621.  
  622. #ifdef __STDC__
  623.  
  624. static void
  625. usage(void)
  626.  
  627. #else
  628.  
  629. static void
  630. usage()
  631.  
  632. #endif
  633. {
  634.     DBUG_ENTER("usage");
  635. #ifdef PC
  636.     printf("\r\nPAX version 2.0 - POSIX conforming tar and cpio archiver\r\n");
  637.  
  638.     printf("\r\nUsage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\r\n", myname);
  639.     printf("       %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\r\n", myname);
  640.     printf("       %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\r\n"
  641.            "              [-t device] [-x format] [pathname...]\r\n", myname);
  642.     printf("       %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\r\n", myname);
  643.  
  644.     printf("\r\nRename PAX.EXE to TAR.EXE or CPIO.EXE to get the TAR or CPIO user interface.\r\n");
  645.  
  646. #ifdef DISKACC
  647.     printf("\r\nUse the option -t with drive letter arguments to access Unix floppy"
  648.            "\r\ndisks with tar or cpio archives. The disk type is automatically detected.\r\n");
  649. #endif
  650. #else
  651.     fprintf(stderr, "Usage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
  652.         myname);
  653.     fprintf(stderr, "       %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
  654.         myname);
  655.     fprintf(stderr, "       %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\n"
  656.                     "              [-t device] [-x format] [pathname...]\n",
  657.         myname);
  658.     fprintf(stderr, "       %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\n",
  659.             myname);
  660. #endif
  661.     exit(1);
  662. }
  663.