📄 extract.c
字号:
/* Extract files from a tar archive. Copyright (C) 1988 Free Software FoundationThis file is part of GNU Tar.GNU Tar is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Tar; see the file COPYING. If not, write tothe 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"#endifextern 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 (f_do_chown || 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. */voidextract_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++) { if (!head->header.sp[i].numbytes) break; sparsearray[i].offset = from_oct(1+12, head->header.sp[i].offset); sparsearray[i].numbytes = from_oct(1+12, head->header.sp[i].numbytes); } /* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -