tar.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 804 行 · 第 1/2 页

C
804
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  A public domain tar(1) program.
*
****************************************************************************/


/*
 * A public domain tar(1) program.
 *
 * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85.
 * MS-DOS port 2/87 by Eric Roskos.
 * Minix  port 3/88 by Eric Roskos.
 *
 * @(#)tar.c 1.21 10/29/86 Public Domain - gnu
 */

#include <stdio.h>
#include <sys/types.h>                  /* Needed for typedefs in tar.h */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifdef MSDOS
#include <conio.h>
#include <fcntl.h>
#endif
#ifdef V7
FILE *fopen();
char *fgets();
#endif

/*
 * The following causes "tar.h" to produce definitions of all the
 * global variables, rather than just "extern" declarations of them.
 */
#define TAR_EXTERN                              /**/
#include "tar.h"
#include "port.h"
#include "list.h"
#include "create.h"
#include "extract.h"
#include "buffer.h"
#include "getopt.h"

/*
 * We should use a conversion routine that does reasonable error
 * checking -- atoi doesn't.  For now, punt.  FIXME.
 */
#define intconv atoi

static FILE    *namef;                  /* File to read names from */
static char   **n_argv;                 /* Argv used by name routines */
static int      n_argc;                 /* Argc used by name routines */

 /* They also use "optind" from getopt(). */

#ifdef MSDOS
/*
 * see convmode, below.  This list is the list of files that should be
 * opened with mode O_BINARY to prevent CR/LF conversions while they
 * are being read in.  FIXME: it is my intent to eventually add an
 * option to the command line that lets you add arbitrarily many new
 * extensions to this list, so people won't have problems with the
 * list being inadequate for them.  I wish there was an easier way, but
 * this one is fairly consistent if you think about it.
 */
#define NBINEXTS        20

static char    *binexts[NBINEXTS] =             /* extensions for O_BINARY files */
{
        "com",
        "exe",
        "obj",
        0                                                       /* required */
};

#endif

static void name_init( int argc, char **argv );
static void addbinext( char *s );

/*
 * Main routine for tar.
 */
int main( int argc, char **argv )
{

        /*
         * Uncomment this message in particularly buggy versions...
         * fprintf(stderr, "tar: You are running an experimental PD tar, maybe
         * use /bin/tar.\n");
         */

        tar = "tar";                            /* Set program name */
#ifdef MSDOS
        physdrv = 0;                            /* set default drive */
        devsize = 720;                          /* default drive size */
        ftty = open("CON", O_RDWR);             /* open console */
#else /* !MSDOS */
        ftty = open("/dev/tty", 2);
#endif /* !MSDOS */
        if (ftty < 0) {
                fprintf(stderr, "Can't open %s for I/O\n",
#ifdef MSDOS
                "console"
#else
                "/dev/tty"
#endif
                );
                exit(EX_SYSTEM);
        }

        options(argc, argv);

        name_init(argc, argv);

#if defined(MSDOS) && !defined(__NO_PHYS__)
        if (f_phys) {
                uprintf(ftty,"tar: archive on %dK drive %c\n",
                        devsize/2, 'A' +  physdrv);
                uprintf(ftty,"tar: insert %s disk in drive '%c' and press [Enter]: ",
                        f_create? "formatted" : "first",
                        'A' + physdrv);
                while (ugetc(ftty)!='\n') ;
        }
#endif

        if (f_create) {
                if (f_extract || f_list)
                        goto dupflags;
                create_archive();
        } else if (f_extract) {
                if (f_list)
                        goto dupflags;
                read_and(extract_archive);
        } else if (f_list) {
                read_and(list_archive);
        } else {
dupflags:
                fprintf(stderr,
                        "tar: you must specify exactly one of the c, t, or x options\n");
                describe();
                exit(EX_ARGSBAD);
        }
        putchar('\n');
        fflush(stdout);
#ifndef MSDOS
        sync(); /* insure all floppy buffers are written out */
#endif
        return( 0 );
}


/*
 * Parse the options for tar.
 */
