📄 untar.c
字号:
/* untar.c *//*#define VERSION "1.4"*//* DESCRIPTION: * Untar extracts files from an uncompressed tar archive, or one which * has been compressed with gzip. Usually such archives will have file * names that end with ".tar" or ".tgz" respectively, although untar * doesn't depend on any naming conventions. For a summary of the * command-line options, run untar with no arguments. * * HOW TO COMPILE: * Untar doesn't require any special libraries or compile-time flags. * A simple "cc untar.c -o untar" (or the local equivalent) is * sufficient. Even "make untar" works, without needing a Makefile. * For Microsoft Visual C++, the command is "cl /D_WEAK_POSIX untar.c" * (for 32 bit compilers) or "cl /F 1400 untar.c" (for 16-bit). * * IF YOU SEE COMPILER WARNINGS, THAT'S NORMAL; you can ignore them. * Most of the warnings could be eliminated by adding #include <string.h> * but that isn't portable -- some systems require <strings.h> and * <malloc.h>, for example. Because <string.h> isn't quite portable, * and isn't really necessary in the context of this program, it isn't * included. * * PORTABILITY: * Untar only requires the <stdio.h> header. It uses old-style function * definitions. It opens all files in binary mode. Taken together, * this means that untar should compile & run on just about anything. * * If your system supports the POSIX chmod(2), utime(2), link(2), and * symlink(2) calls, then you may wish to compile with -D_POSIX_SOURCE, * which will enable untar to use those system calls to restore the * timestamp and permissions of the extracted files, and restore links. * (For Linux, _POSIX_SOURCE is always defined.) * * For systems which support some POSIX features but not enough to support * -D_POSIX_SOURCE, you might be able to use -D_WEAK_POSIX. This allows * untar to restore time stamps and file permissions, but not links. * This should work for Microsoft systems, and hopefully others as well. * * AUTHOR & COPYRIGHT INFO: * Written by Steve Kirkendall, kirkenda@cs.pdx.edu * Placed in public domain, 6 October 1995 * * Portions derived from inflate.c -- Not copyrighted 1992 by Mark Adler * version c10p1, 10 January 1993 * * Altered by Herman Bloggs <hermanator12002@yahoo.com> * April 4, 2003 * Changes: Stripped out gz compression code, added better interface for * untar. */#include <windows.h>#include <stdio.h>#include <io.h>#include <string.h>#include <stdlib.h>#ifndef SEEK_SET# define SEEK_SET 0#endif#ifdef _WEAK_POSIX# ifndef _POSIX_SOURCE# define _POSIX_SOURCE# endif#endif#ifdef _POSIX_SOURCE# include <sys/types.h># include <sys/stat.h># include <sys/utime.h># ifdef _WEAK_POSIX# define mode_t int# else# include <unistd.h># endif#endif#include "debug.h"#include "untar.h"#include <glib.h>#if GLIB_CHECK_VERSION(2,6,0)# include <glib/gstdio.h>#else#define mkdir(a,b) _mkdir((a))#define g_mkdir mkdir#define g_fopen fopen#define g_unlink unlink#endif#define untar_error( error, args... ) purple_debug(PURPLE_DEBUG_ERROR, "untar", error, ## args )#define untar_warning( warning, args... ) purple_debug(PURPLE_DEBUG_WARNING, "untar", warning, ## args )#define untar_verbose( args... ) purple_debug(PURPLE_DEBUG_INFO, "untar", ## args ) #define WSIZE 32768 /* size of decompression buffer */#define TSIZE 512 /* size of a "tape" block */#define CR 13 /* carriage-return character */#define LF 10 /* line-feed character */typedef unsigned char Uchar_t;typedef unsigned short Ushort_t;typedef unsigned long Ulong_t;typedef struct{ char filename[100]; /* 0 name of next file */ char mode[8]; /* 100 Permissions and type (octal digits) */ char owner[8]; /* 108 Owner ID (ignored) */ char group[8]; /* 116 Group ID (ignored) */ char size[12]; /* 124 Bytes in file (octal digits) */ char mtime[12]; /* 136 Modification time stamp (octal digits)*/ char checksum[8]; /* 148 Header checksum (ignored) */ char type; /* 156 File type (see below) */ char linkto[100]; /* 157 Linked-to name */ char brand[8]; /* 257 Identifies tar version (ignored) */ char ownername[32]; /* 265 Name of owner (ignored) */ char groupname[32]; /* 297 Name of group (ignored) */ char devmajor[8]; /* 329 Device major number (ignored) */ char defminor[8]; /* 337 Device minor number (ignored) */ char prefix[155]; /* 345 Prefix of name (optional) */ char RESERVED[12]; /* 500 Pad header size to 512 bytes */} tar_t;#define ISREGULAR(hdr) ((hdr).type < '1' || (hdr).type > '6')Uchar_t slide[WSIZE];static const char *inname = NULL; /* name of input archive */static FILE *infp = NULL; /* input byte stream */static FILE *outfp = NULL; /* output stream, for file currently being extracted */static Ulong_t outsize = 0; /* number of bytes remainin in file currently being extracted */static char **only = NULL; /* array of filenames to extract/list */static int nonlys = 0; /* number of filenames in "only" array; 0=extract all */static int didabs = 0; /* were any filenames affected by the absence of -p? */static untar_opt untarops = 0; /* Untar options *//* Options checked during untar process */#define LISTING (untarops & UNTAR_LISTING) /* 1 if listing, 0 if extracting */#define QUIET (untarops & UNTAR_QUIET) /* 1 to write nothing to stdout, 0 for normal chatter */#define VERBOSE (untarops & UNTAR_VERBOSE) /* 1 to write extra information to stdout */#define FORCE (untarops & UNTAR_FORCE) /* 1 to overwrite existing files, 0 to skip them */#define ABSPATH (untarops & UNTAR_ABSPATH) /* 1 to allow leading '/', 0 to strip leading '/' */#define CONVERT (untarops & UNTAR_CONVERT) /* 1 to convert newlines, 0 to leave unchanged *//*----------------------------------------------------------------------------*//* create a file for writing. If necessary, create the directories leading up * to that file as well. */static FILE *createpath(name) char *name; /* pathname of file to create */{ FILE *fp; int i; /* if we aren't allowed to overwrite and this file exists, return NULL */ if (!FORCE && access(name, 0) == 0) { untar_warning("%s: exists, will not overwrite without \"FORCE option\"\n", name); return NULL; } /* first try creating it the easy way */ fp = g_fopen(name, CONVERT ? "w" : "wb"); if (fp) return fp; /* Else try making all of its directories, and then try creating * the file again. */ for (i = 0; name[i]; i++) { /* If this is a slash, then temporarily replace the '/' * with a '\0' and do a mkdir() on the resulting string. * Ignore errors for now. */ if (name[i] == '/') { name[i] = '\0'; (void)g_mkdir(name, 0777); name[i] = '/'; } } fp = g_fopen(name, CONVERT ? "w" : "wb"); if (!fp) untar_error("Error opening: %s\n", name); return fp;}/* Create a link, or copy a file. If the file is copied (not linked) then * give a warning. */static void linkorcopy(src, dst, sym) char *src; /* name of existing source file */ char *dst; /* name of new destination file */ int sym; /* use symlink instead of link */{ FILE *fpsrc; FILE *fpdst; int c; /* Open the source file. We do this first to make sure it exists */ fpsrc = g_fopen(src, "rb"); if (!fpsrc) { untar_error("Error opening: %s\n", src); return; } /* Create the destination file. On POSIX systems, this is just to * make sure the directory path exists. */ fpdst = createpath(dst); if (!fpdst) /* error message already given */ return;#ifdef _POSIX_SOURCE# ifndef _WEAK_POSIX /* first try to link it over, instead of copying */ fclose(fpdst); g_unlink(dst); if (sym) { if (symlink(src, dst)) { perror(dst); } fclose(fpsrc); return; } if (!link(src, dst)) { /* This story had a happy ending */ fclose(fpsrc); return; } /* Dang. Reopen the destination again */ fpdst = g_fopen(dst, "wb"); /* This *can't* fail */# endif /* _WEAK_POSIX */#endif /* _POSIX_SOURCE */ /* Copy characters */ while ((c = getc(fpsrc)) != EOF) putc(c, fpdst); /* Close the files */ fclose(fpsrc); fclose(fpdst); /* Give a warning */ untar_warning("%s: copy instead of link\n", dst);}/* This calls fwrite(), possibly after converting CR-LF to LF */static void cvtwrite(blk, size, fp) Uchar_t *blk; /* the block to be written */ Ulong_t size; /* number of characters to be written */ FILE *fp; /* file to write to */{ int i, j; static Uchar_t mod[TSIZE]; if (CONVERT) { for (i = j = 0; i < size; i++) { /* convert LF to local newline convention */ if (blk[i] == LF) mod[j++] = '\n'; /* If CR-LF pair, then delete the CR */ else if (blk[i] == CR && (i+1 >= size || blk[i+1] == LF)) ; /* other characters copied literally */ else mod[j++] = blk[i]; } size = j; blk = mod; } fwrite(blk, (size_t)size, sizeof(Uchar_t), fp);}/* Compute the checksum of a tar header block, and return it as a long int. * The checksum can be computed using either POSIX rules (unsigned bytes) * or Sun rules (signed bytes). */static long checksum(tblk, sunny) tar_t *tblk; /* buffer containing the tar header block */ int sunny; /* Boolean: Sun-style checksums? (else POSIX) */{ long sum; char *scan; /* compute the sum of the first 148 bytes -- everything up to but not * including the checksum field itself. */ sum = 0L; for (scan = (char *)tblk; scan < tblk->checksum; scan++) { sum += (*scan) & 0xff; if (sunny && (*scan & 0x80) != 0) sum -= 256; } /* for the 8 bytes of the checksum field, add blanks to the sum */ sum += ' ' * sizeof tblk->checksum; scan += sizeof tblk->checksum; /* finish counting the sum of the rest of the block */ for (; scan < (char *)tblk + sizeof *tblk; scan++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -