1 /*
2   win32/win32zip.c - Zip 3
3 
4   Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
5 
6   See the accompanying file LICENSE, version 2007-Mar-4 or later
7   (the contents of which are also included in zip.h) for terms of use.
8   If, for some reason, all these files are missing, the Info-ZIP license
9   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
10 */
11 #ifndef UTIL    /* this file contains nothing used by UTIL */
12 
13 #include "../zip.h"
14 
15 #include <ctype.h>
16 #if !defined(__EMX__) && !defined(__CYGWIN__)
17 #include <direct.h>     /* for rmdir() */
18 #endif
19 #include <time.h>
20 
21 #ifndef __BORLANDC__
22 #include <sys/utime.h>
23 #else
24 #include <utime.h>
25 #endif
26 #define WIN32_LEAN_AND_MEAN
27 #include <windows.h> /* for findfirst/findnext stuff */
28 #ifdef __RSXNT__
29 #  include "../win32/rsxntwin.h"
30 #endif
31 
32 #include <io.h>
33 
34 #define PAD           0
35 #define PATH_END      '/'
36 #define HIDD_SYS_BITS (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
37 
38 
39 #ifdef UNICODE_SUPPORT
40 typedef struct zdirscanw {
41   HANDLE d_hFindFile;
42   int    d_first;
43   WIN32_FIND_DATAW d_fdw;
44 } zDIRSCANW;
45 #endif
46 
47 typedef struct zdirscan {
48   HANDLE d_hFindFile;
49   int    d_first;
50   WIN32_FIND_DATA d_fd;
51 } zDIRSCAN;
52 
53 #define INVALID_WIN32_FILE_ATTRIBS ~0
54 #ifdef UNICODE_SUPPORT
55 #define GetDirAttribsW(d)   ((d)->d_fdw.dwFileAttributes)
56 #endif
57 #define GetDirAttribs(d)   ((d)->d_fd.dwFileAttributes)
58 
59 #include "../win32/win32zip.h"
60 #include "../win32/nt.h"
61 
62 /* Local functions */
63 local zDIRSCAN        * OpenDirScan      OF((ZCONST char *n));
64 local struct zdirscan * GetNextDirEntry  OF((zDIRSCAN *d));
65 local void              CloseDirScan     OF((zDIRSCAN *d));
66 
67 #ifdef UNICODE_SUPPORT
68 local zDIRSCANW        * OpenDirScanW     OF((ZCONST wchar_t *wn));
69 local struct zdirscanw * GetNextDirEntryW OF((zDIRSCANW *dw));
70 local void               CloseDirScanW    OF((zDIRSCANW *dw));
71 #endif
72 
73 local char           *readd        OF((zDIRSCAN *));
74 #ifdef UNICODE_SUPPORT
75 local wchar_t        *readdw       OF((zDIRSCANW *));
76 #endif
77 
78 local int             wild_recurse OF((char *, char *));
79 #ifdef UNICODE_SUPPORT
80 local int             wild_recursew OF((wchar_t *, wchar_t *));
81 #endif
82 
83 #ifdef NTSD_EAS
84    local void GetSD OF((char *path, char **bufptr, ush *size,
85                         char **cbufptr, ush *csize));
86 #endif
87 #ifdef USE_EF_UT_TIME
88    local int GetExtraTime OF((struct zlist far *z, iztimes *z_utim));
89 #endif
90 local int procname_win32 OF((char *n, int caseflag, DWORD attribs));
91 #ifdef UNICODE_SUPPORT
92 local int procname_win32w OF((wchar_t *n, int caseflag, DWORD attribs));
93 #endif
94 
95 /* Module level variables */
96 extern char *label /* = NULL */ ;       /* defined in fileio.c */
97 local ulg label_time = 0;
98 local ulg label_mode = 0;
99 local time_t label_utim = 0;
100 
101 /* Module level constants */
102 local ZCONST char wild_match_all[] = "*.*";
103 
104 
105 #ifdef UNICODE_SUPPORT
106 
OpenDirScanW(nw)107 local zDIRSCANW *OpenDirScanW(nw)
108 ZCONST wchar_t *nw;          /* directory to open */
109 /* Start searching for files in the MSDOS directory n */
110 {
111   zDIRSCANW *dw;         /* malloc'd return value */
112   wchar_t *pw;              /* malloc'd temporary string */
113   wchar_t *qw;
114   size_t i;
115 
116   if ((dw = (zDIRSCANW *)malloc(sizeof(zDIRSCANW))) == NULL) {
117     return NULL;
118   }
119 
120   if ((pw = (wchar_t *)malloc(wcslen(nw) * sizeof(wchar_t) +
121       (2 + sizeof(wild_match_all)) * sizeof(wchar_t))) == NULL) {
122     if (dw != NULL) free((zvoid *)dw);
123     return NULL;
124   }
125   wcscpy(pw, nw);
126 
127   qw = pw + wcslen(pw);
128   if ((qw - pw) > 0 && wcschr(pw, (wchar_t)':') == (qw - 1))
129       *qw++ = (wchar_t)'.';
130   if ((qw - pw) > 0 && wcschr(pw, (wchar_t)'/') != (qw - 1))
131     *qw++ = (wchar_t)'/';
132 
133   for (i = 0; i < strlen(wild_match_all); i++) {
134     qw[i] = (wchar_t)wild_match_all[i];
135   }
136   qw[i] = (wchar_t)'\0';
137 
138   dw->d_hFindFile = FindFirstFileW(pw, &dw->d_fdw);
139   free((zvoid *)pw);
140 
141   if (dw->d_hFindFile == INVALID_HANDLE_VALUE)
142   {
143     free((zvoid *)dw);
144     return NULL;
145   }
146 
147   dw->d_first = 1;
148   return dw;
149 }
150 
151 #endif
152 
OpenDirScan(n)153 local zDIRSCAN *OpenDirScan(n)
154 ZCONST char *n;          /* directory to open */
155 /* Start searching for files in the MSDOS directory n */
156 {
157   zDIRSCAN *d;          /* malloc'd return value */
158   char *p;              /* malloc'd temporary string */
159   char *q;
160 
161   if ((d = (zDIRSCAN *)malloc(sizeof(zDIRSCAN))) == NULL ||
162       (p = malloc(strlen(n) + (2 + sizeof(wild_match_all)))) == NULL) {
163     if (d != NULL) free((zvoid *)d);
164     return NULL;
165   }
166   strcpy(p, n);
167   q = p + strlen(p);
168   if ((q - p) > 0 && MBSRCHR(p, ':') == (q - 1))
169       *q++ = '.';
170   if ((q - p) > 0 && MBSRCHR(p, '/') != (q - 1))
171     *q++ = '/';
172   strcpy(q, wild_match_all);
173 
174 #if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
175   OemToAnsi(p, p);
176 #endif
177   d->d_hFindFile = FindFirstFile(p, &d->d_fd);
178   free((zvoid *)p);
179 
180   if (d->d_hFindFile == INVALID_HANDLE_VALUE)
181   {
182     free((zvoid *)d);
183     return NULL;
184   }
185 
186   d->d_first = 1;
187   return d;
188 }
189 
190 
191 #ifdef UNICODE_SUPPORT
192 
GetNextDirEntryW(dw)193 local struct zdirscanw *GetNextDirEntryW(dw)
194 zDIRSCANW *dw;            /* directory stream to read from */
195 /* Return pointer to first or next directory entry, or NULL if end. */
196 {
197   if (dw->d_first)
198     dw->d_first = 0;
199   else
200   {
201     if (!FindNextFileW(dw->d_hFindFile, &dw->d_fdw))
202         return NULL;
203   }
204 #if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
205   CharToOemW(dw->d_fdw.cFileName, dw->d_fdw.cFileName);
206 #endif
207   return (struct zdirscanw *)dw;
208 }
209 
210 #endif
211 
GetNextDirEntry(d)212 local struct zdirscan *GetNextDirEntry(d)
213 zDIRSCAN *d;            /* directory stream to read from */
214 /* Return pointer to first or next directory entry, or NULL if end. */
215 {
216   if (d->d_first)
217     d->d_first = 0;
218   else
219   {
220     if (!FindNextFile(d->d_hFindFile, &d->d_fd))
221         return NULL;
222   }
223 #if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
224   AnsiToOem(d->d_fd.cFileName, d->d_fd.cFileName);
225 #endif
226   return (struct zdirscan *)d;
227 }
228 
CloseDirScan(d)229 local void CloseDirScan(d)
230 zDIRSCAN *d;            /* directory stream to close */
231 {
232   FindClose(d->d_hFindFile);
233   free((zvoid *)d);
234 }
235 
236 #ifdef UNICODE_SUPPORT
237 
CloseDirScanW(dw)238 local void CloseDirScanW(dw)
239 zDIRSCANW *dw;         /* directory stream to close */
240 {
241   FindClose(dw->d_hFindFile);
242   free((zvoid *)dw);
243 }
244 
245 #endif
246 
247 
248 #ifdef UNICODE_SUPPORT
249 
readdw(dw)250 local wchar_t *readdw(dw)
251   zDIRSCANW *dw;         /* directory stream to read from */
252 /* Return a pointer to the next name in the directory stream dw, or NULL if
253    no more entries or an error occurs. */
254 {
255   struct zdirscanw *ew;
256 
257   do
258     ew = GetNextDirEntryW(dw);
259   while (ew &&
260          ((!hidden_files && ew->d_fdw.dwFileAttributes & HIDD_SYS_BITS) ||
261           (only_archive_set &&
262            !(ew->d_fdw.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) &&
263            !(ew->d_fdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))));
264   if (ew == NULL)
265     return (wchar_t *) NULL;
266   return ew->d_fdw.cFileName;
267 }
268 
269 #endif
270 
readd(d)271 local char *readd(d)
272 zDIRSCAN *d;            /* directory stream to read from */
273 /* Return a pointer to the next name in the directory stream d, or NULL if
274    no more entries or an error occurs. */
275 {
276   struct zdirscan *e;
277 
278   do
279     e = GetNextDirEntry(d);
280   while (e &&
281          ((!hidden_files && e->d_fd.dwFileAttributes & HIDD_SYS_BITS) ||
282           (only_archive_set &&
283            !(e->d_fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) &&
284            !(e->d_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))));
285   /* When a wide character that is not supported by the current character
286      set is found, FindFirstFile and FindNextFile return a "?" in that spot.
287      A question mark is illegal in file names, so this flags that something
288      needs to be done.  It seems the fix is to use the 8.3 name in
289      this case, as that allows directory scans to continue.
290    */
291   if (e == NULL)
292     return (char *) NULL;
293   if (strchr(e->d_fd.cFileName, '?') && e->d_fd.cAlternateFileName) {
294     /* Have '?' in name, assume wide character we can't handle is in
295        the name and use short name if there is one.
296     */
297     return e->d_fd.cAlternateFileName;
298   }
299   return e->d_fd.cFileName;
300 }
301 
302 
303 #if 0
304 /* scan for the file in p and return Windows long name */
305 char *get_win32_longpath(p, n)
306   char *p;               /* path to get short name path for */
307   char **n;              /* pointer to name in returned path */
308 {
309   char  *q;              /* return string */
310   char  *c;
311   int    is_dir = 0;
312   char  *f;
313   char  *fp;
314   int    nr;
315   int    fplen;
316   int    fplen2;
317   HANDLE d_hFindFile;
318   WIN32_FIND_DATA d_fd;
319   int slashes = 0;
320   int returnslashes = 0;
321 
322   if (p == NULL)
323     return NULL;
324 
325   /* count path components */
326   for (f = p; *f; f++) {
327     if (*f == '/' || *f == '\\') {
328       slashes++;
329     }
330   }
331   /* Ignore trailing slash */
332   if (*p && (*(f - 1) == '/' || *(f - 1) == '\\'))
333     slashes--;
334 
335   /* get the length of the full path */
336   fplen = GetFullPathName(p, 0, NULL, NULL);
337 
338   if ((fp = malloc(fplen + 1)) == NULL) {
339     return NULL;
340   }
341   /* get full path */
342   fplen2 = GetFullPathName(p, fplen, fp, &f);
343   if (fplen2 > fplen) {
344     /* something changed */
345     free(fp);
346     return NULL;
347   }
348   c = fp + strlen(fp) - 1;
349   if (*c == '\\' || *c == '/') {
350     is_dir = 1;
351     *c = '\0';
352   }
353 
354   d_hFindFile = FindFirstFile(fp, &d_fd);
355   free(fp);
356 
357   if (d_hFindFile == INVALID_HANDLE_VALUE)
358   {
359     return NULL;
360   }
361 #if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
362   AnsiToOem(d->d_fd.cFileName, d->d_fd.cFileName);
363 #endif
364 
365   FindClose(d_hFindFile);
366 
367   if (d_fd.cFileName == NULL) {
368     return NULL;
369   }
370 
371   /* get the length of the full path */
372   fplen = GetFullPathName(d_fd.cFileName, 0, NULL, NULL);
373 
374   if ((fp = malloc(fplen + 1)) == NULL) {
375     return NULL;
376   }
377   /* get full path */
378   fplen2 = GetFullPathName(d_fd.cFileName, fplen, fp, &f);
379   if (fplen2 > fplen) {
380     /* something changed */
381     free(fp);
382     return NULL;
383   }
384 
385   /* characters from end to start of last component */
386   nr = 0;
387 
388   /* find start of relative path we came in with */
389   for (f = fp + strlen(fp); f != fp; f--) {
390     if (*f == ':')
391       break;
392     if (*f == '/' || *f == '\\') {
393       returnslashes++;
394       /* convert \ to / */
395       *f = '/';
396       if (nr == 0)
397         /* first slash from end */
398         nr = strlen(fp) - (f - fp);
399       if (returnslashes > slashes)
400         break;
401     }
402     if (*f == '\\' && *(f + 1) == '\\')
403       break;
404   }
405   if (f != fp)
406     /* on slash in middle */
407     f++;
408 
409   if ((q = malloc(strlen(f) + 2)) == NULL) {
410     return NULL;
411   }
412   strcpy(q, f);
413   *n = q + (strlen(q) - nr + 1);
414   if (is_dir) {
415     strcat(q, "/");
416   }
417   free(fp);
418 
419   return q;
420 }
421 #endif
422 
423 
424 #if 0
425 /* scan for the file in p and return Windows UTF-8 name */
426 char *get_win32_utf8path(p)
427   char *p;               /* path to get utf-8 name for */
428 {
429   char     *q;           /* return string */
430   char     *r = NULL;
431   int       is_dir = 0;
432   char     *f;
433   char     *fcp;
434   char     *fp;
435   wchar_t  *qw;
436   char     *lastc = '\0';
437   int       fplen;
438   int       fplen2;
439   int       ulen;
440   int       ulenw;
441   HANDLE    d_hFindFile;
442   WIN32_FIND_DATAW d_fd;
443   int pathslashes = 0;
444   int componentslashes = 0;
445   int slashes = 0;
446 
447   if (p == NULL)
448     return NULL;
449 
450   /* count path components */
451   for (f = p; *f; PREINCSTR(f)) {
452     if (*f == '/' || *f == '\\') {
453       slashes++;
454     }
455     lastc = f;
456   }
457   /* do not count trailing / */
458   if (*lastc == '/' || *lastc == '\\') {
459     is_dir = 1;
460     slashes--;
461   }
462 
463   /* Get the short path (as a bad long path could cause FindFirstFile to fail) */
464 
465   /* get the length of the short path */
466   fplen = GetShortPathName(p, NULL, 0);
467 
468   if ((fp = malloc(fplen + 1)) == NULL) {
469     return NULL;
470   }
471   /* get short path */
472   fplen2 = GetShortPathName(p, fp, fplen);
473   if (fplen2 > fplen) {
474     /* something changed */
475     free(fp);
476     return NULL;
477   }
478 
479   for (pathslashes = 0; pathslashes <= slashes; pathslashes++)
480   {
481 
482     /* get component path */
483     if ((fcp = malloc(fplen + 1)) == NULL) {
484       return NULL;
485     }
486     strcpy(fcp, fp);
487     componentslashes = 0;
488     for (f = fcp; *f; PREINCSTR(f)) {
489       if (*f == '/' || *f == '\\') {
490         componentslashes++;
491         if (componentslashes > pathslashes)
492           break;
493       }
494       lastc = f;
495     }
496     *f = '\0';
497 
498 
499     /* Get information for the file, including wide path */
500 
501     /* get length */
502     ulenw = MultiByteToWideChar(
503                 CP_ACP,            /* ANSI code page */
504                 0,                 /* flags for character-type options */
505                 fcp,               /* string to convert */
506                 -1,                /* string length (-1 = NULL terminated) */
507                 NULL,              /* buffer */
508                 0 );               /* buffer length (0 = return length) */
509     if (ulenw == 0) {
510       /* failed */
511       free(fcp);
512       free(fp);
513       return NULL;
514     }
515     ulenw++;
516     /* get length in bytes */
517     ulen = sizeof(wchar_t) * (ulenw + 1);
518     if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
519       free(fcp);
520       free(fp);
521       return NULL;
522     }
523     /* convert multibyte to wide */
524     ulen = MultiByteToWideChar(
525                CP_ACP,            /* ANSI code page */
526                0,                 /* flags for character-type options */
527                fcp,               /* string to convert */
528                -1,                /* string length (-1 = NULL terminated) */
529                qw,                /* buffer */
530                ulenw);            /* buffer length (0 = return length) */
531     if (ulen == 0) {
532       /* failed */
533       free(qw);
534       free(fcp);
535       free(fp);
536       return 0;
537     }
538 
539     d_hFindFile = FindFirstFileW(qw, &d_fd);
540     /* If this Win32 platform does not support Unicode wide paths
541        this returns INVALID_HANDLE_VALUE and the OS error is
542        "No such file or directory".  We return NULL and go with
543        the UTF-8 version of z->iname in f->uname.
544      */
545     free(qw);
546     free(fcp);
547     FindClose(d_hFindFile);
548 
549     if (d_hFindFile == INVALID_HANDLE_VALUE)
550     {
551       return NULL;
552     }
553 
554     /* Get buffer length */
555     ulen = WideCharToMultiByte(
556                     CP_UTF8,        /* UTF-8 code page */
557                     0,              /* flags */
558                     d_fd.cFileName, /* string to convert */
559                     -1,             /* input chars (-1 = NULL terminated) */
560                     NULL,           /* buffer */
561                     0,              /* size of buffer (0 = return needed size) */
562                     NULL,           /* default char */
563                     NULL);          /* used default char */
564     if (ulen == 0) {
565       /* failed */
566       return NULL;
567     }
568     ulen += 2;
569     if ((q = malloc(ulen + 1)) == NULL) {
570       return NULL;
571     }
572 
573     /* Convert the Unicode string to UTF-8 */
574     if ((ulen = WideCharToMultiByte(
575                     CP_UTF8,        /* UTF-8 code page */
576                     0,              /* flags */
577                     d_fd.cFileName, /* string to convert */
578                     -1,             /* input chars (-1 = NULL terminated) */
579                     q,              /* buffer */
580                     ulen,           /* size of buffer (0 = return needed size) */
581                     NULL,           /* default char */
582                     NULL)) == 0)    /* used default char */
583     {
584       free(fp);
585       free(q);
586       return NULL;
587     }
588 
589     if (r == NULL) {
590       /* first one */
591       r = q;
592     } else {
593       if ((r = realloc(r, strlen(r) + strlen(q) + 3)) == NULL) {
594         free(fp);
595         free(q);
596         return NULL;
597       }
598       strcat(r, "/");
599       strcat(r, q);
600       free(q);
601     }
602   }
603 
604   free(fp);
605 
606   if (is_dir) {
607     strcat(r, "/");
608   }
609 
610   return r;
611 }
612 #endif
613 
614 
615 #define ONENAMELEN 255
616 
617 /* whole is a pathname with wildcards, wildtail points somewhere in the  */
618 /* middle of it.  All wildcards to be expanded must come AFTER wildtail. */
619 
620 
621 #ifdef UNICODE_SUPPORT
622 
local_to_wchar_string(local_string)623 wchar_t *local_to_wchar_string(local_string)
624   char *local_string;       /* path to get utf-8 name for */
625 {
626   wchar_t  *qw;
627   int       ulen;
628   int       ulenw;
629 
630   if (local_string == NULL)
631     return NULL;
632 
633     /* get length */
634     ulenw = MultiByteToWideChar(
635                 CP_ACP,            /* ANSI code page */
636                 0,                 /* flags for character-type options */
637                 local_string,      /* string to convert */
638                 -1,                /* string length (-1 = NULL terminated) */
639                 NULL,              /* buffer */
640                 0 );               /* buffer length (0 = return length) */
641     if (ulenw == 0) {
642       /* failed */
643       return NULL;
644     }
645     ulenw++;
646     /* get length in bytes */
647     ulen = sizeof(wchar_t) * (ulenw + 1);
648     if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
649       return NULL;
650     }
651     /* convert multibyte to wide */
652     ulen = MultiByteToWideChar(
653                CP_ACP,            /* ANSI code page */
654                0,                 /* flags for character-type options */
655                local_string,      /* string to convert */
656                -1,                /* string length (-1 = NULL terminated) */
657                qw,                /* buffer */
658                ulenw);            /* buffer length (0 = return length) */
659     if (ulen == 0) {
660       /* failed */
661       free(qw);
662       return NULL;
663     }
664 
665   return qw;
666 }
667 
668 
utf8_to_wchar_string(utf8_string)669 wchar_t *utf8_to_wchar_string(utf8_string)
670   char *utf8_string;       /* path to get utf-8 name for */
671 {
672   wchar_t  *qw;
673   int       ulen;
674   int       ulenw;
675 
676   if (utf8_string == NULL)
677     return NULL;
678 
679     /* get length */
680     ulenw = MultiByteToWideChar(
681                 CP_UTF8,           /* UTF-8 code page */
682                 0,                 /* flags for character-type options */
683                 utf8_string,       /* string to convert */
684                 -1,                /* string length (-1 = NULL terminated) */
685                 NULL,              /* buffer */
686                 0 );               /* buffer length (0 = return length) */
687     if (ulenw == 0) {
688       /* failed */
689       return NULL;
690     }
691     ulenw++;
692     /* get length in bytes */
693     ulen = sizeof(wchar_t) * (ulenw + 1);
694     if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
695       return NULL;
696     }
697     /* convert multibyte to wide */
698     ulen = MultiByteToWideChar(
699                CP_UTF8,           /* UTF-8 code page */
700                0,                 /* flags for character-type options */
701                utf8_string,       /* string to convert */
702                -1,                /* string length (-1 = NULL terminated) */
703                qw,                /* buffer */
704                ulenw);            /* buffer length (0 = return length) */
705     if (ulen == 0) {
706       /* failed */
707       free(qw);
708       return NULL;
709     }
710 
711   return qw;
712 }
713 
714 
715 
716 /* Convert wchar_t string to utf8 using Windows calls
717    so any characters needing more than one wchar_t are
718    are handled by Windows */
wchar_to_utf8_string(wstring)719 char *wchar_to_utf8_string(wstring)
720   wchar_t *wstring;
721 {
722   char     *q;           /* return string */
723   int       ulen;
724 
725   if (wstring == NULL)
726     return NULL;
727 
728   /* Get buffer length */
729   ulen = WideCharToMultiByte(
730                   CP_UTF8,        /* UTF-8 code page */
731                   0,              /* flags */
732                   wstring,        /* string to convert */
733                   -1,             /* input chars (-1 = NULL terminated) */
734                   NULL,           /* buffer */
735                   0,              /* size of buffer (0 = return needed size) */
736                   NULL,           /* default char */
737                   NULL);          /* used default char */
738   if (ulen == 0) {
739     /* failed */
740     return NULL;
741   }
742   ulen += 2;
743   if ((q = malloc(ulen + 1)) == NULL) {
744     return NULL;
745   }
746 
747   /* Convert the Unicode string to UTF-8 */
748   if ((ulen = WideCharToMultiByte(
749                   CP_UTF8,        /* UTF-8 code page */
750                   0,              /* flags */
751                   wstring,        /* string to convert */
752                   -1,             /* input chars (-1 = NULL terminated) */
753                   q,              /* buffer */
754                   ulen,           /* size of buffer (0 = return needed size) */
755                   NULL,           /* default char */
756                   NULL)) == 0)    /* used default char */
757   {
758     free(q);
759     return NULL;
760   }
761 
762   return q;
763 }
764 
765 
wild_recursew(whole,wildtail)766 local int wild_recursew(whole, wildtail)
767   wchar_t *whole;
768   wchar_t *wildtail;
769 {
770     zDIRSCANW *dirw;
771     wchar_t *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
772     extent newlen;
773     int amatch = 0, e = ZE_MISS;
774 
775     if (!isshexpw(wildtail)) {
776         if (GetFileAttributesW(whole) != 0xFFFFFFFF) {    /* file exists? */
777 #if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
778             CharToOemW(whole, whole);
779 #endif
780             return procnamew(whole, 0);
781         }
782         else
783             return ZE_MISS;                     /* woops, no wildcards! */
784     }
785 
786     /* back up thru path components till existing dir found */
787     do {
788         name = wildtail + wcslen(wildtail) - 1;
789         for (;;)
790             if (name-- <= wildtail || *name == PATH_END) {
791                 subwild = name + 1;
792                 plug2 = *subwild;
793                 *subwild = 0;
794                 break;
795             }
796         if (glue)
797             *glue = plug;
798         glue = subwild;
799         plug = plug2;
800         dirw = OpenDirScanW(whole);
801     } while (!dirw && subwild > wildtail);
802     wildtail = subwild;                 /* skip past non-wild components */
803 
804     if ((subwild = wcschr(wildtail + 1, PATH_END)) != NULL) {
805         /* this "+ 1" dodges the   ^^^ hole left by *glue == 0 */
806         *(subwild++) = 0;               /* wildtail = one component pattern */
807         newlen = wcslen(whole) + wcslen(subwild) + (ONENAMELEN + 2);
808     } else
809         newlen = wcslen(whole) + (ONENAMELEN + 1);
810     if (!dirw || ((newwhole = malloc(newlen * sizeof(wchar_t))) == NULL)) {
811         if (glue)
812             *glue = plug;
813         e = dirw ? ZE_MEM : ZE_MISS;
814         goto ohforgetit;
815     }
816     wcscpy(newwhole, whole);
817     newlen = wcslen(newwhole);
818     if (glue)
819         *glue = plug;                           /* repair damage to whole */
820     if (!isshexpw(wildtail)) {
821         e = ZE_MISS;                            /* non-wild name not found */
822         goto ohforgetit;
823     }
824 
825     while ((name = readdw(dirw)) != NULL) {
826         if (wcscmp(name, L".") && wcscmp(name, L"..") &&
827             MATCHW(wildtail, name, 0)) {
828             wcscpy(newwhole + newlen, name);
829             if (subwild) {
830                 name = newwhole + wcslen(newwhole);
831                 *(name++) = (wchar_t)PATH_END;
832                 wcscpy(name, subwild);
833                 e = wild_recursew(newwhole, name);
834             } else
835                 e = procname_win32w(newwhole, 0, GetDirAttribsW(dirw));
836             newwhole[newlen] = 0;
837             if (e == ZE_OK)
838                 amatch = 1;
839             else if (e != ZE_MISS)
840                 break;
841         }
842     }
843 
844   ohforgetit:
845     if (dirw) CloseDirScanW(dirw);
846     if (subwild) *--subwild = PATH_END;
847     if (newwhole) free(newwhole);
848     if (e == ZE_MISS && amatch)
849         e = ZE_OK;
850     return e;
851 }
852 
853 #endif
854 
855 
wild_recurse(whole,wildtail)856 local int wild_recurse(whole, wildtail)
857   char *whole;
858   char *wildtail;
859 {
860     zDIRSCAN *dir;
861     char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
862     extent newlen;
863     int amatch = 0, e = ZE_MISS;
864 
865     if (!isshexp(wildtail)) {
866         if (GetFileAttributes(whole) != 0xFFFFFFFF) {    /* file exists? */
867 #if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
868             AnsiToOem(whole, whole);
869 #endif
870             return procname(whole, 0);
871         }
872         else
873             return ZE_MISS;                     /* woops, no wildcards! */
874     }
875 
876     /* back up thru path components till existing dir found */
877     do {
878         name = wildtail + strlen(wildtail) - 1;
879         for (;;)
880             if (name-- <= wildtail || *name == PATH_END) {
881                 subwild = name + 1;
882                 plug2 = *subwild;
883                 *subwild = 0;
884                 break;
885             }
886         if (glue)
887             *glue = plug;
888         glue = subwild;
889         plug = plug2;
890         dir = OpenDirScan(whole);
891     } while (!dir && subwild > wildtail);
892     wildtail = subwild;                 /* skip past non-wild components */
893 
894     if ((subwild = MBSCHR(wildtail + 1, PATH_END)) != NULL) {
895         /* this "+ 1" dodges the   ^^^ hole left by *glue == 0 */
896         *(subwild++) = 0;               /* wildtail = one component pattern */
897         newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
898     } else
899         newlen = strlen(whole) + (ONENAMELEN + 1);
900     if (!dir || ((newwhole = malloc(newlen)) == NULL)) {
901         if (glue)
902             *glue = plug;
903         e = dir ? ZE_MEM : ZE_MISS;
904         goto ohforgetit;
905     }
906     strcpy(newwhole, whole);
907     newlen = strlen(newwhole);
908     if (glue)
909         *glue = plug;                           /* repair damage to whole */
910     if (!isshexp(wildtail)) {
911         e = ZE_MISS;                            /* non-wild name not found */
912         goto ohforgetit;
913     }
914 
915     while ((name = readd(dir)) != NULL) {
916         if (strcmp(name, ".") && strcmp(name, "..") &&
917             MATCH(wildtail, name, 0)) {
918             strcpy(newwhole + newlen, name);
919             if (subwild) {
920                 name = newwhole + strlen(newwhole);
921                 *(name++) = PATH_END;
922                 strcpy(name, subwild);
923                 e = wild_recurse(newwhole, name);
924             } else
925                 e = procname_win32(newwhole, 0, GetDirAttribs(dir));
926             newwhole[newlen] = 0;
927             if (e == ZE_OK)
928                 amatch = 1;
929             else if (e != ZE_MISS)
930                 break;
931         }
932     }
933 
934   ohforgetit:
935     if (dir) CloseDirScan(dir);
936     if (subwild) *--subwild = PATH_END;
937     if (newwhole) free(newwhole);
938     if (e == ZE_MISS && amatch)
939         e = ZE_OK;
940     return e;
941 }
942 
943 
944 #ifdef UNICODE_SUPPORT
has_win32_wide()945 int has_win32_wide() {
946   DWORD r;
947 
948   /* test if we have wide function support */
949 
950   /* check if already set */
951   if (no_win32_wide != -1)
952     return !no_win32_wide;
953 
954   /* assume we don't */
955   no_win32_wide = 1;
956 
957   /* get attributes for this directory */
958   r = GetFileAttributes(".");
959 
960   /* r should be 16 = FILE_ATTRIBUTE_DIRECTORY */
961   if (r == FILE_ATTRIBUTE_DIRECTORY) {
962     /* now see if it works for the wide version */
963     r = GetFileAttributesW(L".");
964     /* if this fails then we probably don't have wide functions */
965     if (r == 0xFFFFFFFF) {
966       /* error is probably "This function is only valid in Win32 mode." */
967     } else if (r == FILE_ATTRIBUTE_DIRECTORY) {
968       /* worked, so assume we have wide support */
969       no_win32_wide = 0;
970     }
971   }
972 
973   return !no_win32_wide;
974 }
975 #endif
976 
977 
wild(w)978 int wild(w)
979   char *w;               /* path/pattern to match */
980 /* If not in exclude mode, expand the pattern based on the contents of the
981    file system.  Return an error code in the ZE_ class. */
982 {
983     char *p;             /* path */
984     char *q;             /* diskless path */
985     int e;               /* result */
986 #ifdef UNICODE_SUPPORT
987     wchar_t *pw;         /* wide path */
988     wchar_t *qw;         /* wide diskless path */
989 #endif
990 
991     if (volume_label == 1) {
992       volume_label = 2;
993       label = getVolumeLabel((w != NULL && isascii((uch)w[0]) && w[1] == ':')
994                              ? to_up(w[0]) : '\0',
995                              &label_time, &label_mode, &label_utim);
996       if (label != NULL)
997         (void)newname(label, 0, 0);
998       if (w == NULL || (isascii((uch)w[0]) && w[1] == ':' && w[2] == '\0'))
999         return ZE_OK;
1000       /* "zip -$ foo a:" can be used to force drive name */
1001     }
1002     /* special handling of stdin request */
1003     if (strcmp(w, "-") == 0)   /* if compressing stdin */
1004         return newname(w, 0, 0);
1005 
1006     /* Allocate and copy pattern, leaving room to add "." if needed */
1007     if ((p = malloc(strlen(w) + 2)) == NULL)
1008         return ZE_MEM;
1009     strcpy(p, w);
1010 
1011     /* Normalize path delimiter as '/' */
1012     for (q = p; *q; INCSTR(q))            /* use / consistently */
1013         if (*q == '\\')
1014             *q = '/';
1015 
1016 #ifdef UNICODE_SUPPORT
1017     if (!no_win32_wide) {
1018       /* wide char version */
1019       pw = local_to_wchar_string(p);
1020 
1021       /* Separate the disk part of the path */
1022       if ((qw = wcschr(pw, ':')) != NULL) {
1023           if (wcschr(++qw, ':'))     /* sanity check for safety of wild_recurse */
1024               return ZE_MISS;
1025       } else
1026           qw = pw;
1027 
1028       /* Normalize bare disk names */
1029       if (qw > pw && !*qw)
1030           wcscpy(qw, L".");
1031     } else {
1032       /* multibyte version */
1033       /* Separate the disk part of the path */
1034       if ((q = MBSCHR(p, ':')) != NULL) {
1035           if (MBSCHR(++q, ':'))     /* sanity check for safety of wild_recurse */
1036               return ZE_MISS;
1037       } else
1038           q = p;
1039 
1040       /* Normalize bare disk names */
1041       if (q > p && !*q)
1042           strcpy(q, ".");
1043     }
1044 #else
1045     /* multibyte version */
1046     /* Separate the disk part of the path */
1047     if ((q = MBSCHR(p, ':')) != NULL) {
1048         if (MBSCHR(++q, ':'))     /* sanity check for safety of wild_recurse */
1049             return ZE_MISS;
1050     } else
1051         q = p;
1052 
1053     /* Normalize bare disk names */
1054     if (q > p && !*q)
1055         strcpy(q, ".");
1056 #endif
1057 
1058     /* Here we go */
1059 #ifdef UNICODE_SUPPORT
1060     if (!no_win32_wide) {
1061       /* use wide Unicode directory scan */
1062       e = wild_recursew(pw, qw);
1063 
1064       free(pw);
1065     } else {
1066       /* use multibyte directory scan */
1067       e = wild_recurse(p, q);
1068     }
1069 #else
1070     e = wild_recurse(p, q);
1071 #endif
1072     free((zvoid *)p);
1073     return e;
1074 }
1075 
1076 
procname_win32(n,caseflag,attribs)1077 local int procname_win32(n, caseflag, attribs)
1078   char *n;                /* name to process */
1079   int caseflag;           /* true to force case-sensitive match */
1080   DWORD attribs;
1081 /* Process a name or sh expression to operate on (or exclude).  Return
1082    an error code in the ZE_ class. */
1083 {
1084   char *a;              /* path and name for recursion */
1085   zDIRSCAN *d;          /* directory stream from OpenDirScan() */
1086   char *e;              /* pointer to name from readd() */
1087   int m;                /* matched flag */
1088   char *p;              /* path for recursion */
1089   z_stat s;             /* result of stat() */
1090   struct zlist far *z;  /* steps through zfiles list */
1091 
1092   if (strcmp(n, "-") == 0)   /* if compressing stdin */
1093     return newname(n, 0, caseflag);
1094   else if (attribs != INVALID_WIN32_FILE_ATTRIBS)
1095   {
1096     /* Avoid calling stat() for performance reasons when it is already known
1097        (from a previous directory scan) that the passed name corresponds to
1098        a "real existing" file.  The only information needed further down in
1099        this function is the distinction between directory entries and other
1100        (typically normal file) entries.  This distinction can be derived from
1101        the file's attributes that the directory lookup has already provided
1102        "for free".
1103      */
1104     s.st_mode = ((attribs & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG);
1105   }
1106   else if (LSSTAT(n, &s)
1107 #ifdef __TURBOC__
1108            /* For this compiler, stat() succeeds on wild card names! */
1109            /* Unfortunately, this causes failure on names containing */
1110            /* square bracket characters, which are legal in win32.   */
1111            || isshexp(n)
1112 #endif
1113           )
1114   {
1115 #ifdef UNICODE_SUPPORT
1116     char *uname = NULL;
1117 #endif
1118     /* Not a file or directory--search for shell expression in zip file */
1119     p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
1120     m = 1;
1121     for (z = zfiles; z != NULL; z = z->nxt) {
1122       if (MATCH(p, z->iname, caseflag))
1123       {
1124         z->mark = pcount ? filter(z->zname, caseflag) : 1;
1125         if (verbose)
1126             fprintf(mesg, "zip diagnostic: %scluding %s\n",
1127                z->mark ? "in" : "ex", z->oname);
1128         m = 0;
1129       }
1130     }
1131 #ifdef UNICODE_SUPPORT
1132     /* also check escaped Unicode names */
1133     for (z = zfiles; z != NULL; z = z->nxt) {
1134       if (z->zuname) {
1135 #ifdef WIN32
1136         /* It seems something is lost in going from a listed
1137            name from zip -su in a console window to using that
1138            name in a command line.  This kluge may fix it
1139            and just takes zuname, converts to oem (i.e.ouname),
1140            then converts it back which ends up not the same as
1141            started with.
1142          */
1143         uname = z->wuname;
1144 #else
1145         uname = z->zuname;
1146 #endif
1147         if (MATCH(p, uname, caseflag))
1148         {
1149           z->mark = pcount ? filter(uname, caseflag) : 1;
1150           if (verbose) {
1151               fprintf(mesg, "zip diagnostic: %scluding %s\n",
1152                  z->mark ? "in" : "ex", z->oname);
1153               fprintf(mesg, "     Escaped Unicode:  %s\n",
1154                  z->ouname);
1155           }
1156           m = 0;
1157         }
1158       }
1159     }
1160 #endif
1161     free((zvoid *)p);
1162     return m ? ZE_MISS : ZE_OK;
1163   }
1164 
1165   /* Live name--use if file, recurse if directory */
1166   for (p = n; *p; INCSTR(p))    /* use / consistently */
1167     if (*p == '\\')
1168       *p = '/';
1169   if ((s.st_mode & S_IFDIR) == 0)
1170   {
1171     /* add exclusions in directory recurse but ignored for single file */
1172     DWORD dwAttr;
1173 
1174     dwAttr = GetFileMode(n);
1175 
1176     if ((hidden_files ||
1177          !(dwAttr & FILE_ATTRIBUTE_HIDDEN || dwAttr & FILE_ATTRIBUTE_SYSTEM)) &&
1178         (!only_archive_set || (dwAttr & FILE_ATTRIBUTE_ARCHIVE)))
1179     {
1180       /* add or remove name of file */
1181       if ((m = newname(n, 0, caseflag)) != ZE_OK)
1182         return m;
1183     }
1184   } else {
1185     /* Add trailing / to the directory name */
1186     if ((p = (char *) malloc(strlen(n)+2)) == NULL)
1187       return ZE_MEM;
1188     if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
1189       *p = '\0';  /* avoid "./" prefix and do not create zip entry */
1190     } else {
1191       strcpy(p, n);
1192       a = p + strlen(p);
1193       if (lastchar(p) != '/')
1194         strcpy(a, "/");
1195       if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
1196         free((zvoid *)p);
1197         return m;
1198       }
1199     }
1200     /* recurse into directory */
1201     if (recurse && (d = OpenDirScan(n)) != NULL)
1202     {
1203       while ((e = readd(d)) != NULL) {
1204         if (strcmp(e, ".") && strcmp(e, ".."))
1205         {
1206           if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
1207           {
1208             CloseDirScan(d);
1209             free((zvoid *)p);
1210             return ZE_MEM;
1211           }
1212           strcat(strcpy(a, p), e);
1213           if ((m = procname_win32(a, caseflag, GetDirAttribs(d)))
1214               != ZE_OK)         /* recurse on name */
1215           {
1216             if (m == ZE_MISS)
1217               zipwarn("name not matched: ", a);
1218             else
1219               ziperr(m, a);
1220           }
1221           free((zvoid *)a);
1222         }
1223       }
1224       CloseDirScan(d);
1225     }
1226     free((zvoid *)p);
1227   } /* (s.st_mode & S_IFDIR) == 0) */
1228   return ZE_OK;
1229 }
1230 
1231 
1232 #ifdef UNICODE_SUPPORT
procname_win32w(nw,caseflag,attribs)1233 local int procname_win32w(nw, caseflag, attribs)
1234   wchar_t *nw;             /* name to process */
1235   int caseflag;           /* true to force case-sensitive match */
1236   DWORD attribs;
1237 /* Process a name or sh expression to operate on (or exclude).  Return
1238    an error code in the ZE_ class. */
1239 {
1240   wchar_t *aw;          /* path and name for recursion */
1241   zDIRSCANW *dw;        /* directory stream from OpenDirScan() */
1242   wchar_t *ew;          /* pointer to name from readd() */
1243   int m;                /* matched flag */
1244   wchar_t *pw;          /* path for recursion */
1245   zw_stat s;            /* result of stat() */
1246   struct zlist far *z;  /* steps through zfiles list */
1247 
1248   if (wcscmp(nw, L"-") == 0)   /* if compressing stdin */
1249     return newnamew(nw, 0, caseflag);
1250   else if (attribs != INVALID_WIN32_FILE_ATTRIBS)
1251   {
1252     /* Avoid calling stat() for performance reasons when it is already known
1253        (from a previous directory scan) that the passed name corresponds to
1254        a "real existing" file.  The only information needed further down in
1255        this function is the distinction between directory entries and other
1256        (typically normal file) entries.  This distinction can be derived from
1257        the file's attributes that the directory lookup has already provided
1258        "for free".
1259      */
1260     s.st_mode = ((attribs & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG);
1261   }
1262   else if (LSSTATW(nw, &s)
1263 #ifdef __TURBOC__
1264            /* For this compiler, stat() succeeds on wild card names! */
1265            /* Unfortunately, this causes failure on names containing */
1266            /* square bracket characters, which are legal in win32.   */
1267            || isshexpw(nw)
1268 #endif
1269           )
1270   {
1271     wchar_t *unamew = NULL;
1272     /* Not a file or directory--search for shell expression in zip file */
1273     pw = ex2inw(nw, 0, (int *)NULL);     /* shouldn't affect matching chars */
1274     m = 1;
1275     for (z = zfiles; z != NULL; z = z->nxt) {
1276       if (MATCHW(pw, z->znamew, caseflag))
1277       {
1278         z->mark = pcount ? filter(z->zname, caseflag) : 1;
1279         if (verbose)
1280             fprintf(mesg, "zip diagnostic: %scluding %s\n",
1281                z->mark ? "in" : "ex", z->oname);
1282         m = 0;
1283       }
1284     }
1285     /* also check escaped Unicode names */
1286     for (z = zfiles; z != NULL; z = z->nxt) {
1287       if (z->zuname) {
1288         unamew = z->znamew;
1289         if (MATCHW(pw, unamew, caseflag))
1290         {
1291           z->mark = pcount ? filter(z->iname, caseflag) : 1;
1292           if (verbose) {
1293               fprintf(mesg, "zip diagnostic: %scluding %s\n",
1294                  z->mark ? "in" : "ex", z->oname);
1295               fprintf(mesg, "     Escaped Unicode:  %s\n",
1296                  z->ouname);
1297           }
1298           m = 0;
1299         }
1300       }
1301     }
1302     free((zvoid *)pw);
1303     return m ? ZE_MISS : ZE_OK;
1304   }
1305 
1306   /* Live name--use if file, recurse if directory */
1307   for (pw = nw; *pw; pw++)    /* use / consistently */
1308     if (*pw == (wchar_t)'\\')
1309       *pw = (wchar_t)'/';
1310   if ((s.st_mode & S_IFDIR) == 0)
1311   {
1312     /* add exclusions in directory recurse but ignored for single file */
1313     DWORD dwAttr;
1314 
1315     dwAttr = GetFileModeW(nw);
1316 
1317     if ((hidden_files ||
1318          !(dwAttr & FILE_ATTRIBUTE_HIDDEN || dwAttr & FILE_ATTRIBUTE_SYSTEM)) &&
1319         (!only_archive_set || (dwAttr & FILE_ATTRIBUTE_ARCHIVE)))
1320     {
1321       /* add or remove name of file */
1322       if ((m = newnamew(nw, 0, caseflag)) != ZE_OK)
1323         return m;
1324     }
1325   } else {
1326     /* Add trailing / to the directory name */
1327     pw = (wchar_t *)malloc( (wcslen(nw)+2) * sizeof(wchar_t) );
1328     if (pw == NULL)
1329       return ZE_MEM;
1330     if (wcscmp(nw, L".") == 0 || wcscmp(nw, L"/.") == 0) {
1331       *pw = (wchar_t)'\0';  /* avoid "./" prefix and do not create zip entry */
1332     } else {
1333       wcscpy(pw, nw);
1334       aw = pw + wcslen(pw);
1335       if (pw[wcslen(pw) - 1] != (wchar_t)'/')
1336         wcscpy(aw, L"/");
1337       if (dirnames && (m = newnamew(pw, 1, caseflag)) != ZE_OK) {
1338         free((zvoid *)pw);
1339         return m;
1340       }
1341     }
1342     /* recurse into directory */
1343     if (recurse && (dw = OpenDirScanW(nw)) != NULL)
1344     {
1345       while ((ew = readdw(dw)) != NULL) {
1346         if (wcscmp(ew, L".") && wcscmp(ew, L".."))
1347         {
1348           if ((aw = malloc((wcslen(pw) + wcslen(ew) + 1) * sizeof(wchar_t))) == NULL)
1349           {
1350             CloseDirScanW(dw);
1351             free((zvoid *)pw);
1352             return ZE_MEM;
1353           }
1354           wcscat(wcscpy(aw, pw), ew);
1355           if ((m = procname_win32w(aw, caseflag, GetDirAttribsW(dw)))
1356               != ZE_OK)         /* recurse on name */
1357           {
1358             char *a;
1359             char *ad;
1360 
1361             a = wchar_to_local_string(aw);
1362             ad = local_to_display_string(a);
1363 
1364             if (m == ZE_MISS)
1365               zipwarn("name not matched: ", ad);
1366             else
1367               ziperr(m, a);
1368             free(ad);
1369             free(a);
1370           }
1371           free((zvoid *)aw);
1372         }
1373       }
1374       CloseDirScanW(dw);
1375     }
1376     free((zvoid *)pw);
1377   } /* (s.st_mode & S_IFDIR) == 0) */
1378   return ZE_OK;
1379 }
1380 #endif
1381 
1382 
1383 #ifdef UNICODE_SUPPORT
procnamew(nw,caseflag)1384 int procnamew(nw, caseflag)
1385   wchar_t *nw;          /* name to process */
1386   int caseflag;         /* true to force case-sensitive match */
1387 {
1388     return procname_win32w(nw, caseflag, INVALID_WIN32_FILE_ATTRIBS);
1389 }
1390 #endif
1391 
procname(n,caseflag)1392 int procname(n, caseflag)
1393   char *n;             /* name to process */
1394   int caseflag;         /* true to force case-sensitive match */
1395 {
1396     return procname_win32(n, caseflag, INVALID_WIN32_FILE_ATTRIBS);
1397 }
1398 
ex2in(x,isdir,pdosflag)1399 char *ex2in(x, isdir, pdosflag)
1400   char *x;             /* external file name */
1401   int isdir;            /* input: x is a directory */
1402   int *pdosflag;        /* output: force MSDOS file attributes? */
1403 /* Convert the external file name to a zip file name, returning the malloc'ed
1404    string or NULL if not enough memory. */
1405 {
1406   char *n;              /* internal file name (malloc'ed) */
1407   char *t;              /* shortened name */
1408   int dosflag;
1409 
1410 
1411   dosflag = dosify || IsFileSystemOldFAT(x);
1412   if (!dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL)
1413   {
1414     x = t;
1415     dosflag = 0;
1416   }
1417 
1418   /* Find starting point in name before doing malloc */
1419   /* Strip drive specification */
1420   t = *x && isascii((uch)*x) && *(x + 1) == ':' ? x + 2 : x;
1421   /* Strip "//host/share/" part of a UNC name */
1422   if ((!strncmp(x,"//",2) || !strncmp(x,"\\\\",2)) &&
1423       (x[2] != '\0' && x[2] != '/' && x[2] != '\\')) {
1424     n = x + 2;
1425     while (*n != '\0' && *n != '/' && *n != '\\')
1426       INCSTR(n);        /* strip host name */
1427     if (*n != '\0') {
1428       INCSTR(n);
1429       while (*n != '\0' && *n != '/' && *n != '\\')
1430         INCSTR(n);      /* strip `share' name */
1431     }
1432     if (*n != '\0')
1433       t = n + MB_CLEN(n);
1434   }
1435   /* Strip leading "/" to convert an absolute path into a relative path */
1436   while (*t == '/' || *t == '\\')
1437     t++;
1438   /* Strip leading "./" as well as drive letter */
1439   while (*t == '.' && (t[1] == '/' || t[1] == '\\'))
1440     t += 2;
1441 
1442   /* Make changes, if any, to the copied name (leave original intact) */
1443   for (n = t; *n; INCSTR(n))
1444     if (*n == '\\')
1445       *n = '/';
1446 
1447   if (!pathput)
1448     t = last(t, PATH_END);
1449 
1450   /* Malloc space for internal name and copy it */
1451   if ((n = malloc(strlen(t) + 1)) == NULL)
1452     return NULL;
1453   strcpy(n, t);
1454 
1455   if (dosify)
1456     msname(n);
1457 
1458   /* Returned malloc'ed name */
1459   if (pdosflag)
1460     *pdosflag = dosflag;
1461 #if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
1462   OemToAnsi(n, n);
1463 #endif
1464   return n;
1465 }
1466 
1467 #ifdef UNICODE_SUPPORT
ex2inw(xw,isdir,pdosflag)1468 wchar_t *ex2inw(xw, isdir, pdosflag)
1469   wchar_t *xw;          /* external file name */
1470   int isdir;            /* input: x is a directory */
1471   int *pdosflag;        /* output: force MSDOS file attributes? */
1472 /* Convert the external file name to a zip file name, returning the malloc'ed
1473    string or NULL if not enough memory. */
1474 {
1475   wchar_t *nw;          /* internal file name (malloc'ed) */
1476   wchar_t *tw;          /* shortened name */
1477   int dosflag;
1478 
1479 
1480   dosflag = dosify || IsFileSystemOldFATW(xw);
1481   if (!dosify && use_longname_ea && (tw = GetLongPathEAW(xw)) != NULL)
1482   {
1483     xw = tw;
1484     dosflag = 0;
1485   }
1486 
1487   /* Find starting point in name before doing malloc */
1488   /* Strip drive specification */
1489   tw = *xw && iswascii(*xw) && *(xw + 1) == (wchar_t)':' ? xw + 2 : xw;
1490   /* Strip "//host/share/" part of a UNC name */
1491   if ((!wcsncmp(xw,L"//",2) || !wcsncmp(xw,L"\\\\",2)) &&
1492       (xw[2] != (wchar_t)'\0' && xw[2] != (wchar_t)'/' && xw[2] != (wchar_t)'\\')) {
1493     nw = xw + 2;
1494     while (*nw != (wchar_t)'\0' && *nw != (wchar_t)'/' && *nw != (wchar_t)'\\')
1495       nw++;        /* strip host name */
1496     if (*nw != (wchar_t)'\0') {
1497       nw++;
1498       while (*nw != (wchar_t)'\0' && *nw != (wchar_t)'/' && *nw != (wchar_t)'\\')
1499         nw++;      /* strip `share' name */
1500     }
1501     if (*nw != (wchar_t)'\0')
1502       tw = nw++;
1503   }
1504   /* Strip leading "/" to convert an absolute path into a relative path */
1505   while (*tw == (wchar_t)'/' || *tw == (wchar_t)'\\')
1506     tw++;
1507   /* Strip leading "./" as well as drive letter */
1508   while (*tw == (wchar_t)'.' && (tw[1] == (wchar_t)'/' || tw[1] == (wchar_t)'\\'))
1509     tw += 2;
1510 
1511   /* Make changes, if any, to the copied name (leave original intact) */
1512   for (nw = tw; *nw; nw++)
1513     if (*nw == '\\')
1514       *nw = '/';
1515 
1516   if (!pathput)
1517     tw = lastw(tw, PATH_END);
1518 
1519   /* Malloc space for internal name and copy it */
1520   if ((nw = malloc((wcslen(tw) + 1) * sizeof(wchar_t))) == NULL)
1521     return NULL;
1522   wcscpy(nw, tw);
1523 
1524   if (dosify)
1525     msnamew(nw);
1526 
1527   /* Returned malloc'ed name */
1528   if (pdosflag)
1529     *pdosflag = dosflag;
1530 #if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
1531   CharToAnsiW(nw, nw);
1532 #endif
1533   return nw;
1534 }
1535 #endif
1536 
1537 
in2ex(n)1538 char *in2ex(n)
1539   char *n;             /* internal file name */
1540 /* Convert the zip file name to an external file name, returning the malloc'ed
1541    string or NULL if not enough memory. */
1542 {
1543   char *x;             /* external file name */
1544 
1545   if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
1546     return NULL;
1547   strcpy(x, n);
1548 # if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
1549   AnsiToOem(x, x);
1550 # endif
1551   return x;
1552 }
1553 
1554 #ifdef UNICODE_SUPPORT
in2exw(nw)1555 wchar_t *in2exw(nw)
1556   wchar_t *nw;            /* internal file name */
1557 /* Convert the zip file name to an external file name, returning the malloc'ed
1558    string or NULL if not enough memory. */
1559 {
1560   wchar_t *xw;            /* external file name */
1561 
1562   if ((xw = malloc((wcslen(nw) + 1 + PAD) * sizeof(wchar_t))) == NULL)
1563     return NULL;
1564   wcscpy(xw, nw);
1565 # if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
1566   CharToOemW(xw, xw);
1567 # endif
1568   return xw;
1569 }
1570 #endif
1571 
1572 
stamp(f,d)1573 void stamp(f, d)
1574   char *f;                /* name of file to change */
1575   ulg d;                  /* dos-style time to change it to */
1576 /* Set last updated and accessed time of file f to the DOS time d. */
1577 {
1578 #if defined(__TURBOC__) && !defined(__BORLANDC__)
1579   int h;                /* file handle */
1580 
1581   if ((h = open(f, 0)) != -1)
1582   {
1583     setftime(h, (struct ftime *)&d);
1584     close(h);
1585   }
1586 #else /* !__TURBOC__ */
1587 
1588   struct utimbuf u;     /* argument for utime() */
1589 
1590   /* Convert DOS time to time_t format in u.actime and u.modtime */
1591   u.actime = u.modtime = dos2unixtime(d);
1592 
1593   /* Set updated and accessed times of f */
1594   utime(f, &u);
1595 #endif /* ?__TURBOC__ */
1596 }
1597 
filetime(f,a,n,t)1598 ulg filetime(f, a, n, t)
1599   char *f;              /* name of file to get info on */
1600   ulg *a;               /* return value: file attributes */
1601   zoff_t *n;            /* return value: file size */
1602   iztimes *t;           /* return value: access, modific. and creation times */
1603 /* If file *f does not exist, return 0.  Else, return the file's last
1604    modified date and time as an MSDOS date and time.  The date and
1605    time is returned in a long with the date most significant to allow
1606    unsigned integer comparison of absolute times.  Also, if a is not
1607    a NULL pointer, store the file attributes there, with the high two
1608    bytes being the Unix attributes, and the low byte being a mapping
1609    of that to DOS attributes.  If n is not NULL, store the file size
1610    there.  If t is not NULL, the file's access, modification and creation
1611    times are stored there as UNIX time_t values.
1612    If f is "-", use standard input as the file. If f is a device, return
1613    a file size of -1 */
1614 {
1615   z_stat s;             /* results of zstat() */
1616 
1617   /* converted to malloc instead of using FNMAX - 11/8/04 EG */
1618   char *name;
1619   unsigned int len = strlen(f);
1620   int isstdin = !strcmp(f, "-");
1621 
1622   if (f == label) {
1623     if (a != NULL)
1624       *a = label_mode;
1625     if (n != NULL)
1626       *n = -2L; /* convention for a label name */
1627     if (t != NULL)
1628       t->atime = t->mtime = t->ctime = label_utim;
1629     return label_time;
1630   }
1631   if ((name = malloc(len + 1)) == NULL) {
1632     ZIPERR(ZE_MEM, "filetime");
1633   }
1634   strcpy(name, f);
1635   if (MBSRCHR(name, '/') == (name + len - 1))
1636     name[len - 1] = '\0';
1637   /* not all systems allow stat'ing a file with / appended */
1638 
1639   /* zip64 support 08/31/2003 R.Nausedat */
1640   if (isstdin) {
1641     if (zfstat(fileno(stdin), &s) != 0) {
1642       free(name);
1643       error("fstat(stdin)");
1644     }
1645     time((time_t *)&s.st_mtime);       /* some fstat()s return time zero */
1646   } else if (LSSTAT(name, &s) != 0) {
1647              /* Accept about any file kind including directories
1648               * (stored with trailing / with -r option)
1649               */
1650     free(name);
1651     return 0;
1652   }
1653 
1654   if (a != NULL) {
1655 #ifdef WIN32_OEM
1656     /* When creating DOS-like archives with OEM-charset names, only the
1657        standard FAT attributes should be used.
1658        (Note: On a Win32 system, the UNIX style attributes from stat()
1659               do not contain any additional information...)
1660      */
1661     *a = (isstdin ? 0L : (ulg)GetFileMode(name));
1662 #else
1663     *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
1664 #endif
1665   }
1666   if (n != NULL)
1667     /* device return -1 */
1668     *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
1669   if (t != NULL) {
1670     t->atime = s.st_atime;
1671     t->mtime = s.st_mtime;
1672     t->ctime = s.st_ctime;
1673   }
1674   free(name);
1675 
1676   return unix2dostime((time_t *)&s.st_mtime);
1677 }
1678 
1679 #ifdef UNICODE_SUPPORT
filetimew(fw,a,n,t)1680 ulg filetimew(fw, a, n, t)
1681   wchar_t *fw;          /* name of file to get info on */
1682   ulg *a;               /* return value: file attributes */
1683   zoff_t *n;            /* return value: file size */
1684   iztimes *t;           /* return value: access, modific. and creation times */
1685 /* If file *f does not exist, return 0.  Else, return the file's last
1686    modified date and time as an MSDOS date and time.  The date and
1687    time is returned in a long with the date most significant to allow
1688    unsigned integer comparison of absolute times.  Also, if a is not
1689    a NULL pointer, store the file attributes there, with the high two
1690    bytes being the Unix attributes, and the low byte being a mapping
1691    of that to DOS attributes.  If n is not NULL, store the file size
1692    there.  If t is not NULL, the file's access, modification and creation
1693    times are stored there as UNIX time_t values.
1694    If f is "-", use standard input as the file. If f is a device, return
1695    a file size of -1 */
1696 {
1697   zw_stat sw;           /* results of zstat() */
1698 
1699   /* converted to malloc instead of using FNMAX - 11/8/04 EG */
1700   wchar_t *namew;
1701   unsigned int len = wcslen(fw);
1702   int isstdin = !wcscmp(fw, L"-");
1703   wchar_t *labelw = local_to_wchar_string(label);
1704 
1705   if (labelw && wcscmp(fw, labelw) == 0) {
1706     if (a != NULL)
1707       *a = label_mode;
1708     if (n != NULL)
1709       *n = -2L; /* convention for a label name */
1710     if (t != NULL)
1711       t->atime = t->mtime = t->ctime = label_utim;
1712     return label_time;
1713   }
1714   if ((namew = malloc((len + 1) * sizeof(wchar_t))) == NULL) {
1715     ZIPERR(ZE_MEM, "filetime");
1716   }
1717   wcscpy(namew, fw);
1718   if (wcsrchr(namew, (wchar_t)'/') == (namew + len - 1))
1719     namew[len - 1] = '\0';
1720   /* not all systems allow stat'ing a file with / appended */
1721 
1722   /* zip64 support 08/31/2003 R.Nausedat */
1723   if (isstdin) {
1724     if (zwfstat(fileno(stdin), &sw) != 0) {
1725       free(namew);
1726       error("fstat(stdin)");
1727     }
1728     time((time_t *)&sw.st_mtime);       /* some fstat()s return time zero */
1729   } else if (LSSTATW(namew, &sw) != 0) {
1730              /* Accept about any file kind including directories
1731               * (stored with trailing / with -r option)
1732               */
1733     free(namew);
1734     return 0;
1735   }
1736 
1737   if (a != NULL) {
1738 #ifdef WIN32_OEM
1739     /* When creating DOS-like archives with OEM-charset names, only the
1740        standard FAT attributes should be used.
1741        (Note: On a Win32 system, the UNIX style attributes from stat()
1742               do not contain any additional information...)
1743      */
1744     *a = (isstdin ? 0L : (ulg)GetFileModeW(namew));
1745 #else
1746     *a = ((ulg)sw.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileModeW(namew));
1747 #endif
1748   }
1749   if (n != NULL)
1750     /* device return -1 */
1751     *n = (sw.st_mode & S_IFMT) == S_IFREG ? sw.st_size : -1L;
1752   if (t != NULL) {
1753     t->atime = sw.st_atime;
1754     t->mtime = sw.st_mtime;
1755     t->ctime = sw.st_ctime;
1756   }
1757   free(namew);
1758 
1759   return unix2dostime((time_t *)&sw.st_mtime);
1760 }
1761 #endif
1762 
1763 
1764 
1765 #ifdef NTSD_EAS
1766 
1767 /* changed size, csize from size_t to ush 3/10/2005 EG */
GetSD(char * path,char ** bufptr,ush * size,char ** cbufptr,ush * csize)1768 local void GetSD(char *path, char **bufptr, ush *size,
1769                         char **cbufptr, ush *csize)
1770 {
1771   unsigned char stackbuffer[NTSD_BUFFERSIZE];
1772   unsigned long bytes = NTSD_BUFFERSIZE;
1773   unsigned char *buffer = stackbuffer;
1774   unsigned char *DynBuffer = NULL;
1775   ulg cbytes;
1776   PEF_NTSD_L_HEADER pLocalHeader;
1777   PEF_NTSD_C_HEADER pCentralHeader;
1778   VOLUMECAPS VolumeCaps;
1779 
1780   /* check target volume capabilities */
1781   if (!ZipGetVolumeCaps(path, path, &VolumeCaps) ||
1782      !(VolumeCaps.dwFileSystemFlags & FS_PERSISTENT_ACLS)) {
1783     return;
1784   }
1785 
1786   VolumeCaps.bUsePrivileges = use_privileges;
1787   VolumeCaps.dwFileAttributes = 0;
1788   /* should set to file attributes, if possible */
1789 
1790   if (!SecurityGet(path, &VolumeCaps, buffer, (LPDWORD)&bytes)) {
1791 
1792     /* try to malloc the buffer if appropriate */
1793     if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1794         DynBuffer = malloc(bytes);
1795         if(DynBuffer == NULL) return;
1796 
1797         buffer = DynBuffer; /* switch to the new buffer and try again */
1798 
1799         if(!SecurityGet(path, &VolumeCaps, buffer, (LPDWORD)&bytes)) {
1800             free(DynBuffer);
1801             return;
1802         }
1803 
1804     } else {
1805         return; /* bail */
1806     }
1807   }
1808 
1809   /* # bytes to compress: compress type, CRC, data bytes */
1810   cbytes = (2 + 4 + EB_DEFLAT_EXTRA) + bytes;
1811 
1812 
1813   /* our two possible failure points.  don't allow trashing of any data
1814      if either fails - notice that *size and *csize don't get updated.
1815      *bufptr leaks if malloc() was used and *cbufptr alloc fails - this
1816      isn't relevant because it's probably indicative of a bigger problem. */
1817 
1818   if(*size)
1819     *bufptr = realloc(*bufptr, *size + EF_NTSD_L_LEN + cbytes);
1820   else
1821     *bufptr = malloc(EF_NTSD_L_LEN + cbytes);
1822 
1823   if(*csize)
1824     *cbufptr = realloc(*cbufptr, *csize + EF_NTSD_C_LEN);
1825   else
1826     *cbufptr = malloc(EF_NTSD_C_LEN);
1827 
1828   if(*bufptr == NULL || *cbufptr == NULL) {
1829     if(DynBuffer) free(DynBuffer);
1830     return;
1831   }
1832 
1833   /* local header */
1834 
1835   pLocalHeader = (PEF_NTSD_L_HEADER) (*bufptr + *size);
1836 
1837   cbytes = memcompress(((char *)pLocalHeader + EF_NTSD_L_LEN), cbytes,
1838                        (char *)buffer, bytes);
1839 
1840   if (cbytes > 0x7FFF) {
1841     sprintf(errbuf, "security info too large to store (%ld bytes), %d max", bytes, 0x7FFF);
1842     zipwarn(errbuf, "");
1843     zipwarn("security info not stored: ", path);
1844     if(DynBuffer) free(DynBuffer);
1845     return;
1846   }
1847 
1848   *size += EF_NTSD_L_LEN + (ush)cbytes;
1849 
1850   pLocalHeader->nID = EF_NTSD;
1851   pLocalHeader->nSize = (USHORT)(EF_NTSD_L_LEN - EB_HEADSIZE
1852                                  + cbytes);
1853   pLocalHeader->lSize = bytes; /* uncompressed size */
1854   pLocalHeader->Version = 0;
1855 
1856   /* central header */
1857 
1858   pCentralHeader = (PEF_NTSD_C_HEADER) (*cbufptr + *csize);
1859   *csize += EF_NTSD_C_LEN;
1860 
1861   pCentralHeader->nID = EF_NTSD;
1862   pCentralHeader->nSize = EF_NTSD_C_LEN - EB_HEADSIZE;  /* sbz */
1863   pCentralHeader->lSize = bytes;
1864 
1865   if (noisy) {
1866     sprintf(errbuf, " (%ld bytes security)", bytes);
1867     zipmessage_nl(errbuf, 0);
1868   }
1869 
1870   if(DynBuffer) free(DynBuffer);
1871 }
1872 #endif /* NTSD_EAS */
1873 
1874 
1875 #ifdef USE_EF_UT_TIME
1876 
1877 #define EB_L_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(3))
1878 #define EB_C_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(1))
1879 
GetExtraTime(struct zlist far * z,iztimes * z_utim)1880 local int GetExtraTime(struct zlist far *z, iztimes *z_utim)
1881 {
1882   char *eb_l_ptr;
1883   char *eb_c_ptr;
1884   ulg ultime;
1885   /* brain-dead IBM compiler defines time_t as "double", so we have to convert
1886    * it into unsigned long integer number...
1887    */
1888 
1889 #ifdef IZ_CHECK_TZ
1890   if (!zp_tz_is_valid) return ZE_OK;    /* skip silently if no valid TZ info */
1891 #endif
1892 
1893   if(z->ext)
1894     eb_l_ptr = realloc(z->extra, (z->ext + EB_L_UT_SIZE));
1895   else
1896     eb_l_ptr = malloc(EB_L_UT_SIZE);
1897 
1898   if (eb_l_ptr == NULL)
1899     return ZE_MEM;
1900 
1901   if(z->cext)
1902     eb_c_ptr = realloc(z->cextra, (z->cext + EB_C_UT_SIZE));
1903   else
1904     eb_c_ptr = malloc(EB_C_UT_SIZE);
1905 
1906   if (eb_c_ptr == NULL)
1907     return ZE_MEM;
1908 
1909   z->extra = eb_l_ptr;
1910   eb_l_ptr += z->ext;
1911   z->ext += EB_L_UT_SIZE;
1912 
1913   eb_l_ptr[0]  = 'U';
1914   eb_l_ptr[1]  = 'T';
1915   eb_l_ptr[2]  = EB_UT_LEN(3);          /* length of data part of e.f. */
1916   eb_l_ptr[3]  = 0;
1917   eb_l_ptr[4]  = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
1918   ultime = (ulg)z_utim->mtime;
1919   eb_l_ptr[5]  = (char)(ultime);
1920   eb_l_ptr[6]  = (char)(ultime >> 8);
1921   eb_l_ptr[7]  = (char)(ultime >> 16);
1922   eb_l_ptr[8]  = (char)(ultime >> 24);
1923   ultime = (ulg)z_utim->atime;
1924   eb_l_ptr[9]  = (char)(ultime);
1925   eb_l_ptr[10] = (char)(ultime >> 8);
1926   eb_l_ptr[11] = (char)(ultime >> 16);
1927   eb_l_ptr[12] = (char)(ultime >> 24);
1928   ultime = (ulg)z_utim->ctime;
1929   eb_l_ptr[13] = (char)(ultime);
1930   eb_l_ptr[14] = (char)(ultime >> 8);
1931   eb_l_ptr[15] = (char)(ultime >> 16);
1932   eb_l_ptr[16] = (char)(ultime >> 24);
1933 
1934   z->cextra = eb_c_ptr;
1935   eb_c_ptr += z->cext;
1936   z->cext += EB_C_UT_SIZE;
1937 
1938   memcpy(eb_c_ptr, eb_l_ptr, EB_C_UT_SIZE);
1939   eb_c_ptr[EB_LEN] = EB_UT_LEN(1);
1940 
1941   return ZE_OK;
1942 }
1943 
1944 #endif /* USE_EF_UT_TIME */
1945 
1946 
1947 
set_extra_field(z,z_utim)1948 int set_extra_field(z, z_utim)
1949   struct zlist far *z;
1950   iztimes *z_utim;
1951   /* create extra field and change z->att if desired */
1952 {
1953 
1954 #ifdef NTSD_EAS
1955   if(ZipIsWinNT()) {
1956     /* store SECURITY_DECRIPTOR data in local header,
1957        and size only in central headers */
1958     GetSD(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
1959   }
1960 #endif /* NTSD_EAS */
1961 
1962 #ifdef USE_EF_UT_TIME
1963   /* store extended time stamps in both headers */
1964   return GetExtraTime(z, z_utim);
1965 #else /* !USE_EF_UT_TIME */
1966   return ZE_OK;
1967 #endif /* ?USE_EF_UT_TIME */
1968 }
1969 
deletedir(d)1970 int deletedir(d)
1971 char *d;                /* directory to delete */
1972 /* Delete the directory *d if it is empty, do nothing otherwise.
1973    Return the result of rmdir(), delete(), or system().
1974    For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
1975  */
1976 {
1977     return rmdir(d);
1978 }
1979 
1980 #endif /* !UTIL */
1981