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 + -
显示快捷键?