Home | History | Annotate | Line # | Download | only in minizip
miniunz.c revision 1.1
      1 /*	$NetBSD: miniunz.c,v 1.1 2006/01/14 20:10:58 christos Exp $	*/
      2 
      3 /*
      4    miniunz.c
      5    Version 1.01e, February 12th, 2005
      6 
      7    Copyright (C) 1998-2005 Gilles Vollant
      8 */
      9 
     10 
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <time.h>
     15 #include <errno.h>
     16 #include <fcntl.h>
     17 
     18 #ifdef unix
     19 # include <unistd.h>
     20 # include <utime.h>
     21 #else
     22 # include <direct.h>
     23 # include <io.h>
     24 #endif
     25 
     26 #include "unzip.h"
     27 
     28 #define CASESENSITIVITY (0)
     29 #define WRITEBUFFERSIZE (8192)
     30 #define MAXFILENAME (256)
     31 
     32 #ifdef WIN32
     33 #define USEWIN32IOAPI
     34 #include "iowin32.h"
     35 #endif
     36 /*
     37   mini unzip, demo of unzip package
     38 
     39   usage :
     40   Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir]
     41 
     42   list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT
     43     if it exists
     44 */
     45 
     46 
     47 /* change_file_date : change the date/time of a file
     48     filename : the filename of the file where date/time must be modified
     49     dosdate : the new date at the MSDos format (4 bytes)
     50     tmu_date : the SAME new date at the tm_unz format */
     51 void change_file_date(filename,dosdate,tmu_date)
     52     const char *filename;
     53     uLong dosdate;
     54     tm_unz tmu_date;
     55 {
     56 #ifdef WIN32
     57   HANDLE hFile;
     58   FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
     59 
     60   hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE,
     61                       0,NULL,OPEN_EXISTING,0,NULL);
     62   GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
     63   DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
     64   LocalFileTimeToFileTime(&ftLocal,&ftm);
     65   SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
     66   CloseHandle(hFile);
     67 #else
     68 #ifdef unix
     69   struct utimbuf ut;
     70   struct tm newdate;
     71   newdate.tm_sec = tmu_date.tm_sec;
     72   newdate.tm_min=tmu_date.tm_min;
     73   newdate.tm_hour=tmu_date.tm_hour;
     74   newdate.tm_mday=tmu_date.tm_mday;
     75   newdate.tm_mon=tmu_date.tm_mon;
     76   if (tmu_date.tm_year > 1900)
     77       newdate.tm_year=tmu_date.tm_year - 1900;
     78   else
     79       newdate.tm_year=tmu_date.tm_year ;
     80   newdate.tm_isdst=-1;
     81 
     82   ut.actime=ut.modtime=mktime(&newdate);
     83   utime(filename,&ut);
     84 #endif
     85 #endif
     86 }
     87 
     88 
     89 /* mymkdir and change_file_date are not 100 % portable
     90    As I don't know well Unix, I wait feedback for the unix portion */
     91 
     92 int mymkdir(dirname)
     93     const char* dirname;
     94 {
     95     int ret=0;
     96 #ifdef WIN32
     97     ret = mkdir(dirname);
     98 #else
     99 #ifdef unix
    100     ret = mkdir (dirname,0775);
    101 #endif
    102 #endif
    103     return ret;
    104 }
    105 
    106 int makedir (newdir)
    107     char *newdir;
    108 {
    109   char *buffer ;
    110   char *p;
    111   int  len = (int)strlen(newdir);
    112 
    113   if (len <= 0)
    114     return 0;
    115 
    116   buffer = (char*)malloc(len+1);
    117   strcpy(buffer,newdir);
    118 
    119   if (buffer[len-1] == '/') {
    120     buffer[len-1] = '\0';
    121   }
    122   if (mymkdir(buffer) == 0)
    123     {
    124       free(buffer);
    125       return 1;
    126     }
    127 
    128   p = buffer+1;
    129   while (1)
    130     {
    131       char hold;
    132 
    133       while(*p && *p != '\\' && *p != '/')
    134         p++;
    135       hold = *p;
    136       *p = 0;
    137       if ((mymkdir(buffer) == -1) && (errno == ENOENT))
    138         {
    139           printf("couldn't create directory %s\n",buffer);
    140           free(buffer);
    141           return 0;
    142         }
    143       if (hold == 0)
    144         break;
    145       *p++ = hold;
    146     }
    147   free(buffer);
    148   return 1;
    149 }
    150 
    151 void do_banner()
    152 {
    153     printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n");
    154     printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n");
    155 }
    156 
    157 void do_help()
    158 {
    159     printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \
    160            "  -e  Extract without pathname (junk paths)\n" \
    161            "  -x  Extract with pathname\n" \
    162            "  -v  list files\n" \
    163            "  -l  list files\n" \
    164            "  -d  directory to extract into\n" \
    165            "  -o  overwrite files without prompting\n" \
    166            "  -p  extract crypted file using password\n\n");
    167 }
    168 
    169 
    170 int do_list(uf)
    171     unzFile uf;
    172 {
    173     uLong i;
    174     unz_global_info gi;
    175     int err;
    176 
    177     err = unzGetGlobalInfo (uf,&gi);
    178     if (err!=UNZ_OK)
    179         printf("error %d with zipfile in unzGetGlobalInfo \n",err);
    180     printf(" Length  Method   Size  Ratio   Date    Time   CRC-32     Name\n");
    181     printf(" ------  ------   ----  -----   ----    ----   ------     ----\n");
    182     for (i=0;i<gi.number_entry;i++)
    183     {
    184         char filename_inzip[256];
    185         unz_file_info file_info;
    186         uLong ratio=0;
    187         const char *string_method;
    188         char charCrypt=' ';
    189         err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
    190         if (err!=UNZ_OK)
    191         {
    192             printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
    193             break;
    194         }
    195         if (file_info.uncompressed_size>0)
    196             ratio = (file_info.compressed_size*100)/file_info.uncompressed_size;
    197 
    198         /* display a '*' if the file is crypted */
    199         if ((file_info.flag & 1) != 0)
    200             charCrypt='*';
    201 
    202         if (file_info.compression_method==0)
    203             string_method="Stored";
    204         else
    205         if (file_info.compression_method==Z_DEFLATED)
    206         {
    207             uInt iLevel=(uInt)((file_info.flag & 0x6)/2);
    208             if (iLevel==0)
    209               string_method="Defl:N";
    210             else if (iLevel==1)
    211               string_method="Defl:X";
    212             else if ((iLevel==2) || (iLevel==3))
    213               string_method="Defl:F"; /* 2:fast , 3 : extra fast*/
    214         }
    215         else
    216             string_method="Unkn. ";
    217 
    218         printf("%7lu  %6s%c%7lu %3lu%%  %2.2lu-%2.2lu-%2.2lu  %2.2lu:%2.2lu  %8.8lx   %s\n",
    219                 file_info.uncompressed_size,string_method,
    220                 charCrypt,
    221                 file_info.compressed_size,
    222                 ratio,
    223                 (uLong)file_info.tmu_date.tm_mon + 1,
    224                 (uLong)file_info.tmu_date.tm_mday,
    225                 (uLong)file_info.tmu_date.tm_year % 100,
    226                 (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min,
    227                 (uLong)file_info.crc,filename_inzip);
    228         if ((i+1)<gi.number_entry)
    229         {
    230             err = unzGoToNextFile(uf);
    231             if (err!=UNZ_OK)
    232             {
    233                 printf("error %d with zipfile in unzGoToNextFile\n",err);
    234                 break;
    235             }
    236         }
    237     }
    238 
    239     return 0;
    240 }
    241 
    242 
    243 int do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite,password)
    244     unzFile uf;
    245     const int* popt_extract_without_path;
    246     int* popt_overwrite;
    247     const char* password;
    248 {
    249     char filename_inzip[256];
    250     char* filename_withoutpath;
    251     char* p;
    252     int err=UNZ_OK;
    253     FILE *fout=NULL;
    254     void* buf;
    255     uInt size_buf;
    256 
    257     unz_file_info file_info;
    258     uLong ratio=0;
    259     err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
    260 
    261     if (err!=UNZ_OK)
    262     {
    263         printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
    264         return err;
    265     }
    266 
    267     size_buf = WRITEBUFFERSIZE;
    268     buf = (void*)malloc(size_buf);
    269     if (buf==NULL)
    270     {
    271         printf("Error allocating memory\n");
    272         return UNZ_INTERNALERROR;
    273     }
    274 
    275     p = filename_withoutpath = filename_inzip;
    276     while ((*p) != '\0')
    277     {
    278         if (((*p)=='/') || ((*p)=='\\'))
    279             filename_withoutpath = p+1;
    280         p++;
    281     }
    282 
    283     if ((*filename_withoutpath)=='\0')
    284     {
    285         if ((*popt_extract_without_path)==0)
    286         {
    287             printf("creating directory: %s\n",filename_inzip);
    288             mymkdir(filename_inzip);
    289         }
    290     }
    291     else
    292     {
    293         const char* write_filename;
    294         int skip=0;
    295 
    296         if ((*popt_extract_without_path)==0)
    297             write_filename = filename_inzip;
    298         else
    299             write_filename = filename_withoutpath;
    300 
    301         err = unzOpenCurrentFilePassword(uf,password);
    302         if (err!=UNZ_OK)
    303         {
    304             printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err);
    305         }
    306 
    307         if (((*popt_overwrite)==0) && (err==UNZ_OK))
    308         {
    309             char rep=0;
    310             FILE* ftestexist;
    311             ftestexist = fopen(write_filename,"rb");
    312             if (ftestexist!=NULL)
    313             {
    314                 fclose(ftestexist);
    315                 do
    316                 {
    317                     char answer[128];
    318                     int ret;
    319 
    320                     printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename);
    321                     ret = scanf("%1s",answer);
    322                     if (ret != 1)
    323                     {
    324                        exit(EXIT_FAILURE);
    325                     }
    326                     rep = answer[0] ;
    327                     if ((rep>='a') && (rep<='z'))
    328                         rep -= 0x20;
    329                 }
    330                 while ((rep!='Y') && (rep!='N') && (rep!='A'));
    331             }
    332 
    333             if (rep == 'N')
    334                 skip = 1;
    335 
    336             if (rep == 'A')
    337                 *popt_overwrite=1;
    338         }
    339 
    340         if ((skip==0) && (err==UNZ_OK))
    341         {
    342             fout=fopen(write_filename,"wb");
    343 
    344             /* some zipfile don't contain directory alone before file */
    345             if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
    346                                 (filename_withoutpath!=(char*)filename_inzip))
    347             {
    348                 char c=*(filename_withoutpath-1);
    349                 *(filename_withoutpath-1)='\0';
    350                 makedir(write_filename);
    351                 *(filename_withoutpath-1)=c;
    352                 fout=fopen(write_filename,"wb");
    353             }
    354 
    355             if (fout==NULL)
    356             {
    357                 printf("error opening %s\n",write_filename);
    358             }
    359         }
    360 
    361         if (fout!=NULL)
    362         {
    363             printf(" extracting: %s\n",write_filename);
    364 
    365             do
    366             {
    367                 err = unzReadCurrentFile(uf,buf,size_buf);
    368                 if (err<0)
    369                 {
    370                     printf("error %d with zipfile in unzReadCurrentFile\n",err);
    371                     break;
    372                 }
    373                 if (err>0)
    374                     if (fwrite(buf,err,1,fout)!=1)
    375                     {
    376                         printf("error in writing extracted file\n");
    377                         err=UNZ_ERRNO;
    378                         break;
    379                     }
    380             }
    381             while (err>0);
    382             if (fout)
    383                     fclose(fout);
    384 
    385             if (err==0)
    386                 change_file_date(write_filename,file_info.dosDate,
    387                                  file_info.tmu_date);
    388         }
    389 
    390         if (err==UNZ_OK)
    391         {
    392             err = unzCloseCurrentFile (uf);
    393             if (err!=UNZ_OK)
    394             {
    395                 printf("error %d with zipfile in unzCloseCurrentFile\n",err);
    396             }
    397         }
    398         else
    399             unzCloseCurrentFile(uf); /* don't lose the error */
    400     }
    401 
    402     free(buf);
    403     return err;
    404 }
    405 
    406 
    407 int do_extract(uf,opt_extract_without_path,opt_overwrite,password)
    408     unzFile uf;
    409     int opt_extract_without_path;
    410     int opt_overwrite;
    411     const char* password;
    412 {
    413     uLong i;
    414     unz_global_info gi;
    415     int err;
    416     FILE* fout=NULL;
    417 
    418     err = unzGetGlobalInfo (uf,&gi);
    419     if (err!=UNZ_OK)
    420         printf("error %d with zipfile in unzGetGlobalInfo \n",err);
    421 
    422     for (i=0;i<gi.number_entry;i++)
    423     {
    424         if (do_extract_currentfile(uf,&opt_extract_without_path,
    425                                       &opt_overwrite,
    426                                       password) != UNZ_OK)
    427             break;
    428 
    429         if ((i+1)<gi.number_entry)
    430         {
    431             err = unzGoToNextFile(uf);
    432             if (err!=UNZ_OK)
    433             {
    434                 printf("error %d with zipfile in unzGoToNextFile\n",err);
    435                 break;
    436             }
    437         }
    438     }
    439 
    440     return 0;
    441 }
    442 
    443 int do_extract_onefile(uf,filename,opt_extract_without_path,opt_overwrite,password)
    444     unzFile uf;
    445     const char* filename;
    446     int opt_extract_without_path;
    447     int opt_overwrite;
    448     const char* password;
    449 {
    450     int err = UNZ_OK;
    451     if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
    452     {
    453         printf("file %s not found in the zipfile\n",filename);
    454         return 2;
    455     }
    456 
    457     if (do_extract_currentfile(uf,&opt_extract_without_path,
    458                                       &opt_overwrite,
    459                                       password) == UNZ_OK)
    460         return 0;
    461     else
    462         return 1;
    463 }
    464 
    465 
    466 int main(argc,argv)
    467     int argc;
    468     char *argv[];
    469 {
    470     const char *zipfilename=NULL;
    471     const char *filename_to_extract=NULL;
    472     const char *password=NULL;
    473     char filename_try[MAXFILENAME+16] = "";
    474     int i;
    475     int opt_do_list=0;
    476     int opt_do_extract=1;
    477     int opt_do_extract_withoutpath=0;
    478     int opt_overwrite=0;
    479     int opt_extractdir=0;
    480     const char *dirname=NULL;
    481     unzFile uf=NULL;
    482 
    483     do_banner();
    484     if (argc==1)
    485     {
    486         do_help();
    487         return 0;
    488     }
    489     else
    490     {
    491         for (i=1;i<argc;i++)
    492         {
    493             if ((*argv[i])=='-')
    494             {
    495                 const char *p=argv[i]+1;
    496 
    497                 while ((*p)!='\0')
    498                 {
    499                     char c=*(p++);;
    500                     if ((c=='l') || (c=='L'))
    501                         opt_do_list = 1;
    502                     if ((c=='v') || (c=='V'))
    503                         opt_do_list = 1;
    504                     if ((c=='x') || (c=='X'))
    505                         opt_do_extract = 1;
    506                     if ((c=='e') || (c=='E'))
    507                         opt_do_extract = opt_do_extract_withoutpath = 1;
    508                     if ((c=='o') || (c=='O'))
    509                         opt_overwrite=1;
    510                     if ((c=='d') || (c=='D'))
    511                     {
    512                         opt_extractdir=1;
    513                         dirname=argv[i+1];
    514                     }
    515 
    516                     if (((c=='p') || (c=='P')) && (i+1<argc))
    517                     {
    518                         password=argv[i+1];
    519                         i++;
    520                     }
    521                 }
    522             }
    523             else
    524             {
    525                 if (zipfilename == NULL)
    526                     zipfilename = argv[i];
    527                 else if ((filename_to_extract==NULL) && (!opt_extractdir))
    528                         filename_to_extract = argv[i] ;
    529             }
    530         }
    531     }
    532 
    533     if (zipfilename!=NULL)
    534     {
    535 
    536 #        ifdef USEWIN32IOAPI
    537         zlib_filefunc_def ffunc;
    538 #        endif
    539 
    540         strncpy(filename_try, zipfilename,MAXFILENAME-1);
    541         /* strncpy doesnt append the trailing NULL, of the string is too long. */
    542         filename_try[ MAXFILENAME ] = '\0';
    543 
    544 #        ifdef USEWIN32IOAPI
    545         fill_win32_filefunc(&ffunc);
    546         uf = unzOpen2(zipfilename,&ffunc);
    547 #        else
    548         uf = unzOpen(zipfilename);
    549 #        endif
    550         if (uf==NULL)
    551         {
    552             strcat(filename_try,".zip");
    553 #            ifdef USEWIN32IOAPI
    554             uf = unzOpen2(filename_try,&ffunc);
    555 #            else
    556             uf = unzOpen(filename_try);
    557 #            endif
    558         }
    559     }
    560 
    561     if (uf==NULL)
    562     {
    563         printf("Cannot open %s or %s.zip\n",zipfilename,zipfilename);
    564         return 1;
    565     }
    566     printf("%s opened\n",filename_try);
    567 
    568     if (opt_do_list==1)
    569         return do_list(uf);
    570     else if (opt_do_extract==1)
    571     {
    572         if (opt_extractdir && chdir(dirname))
    573         {
    574           printf("Error changing into %s, aborting\n", dirname);
    575           exit(-1);
    576         }
    577 
    578         if (filename_to_extract == NULL)
    579             return do_extract(uf,opt_do_extract_withoutpath,opt_overwrite,password);
    580         else
    581             return do_extract_onefile(uf,filename_to_extract,
    582                                       opt_do_extract_withoutpath,opt_overwrite,password);
    583     }
    584     unzCloseCurrentFile(uf);
    585 
    586     return 0;
    587 }
    588