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