home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip21.zip / win32 / win32zip.c < prev    next >
C/C++ Source or Header  |  1996-04-24  |  17KB  |  622 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1996 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel, Onno van der Linden and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included,
  7.  that it is not sold for profit, and that this copyright notice is retained.
  8.  
  9. */
  10.  
  11. #ifndef UTIL    /* this file contains nothing used by UTIL */
  12.  
  13. #include "zip.h"
  14.  
  15. #include <direct.h>     /* for rmdir() */
  16. #include <time.h>
  17.  
  18. #ifndef __BORLANDC__
  19. #include <sys/utime.h>
  20. #else
  21. #include <utime.h>
  22. #endif
  23. #include <windows.h> /* for findfirst/findnext stuff */
  24. char *GetLongPathEA OF((char *name));
  25.  
  26. #include <io.h>
  27. #define MATCH         shmatch
  28.  
  29. #define PAD           0
  30. #define PATH_END      '/'
  31. #define HIDD_SYS_BITS (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
  32.  
  33.  
  34. typedef struct zdirent {
  35.   ush    d_date, d_time;
  36.   ulg    d_size;
  37.   char   d_attr;
  38.   char   d_name[MAX_PATH];
  39.   int    d_first;
  40.   HANDLE d_hFindFile;
  41. } zDIR;
  42.  
  43. #include "win32/win32zip.h"
  44.  
  45. /* Local functions */
  46. local zDIR           *Opendir  OF((const char *));
  47. local struct zdirent *Readdir  OF((zDIR *));
  48. local void            Closedir OF((zDIR *));
  49.  
  50. local char           *readd    OF((zDIR *));
  51.  
  52. /* Module level variables */
  53. extern char *label /* = NULL */ ;       /* defined in fileio.c */
  54. local ulg label_time = 0;
  55. local ulg label_mode = 0;
  56. local time_t label_utim = 0;
  57.  
  58. /* Module level constants */
  59. local const char wild_match_all[] = "*.*";
  60.  
  61. local zDIR *Opendir(n)
  62. const char *n;          /* directory to open */
  63. /* Start searching for files in the MSDOS directory n */
  64. {
  65.   zDIR *d;              /* malloc'd return value */
  66.   char *p;              /* malloc'd temporary string */
  67.   char *q;
  68.   WIN32_FIND_DATA fd;
  69.  
  70.   if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL ||
  71.       (p = malloc(strlen(n) + 5)) == NULL) {
  72.     if (d != NULL) free((zvoid *)d);
  73.     return NULL;
  74.   }
  75.   strcpy(p, n);
  76.   q = p + strlen(p);
  77.   if ((q - p) > 0 && *(q - 1) != '/')
  78.     *q++ = '/';
  79.   strcpy(q, wild_match_all);
  80.  
  81.   d->d_hFindFile = FindFirstFile(p, &fd);
  82.   free((zvoid *)p);
  83.  
  84.   if (d->d_hFindFile == INVALID_HANDLE_VALUE)
  85.   {
  86.     free((zvoid *)d);
  87.     return NULL;
  88.   }
  89.  
  90.   strcpy(d->d_name, fd.cFileName);
  91.   d->d_attr = (unsigned char) fd.dwFileAttributes;
  92.   d->d_first = 1;
  93.   return d;
  94. }
  95.  
  96. local struct zdirent *Readdir(d)
  97. zDIR *d;                /* directory stream to read from */
  98. /* Return pointer to first or next directory entry, or NULL if end. */
  99. {
  100.   if (d->d_first)
  101.     d->d_first = 0;
  102.   else
  103.   {
  104.     WIN32_FIND_DATA fd;
  105.  
  106.     if (!FindNextFile(d->d_hFindFile, &fd))
  107.         return NULL;
  108.     strcpy(d->d_name, fd.cFileName);
  109.     d->d_attr = (unsigned char) fd.dwFileAttributes;
  110.   }
  111.   return (struct zdirent *)d;
  112. }
  113.  
  114. local void Closedir(d)
  115. zDIR *d;                /* directory stream to close */
  116. {
  117.   FindClose(d->d_hFindFile);
  118.   free((zvoid *)d);
  119. }
  120.  
  121.  
  122. local char *readd(d)
  123. zDIR *d;                /* directory stream to read from */
  124. /* Return a pointer to the next name in the directory stream d, or NULL if
  125.    no more entries or an error occurs. */
  126. {
  127.   struct zdirent *e;
  128.  
  129.   do
  130.     e = Readdir(d);
  131.   while (!hidden_files && e && e->d_attr & HIDD_SYS_BITS);
  132.   return e == NULL ? (char *) NULL : e->d_name;
  133. }
  134.  
  135. int wild(w)
  136. char *w;                /* path/pattern to match */
  137. /* If not in exclude mode, expand the pattern based on the contents of the
  138.    file system.  Return an error code in the ZE_ class. */
  139. {
  140.   zDIR *d;              /* stream for reading directory */
  141.   char *e;              /* name found in directory */
  142.   int r;                /* temporary variable */
  143.   char *n;              /* constructed name from directory */
  144.   int f;                /* true if there was a match */
  145.   char *a;              /* alloc'ed space for name */
  146.   char *p;              /* path */
  147.   char *q;              /* name */
  148.   char v[5];            /* space for device current directory */
  149.  
  150.   /* special handling of stdin request */
  151.   if (strcmp(w, "-") == 0)   /* if compressing stdin */
  152.     return newname(w, 0);
  153.  
  154.   /* Allocate and copy pattern */
  155.   if ((p = a = malloc(strlen(w) + 1)) == NULL)
  156.     return ZE_MEM;
  157.   strcpy(p, w);
  158.  
  159.   /* Normalize path delimiter as '/'. */
  160.   for (q = p; *q; q++)                  /* use / consistently */
  161.     if (*q == '\\')
  162.       *q = '/';
  163.  
  164.   /* Only name can have special matching characters */
  165.   if ((q = isshexp(p)) != NULL &&
  166.       (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
  167.   {
  168.     free((zvoid *)a);
  169.     return ZE_PARMS;
  170.   }
  171.  
  172.   /* Separate path and name into p and q */
  173.   if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
  174.   {
  175.     *q++ = '\0';                        /* path/name -> path, name */
  176.     if (*p == '\0')                     /* path is just / */
  177.       p = strcpy(v, "/.");
  178.   }
  179.   else if ((q = strrchr(p, ':')) != NULL)
  180.   {                                     /* has device and no or root path */
  181.     *q++ = '\0';
  182.     p = strcat(strcpy(v, p), ":");      /* copy device as path */
  183.     if (*q == '/')                      /* -> device:/., name */
  184.     {
  185.       strcat(p, "/");
  186.       q++;
  187.     }
  188.     strcat(p, ".");
  189.   }
  190.   else if (recurse && (strcmp(p, ".") == 0 ||  strcmp(p, "..") == 0))
  191.   {                                    /* current or parent directory */
  192.     /* I can't understand Mark's code so I am adding a hack here to get
  193.      * "zip -r foo ." to work. Allow the dubious "zip -r foo .." but
  194.      * reject "zip -rm foo ..".
  195.      */
  196.     if (dispose && strcmp(p, "..") == 0)
  197.        ziperr(ZE_PARMS, "cannot remove parent directory");
  198.     q = (char *)wild_match_all;
  199.   }
  200.   else                                  /* no path or device */
  201.   {
  202.     q = p;
  203.     p = strcpy(v, ".");
  204.   }
  205.   if (recurse && *q == '\0') {
  206.     q = (char *)wild_match_all;
  207.   }
  208.   /* Search that level for matching names */
  209.   if ((d = Opendir(p)) == NULL)
  210.   {
  211.     free((zvoid *)a);
  212.     return ZE_MISS;
  213.   }
  214.   if ((r = strlen(p)) > 1 &&
  215.       (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
  216.     *(p + r - 1) = '\0';
  217.   f = 0;
  218.   while ((e = readd(d)) != NULL) {
  219.     if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
  220.     {
  221.       f = 1;
  222.       if (strcmp(p, ".") == 0) {                /* path is . */
  223.         r = procname(e);                        /* name is name */
  224.         if (r) {
  225.            f = 0;
  226.            break;
  227.         }
  228.       } else
  229.       {
  230.         if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
  231.         {
  232.           free((zvoid *)a);
  233.           Closedir(d);
  234.           return ZE_MEM;
  235.         }
  236.         n = strcpy(n, p);
  237.         if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
  238.           strcat(n, "/");
  239.         r = procname(strcat(n, e));             /* name is path/name */
  240.         free((zvoid *)n);
  241.         if (r) {
  242.           f = 0;
  243.           break;
  244.         }
  245.       }
  246.     }
  247.   }
  248.   Closedir(d);
  249.  
  250.   /* Done */
  251.   free((zvoid *)a);
  252.   return f ? ZE_OK : ZE_MISS;
  253. }
  254.  
  255. int procname(n)
  256. char *n;                /* name to process */
  257. /* Process a name or sh expression to operate on (or exclude).  Return
  258.    an error code in the ZE_ class. */
  259. {
  260.   char *a;              /* path and name for recursion */
  261.   zDIR *d;              /* directory stream from opendir() */
  262.   char *e;              /* pointer to name from readd() */
  263.   int m;                /* matched flag */
  264.   char *p;              /* path for recursion */
  265.   struct stat s;        /* result of stat() */
  266.   struct zlist far *z;  /* steps through zfiles list */
  267.  
  268.   if (strcmp(n, "-") == 0)   /* if compressing stdin */
  269.     return newname(n, 0);
  270.   else if (LSSTAT(n, &s)
  271. #if defined(__TURBOC__) || defined(VMS) || defined(__WATCOMC__)
  272.            /* For these 3 compilers, stat() succeeds on wild card names! */
  273.            || isshexp(n)
  274. #endif
  275.           )
  276.   {
  277.     /* Not a file or directory--search for shell expression in zip file */
  278.     p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
  279.     m = 1;
  280.     for (z = zfiles; z != NULL; z = z->nxt) {
  281.       if (MATCH(p, z->zname))
  282.       {
  283.         z->mark = pcount ? filter(z->zname) : 1;
  284.         if (verbose)
  285.             fprintf(mesg, "zip diagnostic: %scluding %s\n",
  286.                z->mark ? "in" : "ex", z->name);
  287.         m = 0;
  288.       }
  289.     }
  290.     free((zvoid *)p);
  291.     return m ? ZE_MISS : ZE_OK;
  292.   }
  293.  
  294.   /* Live name--use if file, recurse if directory */
  295.   for (p = n; *p; p++)          /* use / consistently */
  296.     if (*p == '\\')
  297.       *p = '/';
  298.   if ((s.st_mode & S_IFDIR) == 0)
  299.   {
  300.     /* add or remove name of file */
  301.     if ((m = newname(n, 0)) != ZE_OK)
  302.       return m;
  303.   } else {
  304.     /* Add trailing / to the directory name */
  305.     if ((p = malloc(strlen(n)+2)) == NULL)
  306.       return ZE_MEM;
  307.     if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
  308.       *p = '\0';  /* avoid "./" prefix and do not create zip entry */
  309.     } else {
  310.       strcpy(p, n);
  311.       a = p + strlen(p);
  312.       if (a[-1] != '/')
  313.         strcpy(a, "/");
  314.       if (dirnames && (m = newname(p, 1)) != ZE_OK) {
  315.         free((zvoid *)p);
  316.         return m;
  317.       }
  318.     }
  319.     /* recurse into directory */
  320.     if (recurse && (d = Opendir(n)) != NULL)
  321.     {
  322.       while ((e = readd(d)) != NULL) {
  323.         if (strcmp(e, ".") && strcmp(e, ".."))
  324.         {
  325.           if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
  326.           {
  327.             Closedir(d);
  328.             free((zvoid *)p);
  329.             return ZE_MEM;
  330.           }
  331.           strcat(strcpy(a, p), e);
  332.           if ((m = procname(a)) != ZE_OK)   /* recurse on name */
  333.           {
  334.             if (m == ZE_MISS)
  335.               zipwarn("name not matched: ", a);
  336.             else
  337.               ziperr(m, a);
  338.           }
  339.           free((zvoid *)a);
  340.         }
  341.       }
  342.       Closedir(d);
  343.     }
  344.     free((zvoid *)p);
  345.   } /* (s.st_mode & S_IFDIR) == 0) */
  346.   return ZE_OK;
  347. }
  348.  
  349. char *ex2in(x, isdir, pdosflag)
  350. char *x;                /* external file name */
  351. int isdir;              /* input: x is a directory */
  352. int *pdosflag;          /* output: force MSDOS file attributes? */
  353. /* Convert the external file name to a zip file name, returning the malloc'ed
  354.    string or NULL if not enough memory. */
  355. {
  356.   char *n;              /* internal file name (malloc'ed) */
  357.   char *t;              /* shortened name */
  358.   int dosflag;
  359.  
  360.  
  361.   dosflag = dosify || IsFileSystemOldFAT(x);
  362.   if (!dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL)
  363.   {
  364.     x = t;
  365.     dosflag = 0;
  366.   }
  367.  
  368.   /* Find starting point in name before doing malloc */
  369.   t = *x && *(x + 1) == ':' ? x + 2 : x;
  370.   while (*t == '/' || *t == '\\')
  371.     t++;
  372.  
  373.   /* Make changes, if any, to the copied name (leave original intact) */
  374.   for (n = t; *n; n++)
  375.     if (*n == '\\')
  376.       *n = '/';
  377.  
  378.   if (!pathput)
  379.     t = last(t, PATH_END);
  380.  
  381.   /* Malloc space for internal name and copy it */
  382.   if ((n = malloc(strlen(t) + 1)) == NULL)
  383.     return NULL;
  384.   strcpy(n, t);
  385.  
  386.   if (dosify)
  387.     msname(n);
  388.  
  389.   /* Returned malloc'ed name */
  390.   if (pdosflag)
  391.     *pdosflag = dosflag;
  392.   return n;
  393. }
  394.  
  395.  
  396. char *in2ex(n)
  397. char *n;                /* internal file name */
  398. /* Convert the zip file name to an external file name, returning the malloc'ed
  399.    string or NULL if not enough memory. */
  400. {
  401.   char *x;              /* external file name */
  402.  
  403.   if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
  404.     return NULL;
  405.   strcpy(x, n);
  406.  
  407.   if ( !IsFileNameValid(x) )
  408.     ChangeNameForFAT(x);
  409.   return x;
  410. }
  411.  
  412.  
  413. void stamp(f, d)
  414. char *f;                /* name of file to change */
  415. ulg d;                  /* dos-style time to change it to */
  416. /* Set last updated and accessed time of file f to the DOS time d. */
  417. {
  418. #if defined(__TURBOC__) && !defined(__BORLANDC__)
  419.   int h;                /* file handle */
  420.  
  421.   if ((h = open(f, 0)) != -1)
  422.   {
  423.     setftime(h, (struct ftime *)&d);
  424.     close(h);
  425.   }
  426. #else /* !__TURBOC__ */
  427.  
  428.   struct utimbuf u;     /* argument for utime() */
  429.  
  430.   /* Convert DOS time to time_t format in u.actime and u.modtime */
  431.   u.actime = u.modtime = dos2unixtime(d);
  432.  
  433.   /* Set updated and accessed times of f */
  434.   utime(f, &u);
  435. #endif /* ?__TURBOC__ */
  436. }
  437.  
  438.  
  439. ulg filetime(f, a, n, t)
  440. char *f;                /* name of file to get info on */
  441. ulg *a;                 /* return value: file attributes */
  442. long *n;                /* return value: file size */
  443. ztimbuf *t;             /* return value: access and modification time */
  444. /* If file *f does not exist, return 0.  Else, return the file's last
  445.    modified date and time as an MSDOS date and time.  The date and
  446.    time is returned in a long with the date most significant to allow
  447.    unsigned integer comparison of absolute times.  Also, if a is not
  448.    a NULL pointer, store the file attributes there, with the high two
  449.    bytes being the Unix attributes, and the low byte being a mapping
  450.    of that to DOS attributes.  If n is not NULL, store the file size
  451.    there.  If t is not NULL, the file's access and modification time
  452.    are stored there as UNIX time_t values.
  453.    If f is "-", use standard input as the file. If f is a device, return
  454.    a file size of -1 */
  455. {
  456.   struct stat s;        /* results of stat() */
  457.   char name[FNMAX];
  458.   int len = strlen(f), isstdin = !strcmp(f, "-");
  459.  
  460.   if (f == label) {
  461.     if (a != NULL)
  462.       *a = label_mode;
  463.     if (n != NULL)
  464.       *n = -2L; /* convention for a label name */
  465.     if (t != NULL)
  466.       t->actime = t->modtime = label_utim;
  467.     return label_time;
  468.   }
  469.   strcpy(name, f);
  470.   if (name[len - 1] == '/')
  471.     name[len - 1] = '\0';
  472.   /* not all systems allow stat'ing a file with / appended */
  473.  
  474.   if (isstdin) {
  475.     if (fstat(fileno(stdin), &s) != 0)
  476.       error("fstat(stdin)");
  477.     time((time_t *)&s.st_mtime);       /* some fstat()s return time zero */
  478.   } else if (LSSTAT(name, &s) != 0)
  479.              /* Accept about any file kind including directories
  480.               * (stored with trailing / with -r option)
  481.               */
  482.     return 0;
  483.  
  484.   if (a != NULL) {
  485.     *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
  486.   }
  487.   if (n != NULL)
  488.     *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
  489.   if (t != NULL) {
  490.     t->actime = s.st_atime;
  491.     t->modtime = s.st_mtime;
  492.   }
  493.  
  494.   return unix2dostime((time_t *)&s.st_mtime);
  495. }
  496.  
  497. int set_extra_field(z, z_utim)
  498.   struct zlist far *z;
  499.   ztimbuf *z_utim;
  500.   /* create extra field and change z->att if desired */
  501. {
  502. #ifdef USE_EF_UX_TIME
  503.   if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UX_MINLEN)) == NULL)
  504.     return ZE_MEM;
  505.  
  506.   z->extra[0]  = 'U';
  507.   z->extra[1]  = 'X';
  508.   z->extra[2]  = EB_UX_MINLEN;          /* length of data part of e.f. */
  509.   z->extra[3]  = 0;
  510.   z->extra[4]  = (char)(z_utim->actime);
  511.   z->extra[5]  = (char)(z_utim->actime >> 8);
  512.   z->extra[6]  = (char)(z_utim->actime >> 16);
  513.   z->extra[7]  = (char)(z_utim->actime >> 24);
  514.   z->extra[8]  = (char)(z_utim->modtime);
  515.   z->extra[9]  = (char)(z_utim->modtime >> 8);
  516.   z->extra[10] = (char)(z_utim->modtime >> 16);
  517.   z->extra[11] = (char)(z_utim->modtime >> 24);
  518.  
  519.   z->cext = z->ext = (EB_HEADSIZE+EB_UX_MINLEN);
  520.   z->cextra = z->extra;
  521.  
  522.   return ZE_OK;
  523. #else /* !USE_EF_UX_TIME */
  524.   return (int)(z-z);
  525. #endif /* ?USE_EF_UX_TIME */
  526. }
  527.  
  528. int deletedir(d)
  529. char *d;                /* directory to delete */
  530. /* Delete the directory *d if it is empty, do nothing otherwise.
  531.    Return the result of rmdir(), delete(), or system().
  532.    For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
  533.  */
  534. {
  535.     return rmdir(d);
  536. }
  537.  
  538. /******************************/
  539. /*  Function version_local()  */
  540. /******************************/
  541.  
  542. void version_local()
  543. {
  544.     static const char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
  545. #if (defined(_MSC_VER) || defined(__WATCOMC__))
  546.     char buf[80];
  547. #endif
  548.  
  549.     printf(CompiledWith,
  550.  
  551. #ifdef _MSC_VER  /* MSC == MSVC++, including the SDK compiler */
  552.       (sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100), buf),
  553. #  if (_MSC_VER == 800)
  554.         "(Visual C++ v1.1)",
  555. #  elif (_MSC_VER == 850)
  556.         "(Windows NT v3.5 SDK)",
  557. #  elif (_MSC_VER == 900)
  558.         "(Visual C++ v2.0/v2.1)",
  559. #  elif (_MSC_VER == 1000)
  560.         "(Visual C++ v4.0)",
  561. #  elif (_MSC_VER == 1010)
  562.         "(Visual C++ v4.1)",
  563. #  elif (_MSC_VER > 800)
  564.         "(Visual C++)",
  565. #  else
  566.         "(bad version)",
  567. #  endif
  568. #endif /* _MSC_VER */
  569.  
  570. #ifdef __WATCOMC__
  571. #  if (__WATCOMC__ % 10 > 0)
  572. /* We do this silly test because __WATCOMC__ gives two digits for the  */
  573. /* minor version, but Watcom packaging prefers to show only one digit. */
  574.         (sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
  575.                  __WATCOMC__ % 100), buf), "",
  576. #  else
  577.       (sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
  578.                (__WATCOMC__ % 100) / 10), buf), "",
  579. #  endif /* __WATCOMC__ % 10 > 0 */
  580. #endif /* __WATCOMC__ */
  581.  
  582. #ifdef __TURBOC__
  583. #  ifdef __BORLANDC__
  584.      "Borland C++",
  585. #    if (__BORLANDC__ == 0x0452)   /* __BCPLUSPLUS__ = 0x0320 */
  586.         " 4.0 or 4.02",
  587. #    elif (__BORLANDC__ == 0x0460)   /* __BCPLUSPLUS__ = 0x0340 */
  588.         " 4.5",
  589. #    elif (__BORLANDC__ == 0x0500)   /* __TURBOC__ = 0x0500 */
  590.         " 5.0",
  591. #    else
  592.         " later than 5.0",
  593. #    endif
  594. #  else /* !__BORLANDC__ */
  595.      "Turbo C",
  596. #    if (__TURBOC__ >= 0x0400)     /* Kevin:  3.0 -> 0x0401 */
  597.         "++ 3.0 or later",
  598. #    elif (__TURBOC__ == 0x0295)     /* [661] vfy'd by Kevin */
  599.         "++ 1.0",
  600. #    endif
  601. #  endif /* __BORLANDC__ */
  602. #endif /* __TURBOC__ */
  603.  
  604. #if !defined(__TURBOC__) && !defined(__WATCOMC__) && !defined(_MSC_VER)
  605.       "unknown compiler (SDK?)", "",
  606. #endif
  607.  
  608.       "\n\tWindows 95 / Windows NT", " (32-bit)",
  609.  
  610. #ifdef __DATE__
  611.       " on ", __DATE__
  612. #else
  613.       "", ""
  614. #endif
  615.     );
  616.  
  617.     return;
  618.  
  619. } /* end function version_local() */
  620.  
  621. #endif /* !UTIL */
  622.