extract.c

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

C
420
字号
/****************************************************************************
*
*                            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:  Extract files from a tar archive.
*
****************************************************************************/


/*
 * Extract files from a tar archive.
 *
 * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
 * MS-DOS port 2/87 by Eric Roskos.
 * Minix  port 3/88 by Eric Roskos.
 *
 * @(#) extract.c 1.17 86/10/29 Public Domain - gnu
 */

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <direct.h>
#include <process.h>
#include <sys/utime.h>
#include <time.h>

#ifdef BSD42
#include <sys/file.h>
#endif

#ifdef USG
#include <fcntl.h>
#endif

#include "tar.h"
#include "list.h"
#include "buffer.h"
#include "port.h"


static time_t          now = 0;                /* Current time */

/*
 * After a file/link/symlink/dir creation has failed, see if
 * it's because some required directory was not present, and if
 * so, create all required dirs.
 */
int make_dirs( char *pathname, int uid, int gid) /* added -- JER */
{
    char    *p;                      /* Points into path */
    int     madeone = 0;/* Did we do anything yet? */
    int     save_errno = errno;     /* Remember caller's errno */
    int     check;

    if (errno != ENOENT)
        return 0;                               /* Not our problem */

    for (p = index(pathname, '/'); p != NULL; p = index(p + 1, '/')) {
        /* Avoid mkdir of empty string, if leading or double '/' */
        if (p == pathname || p[-1] == '/')
            continue;
        /* Avoid mkdir where last part of path is '.' */
        if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/'))
            continue;
        *p = 0;                                 /* Truncate the path there */
#ifdef MSDOS
        check = mkdir(pathname);  /* Try to create it as a dir */
#else
        check = mkdir(pathname, 0777);  /* Try to create it as a dir */
#endif
        *p = '/';
        if (check == 0) {
#ifndef MSDOS
            /* chown, chgrp it same as file being created */
            chown(pathname, uid, gid);      /* JER */
#endif
            /* FIXME, show mode as modified by current umask */
            pr_mkdir(pathname, p - pathname, 0777);
            madeone++;                      /* Remember if we made one */
            continue;
        }
        if (errno == EEXIST)    /* Directory already exists */
            continue;
#ifdef MSDOS
        if (errno == EACCES)    /* DOS version of 'already exists' */
                continue;
#endif
        /*
        * Some other error in the mkdir.  We return to the caller.
        */
        break;
    }

    errno = save_errno;                     /* Restore caller's errno */
    return madeone;                         /* Tell them to retry if we made one */
}

/*
 * Extract a file from the archive.
 * Note: xname is the "fixed name" which is supposed to be acceptable
 * to the OS.  We use this instead of the name in the header, but only
 * if we're actually creating a data file.
 */
void extract_archive( char *xname )
{
        char    *data;
        int     fd, check, namelen, written;
        long    size;
        int     standard;       /* Is header standard? */
        struct  utimbuf  acc_upd_times;
        struct  stat     st;

        saverec(&head);                         /* Make sure it sticks around */
        userec(head);                           /* And go past it in the archive */
        decode_header(head, hstat, &standard, 1);       /* Snarf fields */

        /* Print the record from 'head' and 'hstat' */
        if (f_verbose)
                print_header(xname);

        switch (head->header.linkflag)
        {

        default:
                annofile(stderr, tar);
                fprintf(stderr, "Unknown file type %d for %s\n",
                        head->header.linkflag, head->header.name);
                /* FALL THRU */

        case LF_OLDNORMAL:
        case LF_NORMAL:

                /*
                 * Appears to be a file. See if it's really a directory.
                 */
                namelen = strlen(head->header.name) - 1;
                if (head->header.name[namelen] == '/')
                        goto really_dir;

                /* FIXME, deal with protection issues */
                /* FIXME, f_keep doesn't work on V7, st_mode loses too */
again_file:
#ifdef V7
                fd = creat(xname, phstat->st_mode);
#else
                fd = open( /* head->header.name */ xname,
                        f_keep ?
                        O_NDELAY | O_WRONLY | O_APPEND | O_CREAT |
                        O_EXCL | convmode(xname) :
                        O_NDELAY | O_WRONLY | O_APPEND | O_CREAT | O_TRUNC |
                        convmode(xname),
                        phstat->st_mode);
#endif
                if (fd < 0)
                {
                        if (make_dirs(head->header.name,        /* use original name here */
                                from_oct(8, head->header.uid),
                                from_oct(8, head->header.gid))) /* added uid/gid - JER */
                                goto again_file;
                        annofile(stderr, tar);
                        fprintf(stderr, "Could not make file ");
                        perror( /* head->header.name */ xname);
                        skip_file((long) phstat->st_size);
                        goto quit;
                }

                for (size = phstat->st_size;
                        size > 0;
                        size -= written)
                {

                        /*
                         * Locate data, determine max length writeable, write it, record
                         * that we have used the data, then check if the write worked.
                         */
                        data = findrec()->charptr;
                        written = endofrecs()->charptr - data;
                        if (written > size)
                                written = size;
                        errno = 0;
                        check = write(fd, data, written);

                        /*
                         * The following is in violation of strict typing, since the arg

⌨️ 快捷键说明

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