void options( int argc, char **argv )
{
        int    c;                      /* Option letter */

        /* Set default option values */
        blocking = DEFBLOCKING;         /* From Makefile */
        ar_file = DEF_AR_FILE;          /* From Makefile */

        /* Parse options */
        while ((c = getoldopt(argc, argv, "b:BcdDf:hikmopsS:tT:u:vV:xzZ")
                ) != EOF)
        {
                switch (c)
                {

                case 'b':
                        blocking = intconv(optarg);
                        break;

                case 'B':
                        f_reblock++;            /* For reading 4.2BSD pipes */
                        break;

                case 'c':
                        f_create++;
                        break;

                case 'd':
                        f_debug++;                      /* Debugging code */
                        break;                          /* Yes, even with dbx */

                case 'D':
                        f_sayblock++;           /* Print block #s for debug */
                        break;                          /* of bad tar archives */

                case 'f':
                        ar_file = optarg;
                        break;

                case 'h':
                        f_follow_links++;       /* follow symbolic links */
                        break;

                case 'i':
                        f_ignorez++;            /* Ignore zero records (eofs) */

                        /*
                         * This can't be the default, because Unix tar writes two records
                         * of zeros, then pads out the block with garbage.
                         */
                        break;

                case 'k':                               /* Don't overwrite files */
                        f_keep++;
                        break;

                case 'm':
                        f_modified++;
                        break;

                case 'o':                               /* Generate old archive */
                        f_oldarch++;
                        break;

                case 'p':
                        f_use_protection++;
                        (void) umask(0);        /* Turn off kernel "help" */
                        break;

                case 's':
                        f_sorted_names++;       /* Names to extr are sorted */
                        break;
#ifdef MSDOS
                case 'S':
                        devsize = atoi(optarg); /* size of DOS disk drive */
                        devsize <<= 1;          /* convert K to blocks */
                        break;
#endif
                case 't':
                        f_list++;
                        break;

                case 'T':
                        name_file = optarg;
                        f_namefile++;
                        break;
#ifdef MSDOS
                case 'u':
                        addbinext(optarg);
                        break;
#endif
                case 'v':
                        f_verbose++;
                        break;
#if defined(MSDOS) && !defined(__NO_PHYS__)
                case 'V':
                        f_phys++;
                        physdrv = toupper(*optarg) - 'A';
                        if (physdrv > 4 || physdrv < 0)
                        {
                                fprintf(stderr, "tar: drive letter for -V must be A-D\n");
                                exit(EX_ARGSBAD);
                        }
                        break;
#endif /* MSDOS */

                case 'x':
                        f_extract++;
                        break;

                case 'z':                               /* Easy to type */
                case 'Z':                               /* Like the filename extension .Z */
#ifndef MSDOS
                        f_compress++;
#else
                        fprintf(stderr, "Running compress as a subprocess is not supported under DOS.\n");
                        fprintf(stderr, "Run compress separately instead, for same effect.\n");
#endif
                        break;

                default:
                case '?':
                        describe();
                        exit(EX_ARGSBAD);

                }
        }

        blocksize = blocking * RECORDSIZE;
}


/* FIXME, describe tar options here */
void describe( void )
{

        fputs("tar: valid options:\n\
-b N    blocking factor N (block size = Nx512 bytes)\n\
-B      reblock as we read (for reading 4.2BSD pipes)\n\
-c      create an archive\n\
-D      dump record number within archive with each message\n\
-f F    read/write archive from file or device F\n", stderr);
        fputs("-h       don't dump symbolic links; dump the files they point to\n\
-i      ignore blocks of zeros in the archive, which normally mean EOF\n\
-k      keep existing files, don't overwrite them from the archive\n\
-m      don't extract file modified time\n\
-o      write an old V7 format archive, rather than ANSI [draft 6] format\n\
-p      do extract all protection information\n", stderr);
#ifdef MSDOS
        fputs("-S X     device for -V option is X Kbyte drive\n", stderr);
#endif
        fputs("-s       list of names to extract is sorted to match the archive\n\
-t      list a table of contents of an archive\n\
-T F    get names to extract or create from file F\n", stderr);
#ifdef MSDOS
        fputs("\
-u X    add X to list of file extensions to be opened in BINARY mode\n\
        (use '.' to denote 'files with no extension')\n\
-V X    use drive X (X=A..D) in multivolume mode; ignore -f if present\n",
                stderr);
#endif
        fputs("\
-v      verbosely list what files we process\n\
-x      extract files from an archive\n", stderr);
#ifndef MSDOS

        /*
         * regrettably, DOS doesn't have real pipes, just artificial shell-level
         * ones.  It is better to just use those.
         */
        fputs("\
-z or Z run the archive through compress(1)\n", stderr);
#endif
}


/*
 * Set up to gather file names for tar.
 *
 * They can either come from stdin or from argv.
 */
static void name_init( int argc, char **argv )
{
    if (f_namefile) {
        if (optind < argc) {
            fprintf(stderr, "tar: too many args with -T option\n");
            exit(EX_ARGSBAD);
        }
        if (!strcmp(name_file, "-")) {
            namef = stdin;
        } else {
            namef = fopen(name_file, "r");
            if (namef == NULL) {
                fprintf(stderr, "tar: ");
                perror(name_file);
                exit(EX_BADFILE);
            }
        }
    } else {
        /* Get file names from argv, after options. */
        n_argc = argc;
        n_argv = argv;
    }
}

/*
 * Name translation function for MS-DOS support; can also be
 * extended via #ifdef for other os's.
 *
 * Convert a name to one suitable to this OS.  If this can't be done
 * automatically, let the user choose a name.
 *
 * The user prompting is done only if stdin isatty.
 *
 * It is important to understand the name translation, which occurs
 * in two steps.  First, the actual name string passed in s is modified
 * in place to change case and direction of slashes, because DOS's
 * directory routines return uppercase names with backslashes, which
 * are not suitable for Unix.  This changes the string into a unix-like
 * filename.  Second, this string is copied into a local buffer and
 * transformed, if necessary, into a filename that is syntactically

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?