X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=zlib%2Fcontrib%2Funtgz%2Funtgz.c;fp=zlib%2Fcontrib%2Funtgz%2Funtgz.c;h=2c391e5986753de7b6d9eeccfe919d543698925f;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=4a431ff3163f8735246a92237e4321363af55502;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/zlib/contrib/untgz/untgz.c b/zlib/contrib/untgz/untgz.c index 4a431ff3..2c391e59 100644 --- a/zlib/contrib/untgz/untgz.c +++ b/zlib/contrib/untgz/untgz.c @@ -1,8 +1,9 @@ /* - * untgz.c -- Display contents and/or extract file from - * a gzip'd TAR file - * written by "Pedro A. Aranda Guti\irrez" + * untgz.c -- Display contents and extract files from a gzip'd TAR file + * + * written by Pedro A. Aranda Gutierrez * adaptation to Unix by Jean-loup Gailly + * various fixes by Cosmin Truta */ #include @@ -10,204 +11,317 @@ #include #include #include -#include + +#include "zlib.h" + #ifdef unix -# include +# include #else -# include -# include +# include +# include #endif -#include "zlib.h" - #ifdef WIN32 +#include # ifndef F_OK -# define F_OK (0) +# define F_OK 0 # endif +# define mkdir(dirname,mode) _mkdir(dirname) # ifdef _MSC_VER -# define mkdir(dirname,mode) _mkdir(dirname) -# define strdup(str) _strdup(str) -# define unlink(fn) _unlink(fn) # define access(path,mode) _access(path,mode) -# else -# define mkdir(dirname,mode) _mkdir(dirname) +# define chmod(path,mode) _chmod(path,mode) +# define strdup(str) _strdup(str) # endif #else # include #endif -/* Values used in typeflag field. */ +/* values used in typeflag field */ + +#define REGTYPE '0' /* regular file */ +#define AREGTYPE '\0' /* regular file */ +#define LNKTYPE '1' /* link */ +#define SYMTYPE '2' /* reserved */ +#define CHRTYPE '3' /* character special */ +#define BLKTYPE '4' /* block special */ +#define DIRTYPE '5' /* directory */ +#define FIFOTYPE '6' /* FIFO special */ +#define CONTTYPE '7' /* reserved */ + +/* GNU tar extensions */ -#define REGTYPE '0' /* regular file */ -#define AREGTYPE '\0' /* regular file */ -#define LNKTYPE '1' /* link */ -#define SYMTYPE '2' /* reserved */ -#define CHRTYPE '3' /* character special */ -#define BLKTYPE '4' /* block special */ -#define DIRTYPE '5' /* directory */ -#define FIFOTYPE '6' /* FIFO special */ -#define CONTTYPE '7' /* reserved */ +#define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */ +#define GNUTYPE_LONGLINK 'K' /* long link name */ +#define GNUTYPE_LONGNAME 'L' /* long file name */ +#define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */ +#define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */ +#define GNUTYPE_SPARSE 'S' /* sparse file */ +#define GNUTYPE_VOLHDR 'V' /* tape/volume header */ -#define BLOCKSIZE 512 + +/* tar header */ + +#define BLOCKSIZE 512 +#define SHORTNAMESIZE 100 struct tar_header -{ /* byte offset */ - char name[100]; /* 0 */ - char mode[8]; /* 100 */ - char uid[8]; /* 108 */ - char gid[8]; /* 116 */ - char size[12]; /* 124 */ - char mtime[12]; /* 136 */ - char chksum[8]; /* 148 */ - char typeflag; /* 156 */ - char linkname[100]; /* 157 */ - char magic[6]; /* 257 */ - char version[2]; /* 263 */ - char uname[32]; /* 265 */ - char gname[32]; /* 297 */ - char devmajor[8]; /* 329 */ - char devminor[8]; /* 337 */ - char prefix[155]; /* 345 */ - /* 500 */ +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ }; -union tar_buffer { +union tar_buffer +{ char buffer[BLOCKSIZE]; struct tar_header header; }; -enum { TGZ_EXTRACT = 0, TGZ_LIST }; +struct attr_item +{ + struct attr_item *next; + char *fname; + int mode; + time_t time; +}; + +enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; -static char *TGZfname OF((const char *)); -void TGZnotfound OF((const char *)); +char *TGZfname OF((const char *)); +void TGZnotfound OF((const char *)); -int getoct OF((char *, int)); -char *strtime OF((time_t *)); -int ExprMatch OF((char *,char *)); +int getoct OF((char *, int)); +char *strtime OF((time_t *)); +int setfiletime OF((char *, time_t)); +void push_attr OF((struct attr_item **, char *, int, time_t)); +void restore_attr OF((struct attr_item **)); -int makedir OF((char *)); -int matchname OF((int,int,char **,char *)); +int ExprMatch OF((char *, char *)); -void error OF((const char *)); -int tar OF((gzFile, int, int, int, char **)); +int makedir OF((char *)); +int matchname OF((int, int, char **, char *)); -void help OF((int)); -int main OF((int, char **)); +void error OF((const char *)); +int tar OF((gzFile, int, int, int, char **)); -char *prog; +void help OF((int)); +int main OF((int, char **)); -/* This will give a benign warning */ +char *prog; -static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", ".tar", NULL }; +const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL }; -/* Return the real name of the TGZ archive */ -/* or NULL if it does not exist. */ +/* return the file name of the TGZ archive */ +/* or NULL if it does not exist */ -static char *TGZfname OF((const char *fname)) +char *TGZfname (const char *arcname) { static char buffer[1024]; int origlen,i; - - strcpy(buffer,fname); + + strcpy(buffer,arcname); origlen = strlen(buffer); - for (i=0; TGZprefix[i]; i++) + for (i=0; TGZsuffix[i]; i++) { - strcpy(buffer+origlen,TGZprefix[i]); + strcpy(buffer+origlen,TGZsuffix[i]); if (access(buffer,F_OK) == 0) return buffer; } return NULL; } + /* error message for the filename */ -void TGZnotfound OF((const char *fname)) +void TGZnotfound (const char *arcname) { int i; - fprintf(stderr,"%s : couldn't find ",prog); - for (i=0;TGZprefix[i];i++) - fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n", - fname, - TGZprefix[i]); + fprintf(stderr,"%s: Couldn't find ",prog); + for (i=0;TGZsuffix[i];i++) + fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n", + arcname, + TGZsuffix[i]); exit(1); } -/* help functions */ +/* convert octal digits to int */ +/* on error return -1 */ -int getoct(char *p,int width) +int getoct (char *p,int width) { int result = 0; char c; - - while (width --) + + while (width--) { c = *p++; - if (c == ' ') - continue; if (c == 0) - break; + break; + if (c == ' ') + continue; + if (c < '0' || c > '7') + return -1; result = result * 8 + (c - '0'); } return result; } + +/* convert time_t to string */ +/* use the "YYYY/MM/DD hh:mm:ss" format */ + char *strtime (time_t *t) { struct tm *local; static char result[32]; local = localtime(t); - sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d", - local->tm_mday, local->tm_mon+1, local->tm_year+1900, - local->tm_hour, local->tm_min, local->tm_sec); + sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d", + local->tm_year+1900, local->tm_mon+1, local->tm_mday, + local->tm_hour, local->tm_min, local->tm_sec); return result; } -/* regular expression matching */ +/* set file time */ + +int setfiletime (char *fname,time_t ftime) +{ +#ifdef WIN32 + static int isWinNT = -1; + SYSTEMTIME st; + FILETIME locft, modft; + struct tm *loctm; + HANDLE hFile; + int result; + + loctm = localtime(&ftime); + if (loctm == NULL) + return -1; + + st.wYear = (WORD)loctm->tm_year + 1900; + st.wMonth = (WORD)loctm->tm_mon + 1; + st.wDayOfWeek = (WORD)loctm->tm_wday; + st.wDay = (WORD)loctm->tm_mday; + st.wHour = (WORD)loctm->tm_hour; + st.wMinute = (WORD)loctm->tm_min; + st.wSecond = (WORD)loctm->tm_sec; + st.wMilliseconds = 0; + if (!SystemTimeToFileTime(&st, &locft) || + !LocalFileTimeToFileTime(&locft, &modft)) + return -1; + + if (isWinNT < 0) + isWinNT = (GetVersion() < 0x80000000) ? 1 : 0; + hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0), + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return -1; + result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1; + CloseHandle(hFile); + return result; +#else + struct utimbuf settime; + + settime.actime = settime.modtime = ftime; + return utime(fname,&settime); +#endif +} + + +/* push file attributes */ + +void push_attr(struct attr_item **list,char *fname,int mode,time_t time) +{ + struct attr_item *item; + + item = (struct attr_item *)malloc(sizeof(struct attr_item)); + if (item == NULL) + error("Out of memory"); + item->fname = strdup(fname); + item->mode = mode; + item->time = time; + item->next = *list; + *list = item; +} + + +/* restore file attributes */ + +void restore_attr(struct attr_item **list) +{ + struct attr_item *item, *prev; + + for (item = *list; item != NULL; ) + { + setfiletime(item->fname,item->time); + chmod(item->fname,item->mode); + prev = item; + item = item->next; + free(prev); + } + *list = NULL; +} + + +/* match regular expression */ #define ISSPECIAL(c) (((c) == '*') || ((c) == '/')) -int ExprMatch(char *string,char *expr) +int ExprMatch (char *string,char *expr) { while (1) { if (ISSPECIAL(*expr)) - { - if (*expr == '/') - { - if (*string != '\\' && *string != '/') - return 0; - string ++; expr++; - } - else if (*expr == '*') - { - if (*expr ++ == 0) - return 1; - while (*++string != *expr) - if (*string == 0) - return 0; - } - } + { + if (*expr == '/') + { + if (*string != '\\' && *string != '/') + return 0; + string ++; expr++; + } + else if (*expr == '*') + { + if (*expr ++ == 0) + return 1; + while (*++string != *expr) + if (*string == 0) + return 0; + } + } else - { - if (*string != *expr) - return 0; - if (*expr++ == 0) - return 1; - string++; - } + { + if (*string != *expr) + return 0; + if (*expr++ == 0) + return 1; + string++; + } } } -/* recursive make directory */ -/* abort if you get an ENOENT errno somewhere in the middle */ -/* e.g. ignore error "mkdir on existing directory" */ -/* */ + +/* recursive mkdir */ +/* abort on ENOENT; ignore other errors like "directory already exists" */ /* return 1 if OK */ /* 0 on error */ @@ -216,7 +330,7 @@ int makedir (char *newdir) char *buffer = strdup(newdir); char *p; int len = strlen(buffer); - + if (len <= 0) { free(buffer); return 0; @@ -224,7 +338,7 @@ int makedir (char *newdir) if (buffer[len-1] == '/') { buffer[len-1] = '\0'; } - if (mkdir(buffer, 0775) == 0) + if (mkdir(buffer, 0755) == 0) { free(buffer); return 1; @@ -234,28 +348,29 @@ int makedir (char *newdir) while (1) { char hold; - + while(*p && *p != '\\' && *p != '/') - p++; + p++; hold = *p; *p = 0; - if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT)) - { - fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer); - free(buffer); - return 0; - } + if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT)) + { + fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer); + free(buffer); + return 0; + } if (hold == 0) - break; + break; *p++ = hold; } free(buffer); return 1; } + int matchname (int arg,int argc,char **argv,char *fname) { - if (arg == argc) /* no arguments given (untgz tgzarchive) */ + if (arg == argc) /* no arguments given (untgz tgzarchive) */ return 1; while (arg < argc) @@ -266,7 +381,7 @@ int matchname (int arg,int argc,char **argv,char *fname) } -/* Tar file list or extract */ +/* tar file list or extract */ int tar (gzFile in,int action,int arg,int argc,char **argv) { @@ -277,145 +392,183 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) int remaining = 0; FILE *outfile = NULL; char fname[BLOCKSIZE]; + int tarmode; time_t tartime; - + struct attr_item *attributes = NULL; + if (action == TGZ_LIST) - printf(" day time size file\n" - " ---------- -------- --------- -------------------------------------\n"); + printf(" date time size file\n" + " ---------- -------- --------- -------------------------------------\n"); while (1) { len = gzread(in, &buffer, BLOCKSIZE); if (len < 0) - error (gzerror(in, &err)); + error(gzerror(in, &err)); /* * Always expect complete blocks to process * the tar information. */ if (len != BLOCKSIZE) - error("gzread: incomplete block read"); - + { + action = TGZ_INVALID; /* force error exit */ + remaining = 0; /* force I/O cleanup */ + } + /* * If we have to get a tar header */ - if (getheader == 1) - { - /* - * if we met the end of the tar - * or the end-of-tar block, - * we are done - */ - if ((len == 0) || (buffer.header.name[0]== 0)) break; - - tartime = (time_t)getoct(buffer.header.mtime,12); - strcpy(fname,buffer.header.name); - - switch (buffer.header.typeflag) - { - case DIRTYPE: - if (action == TGZ_LIST) - printf(" %s %s\n",strtime(&tartime),fname); - if (action == TGZ_EXTRACT) - makedir(fname); - break; - case REGTYPE: - case AREGTYPE: - remaining = getoct(buffer.header.size,12); - if (action == TGZ_LIST) - printf(" %s %9d %s\n",strtime(&tartime),remaining,fname); - if (action == TGZ_EXTRACT) - { - if ((remaining) && (matchname(arg,argc,argv,fname))) - { - outfile = fopen(fname,"wb"); - if (outfile == NULL) { - /* try creating directory */ - char *p = strrchr(fname, '/'); - if (p != NULL) { - *p = '\0'; - makedir(fname); - *p = '/'; - outfile = fopen(fname,"wb"); - } - } - fprintf(stderr, - "%s %s\n", - (outfile) ? "Extracting" : "Couldn't create", - fname); - } - else - outfile = NULL; - } - /* - * could have no contents - */ - getheader = (remaining) ? 0 : 1; - break; - default: - if (action == TGZ_LIST) - printf(" %s <---> %s\n",strtime(&tartime),fname); - break; - } - } + if (getheader >= 1) + { + /* + * if we met the end of the tar + * or the end-of-tar block, + * we are done + */ + if (len == 0 || buffer.header.name[0] == 0) + break; + + tarmode = getoct(buffer.header.mode,8); + tartime = (time_t)getoct(buffer.header.mtime,12); + if (tarmode == -1 || tartime == (time_t)-1) + { + buffer.header.name[0] = 0; + action = TGZ_INVALID; + } + + if (getheader == 1) + { + strncpy(fname,buffer.header.name,SHORTNAMESIZE); + if (fname[SHORTNAMESIZE-1] != 0) + fname[SHORTNAMESIZE] = 0; + } + else + { + /* + * The file name is longer than SHORTNAMESIZE + */ + if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0) + error("bad long name"); + getheader = 1; + } + + /* + * Act according to the type flag + */ + switch (buffer.header.typeflag) + { + case DIRTYPE: + if (action == TGZ_LIST) + printf(" %s %s\n",strtime(&tartime),fname); + if (action == TGZ_EXTRACT) + { + makedir(fname); + push_attr(&attributes,fname,tarmode,tartime); + } + break; + case REGTYPE: + case AREGTYPE: + remaining = getoct(buffer.header.size,12); + if (remaining == -1) + { + action = TGZ_INVALID; + break; + } + if (action == TGZ_LIST) + printf(" %s %9d %s\n",strtime(&tartime),remaining,fname); + else if (action == TGZ_EXTRACT) + { + if (matchname(arg,argc,argv,fname)) + { + outfile = fopen(fname,"wb"); + if (outfile == NULL) { + /* try creating directory */ + char *p = strrchr(fname, '/'); + if (p != NULL) { + *p = '\0'; + makedir(fname); + *p = '/'; + outfile = fopen(fname,"wb"); + } + } + if (outfile != NULL) + printf("Extracting %s\n",fname); + else + fprintf(stderr, "%s: Couldn't create %s",prog,fname); + } + else + outfile = NULL; + } + getheader = 0; + break; + case GNUTYPE_LONGLINK: + case GNUTYPE_LONGNAME: + remaining = getoct(buffer.header.size,12); + if (remaining < 0 || remaining >= BLOCKSIZE) + { + action = TGZ_INVALID; + break; + } + len = gzread(in, fname, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining) + { + action = TGZ_INVALID; + break; + } + getheader = 2; + break; + default: + if (action == TGZ_LIST) + printf(" %s <---> %s\n",strtime(&tartime),fname); + break; + } + } else - { - unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining; - - if ((action == TGZ_EXTRACT) && (outfile != NULL)) - { - if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) - { - fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname); - fclose(outfile); - unlink(fname); - } - } - remaining -= bytes; - if (remaining == 0) - { - getheader = 1; - if ((action == TGZ_EXTRACT) && (outfile != NULL)) - { -#ifdef WIN32 - HANDLE hFile; - FILETIME ftm,ftLocal; - SYSTEMTIME st; - struct tm localt; - - fclose(outfile); - - localt = *localtime(&tartime); - - hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); - - st.wYear = (WORD)localt.tm_year+1900; - st.wMonth = (WORD)localt.tm_mon; - st.wDayOfWeek = (WORD)localt.tm_wday; - st.wDay = (WORD)localt.tm_mday; - st.wHour = (WORD)localt.tm_hour; - st.wMinute = (WORD)localt.tm_min; - st.wSecond = (WORD)localt.tm_sec; - st.wMilliseconds = 0; - SystemTimeToFileTime(&st,&ftLocal); - LocalFileTimeToFileTime(&ftLocal,&ftm); - SetFileTime(hFile,&ftm,NULL,&ftm); - CloseHandle(hFile); - - outfile = NULL; -#else - struct utimbuf settime; + { + unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining; + + if (outfile != NULL) + { + if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) + { + fprintf(stderr, + "%s: Error writing %s -- skipping\n",prog,fname); + fclose(outfile); + outfile = NULL; + remove(fname); + } + } + remaining -= bytes; + } + + if (remaining == 0) + { + getheader = 1; + if (outfile != NULL) + { + fclose(outfile); + outfile = NULL; + if (action != TGZ_INVALID) + push_attr(&attributes,fname,tarmode,tartime); + } + } - settime.actime = settime.modtime = tartime; - - fclose(outfile); - outfile = NULL; - utime(fname,&settime); -#endif - } - } - } + /* + * Abandon if errors are found + */ + if (action == TGZ_INVALID) + { + error("broken archive"); + break; + } } - + + /* + * Restore file modes and time stamps + */ + restore_attr(&attributes); + if (gzclose(in) != Z_OK) error("failed gzclose"); @@ -423,73 +576,74 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) } -/* =========================================================== */ +/* ============================================================ */ void help(int exitval) { - fprintf(stderr, - "untgz v 0.1\n" - " an sample application of zlib 1.0.4\n\n" - "Usage : untgz TGZfile to extract all files\n" - " untgz TGZfile fname ... to extract selected files\n" - " untgz -l TGZfile to list archive contents\n" - " untgz -h to display this help\n\n"); + printf("untgz version 0.2.1\n" + " using zlib version %s\n\n", + zlibVersion()); + printf("Usage: untgz file.tgz extract all files\n" + " untgz file.tgz fname ... extract selected files\n" + " untgz -l file.tgz list archive contents\n" + " untgz -h display this help\n"); exit(exitval); } void error(const char *msg) { - fprintf(stderr, "%s: %s\n", prog, msg); - exit(1); + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); } -/* ====================================================================== */ +/* ============================================================ */ -int _CRT_glob = 0; /* disable globbing of the arguments */ +#if defined(WIN32) && defined(__GNUC__) +int _CRT_glob = 0; /* disable argument globbing in MinGW */ +#endif int main(int argc,char **argv) { - int action = TGZ_EXTRACT; - int arg = 1; - char *TGZfile; - gzFile *f; - + int action = TGZ_EXTRACT; + int arg = 1; + char *TGZfile; + gzFile *f; prog = strrchr(argv[0],'\\'); if (prog == NULL) { - prog = strrchr(argv[0],'/'); - if (prog == NULL) - { - prog = strrchr(argv[0],':'); - if (prog == NULL) - prog = argv[0]; - else - prog++; - } - else - prog++; + prog = strrchr(argv[0],'/'); + if (prog == NULL) + { + prog = strrchr(argv[0],':'); + if (prog == NULL) + prog = argv[0]; + else + prog++; + } + else + prog++; } else prog++; - + if (argc == 1) help(0); if (strcmp(argv[arg],"-l") == 0) { - action = TGZ_LIST; - if (argc == ++arg) - help(0); + action = TGZ_LIST; + if (argc == ++arg) + help(0); } else if (strcmp(argv[arg],"-h") == 0) { - help(0); + help(0); } if ((TGZfile = TGZfname(argv[arg])) == NULL) - TGZnotfound(argv[arg]); + TGZnotfound(argv[arg]); ++arg; if ((action == TGZ_LIST) && (arg != argc)) @@ -502,20 +656,18 @@ int main(int argc,char **argv) { case TGZ_LIST: case TGZ_EXTRACT: - f = gzopen(TGZfile,"rb"); - if (f == NULL) - { - fprintf(stderr,"%s: Couldn't gzopen %s\n", - prog, - TGZfile); - return 1; - } - exit(tar(f, action, arg, argc, argv)); + f = gzopen(TGZfile,"rb"); + if (f == NULL) + { + fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile); + return 1; + } + exit(tar(f, action, arg, argc, argv)); break; - + default: - error("Unknown option!"); - exit(1); + error("Unknown option"); + exit(1); } return 0;