⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 extract.c

📁 unix 下tar 执行程序的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Extract files from a tar archive.
   Copyright (C) 1988 Free Software Foundation

This file is part of GNU Tar.

GNU Tar is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GNU Tar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Tar; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/*
 * Extract files from a tar archive.
 *
 * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
 *
 * @(#) extract.c 1.32 87/11/11 - gnu
 */

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

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

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

#ifdef	MSDOS
#include <fcntl.h>
#endif	/* MSDOS */

/*
 * Some people don't have a #define for these.
 */
#ifndef	O_BINARY
#define	O_BINARY	0
#endif
#ifndef O_NDELAY
#define	O_NDELAY	0
#endif

#ifdef NO_OPEN3
/* We need the #define's even though we don't use them. */
#include "open3.h"
#endif

#ifdef EMUL_OPEN3
/* Simulated 3-argument open for systems that don't have it */
#include "open3.h"
#endif

extern int errno;			/* From libc.a */
extern time_t time();			/* From libc.a */
extern char *index();			/* From libc.a or port.c */

#include "tar.h"
#include "port.h"

extern FILE *msg_file;

extern union record *head;		/* Points to current tape header */
extern struct stat hstat;		/* Stat struct corresponding */
extern int head_standard;		/* Tape header is in ANSI format */

extern char *save_name;
extern long save_totsize;
extern long save_sizeleft;

extern void print_header();
extern void skip_file();
extern void skip_extended_headers();
extern void pr_mkdir();

int make_dirs();			/* Makes required directories */

static time_t now = 0;			/* Current time */
static we_are_root = 0;			/* True if our effective uid == 0 */
static int notumask = ~0;		/* Masks out bits user doesn't want */

/*
 * "Scratch" space to store the information about a sparse file before
 * writing the info into the header or extended header
 */
/*struct sp_array	*sparsearray;*/

/* number of elts storable in the sparsearray */
/*int	sp_array_size = 10;*/

/*
 * Set up to extract files.
 */
extr_init()
{
	int ourmask;

	now = time((time_t *)0);
	if (geteuid() == 0)
		we_are_root = 1;

	/*
	 * We need to know our umask.  But if f_use_protection is set,
	 * leave our kernel umask at 0, and our "notumask" at ~0.
	 */
	ourmask = umask(0);		/* Read it */
	if (!f_use_protection) {
		(void) umask (ourmask);	/* Set it back how it was */
		notumask = ~ourmask;	/* Make umask override permissions */
	}
}


/*
 * Extract a file from the archive.
 */
void
extract_archive()
{
	register char *data;
	int fd, check, namelen, written, openflag;
	long size;
	time_t acc_upd_times[2];
	register int skipcrud;
	register int i;
	int sparse_ind = 0;
	union record *exhdr;	
	int end_nulls;
	
	saverec(&head);			/* Make sure it sticks around */
	userec(head);			/* And go past it in the archive */
	decode_header(head, &hstat, &head_standard, 1);	/* Snarf fields */

	if(f_confirm && !confirm("extract",head->header.name)) {
		if (head->header.isextended)
			skip_extended_headers();
		skip_file((long)hstat.st_size);
		saverec((union record **)0);
		return;
	}

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

	/*
	 * Check for fully specified pathnames and other atrocities.
	 *
	 * Note, we can't just make a pointer to the new file name,
	 * since saverec() might move the header and adjust "head".
	 * We have to start from "head" every time we want to touch
	 * the header record.
	 */
	skipcrud = 0;
	while (!f_absolute_paths && '/' == head->header.name[skipcrud]) {
		static int warned_once = 0;

		skipcrud++;	/* Force relative path */
		if (!warned_once++) {
			msg("Removing leading / from absolute path names in the archive.");
		}
	}

	switch (head->header.linkflag) {

	default:
		msg("Unknown file type '%c' for %s, extracted as normal file",
			head->header.linkflag, skipcrud+head->header.name);
		/* FALL THRU */

	/* 
	 * JK - What we want to do if the file is sparse is loop through
	 * the array of sparse structures in the header and read in
	 * and translate the character strings representing  1) the offset
	 * at which to write and 2) how many bytes to write into numbers,
	 * which we store into the scratch array, "sparsearray".  This
	 * array makes our life easier the same way it did in creating
	 * the tar file that had to deal with a sparse file.
	 *
	 * After we read in the first five (at most) sparse structures,
	 * we check to see if the file has an extended header, i.e., 
	 * if more sparse structures are needed to describe the contents
	 * of the new file.  If so, we read in the extended headers
	 * and continue to store their contents into the sparsearray.
	 */
	case LF_SPARSE:
		sp_array_size = 10;
		sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
		for (i = 0; i < SPARSE_IN_HDR; i++) {
			sparsearray[i].offset = 
				from_oct(1+12, head->header.sp[i].offset);
			sparsearray[i].numbytes = 
				from_oct(1+12, head->header.sp[i].numbytes);
			if (!sparsearray[i].numbytes)
				break;
		}
		
/*		end_nulls = from_oct(1+12, head->header.ending_blanks);*/
		
		if (head->header.isextended) {
			/* read in the list of extended headers
			   and translate them into the sparsearray 
			   as before */

			/* static */ int ind = SPARSE_IN_HDR;
			
			for (;;) {
				
				exhdr = findrec();
				for (i = 0; i < SPARSE_EXT_HDR; i++) {
					
					if (i+ind > sp_array_size-1) {
					/*
					 * realloc the scratch area
					 * since we've run out of room --
		 			 */
						sparsearray = (struct sp_array *) 
								realloc(sparsearray,
 								2 * sp_array_size * (sizeof(struct sp_array)));
						sp_array_size *= 2;
					}
					if (!exhdr->ext_hdr.sp[i].numbytes)
						break;
					sparsearray[i+ind].offset = 
						from_oct(1+12, exhdr->ext_hdr.sp[i].offset);
					sparsearray[i+ind].numbytes = 
						from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes);
				}
				if (!exhdr->ext_hdr.isextended) 
					break;
				else {
					ind += SPARSE_EXT_HDR;
					userec(exhdr);
				}
			}
			userec(exhdr);
		}
		
		/* FALL THRU */
	case LF_OLDNORMAL:
	case LF_NORMAL:
	case LF_CONTIG:
		/*
		 * Appears to be a file.
		 * See if it's really a directory.
		 */
		namelen = strlen(skipcrud+head->header.name)-1;
		if (head->header.name[skipcrud+namelen] == '/')
			goto really_dir;

		/* FIXME, deal with protection issues */
	again_file:
		openflag = (f_keep?
			O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL:
			O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC)
			| ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);			
			/*
			 * JK - The last | is a kludge to solve the problem
			 * the O_APPEND flag  causes with files we are
			 * trying to make sparse:  when a file is opened
			 * with O_APPEND, it writes  to the last place
			 * that something was written, thereby ignoring
			 * any lseeks that we have done.  We add this
			 * extra condition to make it able to lseek when
			 * a file is sparse, i.e., we don't open the new
			 * file with this flag.  (Grump -- this bug caused
			 * me to waste a good deal of time, I might add)
  			 */

		if(f_exstdout) {
			fd = 1;
			goto extract_file;
		}
#ifdef O_CTG
		/*
		 * Contiguous files (on the Masscomp) have to specify
		 * the size in the open call that creates them.
		 */
		if (head->header.linkflag == LF_CONTIG)
			fd = open(skipcrud+head->header.name, openflag | O_CTG,
				hstat.st_mode, hstat.st_size);
		else
#endif
		{
#ifdef NO_OPEN3
			/*
			 * On raw V7 we won't let them specify -k (f_keep), but
			 * we just bull ahead and create the files.
			 */
			fd = creat(skipcrud+head->header.name, 
				hstat.st_mode);
#else
			/*
			 * With 3-arg open(), we can do this up right.
			 */
			fd = open(skipcrud+head->header.name, openflag,
				hstat.st_mode);
#endif
		}

		if (fd < 0) {
			if (make_dirs(skipcrud+head->header.name))
				goto again_file;
			msg_perror("Could not create file %s",skipcrud+head->header.name);
			if (head->header.isextended)
				skip_extended_headers();
			skip_file((long)hstat.st_size);
			goto quit;
		}

	extract_file:
		if (head->header.linkflag == LF_SPARSE) {
			char	*name;
			int	namelen;

			/*
			 * Kludge alert.  NAME is assigned to header.name
			 * because during the extraction, the space that
			 * contains the header will get scribbled on, and
			 * the name will get munged, so any error messages
			 * that happen to contain the filename will look
			 * REAL interesting unless we do this.
			 */
			namelen = strlen(skipcrud+head->header.name);
			name = (char *) malloc((sizeof(char)) * namelen);
			bcopy(skipcrud+head->header.name, name, namelen);
			size = hstat.st_size;
			extract_sparse_file(fd, &size, hstat.st_size,
 						name);
		}			
		else 		
		  for (size = hstat.st_size;
		       size > 0;
		       size -= written) {

			long	offset,
 				numbytes;

			if(f_multivol) {
				save_name=head->header.name;
				save_totsize=hstat.st_size;
				save_sizeleft=size;
			}
			
			/*
			 * Locate data, determine max length
			 * writeable, write it, record that
			 * we have used the data, then check
			 * if the write worked.
			 */
			data = findrec()->charptr;
			if (data == NULL) {	/* Check it... */
				msg("Unexpected EOF on archive file");
				break;
			}
			/*
			 * JK - If the file is sparse, use the sparsearray
			 * that we created before to lseek into the new
			 * file the proper amount, and to see how many
			 * bytes we want to write at that position.
			 */

⌨️ 快捷键说明

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