1diff -ru2 unz60d10/extract.c unz60d10_w32w/extract.c 2--- unz60d10/extract.c Thu Dec 27 21:41:40 2007 3+++ unz60d10_w32w/extract.c Mon Feb 11 02:22:00 2008 4@@ -87,4 +87,11 @@ 5 static int store_info OF((__GPRO)); 6 #ifdef SET_DIR_ATTRIB 7+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 8+static int extract_or_test_entrylistw OF((__GPRO__ unsigned numchunk, 9+ ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes, 10+ unsigned *pnum_dirs, 11+ direntryw **pdirlistw, 12+ int error_in_archive)); 13+# endif 14 static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk, 15 ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes, 16@@ -112,4 +119,7 @@ 17 #endif 18 #ifdef SET_DIR_ATTRIB 19+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 20+ static int Cdecl dircompw OF((ZCONST zvoid *a, ZCONST zvoid *b)); 21+# endif 22 static int Cdecl dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b)); 23 #endif 24@@ -336,4 +346,7 @@ 25 #ifdef SET_DIR_ATTRIB 26 unsigned num_dirs=0; 27+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 28+ direntryw *dirlistw=(direntryw *)NULL, **sorted_dirlistw=(direntryw **)NULL; 29+#endif 30 direntry *dirlist=(direntry *)NULL, **sorted_dirlist=(direntry **)NULL; 31 #endif 32@@ -356,8 +369,25 @@ 33 if (uO.exdir != (char *)NULL && G.extract_flag) { 34 G.create_dirs = !uO.fflag; 35+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 36+ if (G.has_win32_wide) { 37+ wchar_t *exdirw = local_to_wchar_string(uO.exdir); 38+ if ((error = checkdirw(exdirw, ROOT)) > MPN_INF_SKIP) { 39+ /* out of memory, or file in way */ 40+ free(exdirw); 41+ return (error == MPN_NOMEM ? PK_MEM : PK_ERR); 42+ } 43+ free(exdirw); 44+ } else { 45+ if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) { 46+ /* out of memory, or file in way */ 47+ return (error == MPN_NOMEM ? PK_MEM : PK_ERR); 48+ } 49+ } 50+# else /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 51 if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) { 52 /* out of memory, or file in way */ 53 return (error == MPN_NOMEM ? PK_MEM : PK_ERR); 54 } 55+# endif /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 56 } 57 #endif /* !SFX || SFX_EXDIR */ 58@@ -570,5 +600,18 @@ 59 -----------------------------------------------------------------------*/ 60 61- error = extract_or_test_entrylist(__G__ j, 62+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 63+ if (G.has_win32_wide) 64+ { 65+ error = extract_or_test_entrylistw(__G__ j, 66+ &filnum, &num_bad_pwd, &old_extra_bytes, 67+# ifdef SET_DIR_ATTRIB 68+ &num_dirs, &dirlistw, 69+# endif 70+ error_in_archive); 71+ } 72+ else 73+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 74+ { 75+ error = extract_or_test_entrylist(__G__ j, 76 &filnum, &num_bad_pwd, &old_extra_bytes, 77 #ifdef SET_DIR_ATTRIB 78@@ -576,4 +619,5 @@ 79 #endif 80 error_in_archive); 81+ } 82 if (error != PK_COOL) { 83 if (error > error_in_archive) 84@@ -643,4 +687,55 @@ 85 #ifdef SET_DIR_ATTRIB 86 if (num_dirs > 0) { 87+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 88+ if (G.has_win32_wide) { 89+ sorted_dirlistw = (direntryw **)malloc(num_dirs*sizeof(direntryw *)); 90+ if (sorted_dirlistw == (direntryw **)NULL) { 91+ Info(slide, 0x401, ((char *)slide, 92+ LoadFarString(DirlistSortNoMem))); 93+ while (dirlistw != (direntryw *)NULL) { 94+ direntryw *dw = dirlistw; 95+ 96+ dirlistw = dirlistw->next; 97+ free(dw); 98+ } 99+ } else { 100+ ulg ndirs_fail = 0; 101+ 102+ if (num_dirs == 1) 103+ sorted_dirlistw[0] = dirlistw; 104+ else { 105+ for (i = 0; i < num_dirs; ++i) { 106+ sorted_dirlistw[i] = dirlistw; 107+ dirlistw = dirlistw->next; 108+ } 109+ qsort((char *)sorted_dirlistw, num_dirs, sizeof(direntryw *), 110+ dircompw); 111+ } 112+ 113+ Trace((stderr, "setting directory times/perms/attributes\n")); 114+ for (i = 0; i < num_dirs; ++i) { 115+ direntryw *dw = sorted_dirlistw[i]; 116+ 117+ Trace((stderr, "dir = %s\n", dw->fn)); 118+ if ((error = set_direc_attribsw(__G__ dw)) != PK_OK) { 119+ ndirs_fail++; 120+ Info(slide, 0x201, ((char *)slide, 121+ LoadFarString(DirlistSetAttrFailed), dw->fnw)); 122+ if (!error_in_archive) 123+ error_in_archive = error; 124+ } 125+ free(dw); 126+ } 127+ free(sorted_dirlistw); 128+ if (!uO.tflag && QCOND2) { 129+ if (ndirs_fail > 0) 130+ Info(slide, 0, ((char *)slide, 131+ LoadFarString(DirlistFailAttrSum), ndirs_fail)); 132+ } 133+ } 134+ } 135+ else 136+# endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 137+ { 138 sorted_dirlist = (direntry **)malloc(num_dirs*sizeof(direntry *)); 139 if (sorted_dirlist == (direntry **)NULL) { 140@@ -688,4 +783,5 @@ 141 } 142 } 143+ } 144 } 145 #endif /* SET_DIR_ATTRIB */ 146@@ -821,190 +917,731 @@ 147 #endif 148 149-#ifdef USE_WAVP 150-# define UNKN_WAVP (G.crec.compression_method!=WAVPACKED) 151-#else 152-# define UNKN_WAVP TRUE /* WavPack unknown */ 153+#ifdef USE_WAVP 154+# define UNKN_WAVP (G.crec.compression_method!=WAVPACKED) 155+#else 156+# define UNKN_WAVP TRUE /* WavPack unknown */ 157+#endif 158+ 159+#ifdef USE_PPMD 160+# define UNKN_PPMD (G.crec.compression_method!=PPMDED) 161+#else 162+# define UNKN_PPMD TRUE /* PPMd unknown */ 163+#endif 164+ 165+#ifdef SFX 166+# ifdef USE_DEFLATE64 167+# define UNKN_COMPR \ 168+ (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \ 169+ && G.crec.compression_method>ENHDEFLATED \ 170+ && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD) 171+# else 172+# define UNKN_COMPR \ 173+ (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\ 174+ && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD) 175+# endif 176+#else 177+# ifdef COPYRIGHT_CLEAN /* no reduced files */ 178+# define UNKN_RED (G.crec.compression_method >= REDUCED1 && \ 179+ G.crec.compression_method <= REDUCED4) 180+# else 181+# define UNKN_RED FALSE /* reducing not unknown */ 182+# endif 183+# ifdef LZW_CLEAN /* no shrunk files */ 184+# define UNKN_SHR (G.crec.compression_method == SHRUNK) 185+# else 186+# define UNKN_SHR FALSE /* unshrinking not unknown */ 187+# endif 188+# ifdef USE_DEFLATE64 189+# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \ 190+ G.crec.compression_method==TOKENIZED || \ 191+ (G.crec.compression_method>ENHDEFLATED && UNKN_BZ2 && UNKN_LZMA \ 192+ && UNKN_WAVP && UNKN_PPMD)) 193+# else 194+# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \ 195+ G.crec.compression_method==TOKENIZED || \ 196+ (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \ 197+ && UNKN_WAVP && UNKN_PPMD)) 198+# endif 199+#endif 200+ 201+#if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS)) 202+ int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS); 203+# define UNZVERS_SUPPORT unzvers_support 204+#else 205+# define UNZVERS_SUPPORT UNZIP_VERSION 206+#endif 207+ 208+/*--------------------------------------------------------------------------- 209+ Check central directory info for version/compatibility requirements. 210+ ---------------------------------------------------------------------------*/ 211+ 212+ G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1; /* bit field */ 213+ G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8; /* bit */ 214+ G.pInfo->textfile = G.crec.internal_file_attributes & 1; /* bit field */ 215+ G.pInfo->crc = G.crec.crc32; 216+ G.pInfo->compr_size = G.crec.csize; 217+ G.pInfo->uncompr_size = G.crec.ucsize; 218+ 219+ switch (uO.aflag) { 220+ case 0: 221+ G.pInfo->textmode = FALSE; /* bit field */ 222+ break; 223+ case 1: 224+ G.pInfo->textmode = G.pInfo->textfile; /* auto-convert mode */ 225+ break; 226+ default: /* case 2: */ 227+ G.pInfo->textmode = TRUE; 228+ break; 229+ } 230+ 231+ if (G.crec.version_needed_to_extract[1] == VMS_) { 232+ if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) { 233+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) 234+ Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg), 235+ FnFilter1(G.filename), "VMS", 236+ G.crec.version_needed_to_extract[0] / 10, 237+ G.crec.version_needed_to_extract[0] % 10, 238+ VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10)); 239+ return 0; 240+ } 241+#ifndef VMS /* won't be able to use extra field, but still have data */ 242+ else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */ 243+ Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery), 244+ FnFilter1(G.filename))); 245+ fgets(G.answerbuf, 9, stdin); 246+ if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y')) 247+ return 0; 248+ } 249+#endif /* !VMS */ 250+ /* usual file type: don't need VMS to extract */ 251+ } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) { 252+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) 253+ Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg), 254+ FnFilter1(G.filename), "PK", 255+ G.crec.version_needed_to_extract[0] / 10, 256+ G.crec.version_needed_to_extract[0] % 10, 257+ UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10)); 258+ return 0; 259+ } 260+ 261+ if (UNKN_COMPR) { 262+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) { 263+#ifndef SFX 264+ unsigned cmpridx; 265+ 266+ if ((cmpridx = find_compr_idx(G.crec.compression_method)) 267+ < NUM_METHODS) 268+ Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName), 269+ FnFilter1(G.filename), 270+ LoadFarStringSmall(ComprNames[cmpridx]))); 271+ else 272+#endif 273+ Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum), 274+ FnFilter1(G.filename), 275+ G.crec.compression_method)); 276+ } 277+ return 0; 278+ } 279+#if (!CRYPT) 280+ if (G.pInfo->encrypted) { 281+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) 282+ Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted), 283+ FnFilter1(G.filename))); 284+ return 0; 285+ } 286+#endif /* !CRYPT */ 287+ 288+#ifndef SFX 289+ /* store a copy of the central header filename for later comparison */ 290+ if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) { 291+ Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName), 292+ FnFilter1(G.filename))); 293+ } else 294+ zfstrcpy(G.pInfo->cfilname, G.filename); 295+#endif /* !SFX */ 296+ 297+ /* map whatever file attributes we have into the local format */ 298+ mapattr(__G); /* GRR: worry about return value later */ 299+ 300+ G.pInfo->diskstart = G.crec.disk_number_start; 301+ G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header; 302+ return 1; 303+ 304+} /* end function store_info() */ 305+ 306+ 307+ 308+ 309+ 310+#ifndef SFX 311+/*******************************/ 312+/* Function find_compr_idx() */ 313+/*******************************/ 314+ 315+unsigned find_compr_idx(compr_methodnum) 316+ unsigned compr_methodnum; 317+{ 318+ unsigned i; 319+ 320+ for (i = 0; i < NUM_METHODS; i++) { 321+ if (ComprIDs[i] == compr_methodnum) break; 322+ } 323+ return i; 324+} 325+#endif /* !SFX */ 326+ 327+ 328+ 329+ 330+ 331+/******************************************/ 332+/* Function extract_or_test_entrylist() */ 333+/******************************************/ 334+ 335+static int extract_or_test_entrylist(__G__ numchunk, 336+ pfilnum, pnum_bad_pwd, pold_extra_bytes, 337+#ifdef SET_DIR_ATTRIB 338+ pnum_dirs, pdirlist, 339+#endif 340+ error_in_archive) /* return PK-type error code */ 341+ __GDEF 342+ unsigned numchunk; 343+ ulg *pfilnum; 344+ ulg *pnum_bad_pwd; 345+ zoff_t *pold_extra_bytes; 346+#ifdef SET_DIR_ATTRIB 347+ unsigned *pnum_dirs; 348+ direntry **pdirlist; 349+#endif 350+ int error_in_archive; 351+{ 352+ unsigned i; 353+ int renamed, query; 354+ int skip_entry; 355+ zoff_t bufstart, inbuf_offset, request; 356+ int error, errcode; 357+ 358+/* possible values for local skip_entry flag: */ 359+#define SKIP_NO 0 /* do not skip this entry */ 360+#define SKIP_Y_EXISTING 1 /* skip this entry, do not overwrite file */ 361+#define SKIP_Y_NONEXIST 2 /* skip this entry, do not create new file */ 362+ 363+ /*----------------------------------------------------------------------- 364+ Second loop: process files in current block, extracting or testing 365+ each one. 366+ -----------------------------------------------------------------------*/ 367+ 368+ for (i = 0; i < numchunk; ++i) { 369+ (*pfilnum)++; /* *pfilnum = i + blknum*DIR_BLKSIZ + 1; */ 370+ G.pInfo = &G.info[i]; 371+#ifdef NOVELL_BUG_FAILSAFE 372+ G.dne = FALSE; /* assume file exists until stat() says otherwise */ 373+#endif 374+ 375+ /* if the target position is not within the current input buffer 376+ * (either haven't yet read far enough, or (maybe) skipping back- 377+ * ward), skip to the target position and reset readbuf(). */ 378+ 379+ /* seek_zipf(__G__ pInfo->offset); */ 380+ request = G.pInfo->offset + G.extra_bytes; 381+ inbuf_offset = request % INBUFSIZ; 382+ bufstart = request - inbuf_offset; 383+ 384+ Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n", 385+ (long)request, (long)inbuf_offset)); 386+ Trace((stderr, 387+ "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n", 388+ (long)bufstart, (long)G.cur_zipfile_bufstart)); 389+ if (request < 0) { 390+ Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg), 391+ G.zipfn, LoadFarString(ReportMsg))); 392+ error_in_archive = PK_ERR; 393+ if (*pfilnum == 1 && G.extra_bytes != 0L) { 394+ Info(slide, 0x401, ((char *)slide, 395+ LoadFarString(AttemptRecompensate))); 396+ *pold_extra_bytes = G.extra_bytes; 397+ G.extra_bytes = 0L; 398+ request = G.pInfo->offset; /* could also check if != 0 */ 399+ inbuf_offset = request % INBUFSIZ; 400+ bufstart = request - inbuf_offset; 401+ Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n", 402+ (long)request, (long)inbuf_offset)); 403+ Trace((stderr, 404+ "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n", 405+ (long)bufstart, (long)G.cur_zipfile_bufstart)); 406+ /* try again */ 407+ if (request < 0) { 408+ Trace((stderr, 409+ "debug: recompensated request still < 0\n")); 410+ Info(slide, 0x401, ((char *)slide, 411+ LoadFarStringSmall(SeekMsg), 412+ G.zipfn, LoadFarString(ReportMsg))); 413+ error_in_archive = PK_BADERR; 414+ continue; 415+ } 416+ } else { 417+ error_in_archive = PK_BADERR; 418+ continue; /* this one hosed; try next */ 419+ } 420+ } 421+ 422+ if (bufstart != G.cur_zipfile_bufstart) { 423+ Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n")); 424+#ifdef USE_STRM_INPUT 425+ zfseeko(G.zipfd, bufstart, SEEK_SET); 426+ G.cur_zipfile_bufstart = zftello(G.zipfd); 427+#else /* !USE_STRM_INPUT */ 428+ G.cur_zipfile_bufstart = 429+ zlseek(G.zipfd, bufstart, SEEK_SET); 430+#endif /* ?USE_STRM_INPUT */ 431+ if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0) 432+ { 433+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), 434+ *pfilnum, "lseek", (long)bufstart)); 435+ error_in_archive = PK_BADERR; 436+ continue; /* can still do next file */ 437+ } 438+ G.inptr = G.inbuf + (int)inbuf_offset; 439+ G.incnt -= (int)inbuf_offset; 440+ } else { 441+ G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset; 442+ G.inptr = G.inbuf + (int)inbuf_offset; 443+ } 444+ 445+ /* should be in proper position now, so check for sig */ 446+ if (readbuf(__G__ G.sig, 4) == 0) { /* bad offset */ 447+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), 448+ *pfilnum, "EOF", (long)request)); 449+ error_in_archive = PK_BADERR; 450+ continue; /* but can still try next one */ 451+ } 452+ if (strncmp(G.sig, local_hdr_sig, 4)) { 453+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), 454+ *pfilnum, LoadFarStringSmall(LocalHdrSig), (long)request)); 455+ /* 456+ GRRDUMP(G.sig, 4) 457+ GRRDUMP(local_hdr_sig, 4) 458+ */ 459+ error_in_archive = PK_ERR; 460+ if ((*pfilnum == 1 && G.extra_bytes != 0L) || 461+ (G.extra_bytes == 0L && *pold_extra_bytes != 0L)) { 462+ Info(slide, 0x401, ((char *)slide, 463+ LoadFarString(AttemptRecompensate))); 464+ if (G.extra_bytes) { 465+ *pold_extra_bytes = G.extra_bytes; 466+ G.extra_bytes = 0L; 467+ } else 468+ G.extra_bytes = *pold_extra_bytes; /* third attempt */ 469+ if (((error = seek_zipf(__G__ G.pInfo->offset)) != PK_OK) || 470+ (readbuf(__G__ G.sig, 4) == 0)) { /* bad offset */ 471+ if (error != PK_BADERR) 472+ Info(slide, 0x401, ((char *)slide, 473+ LoadFarString(OffsetMsg), *pfilnum, "EOF", 474+ (long)request)); 475+ error_in_archive = PK_BADERR; 476+ continue; /* but can still try next one */ 477+ } 478+ if (strncmp(G.sig, local_hdr_sig, 4)) { 479+ Info(slide, 0x401, ((char *)slide, 480+ LoadFarString(OffsetMsg), *pfilnum, 481+ LoadFarStringSmall(LocalHdrSig), (long)request)); 482+ error_in_archive = PK_BADERR; 483+ continue; 484+ } 485+ } else 486+ continue; /* this one hosed; try next */ 487+ } 488+ if ((error = process_local_file_hdr(__G)) != PK_COOL) { 489+ Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr), 490+ *pfilnum)); 491+ error_in_archive = error; /* only PK_EOF defined */ 492+ continue; /* can still try next one */ 493+ } 494+ if ((error = do_string(__G__ G.lrec.filename_length, DS_FN_L)) != 495+ PK_COOL) 496+ { 497+ if (error > error_in_archive) 498+ error_in_archive = error; 499+ if (error > PK_WARN) { 500+ Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg), 501+ FnFilter1(G.filename), "local")); 502+ continue; /* go on to next one */ 503+ } 504+ } 505+ if (G.extra_field != (uch *)NULL) { 506+ free(G.extra_field); 507+ G.extra_field = (uch *)NULL; 508+ } 509+ if ((error = 510+ do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0) 511+ { 512+ if (error > error_in_archive) 513+ error_in_archive = error; 514+ if (error > PK_WARN) { 515+ Info(slide, 0x401, ((char *)slide, 516+ LoadFarString(ExtFieldMsg), 517+ FnFilter1(G.filename), "local")); 518+ continue; /* go on */ 519+ } 520+ } 521+#ifndef SFX 522+ /* Filename consistency checks must come after reading in the local 523+ * extra field, so that a UTF-8 entry name e.f. block has already 524+ * been processed. 525+ */ 526+ if (G.pInfo->cfilname != (char Far *)NULL) { 527+ if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) { 528+# ifdef SMALL_MEM 529+ char *temp_cfilnam = slide + (7 * (WSIZE>>3)); 530+ 531+ zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname); 532+# define cFile_PrintBuf temp_cfilnam 533+# else 534+# define cFile_PrintBuf G.pInfo->cfilname 535+# endif 536+ Info(slide, 0x401, ((char *)slide, 537+ LoadFarStringSmall2(LvsCFNamMsg), 538+ FnFilter2(cFile_PrintBuf), FnFilter1(G.filename))); 539+# undef cFile_PrintBuf 540+ zfstrcpy(G.filename, G.pInfo->cfilname); 541+ if (error_in_archive < PK_WARN) 542+ error_in_archive = PK_WARN; 543+ } 544+ zffree(G.pInfo->cfilname); 545+ G.pInfo->cfilname = (char Far *)NULL; 546+ } 547+#endif /* !SFX */ 548+ /* Size consistency checks must come after reading in the local extra 549+ * field, so that any Zip64 extension local e.f. block has already 550+ * been processed. 551+ */ 552+ if (G.lrec.compression_method == STORED) { 553+ zusz_t csiz_decrypted = G.lrec.csize; 554+ 555+ if (G.pInfo->encrypted) 556+ csiz_decrypted -= 12; 557+ if (G.lrec.ucsize != csiz_decrypted) { 558+ Info(slide, 0x401, ((char *)slide, 559+ LoadFarStringSmall2(WrnStorUCSizCSizDiff), 560+ FnFilter1(G.filename), 561+ FmZofft(G.lrec.ucsize, NULL, "u"), 562+ FmZofft(csiz_decrypted, NULL, "u"))); 563+ G.lrec.ucsize = csiz_decrypted; 564+ if (error_in_archive < PK_WARN) 565+ error_in_archive = PK_WARN; 566+ } 567+ } 568+ 569+#if CRYPT 570+ if (G.pInfo->encrypted && 571+ (error = decrypt(__G__ uO.pwdarg)) != PK_COOL) { 572+ if (error == PK_WARN) { 573+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) 574+ Info(slide, 0x401, ((char *)slide, 575+ LoadFarString(SkipIncorrectPasswd), 576+ FnFilter1(G.filename))); 577+ ++(*pnum_bad_pwd); 578+ } else { /* (error > PK_WARN) */ 579+ if (error > error_in_archive) 580+ error_in_archive = error; 581+ Info(slide, 0x401, ((char *)slide, 582+ LoadFarString(SkipCannotGetPasswd), 583+ FnFilter1(G.filename))); 584+ } 585+ continue; /* go on to next file */ 586+ } 587+#endif /* CRYPT */ 588+ 589+ /* 590+ * just about to extract file: if extracting to disk, check if 591+ * already exists, and if so, take appropriate action according to 592+ * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper 593+ * loop because we don't store the possibly renamed filename[] in 594+ * info[]) 595+ */ 596+#ifdef DLL 597+ if (!uO.tflag && !uO.cflag && !G.redirect_data) 598+#else 599+ if (!uO.tflag && !uO.cflag) 600+#endif 601+ { 602+ renamed = FALSE; /* user hasn't renamed output file yet */ 603+ 604+startover: 605+ query = FALSE; 606+ skip_entry = SKIP_NO; 607+ /* for files from DOS FAT, check for use of backslash instead 608+ * of slash as directory separator (bug in some zipper(s); so 609+ * far, not a problem in HPFS, NTFS or VFAT systems) 610+ */ 611+#ifndef SFX 612+ if (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/')) { 613+ char *p=G.filename; 614+ 615+ if (*p) do { 616+ if (*p == '\\') { 617+ if (!G.reported_backslash) { 618+ Info(slide, 0x21, ((char *)slide, 619+ LoadFarString(BackslashPathSep), G.zipfn)); 620+ G.reported_backslash = TRUE; 621+ if (!error_in_archive) 622+ error_in_archive = PK_WARN; 623+ } 624+ *p = '/'; 625+ } 626+ } while (*PREINCSTR(p)); 627+ } 628+#endif /* !SFX */ 629+ 630+ if (!renamed) { 631+ /* remove absolute path specs */ 632+ if (G.filename[0] == '/') { 633+ Info(slide, 0x401, ((char *)slide, 634+ LoadFarString(AbsolutePathWarning), 635+ FnFilter1(G.filename))); 636+ if (!error_in_archive) 637+ error_in_archive = PK_WARN; 638+ do { 639+ char *p = G.filename + 1; 640+ do { 641+ *(p-1) = *p; 642+ } while (*p++ != '\0'); 643+ } while (G.filename[0] == '/'); 644+ } 645+ } 646+ 647+ /* mapname can create dirs if not freshening or if renamed */ 648+ error = mapname(__G__ renamed); 649+ if ((errcode = error & ~MPN_MASK) != PK_OK && 650+ error_in_archive < errcode) 651+ error_in_archive = errcode; 652+ if ((errcode = error & MPN_MASK) > MPN_INF_TRUNC) { 653+ if (errcode == MPN_CREATED_DIR) { 654+#ifdef SET_DIR_ATTRIB 655+ direntry *d_entry; 656+ 657+ error = defer_dir_attribs(__G__ &d_entry); 658+ if (d_entry == (direntry *)NULL) { 659+ /* There may be no dir_attribs info available, or 660+ * we have encountered a mem allocation error. 661+ * In case of an error, report it and set program 662+ * error state to warning level. 663+ */ 664+ if (error) { 665+ Info(slide, 0x401, ((char *)slide, 666+ LoadFarString(DirlistEntryNoMem))); 667+ if (!error_in_archive) 668+ error_in_archive = PK_WARN; 669+ } 670+ } else { 671+ d_entry->next = (*pdirlist); 672+ (*pdirlist) = d_entry; 673+ ++(*pnum_dirs); 674+ } 675+#endif /* SET_DIR_ATTRIB */ 676+ } else if (errcode == MPN_VOL_LABEL) { 677+#ifdef DOS_OS2_W32 678+ Info(slide, 0x401, ((char *)slide, 679+ LoadFarString(SkipVolumeLabel), 680+ FnFilter1(G.filename), 681+ uO.volflag? "hard disk " : "")); 682+#else 683+ Info(slide, 1, ((char *)slide, 684+ LoadFarString(SkipVolumeLabel), 685+ FnFilter1(G.filename), "")); 686+#endif 687+ } else if (errcode > MPN_INF_SKIP && 688+ error_in_archive < PK_ERR) 689+ error_in_archive = PK_ERR; 690+ Trace((stderr, "mapname(%s) returns error code = %d\n", 691+ FnFilter1(G.filename), error)); 692+ continue; /* go on to next file */ 693+ } 694+ 695+#ifdef QDOS 696+ QFilename(__G__ G.filename); 697+#endif 698+ switch (check_for_newer(__G__ G.filename)) { 699+ case DOES_NOT_EXIST: 700+#ifdef NOVELL_BUG_FAILSAFE 701+ G.dne = TRUE; /* stat() says file DOES NOT EXIST */ 702+#endif 703+ /* freshen (no new files): skip unless just renamed */ 704+ if (uO.fflag && !renamed) 705+ skip_entry = SKIP_Y_NONEXIST; 706+ break; 707+ case EXISTS_AND_OLDER: 708+#ifdef UNIXBACKUP 709+ if (!uO.B_flag) 710+#endif 711+ { 712+ if (IS_OVERWRT_NONE) 713+ /* never overwrite: skip file */ 714+ skip_entry = SKIP_Y_EXISTING; 715+ else if (!IS_OVERWRT_ALL) 716+ query = TRUE; 717+ } 718+ break; 719+ case EXISTS_AND_NEWER: /* (or equal) */ 720+#ifdef UNIXBACKUP 721+ if ((!uO.B_flag && IS_OVERWRT_NONE) || 722+#else 723+ if (IS_OVERWRT_NONE || 724+#endif 725+ (uO.uflag && !renamed)) { 726+ /* skip if update/freshen & orig name */ 727+ skip_entry = SKIP_Y_EXISTING; 728+ } else { 729+#ifdef UNIXBACKUP 730+ if (!IS_OVERWRT_ALL && !uO.B_flag) 731+#else 732+ if (!IS_OVERWRT_ALL) 733+#endif 734+ query = TRUE; 735+ } 736+ break; 737+ } 738+ if (query) { 739+#ifdef WINDLL 740+ switch (G.lpUserFunctions->replace != NULL ? 741+ (*G.lpUserFunctions->replace)(G.filename) : 742+ IDM_REPLACE_NONE) { 743+ case IDM_REPLACE_RENAME: 744+ _ISO_INTERN(G.filename); 745+ renamed = TRUE; 746+ goto startover; 747+ case IDM_REPLACE_ALL: 748+ G.overwrite_mode = OVERWRT_ALWAYS; 749+ /* FALL THROUGH, extract */ 750+ case IDM_REPLACE_YES: 751+ break; 752+ case IDM_REPLACE_NONE: 753+ G.overwrite_mode = OVERWRT_NEVER; 754+ /* FALL THROUGH, skip */ 755+ case IDM_REPLACE_NO: 756+ skip_entry = SKIP_Y_EXISTING; 757+ break; 758+ } 759+#else /* !WINDLL */ 760+ extent fnlen; 761+reprompt: 762+ Info(slide, 0x81, ((char *)slide, 763+ LoadFarString(ReplaceQuery), 764+ FnFilter1(G.filename))); 765+ if (fgets(G.answerbuf, 9, stdin) == (char *)NULL) { 766+ Info(slide, 1, ((char *)slide, 767+ LoadFarString(AssumeNone))); 768+ *G.answerbuf = 'N'; 769+ if (!error_in_archive) 770+ error_in_archive = 1; /* not extracted: warning */ 771+ } 772+ switch (*G.answerbuf) { 773+ case 'r': 774+ case 'R': 775+ do { 776+ Info(slide, 0x81, ((char *)slide, 777+ LoadFarString(NewNameQuery))); 778+ fgets(G.filename, FILNAMSIZ, stdin); 779+ /* usually get \n here: better check for it */ 780+ fnlen = strlen(G.filename); 781+ if (lastchar(G.filename, fnlen) == '\n') 782+ G.filename[--fnlen] = '\0'; 783+ } while (fnlen == 0); 784+#ifdef WIN32 /* WIN32 fgets( ... , stdin) returns OEM coded strings */ 785+ _OEM_INTERN(G.filename); 786+#endif 787+ renamed = TRUE; 788+ goto startover; /* sorry for a goto */ 789+ case 'A': /* dangerous option: force caps */ 790+ G.overwrite_mode = OVERWRT_ALWAYS; 791+ /* FALL THROUGH, extract */ 792+ case 'y': 793+ case 'Y': 794+ break; 795+ case 'N': 796+ G.overwrite_mode = OVERWRT_NEVER; 797+ /* FALL THROUGH, skip */ 798+ case 'n': 799+ /* skip file */ 800+ skip_entry = SKIP_Y_EXISTING; 801+ break; 802+ case '\n': 803+ case '\r': 804+ /* Improve echo of '\n' and/or '\r' 805+ (sizeof(G.answerbuf) == 10 (see globals.h), so 806+ there is enough space for the provided text...) */ 807+ strcpy(G.answerbuf, "{ENTER}"); 808+ /* fall through ... */ 809+ default: 810+ Info(slide, 1, ((char *)slide, 811+ LoadFarString(InvalidResponse), *G.answerbuf)); 812+ goto reprompt; /* yet another goto? */ 813+ } /* end switch (*answerbuf) */ 814+#endif /* ?WINDLL */ 815+ } /* end if (query) */ 816+ if (skip_entry != SKIP_NO) { 817+#ifdef WINDLL 818+ if (skip_entry == SKIP_Y_EXISTING) { 819+ /* report skipping of an existing entry */ 820+ Info(slide, 0, ((char *)slide, 821+ ((IS_OVERWRT_NONE || !uO.uflag || renamed) ? 822+ "Target file exists.\nSkipping %s\n" : 823+ "Target file newer.\nSkipping %s\n"), 824+ FnFilter1(G.filename))); 825+ } 826+#endif /* WINDLL */ 827+ continue; 828+ } 829+ } /* end if (extracting to disk) */ 830+ 831+#ifdef DLL 832+ if ((G.statreportcb != NULL) && 833+ (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn, 834+ G.filename, NULL)) { 835+ return IZ_CTRLC; /* cancel operation by user request */ 836+ } 837 #endif 838- 839-#ifdef USE_PPMD 840-# define UNKN_PPMD (G.crec.compression_method!=PPMDED) 841-#else 842-# define UNKN_PPMD TRUE /* PPMd unknown */ 843+#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ 844+ UserStop(); 845 #endif 846- 847-#ifdef SFX 848-# ifdef USE_DEFLATE64 849-# define UNKN_COMPR \ 850- (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \ 851- && G.crec.compression_method>ENHDEFLATED \ 852- && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD) 853-# else 854-# define UNKN_COMPR \ 855- (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\ 856- && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD) 857-# endif 858-#else 859-# ifdef COPYRIGHT_CLEAN /* no reduced files */ 860-# define UNKN_RED (G.crec.compression_method >= REDUCED1 && \ 861- G.crec.compression_method <= REDUCED4) 862-# else 863-# define UNKN_RED FALSE /* reducing not unknown */ 864-# endif 865-# ifdef LZW_CLEAN /* no shrunk files */ 866-# define UNKN_SHR (G.crec.compression_method == SHRUNK) 867-# else 868-# define UNKN_SHR FALSE /* unshrinking not unknown */ 869-# endif 870-# ifdef USE_DEFLATE64 871-# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \ 872- G.crec.compression_method==TOKENIZED || \ 873- (G.crec.compression_method>ENHDEFLATED && UNKN_BZ2 && UNKN_LZMA \ 874- && UNKN_WAVP && UNKN_PPMD)) 875-# else 876-# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \ 877- G.crec.compression_method==TOKENIZED || \ 878- (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \ 879- && UNKN_WAVP && UNKN_PPMD)) 880-# endif 881+#ifdef AMIGA 882+ G.filenote_slot = i; 883 #endif 884- 885-#if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS)) 886- int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS); 887-# define UNZVERS_SUPPORT unzvers_support 888+ G.disk_full = 0; 889+ if ((error = extract_or_test_member(__G)) != PK_COOL) { 890+ if (error > error_in_archive) 891+ error_in_archive = error; /* ...and keep going */ 892+#ifdef DLL 893+ if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) { 894 #else 895-# define UNZVERS_SUPPORT UNZIP_VERSION 896+ if (G.disk_full > 1) { 897 #endif 898- 899-/*--------------------------------------------------------------------------- 900- Check central directory info for version/compatibility requirements. 901- ---------------------------------------------------------------------------*/ 902- 903- G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1; /* bit field */ 904- G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8; /* bit */ 905- G.pInfo->textfile = G.crec.internal_file_attributes & 1; /* bit field */ 906- G.pInfo->crc = G.crec.crc32; 907- G.pInfo->compr_size = G.crec.csize; 908- G.pInfo->uncompr_size = G.crec.ucsize; 909- 910- switch (uO.aflag) { 911- case 0: 912- G.pInfo->textmode = FALSE; /* bit field */ 913- break; 914- case 1: 915- G.pInfo->textmode = G.pInfo->textfile; /* auto-convert mode */ 916- break; 917- default: /* case 2: */ 918- G.pInfo->textmode = TRUE; 919- break; 920- } 921- 922- if (G.crec.version_needed_to_extract[1] == VMS_) { 923- if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) { 924- if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) 925- Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg), 926- FnFilter1(G.filename), "VMS", 927- G.crec.version_needed_to_extract[0] / 10, 928- G.crec.version_needed_to_extract[0] % 10, 929- VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10)); 930- return 0; 931+ return error_in_archive; /* (unless disk full) */ 932+ } 933 } 934-#ifndef VMS /* won't be able to use extra field, but still have data */ 935- else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */ 936- Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery), 937- FnFilter1(G.filename))); 938- fgets(G.answerbuf, 9, stdin); 939- if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y')) 940- return 0; 941+#ifdef DLL 942+ if ((G.statreportcb != NULL) && 943+ (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn, 944+ G.filename, (zvoid *)&G.lrec.ucsize)) { 945+ return IZ_CTRLC; /* cancel operation by user request */ 946 } 947-#endif /* !VMS */ 948- /* usual file type: don't need VMS to extract */ 949- } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) { 950- if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) 951- Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg), 952- FnFilter1(G.filename), "PK", 953- G.crec.version_needed_to_extract[0] / 10, 954- G.crec.version_needed_to_extract[0] % 10, 955- UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10)); 956- return 0; 957- } 958- 959- if (UNKN_COMPR) { 960- if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) { 961-#ifndef SFX 962- unsigned cmpridx; 963- 964- if ((cmpridx = find_compr_idx(G.crec.compression_method)) 965- < NUM_METHODS) 966- Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName), 967- FnFilter1(G.filename), 968- LoadFarStringSmall(ComprNames[cmpridx]))); 969- else 970 #endif 971- Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum), 972- FnFilter1(G.filename), 973- G.crec.compression_method)); 974- } 975- return 0; 976- } 977-#if (!CRYPT) 978- if (G.pInfo->encrypted) { 979- if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) 980- Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted), 981- FnFilter1(G.filename))); 982- return 0; 983- } 984-#endif /* !CRYPT */ 985- 986-#ifndef SFX 987- /* store a copy of the central header filename for later comparison */ 988- if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) { 989- Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName), 990- FnFilter1(G.filename))); 991- } else 992- zfstrcpy(G.pInfo->cfilname, G.filename); 993-#endif /* !SFX */ 994- 995- /* map whatever file attributes we have into the local format */ 996- mapattr(__G); /* GRR: worry about return value later */ 997- 998- G.pInfo->diskstart = G.crec.disk_number_start; 999- G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header; 1000- return 1; 1001- 1002-} /* end function store_info() */ 1003- 1004- 1005- 1006- 1007- 1008-#ifndef SFX 1009-/*******************************/ 1010-/* Function find_compr_idx() */ 1011-/*******************************/ 1012- 1013-unsigned find_compr_idx(compr_methodnum) 1014- unsigned compr_methodnum; 1015-{ 1016- unsigned i; 1017- 1018- for (i = 0; i < NUM_METHODS; i++) { 1019- if (ComprIDs[i] == compr_methodnum) break; 1020- } 1021- return i; 1022-} 1023-#endif /* !SFX */ 1024+#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ 1025+ UserStop(); 1026+#endif 1027+ } /* end for-loop (i: files in current block) */ 1028 1029+ return error_in_archive; 1030 1031+} /* end function extract_or_test_entrylist() */ 1032 1033 1034 1035-/******************************************/ 1036-/* Function extract_or_test_entrylist() */ 1037-/******************************************/ 1038+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1039 1040-static int extract_or_test_entrylist(__G__ numchunk, 1041+static int extract_or_test_entrylistw(__G__ numchunk, 1042 pfilnum, pnum_bad_pwd, pold_extra_bytes, 1043 #ifdef SET_DIR_ATTRIB 1044- pnum_dirs, pdirlist, 1045+ pnum_dirs, pdirlistw, 1046 #endif 1047 error_in_archive) /* return PK-type error code */ 1048@@ -1016,5 +1653,5 @@ 1049 #ifdef SET_DIR_ATTRIB 1050 unsigned *pnum_dirs; 1051- direntry **pdirlist; 1052+ direntryw **pdirlistw; 1053 #endif 1054 int error_in_archive; 1055@@ -1190,8 +1827,4 @@ 1056 } 1057 #ifndef SFX 1058- /* Filename consistency checks must come after reading in the local 1059- * extra field, so that a UTF-8 entry name e.f. block has already 1060- * been processed. 1061- */ 1062 if (G.pInfo->cfilname != (char Far *)NULL) { 1063 if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) { 1064@@ -1316,5 +1949,8 @@ 1065 1066 /* mapname can create dirs if not freshening or if renamed */ 1067- error = mapname(__G__ renamed); 1068+ if (G.has_win32_wide) 1069+ error = mapnamew(__G__ renamed); 1070+ else 1071+ error = mapname(__G__ renamed); 1072 if ((errcode = error & ~MPN_MASK) != PK_OK && 1073 error_in_archive < errcode) 1074@@ -1323,24 +1959,24 @@ 1075 if (errcode == MPN_CREATED_DIR) { 1076 #ifdef SET_DIR_ATTRIB 1077- direntry *d_entry; 1078+ direntryw *d_entryw; 1079 1080- error = defer_dir_attribs(__G__ &d_entry); 1081- if (d_entry == (direntry *)NULL) { 1082- /* There may be no dir_attribs info available, or 1083- * we have encountered a mem allocation error. 1084- * In case of an error, report it and set program 1085- * error state to warning level. 1086- */ 1087- if (error) { 1088- Info(slide, 0x401, ((char *)slide, 1089- LoadFarString(DirlistEntryNoMem))); 1090- if (!error_in_archive) 1091- error_in_archive = PK_WARN; 1092- } 1093- } else { 1094- d_entry->next = (*pdirlist); 1095- (*pdirlist) = d_entry; 1096- ++(*pnum_dirs); 1097- } 1098+ error = defer_dir_attribsw(__G__ &d_entryw); 1099+ if (d_entryw == (direntryw *)NULL) { 1100+ /* There may be no dir_attribs info available, or 1101+ * we have encountered a mem allocation error. 1102+ * In case of an error, report it and set program 1103+ * error state to warning level. 1104+ */ 1105+ if (error) { 1106+ Info(slide, 0x401, ((char *)slide, 1107+ LoadFarString(DirlistEntryNoMem))); 1108+ if (!error_in_archive) 1109+ error_in_archive = PK_WARN; 1110+ } 1111+ } else { 1112+ d_entryw->next = (*pdirlistw); 1113+ (*pdirlistw) = d_entryw; 1114+ ++(*pnum_dirs); 1115+ } 1116 #endif /* SET_DIR_ATTRIB */ 1117 } else if (errcode == MPN_VOL_LABEL) { 1118@@ -1366,5 +2002,5 @@ 1119 QFilename(__G__ G.filename); 1120 #endif 1121- switch (check_for_newer(__G__ G.filename)) { 1122+ switch (check_for_newerw(__G__ G.unipath_widefilename)) { 1123 case DOES_NOT_EXIST: 1124 #ifdef NOVELL_BUG_FAILSAFE 1125@@ -1538,5 +2174,7 @@ 1126 return error_in_archive; 1127 1128-} /* end function extract_or_test_entrylist() */ 1129+} /* end function extract_or_test_entrylistw() */ 1130+ 1131+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 1132 1133 1134@@ -2565,4 +3203,14 @@ 1135 /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */ 1136 } 1137+ 1138+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1139+static int Cdecl dircompw(a, b) /* used by qsort(); swiped from Zip */ 1140+ ZCONST zvoid *a, *b; 1141+{ 1142+ /* order is significant: this sorts in reverse order (deepest first) */ 1143+ return wcscmp((*(direntryw **)b)->fnw, (*(direntryw **)a)->fnw); 1144+ /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */ 1145+} 1146+# endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 1147 1148 #endif /* SET_DIR_ATTRIB */ 1149diff -ru2 unz60d10/fileio.c unz60d10_w32w/fileio.c 1150--- unz60d10/fileio.c Sun Jan 27 16:39:14 2008 1151+++ unz60d10_w32w/fileio.c Mon Feb 11 01:09:22 2008 1152@@ -294,5 +294,12 @@ 1153 zlstat(G.filename, &G.statbuf) == 0) 1154 #else 1155+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1156+ if ((G.has_win32_wide 1157+ ? SSTATW(G.unipath_widefilename, &G.statbuf) 1158+ : SSTAT(G.filename, &G.statbuf) 1159+ ) == 0) 1160+#else 1161 if (SSTAT(G.filename, &G.statbuf) == 0) 1162+#endif 1163 #endif /* ?SYMLINKS */ 1164 { 1165@@ -378,5 +385,13 @@ 1166 chmod(G.filename, 0); 1167 #endif /* NLM */ 1168- if (unlink(G.filename) != 0) { 1169+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1170+ if ((G.has_win32_wide 1171+ ? _wunlink(G.unipath_widefilename) 1172+ : unlink(G.filename) 1173+ ) != 0) 1174+#else 1175+ if (unlink(G.filename) != 0) 1176+#endif 1177+ { 1178 Info(slide, 0x401, ((char *)slide, 1179 LoadFarString(CannotDeleteOldFile), FnFilter1(G.filename))); 1180@@ -456,5 +471,12 @@ 1181 G.outfile = zfopen(G.filename, FOPWR); 1182 #else 1183+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1184+ G.outfile = (G.has_win32_wide 1185+ ? zfopenw(G.unipath_widefilename, L"wb") 1186+ : zfopen(G.filename, FOPW) 1187+ ); 1188+#else /* (UNICODE_SUPPORT && WIN32_WIDE) */ 1189 G.outfile = zfopen(G.filename, FOPW); 1190+#endif /* ?(UNICODE_SUPPORT && WIN32_WIDE) */ 1191 #endif 1192 #if defined(ATH_BE_UNX) || defined(AOS_VS) || defined(QDOS) || defined(TANDEM) 1193@@ -1984,4 +2006,115 @@ 1194 } /* end function check_for_newer() */ 1195 1196+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1197+int check_for_newerw(__G__ filenamew) /* return 1 if existing file is newer */ 1198+ __GDEF /* or equal; 0 if older; -1 if doesn't */ 1199+ wchar_t *filenamew; /* exist yet */ 1200+{ 1201+ time_t existing, archive; 1202+#ifdef USE_EF_UT_TIME 1203+ iztimes z_utime; 1204+#endif 1205+#ifdef AOS_VS 1206+ long dyy, dmm, ddd, dhh, dmin, dss; 1207+ 1208+ 1209+ dyy = (lrec.last_mod_dos_datetime >> 25) + 1980; 1210+ dmm = (lrec.last_mod_dos_datetime >> 21) & 0x0f; 1211+ ddd = (lrec.last_mod_dos_datetime >> 16) & 0x1f; 1212+ dhh = (lrec.last_mod_dos_datetime >> 11) & 0x1f; 1213+ dmin = (lrec.last_mod_dos_datetime >> 5) & 0x3f; 1214+ dss = (lrec.last_mod_dos_datetime & 0x1f) * 2; 1215+ 1216+ /* under AOS/VS, file times can only be set at creation time, 1217+ * with the info in a special DG format. Make sure we can create 1218+ * it here - we delete it later & re-create it, whether or not 1219+ * it exists now. 1220+ */ 1221+ if (!zvs_create(filenamew, (((ulg)dgdate(dmm, ddd, dyy)) << 16) | 1222+ (dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1)) 1223+ return DOES_NOT_EXIST; 1224+#endif /* AOS_VS */ 1225+ 1226+ Trace((stderr, "check_for_newer: doing stat(%s)\n", FnFilter1(filename))); 1227+ if (SSTATW(filenamew, &G.statbuf)) { 1228+ Trace((stderr, 1229+ "check_for_newer: stat(%s) returns %d: file does not exist\n", 1230+ FnFilter1(filename), SSTAT(filename, &G.statbuf))); 1231+#ifdef SYMLINKS 1232+ Trace((stderr, "check_for_newer: doing lstat(%s)\n", 1233+ FnFilter1(filename))); 1234+ /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */ 1235+ if (zlstat(filename, &G.statbuf) == 0) { 1236+ Trace((stderr, 1237+ "check_for_newer: lstat(%s) returns 0: symlink does exist\n", 1238+ FnFilter1(filename))); 1239+ if (QCOND2 && !IS_OVERWRT_ALL) 1240+ Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink), 1241+ FnFilter1(filename), " with no real file")); 1242+ return EXISTS_AND_OLDER; /* symlink dates are meaningless */ 1243+ } 1244+#endif /* SYMLINKS */ 1245+ return DOES_NOT_EXIST; 1246+ } 1247+ Trace((stderr, "check_for_newer: stat(%s) returns 0: file exists\n", 1248+ FnFilter1(filename))); 1249+ 1250+#ifdef SYMLINKS 1251+ /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */ 1252+ if (zlstat(filename, &G.statbuf) == 0 && S_ISLNK(G.statbuf.st_mode)) { 1253+ Trace((stderr, "check_for_newer: %s is a symbolic link\n", 1254+ FnFilter1(filename))); 1255+ if (QCOND2 && !IS_OVERWRT_ALL) 1256+ Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink), 1257+ FnFilter1(filename), "")); 1258+ return EXISTS_AND_OLDER; /* symlink dates are meaningless */ 1259+ } 1260+#endif /* SYMLINKS */ 1261+ 1262+ NATIVE_TO_TIMET(G.statbuf.st_mtime) /* NOP unless MSC 7.0 or Macintosh */ 1263+ 1264+#ifdef USE_EF_UT_TIME 1265+ /* The `Unix extra field mtime' should be used for comparison with the 1266+ * time stamp of the existing file >>>ONLY<<< when the EF info is also 1267+ * used to set the modification time of the extracted file. 1268+ */ 1269+ if (G.extra_field && 1270+#ifdef IZ_CHECK_TZ 1271+ G.tz_is_valid && 1272+#endif 1273+ (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0, 1274+ G.lrec.last_mod_dos_datetime, &z_utime, NULL) 1275+ & EB_UT_FL_MTIME)) 1276+ { 1277+ TTrace((stderr, "check_for_newer: using Unix extra field mtime\n")); 1278+ existing = G.statbuf.st_mtime; 1279+ archive = z_utime.mtime; 1280+ } else { 1281+ /* round up existing filetime to nearest 2 seconds for comparison, 1282+ * but saturate in case of arithmetic overflow 1283+ */ 1284+ existing = ((G.statbuf.st_mtime & 1) && 1285+ (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ? 1286+ G.statbuf.st_mtime + 1 : G.statbuf.st_mtime; 1287+ archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime); 1288+ } 1289+#else /* !USE_EF_UT_TIME */ 1290+ /* round up existing filetime to nearest 2 seconds for comparison, 1291+ * but saturate in case of arithmetic overflow 1292+ */ 1293+ existing = ((G.statbuf.st_mtime & 1) && 1294+ (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ? 1295+ G.statbuf.st_mtime + 1 : G.statbuf.st_mtime; 1296+ archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime); 1297+#endif /* ?USE_EF_UT_TIME */ 1298+ 1299+ TTrace((stderr, "check_for_newer: existing %lu, archive %lu, e-a %ld\n", 1300+ (ulg)existing, (ulg)archive, (long)(existing-archive))); 1301+ 1302+ return (existing >= archive); 1303+ 1304+} /* end function check_for_newerw() */ 1305+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 1306+ 1307 #endif /* !VMS && !OS2 && !CMS_MVS */ 1308 1309@@ -2319,4 +2452,23 @@ 1310 free(fn); 1311 } 1312+# ifdef WIN32_WIDE 1313+ G.unipath_widefilename = NULL; 1314+ if (G.has_win32_wide) { 1315+ if (G.unipath_filename) 1316+ /* Get wide path from UTF-8 */ 1317+ G.unipath_widefilename = utf8_to_wchar_string(G.unipath_filename); 1318+ else 1319+ G.unipath_widefilename = utf8_to_wchar_string(G.filename); 1320+ 1321+ if (G.pInfo->lcflag) /* replace with lowercase filename */ 1322+ wcslwr(G.unipath_widefilename); 1323+ 1324+ if (G.pInfo->vollabel && length > 8 && G.unipath_widefilename[8] == '.') { 1325+ wchar_t *p = G.unipath_widefilename+8; 1326+ while (*p++) 1327+ p[-1] = *p; /* disk label, and 8th char is dot: remove dot */ 1328+ } 1329+ } 1330+# endif /* WIN32_WIDE */ 1331 } 1332 #endif /* UNICODE_SUPPORT */ 1333diff -ru2 unz60d10/globals.h unz60d10_w32w/globals.h 1334--- unz60d10/globals.h Sun Jan 27 16:31:56 2008 1335+++ unz60d10_w32w/globals.h Mon Feb 11 01:09:22 2008 1336@@ -302,4 +302,8 @@ 1337 ulg unipath_checksum; /* Unicode field checksum */ 1338 char *unipath_filename; /* UTF-8 path */ 1339+# ifdef WIN32_WIDE 1340+ wchar_t *unipath_widefilename; /* wide character filename */ 1341+ int has_win32_wide; /* true if Win32 W calls work */ 1342+# endif 1343 char *unipath_escapedfilename; 1344 #endif /* UNICODE_SUPPORT */ 1345diff -ru2 unz60d10/match.c unz60d10_w32w/match.c 1346--- unz60d10/match.c Sun Aug 14 20:00:36 2005 1347+++ unz60d10_w32w/match.c Sun Jan 6 18:19:46 2008 1348@@ -1,4 +1,4 @@ 1349 /* 1350- Copyright (c) 1990-2005 Info-ZIP. All rights reserved. 1351+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved. 1352 1353 See the accompanying file LICENSE, version 2000-Apr-09 or later 1354@@ -407,5 +407,18 @@ 1355 } /* end function iswild() */ 1356 1357+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1358+int iswildw(pw) /* originally only used for stat()-bug workaround in */ 1359+ ZCONST wchar_t *pw; /* VAX C, Turbo/Borland C, Watcom C, Atari MiNT libs; */ 1360+{ /* now used in process_zipfiles() as well */ 1361+ for (; *pw; pw++) 1362+ if (*pw == '\\' && *(pw+1)) 1363+ ++pw; 1364+ else if (*pw == '?' || *pw == '*' || *pw == '[') 1365+ return TRUE; 1366+ 1367+ return FALSE; 1368 1369+} /* end function iswildw() */ 1370+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 1371 1372 1373diff -ru2 unz60d10/process.c unz60d10_w32w/process.c 1374--- unz60d10/process.c Sun Feb 3 00:03:34 2008 1375+++ unz60d10_w32w/process.c Mon Feb 11 01:09:22 2008 1376@@ -43,4 +43,7 @@ 1377 # include "crc32.h" 1378 #endif 1379+#ifdef UNICODE_SUPPORT 1380+# include <wchar.h> 1381+#endif /* def UNICODE_SUPPORT */ 1382 1383 static int do_seekable OF((__GPRO__ int lastchance)); 1384@@ -552,5 +555,12 @@ 1385 1386 inflate_free(__G); 1387+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1388+ if (G.has_win32_wide) 1389+ checkdirw(__G__ (wchar_t *)NULL, END); 1390+ else 1391+ checkdir(__G__ (char *)NULL, END); 1392+#else 1393 checkdir(__G__ (char *)NULL, END); 1394+#endif 1395 1396 #ifdef DYNALLOC_CRCTAB 1397@@ -1507,26 +1517,4 @@ 1398 */ 1399 1400- /* This is an internal comment. Remove before the next public beta. 1401- 1402- Below check does not catch when an entry requires Zip64, as 1403- when the uncompressed size is larger than 4 GB, but the 1404- standard fields in ecrec (called EOCDR in the Zip source) 1405- are sufficient, as when the file compresses under the Zip64 1406- limit. In such cases ecrec64 (called Zip64 EOCDR in Zip) 1407- will exist to flag the archive as Zip64, even though none 1408- of the ecrec values are set to the FFFF or FFFFFFFF flag 1409- values. 1410- 1411- if(check_ecrec_zip64(__G)){ 1412- need_zip64 = TRUE; 1413- } 1414- 1415- In fact, this check is not needed, as ecrec64 will ALWAYS 1416- exist for a proper Zip64 archive, as the Version Needed To Extract 1417- field is required to be set to 4.5 or higher. 1418- 1419- End of internal comment. 1420- */ 1421- 1422 /* The ecrec64 will ALWAYS exist for a proper Zip64 archive, as 1423 the Version Needed To Extract field is required to be set to 1424@@ -1954,7 +1942,4 @@ 1425 G.unipath_filename[ULen] = '\0'; 1426 } 1427-# if 0 1428- G.unipath_escapedfilename = utf8_to_escaped_string(G.unipath_filename); 1429-# endif 1430 } 1431 1432@@ -2324,4 +2309,37 @@ 1433 return w; 1434 } 1435+ 1436+char *wchar_to_local_string(wchar_string, escape_all) 1437+ wchar_t *wchar_string; 1438+ int escape_all; 1439+{ 1440+ zwchar *wide_string = wchar_to_wide_string(wchar_string); 1441+ char *local_string = wide_to_local_string(wide_string, escape_all); 1442+ 1443+ free(wide_string); 1444+ 1445+ return local_string; 1446+} 1447+ 1448+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1449+zwchar *wchar_to_wide_string(wchar_string) 1450+ wchar_t *wchar_string; 1451+{ 1452+ int i; 1453+ int wchar_len; 1454+ zwchar *wide_string; 1455+ 1456+ wchar_len = wcslen(wchar_string); 1457+ 1458+ if ((wide_string = malloc((wchar_len + 1) * sizeof(zwchar))) == NULL) { 1459+ return NULL; 1460+ } 1461+ for (i = 0; i <= wchar_len; i++) { 1462+ wide_string[i] = wchar_string[i]; 1463+ } 1464+ 1465+ return wide_string; 1466+} 1467+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 1468 1469 char *utf8_to_escaped_string(utf8_string, escape_all) 1470diff -ru2 unz60d10/unzpriv.h unz60d10_w32w/unzpriv.h 1471--- unz60d10/unzpriv.h Sun Feb 3 15:50:52 2008 1472+++ unz60d10_w32w/unzpriv.h Mon Feb 11 02:05:46 2008 1473@@ -1318,4 +1318,7 @@ 1474 # define zstat _stati64 1475 # define zfstat _fstati64 1476+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1477+# define zstatw _wstati64 1478+# endif 1479 1480 /* 64-bit lseek */ 1481@@ -1332,4 +1335,7 @@ 1482 /* 64-bit fopen */ 1483 # define zfopen fopen 1484+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1485+# define zfopenw _wfopen 1486+# endif 1487 # define zfdopen fdopen 1488 1489@@ -1904,4 +1910,11 @@ 1490 char buf[1]; /* start of system-specific internal data */ 1491 } direntry; 1492+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1493+ typedef struct direntryw { /* head of system-specific struct holding */ 1494+ struct direntryw *next; /* defered directory attributes info */ 1495+ wchar_t *fnw; /* filename of directory */ 1496+ wchar_t buf[1]; /* start of system-specific internal data */ 1497+ } direntryw; 1498+# endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 1499 #endif /* SET_DIR_ATTRIB */ 1500 1501@@ -2225,4 +2238,7 @@ 1502 time_t dos_to_unix_time OF((ulg dos_datetime)); 1503 int check_for_newer OF((__GPRO__ char *filename)); /* os2,vmcms,vms */ 1504+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1505+int check_for_newerw OF((__GPRO__ wchar_t *filenamew)); /* os2,vmcms,vms */ 1506+#endif 1507 int do_string OF((__GPRO__ unsigned int length, int option)); 1508 ush makeword OF((ZCONST uch *b)); 1509@@ -2468,4 +2484,8 @@ 1510 int zstat_win32 OF((__W32STAT_GLOBALS__ 1511 const char *path, z_stat *buf)); /* win32.c */ 1512+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1513+ int zstat_win32w OF((__W32STAT_GLOBALS__ 1514+ const wchar_t *pathw, z_stat *buf)); /* win32.c */ 1515+# endif 1516 #endif 1517 #endif 1518@@ -2485,4 +2505,7 @@ 1519 int ic __WDLPRO)); /* match.c */ 1520 int iswild OF((ZCONST char *p)); /* match.c */ 1521+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1522+int iswildw OF((ZCONST wchar_t *pw)); /* match.c */ 1523+#endif 1524 1525 /* declarations of public CRC-32 functions have been moved into crc32.h 1526@@ -2497,4 +2520,8 @@ 1527 int mapname OF((__GPRO__ int renamed)); /* local */ 1528 int checkdir OF((__GPRO__ char *pathcomp, int flag)); /* local */ 1529+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1530+ int mapnamew OF((__GPRO__ int renamed)); /* local */ 1531+ int checkdirw OF((__GPRO__ wchar_t *pathcomp, int flag)); /* local */ 1532+#endif 1533 char *do_wild OF((__GPRO__ ZCONST char *wildzipfn)); /* local */ 1534 char *GetLoadPath OF((__GPRO)); /* local */ 1535@@ -2517,4 +2544,8 @@ 1536 int defer_dir_attribs OF((__GPRO__ direntry **pd)); /* local */ 1537 int set_direc_attribs OF((__GPRO__ direntry *d)); /* local */ 1538+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1539+ int defer_dir_attribsw OF((__GPRO__ direntryw **pd)); /* local */ 1540+ int set_direc_attribsw OF((__GPRO__ direntryw *d)); /* local */ 1541+# endif 1542 #endif 1543 #ifdef TIMESTAMP 1544@@ -2980,4 +3011,8 @@ 1545 /* convert UTF-8 string to wide string */ 1546 zwchar *utf8_to_wide_string OF((char *)); 1547+ 1548+ char *wchar_to_local_string OF((wchar_t *, int)); 1549+ 1550+ zwchar *wchar_to_wide_string OF((wchar_t *)); 1551 1552 /* convert wide string to multi-byte string */ 1553diff -ru2 unz60d10/win32/nt.c unz60d10_w32w/win32/nt.c 1554--- unz60d10/win32/nt.c Tue Dec 25 12:34:50 2007 1555+++ unz60d10_w32w/win32/nt.c Mon Feb 11 02:09:20 2008 1556@@ -1,6 +1,6 @@ 1557 /* 1558- Copyright (c) 1990-2007 Info-ZIP. All rights reserved. 1559+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved. 1560 1561- See the accompanying file LICENSE, version 2000-Apr-09 or later 1562+ See the accompanying file LICENSE, version 2007-Mar-04 or later 1563 (the contents of which are also included in unzip.h) for terms of use. 1564 If, for some reason, all these files are missing, the Info-ZIP license 1565@@ -63,5 +63,10 @@ 1566 1567 static BOOL Initialize(VOID); 1568+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1569+static VOID GetRemotePrivilegesSet(wchar_t *FileName, 1570+ PDWORD dwRemotePrivileges); 1571+#else 1572 static VOID GetRemotePrivilegesSet(CHAR *FileName, PDWORD dwRemotePrivileges); 1573+#endif 1574 static VOID InitLocalPrivileges(VOID); 1575 1576@@ -191,5 +196,10 @@ 1577 } 1578 1579+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1580+static VOID GetRemotePrivilegesSet(wchar_t *FileName, 1581+ PDWORD dwRemotePrivileges) 1582+#else 1583 static VOID GetRemotePrivilegesSet(char *FileName, PDWORD dwRemotePrivileges) 1584+#endif 1585 { 1586 HANDLE hFile; 1587@@ -199,5 +209,9 @@ 1588 /* see if we have the SeRestorePrivilege */ 1589 1590+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1591+ hFile = CreateFileW( 1592+#else 1593 hFile = CreateFileA( 1594+#endif 1595 FileName, 1596 ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER | READ_CONTROL, 1597@@ -236,5 +250,9 @@ 1598 /* note we don't need this if we have SeRestorePrivilege */ 1599 1600+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1601+ hFile = CreateFileW( 1602+#else 1603 hFile = CreateFileA( 1604+#endif 1605 FileName, 1606 ACCESS_SYSTEM_SECURITY, 1607@@ -255,10 +273,19 @@ 1608 1609 BOOL GetVolumeCaps( 1610+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1611+ wchar_t *rootpath, /* filepath, or NULL */ 1612+ wchar_t *name, /* filename associated with rootpath */ 1613+#else 1614 char *rootpath, /* filepath, or NULL */ 1615 char *name, /* filename associated with rootpath */ 1616+#endif 1617 PVOLUMECAPS VolumeCaps /* result structure describing capabilities */ 1618 ) 1619 { 1620+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1621+ wchar_t TempRootPath[MAX_PATH + 1]; 1622+#else 1623 char TempRootPath[MAX_PATH + 1]; 1624+#endif 1625 DWORD cchTempRootPath = 0; 1626 BOOL bSuccess = TRUE; /* assume success until told otherwise */ 1627@@ -273,5 +300,9 @@ 1628 DWORD i; 1629 1630+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1631+ cchTempRootPath = lstrlenW(rootpath); 1632+#else 1633 cchTempRootPath = lstrlenA(rootpath); 1634+#endif 1635 if(cchTempRootPath > MAX_PATH) return FALSE; 1636 1637@@ -345,5 +376,9 @@ 1638 1639 if(!g_VolumeCaps.bValid || 1640+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1641+ lstrcmpiW(g_VolumeCaps.RootPath, TempRootPath) != 0) 1642+#else 1643 lstrcmpiA(g_VolumeCaps.RootPath, TempRootPath) != 0) 1644+#endif 1645 { 1646 1647@@ -357,5 +392,9 @@ 1648 LeaveCriticalSection( &VolumeCapsLock ); 1649 1650+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1651+ bSuccess = GetVolumeInformationW( 1652+#else 1653 bSuccess = GetVolumeInformationA( 1654+#endif 1655 (TempRootPath[0] == '\0') ? NULL : TempRootPath, 1656 NULL, 0, 1657@@ -371,5 +410,9 @@ 1658 VolumeCaps->bUsePrivileges) 1659 { 1660+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1661+ if(GetDriveTypeW( (TempRootPath[0] == '\0') ? NULL : TempRootPath ) 1662+#else 1663 if(GetDriveTypeA( (TempRootPath[0] == '\0') ? NULL : TempRootPath ) 1664+#endif 1665 == DRIVE_REMOTE) 1666 { 1667@@ -388,5 +431,9 @@ 1668 if(bSuccess) { 1669 1670+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1671+ lstrcpynW(g_VolumeCaps.RootPath, TempRootPath, cchTempRootPath+1); 1672+#else 1673 lstrcpynA(g_VolumeCaps.RootPath, TempRootPath, cchTempRootPath+1); 1674+#endif 1675 g_VolumeCaps.dwFileSystemFlags = dwFileSystemFlags; 1676 g_VolumeCaps.bRemote = bRemote; 1677@@ -413,5 +460,9 @@ 1678 1679 1680+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1681+BOOL SecuritySet(wchar_t *resource, PVOLUMECAPS VolumeCaps, uch *securitydata) 1682+#else 1683 BOOL SecuritySet(char *resource, PVOLUMECAPS VolumeCaps, uch *securitydata) 1684+#endif 1685 { 1686 HANDLE hFile; 1687@@ -491,5 +542,9 @@ 1688 dwFlags |= FILE_FLAG_BACKUP_SEMANTICS; 1689 1690+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1691+ hFile = CreateFileW( 1692+#else 1693 hFile = CreateFileA( 1694+#endif 1695 resource, 1696 dwDesiredAccess, 1697diff -ru2 unz60d10/win32/nt.h unz60d10_w32w/win32/nt.h 1698--- unz60d10/win32/nt.h Mon Jan 24 02:46:38 2005 1699+++ unz60d10_w32w/win32/nt.h Mon Feb 11 02:07:20 2008 1700@@ -1,4 +1,4 @@ 1701 /* 1702- Copyright (c) 1990-2005 Info-ZIP. All rights reserved. 1703+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved. 1704 1705 See the accompanying file LICENSE, version 2000-Apr-09 or later 1706@@ -24,9 +24,18 @@ 1707 DWORD dwRemotePrivileges; /* relevant only on remote volumes */ 1708 DWORD dwFileAttributes; 1709+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1710+ wchar_t RootPath[MAX_PATH+1]; /* path to network / filesystem */ 1711+#else 1712 char RootPath[MAX_PATH+1]; /* path to network / filesystem */ 1713+#endif 1714 } VOLUMECAPS, *PVOLUMECAPS, *LPVOLUMECAPS; 1715 1716+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1717+BOOL SecuritySet(wchar_t *resource, PVOLUMECAPS VolumeCaps, uch *securitydata); 1718+BOOL GetVolumeCaps(wchar_t *rootpath, wchar_t *name, PVOLUMECAPS VolumeCaps); 1719+#else 1720 BOOL SecuritySet(char *resource, PVOLUMECAPS VolumeCaps, uch *securitydata); 1721 BOOL GetVolumeCaps(char *rootpath, char *name, PVOLUMECAPS VolumeCaps); 1722+#endif 1723 BOOL ValidateSecurity(uch *securitydata); 1724 1725diff -ru2 unz60d10/win32/vc6/funzip.dsp unz60d10_w32w/win32/vc6/funzip.dsp 1726--- unz60d10/win32/vc6/funzip.dsp Mon Feb 11 02:55:18 2008 1727+++ unz60d10_w32w/win32/vc6/funzip.dsp Mon Feb 11 02:55:38 2008 1728@@ -45,5 +45,5 @@ 1729 # PROP Target_Dir "" 1730 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c 1731-# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "_MBCS" /FD /c 1732+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c 1733 # ADD BASE RSC /l 0x409 /d "NDEBUG" 1734 # ADD RSC /l 0x409 /d "NDEBUG" 1735@@ -69,5 +69,5 @@ 1736 # PROP Target_Dir "" 1737 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c 1738-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 1739+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "_MBCS" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FD /GZ /c 1740 # ADD BASE RSC /l 0x409 /d "_DEBUG" 1741 # ADD RSC /l 0x409 /d "_DEBUG" 1742@@ -93,5 +93,5 @@ 1743 # PROP Target_Dir "" 1744 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /FD /c 1745-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c 1746+# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c 1747 # ADD BASE RSC /l 0x409 /d "NDEBUG" 1748 # ADD RSC /l 0x409 /d "NDEBUG" 1749@@ -117,5 +117,5 @@ 1750 # PROP Target_Dir "" 1751 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "FUNZIP" /FD /GZ /c 1752-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 1753+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /GZ /c 1754 # ADD BASE RSC /l 0x409 /d "_DEBUG" 1755 # ADD RSC /l 0x409 /d "_DEBUG" 1756diff -ru2 unz60d10/win32/vc6/unzip.dsp unz60d10_w32w/win32/vc6/unzip.dsp 1757--- unz60d10/win32/vc6/unzip.dsp Sat Mar 24 19:51:24 2007 1758+++ unz60d10_w32w/win32/vc6/unzip.dsp Mon Feb 11 02:52:48 2008 1759@@ -45,5 +45,5 @@ 1760 # PROP Target_Dir "" 1761 # ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c 1762-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c 1763+# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c 1764 # ADD BASE RSC /l 0x409 /d "NDEBUG" 1765 # ADD RSC /l 0x409 /d "NDEBUG" 1766@@ -69,5 +69,5 @@ 1767 # PROP Target_Dir "" 1768 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c 1769-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 1770+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FR /FD /GZ /c 1771 # ADD BASE RSC /l 0x409 /d "_DEBUG" 1772 # ADD RSC /l 0x409 /d "_DEBUG" 1773@@ -93,5 +93,5 @@ 1774 # PROP Target_Dir "" 1775 # ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c 1776-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c 1777+# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c 1778 # ADD BASE RSC /l 0x409 /d "NDEBUG" 1779 # ADD RSC /l 0x409 /d "NDEBUG" 1780@@ -118,5 +118,5 @@ 1781 # PROP Target_Dir "" 1782 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c 1783-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 1784+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /GZ /c 1785 # ADD BASE RSC /l 0x409 /d "_DEBUG" 1786 # ADD RSC /l 0x409 /d "_DEBUG" 1787diff -ru2 unz60d10/win32/vc6/unzipbz2.dsp unz60d10_w32w/win32/vc6/unzipbz2.dsp 1788--- unz60d10/win32/vc6/unzipbz2.dsp Sun Jan 6 19:14:44 2008 1789+++ unz60d10_w32w/win32/vc6/unzipbz2.dsp Mon Feb 11 02:52:48 2008 1790@@ -45,5 +45,5 @@ 1791 # PROP Target_Dir "" 1792 # ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c 1793-# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /c 1794+# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c 1795 # ADD BASE RSC /l 0x409 /d "NDEBUG" 1796 # ADD RSC /l 0x409 /d "NDEBUG" 1797@@ -69,5 +69,5 @@ 1798 # PROP Target_Dir "" 1799 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c 1800-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 1801+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FD /GZ /c 1802 # ADD BASE RSC /l 0x409 /d "_DEBUG" 1803 # ADD RSC /l 0x409 /d "_DEBUG" 1804@@ -93,5 +93,5 @@ 1805 # PROP Target_Dir "" 1806 # ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c 1807-# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /c 1808+# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c 1809 # ADD BASE RSC /l 0x409 /d "NDEBUG" 1810 # ADD RSC /l 0x409 /d "NDEBUG" 1811@@ -118,5 +118,5 @@ 1812 # PROP Target_Dir "" 1813 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c 1814-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 1815+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /GZ /c 1816 # ADD BASE RSC /l 0x409 /d "_DEBUG" 1817 # ADD RSC /l 0x409 /d "_DEBUG" 1818diff -ru2 unz60d10/win32/vc6/unzipsfx.dsp unz60d10_w32w/win32/vc6/unzipsfx.dsp 1819--- unz60d10/win32/vc6/unzipsfx.dsp Sun Jan 6 19:13:46 2008 1820+++ unz60d10_w32w/win32/vc6/unzipsfx.dsp Mon Feb 11 02:52:48 2008 1821@@ -45,5 +45,5 @@ 1822 # PROP Target_Dir "" 1823 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c 1824-# ADD CPP /nologo /W3 /GX /O1 /D "WIN32" /D "SFX" /D "_CONSOLE" /D "_MBCS" /FD /c 1825+# ADD CPP /nologo /W3 /GX /O1 /D "WIN32" /D "SFX" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c 1826 # ADD BASE RSC /l 0x409 /d "NDEBUG" 1827 # ADD RSC /l 0x409 /d "NDEBUG" 1828@@ -69,5 +69,5 @@ 1829 # PROP Target_Dir "" 1830 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c 1831-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 1832+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "_CONSOLE" /D "_MBCS" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FD /GZ /c 1833 # ADD BASE RSC /l 0x409 /d "_DEBUG" 1834 # ADD RSC /l 0x409 /d "_DEBUG" 1835@@ -93,5 +93,5 @@ 1836 # PROP Target_Dir "" 1837 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "SFX" /FD /c 1838-# ADD CPP /nologo /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c 1839+# ADD CPP /nologo /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c 1840 # ADD BASE RSC /l 0x409 /d "NDEBUG" 1841 # ADD RSC /l 0x409 /d "NDEBUG" 1842@@ -117,5 +117,5 @@ 1843 # PROP Target_Dir "" 1844 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "SFX" /FD /GZ /c 1845-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 1846+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /GZ /c 1847 # ADD BASE RSC /l 0x409 /d "_DEBUG" 1848 # ADD RSC /l 0x409 /d "_DEBUG" 1849diff -ru2 unz60d10/win32/w32cfg.h unz60d10_w32w/win32/w32cfg.h 1850--- unz60d10/win32/w32cfg.h Thu Oct 4 02:05:42 2007 1851+++ unz60d10_w32w/win32/w32cfg.h Tue Jan 1 18:34:48 2008 1852@@ -271,15 +271,38 @@ 1853 #define STR_TO_ISO 1854 1855+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1856+ wchar_t *utf8_to_wchar_string OF((char *)); 1857+ wchar_t *local_to_wchar_string OF((char *)); 1858+ int has_win32_wide(); 1859+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 1860+ 1861 /* Static variables that we have to add to Uz_Globs: */ 1862+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1863 #define SYSTEM_SPECIFIC_GLOBALS \ 1864 int created_dir, renamed_fullpath, fnlen;\ 1865 unsigned nLabelDrive;\ 1866 char lastRootPath[4];\ 1867+ wchar_t lastRootPathw[4];\ 1868 int lastVolOldFAT, lastVolLocTim;\ 1869 char *rootpath, *buildpathHPFS, *buildpathFAT, *endHPFS, *endFAT;\ 1870+ wchar_t *rootpathw, *buildpathHPFSw, *buildpathFATw, *endHPFSw, *endFATw;\ 1871 ZCONST char *wildname;\ 1872+ ZCONST wchar_t *wildnamew;\ 1873 char *dirname, matchname[FILNAMSIZ];\ 1874+ wchar_t *dirnamew, matchnamew[FILNAMSIZ];\ 1875 int rootlen, have_dirname, dirnamelen, notfirstcall;\ 1876 zvoid *wild_dir; 1877+#else /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 1878+#define SYSTEM_SPECIFIC_GLOBALS \ 1879+ int created_dir, renamed_fullpath, fnlen;\ 1880+ unsigned nLabelDrive;\ 1881+ char lastRootPath[4];\ 1882+ int lastVolOldFAT, lastVolLocTim;\ 1883+ char *rootpath, *buildpathHPFS, *buildpathFAT, *endHPFS, *endFAT;\ 1884+ ZCONST char *wildname;\ 1885+ char *dirname, matchname[FILNAMSIZ];\ 1886+ int rootlen, have_dirname, dirnamelen, notfirstcall;\ 1887+ zvoid *wild_dir; 1888+#endif /* ?(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 1889 1890 /* created_dir, renamed_fullpath, fnlen, and nLabelDrive are used by */ 1891@@ -342,4 +365,13 @@ 1892 # define SSTAT(path, pbuf) zstat_win32(__W32STAT_G__ path, pbuf) 1893 #endif 1894+ 1895+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1896+# ifdef WILD_STAT_BUG 1897+# define SSTATW(pathw, pbuf) (iswildw(pathw) || zstat_win32w(__W32STAT_G__ pathw, pbuf)) 1898+# else 1899+# define SSTATW(pathw, pbuf) zstat_win32w(__W32STAT_G__ pathw, pbuf) 1900+# endif 1901+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 1902+ 1903 1904 #ifdef __WATCOMC__ 1905diff -ru2 unz60d10/win32/win32.c unz60d10_w32w/win32/win32.c 1906--- unz60d10/win32/win32.c Tue Jan 1 21:26:22 2008 1907+++ unz60d10_w32w/win32/win32.c Tue Jan 1 21:26:24 2008 1908@@ -75,4 +75,12 @@ 1909 #endif 1910 1911+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1912+# if (defined(__EMX__) || defined(__CYGWIN__)) 1913+# define MKDIRW(pathw,mode) _wmkdir(pathw,mode) 1914+# else 1915+# define MKDIRW(pathw,mode) _wmkdir(pathw) 1916+# endif 1917+#endif 1918+ 1919 #ifdef HAVE_WORKING_DIRENT_H 1920 # undef HAVE_WORKING_DIRENT_H 1921@@ -124,4 +132,22 @@ 1922 } NTdirattr; 1923 #define NtAtt(d) ((NTdirattr *)d) /* typecast shortcut */ 1924+ 1925+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1926+ typedef struct NTdirattrw { /* struct for holding unix style directory */ 1927+ struct NTdirattrw *next; /* info until can be sorted and set at end */ 1928+ wchar_t *fnw; /* filename of directory */ 1929+ FILETIME Modft; /* File time type defined in NT, `last modified' time */ 1930+ FILETIME Accft; /* NT file time type, `last access' time */ 1931+ FILETIME Creft; /* NT file time type, `file creation' time */ 1932+ int gotTime; 1933+ unsigned perms; /* same as min_info.file_attr */ 1934+# ifdef NTSD_EAS 1935+ unsigned SDlen; /* length of SD data in buf */ 1936+# endif 1937+ wchar_t buf[1]; /* buffer stub for directory SD and name */ 1938+ } NTdirattrw; 1939+# define NtAttw(dw) ((NTdirattrw *)dw) /* typecast shortcut */ 1940+# endif 1941+ 1942 #endif /* SET_DIR_ATTRIB */ 1943 1944@@ -129,10 +155,15 @@ 1945 /* Function prototypes */ 1946 #ifdef NTSD_EAS 1947+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1948+ static int SetSD(__GPRO__ wchar_t *path, unsigned fperms, 1949+ uch *eb_ptr, unsigned eb_len); 1950+# else 1951 static int SetSD(__GPRO__ char *path, unsigned fperms, 1952 uch *eb_ptr, unsigned eb_len); 1953+# endif 1954 static int FindSDExtraField(__GPRO__ 1955 uch *ef_ptr, unsigned ef_len, 1956 uch **p_ebSD_ptr, unsigned *p_ebSD_len); 1957-#endif 1958+#endif /* NTSD_EAS */ 1959 1960 #ifndef NO_W32TIMES_IZFIX 1961@@ -147,13 +178,27 @@ 1962 #endif 1963 static int FStampIsLocTime(__GPRO__ const char *path); 1964+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1965+ static int FStampIsLocTimeW(__GPRO__ const wchar_t *pathw); 1966+#endif 1967 1968 1969 static int getNTfiletime (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT, 1970 FILETIME *pCreFT); 1971+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1972+static int getNTfiletimeW (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT, 1973+ FILETIME *pCreFT); 1974+#endif 1975 static int isfloppy (int nDrive); 1976 static int NTQueryVolInfo (__GPRO__ const char *name); 1977+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1978+ static int NTQueryVolInfoW (__GPRO__ const wchar_t *namew); 1979+#endif 1980 static int IsVolumeOldFAT (__GPRO__ const char *name); 1981 static void maskDOSdevice (__GPRO__ char *pathcomp); 1982 static void map2fat (char *pathcomp, char **pEndFAT); 1983+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1984+ static void maskDOSdevicew (__GPRO__ wchar_t *pathcompw); 1985+ static void map2fatw (wchar_t *pathcompw, wchar_t **pEndFATw); 1986+#endif 1987 1988 1989@@ -309,7 +354,13 @@ 1990 /**********************/ 1991 1992+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 1993+static int SetSD(__G__ path, fperms, eb_ptr, eb_len) 1994+ __GDEF 1995+ wchar_t *path; 1996+#else 1997 static int SetSD(__G__ path, fperms, eb_ptr, eb_len) 1998 __GDEF 1999 char *path; 2000+#endif 2001 unsigned fperms; 2002 uch *eb_ptr; 2003@@ -918,4 +969,12 @@ 2004 2005 2006+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2007+static int FStampIsLocTimeW(__GPRO__ const wchar_t *pathw) 2008+{ 2009+ return (NTQueryVolInfoW(__G__ pathw) ? G.lastVolLocTim : FALSE); 2010+} 2011+#endif 2012+ 2013+ 2014 2015 #ifndef NO_W32TIMES_IZFIX 2016@@ -991,4 +1050,63 @@ 2017 2018 2019+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2020+ static int getNTfiletimeW(__G__ pModFT, pAccFT, pCreFT) 2021+ __GDEF 2022+ FILETIME *pModFT; 2023+ FILETIME *pAccFT; 2024+ FILETIME *pCreFT; 2025+ { 2026+# ifdef USE_EF_UT_TIME 2027+ unsigned eb_izux_flg; 2028+ iztimes z_utime; /* struct for Unix-style actime & modtime, + creatime */ 2029+# endif 2030+ int fs_uses_loctime = FStampIsLocTimeW(__G__ G.unipath_widefilename); 2031+ 2032+ /* Copy and/or convert time and date variables, if necessary; 2033+ * return a flag indicating which time stamps are available. */ 2034+# ifdef USE_EF_UT_TIME 2035+ if (G.extra_field && 2036+# ifdef IZ_CHECK_TZ 2037+ G.tz_is_valid && 2038+# endif 2039+ ((eb_izux_flg = ef_scan_for_izux(G.extra_field, 2040+ G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime, 2041+ &z_utime, NULL)) & EB_UT_FL_MTIME)) 2042+ { 2043+ TTrace((stderr, "getNTfiletime: Unix e.f. modif. time = %lu\n", 2044+ z_utime.mtime)); 2045+ UTIME_2_IZFILETIME(z_utime.mtime, pModFT) 2046+ if (eb_izux_flg & EB_UT_FL_ATIME) { 2047+ UTIME_2_IZFILETIME(z_utime.atime, pAccFT) 2048+ } 2049+ if (eb_izux_flg & EB_UT_FL_CTIME) { 2050+ UTIME_2_IZFILETIME(z_utime.ctime, pCreFT) 2051+ } 2052+ return (int)eb_izux_flg; 2053+ } 2054+# endif /* USE_EF_UT_TIME */ 2055+# ifndef NO_W32TIMES_IZFIX 2056+ if (!fs_uses_loctime) { 2057+ time_t ux_modtime; 2058+ 2059+ ux_modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime); 2060+ utime2NtfsFileTime(ux_modtime, pModFT); 2061+ } else 2062+#endif /* NO_W32TIMES_IZFIX */ 2063+ { 2064+ FILETIME lft; 2065+ 2066+ DosDateTimeToFileTime((WORD)(G.lrec.last_mod_dos_datetime >> 16), 2067+ (WORD)(G.lrec.last_mod_dos_datetime & 0xFFFFL), 2068+ &lft); 2069+ LocalFileTimeToFileTime(&lft, pModFT); 2070+ } 2071+ *pAccFT = *pModFT; 2072+ return (EB_UT_FL_MTIME | EB_UT_FL_ATIME); 2073+ 2074+ } /* end function getNTfiletime() */ 2075+#endif /* (UNICODE_SUPPORT && WIN32_WIDE) */ 2076+ 2077+ 2078 2079 2080@@ -1059,66 +1177,72 @@ 2081 unsigned ebSDlen; 2082 #endif 2083+ 2084+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2085+ if (!G.has_win32_wide) { 2086+#endif 2087 #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */ 2088- char *ansi_name = (char *)alloca(strlen(G.filename) + 1); 2089+ char *ansi_name = (char *)alloca(strlen(G.filename) + 1); 2090 2091- INTERN_TO_ISO(G.filename, ansi_name); 2092-# define Ansi_Fname ansi_name 2093+ INTERN_TO_ISO(G.filename, ansi_name); 2094+# define Ansi_Fname ansi_name 2095 #else 2096-# define Ansi_Fname G.filename 2097+# define Ansi_Fname G.filename 2098 #endif 2099 2100 #ifndef __RSXNT__ 2101- if (IsWinNT()) { 2102+# if !(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) 2103+ if (IsWinNT()) { 2104 /* Truncate the file to the current position. 2105 * This is needed to remove excess allocation in case the 2106 * extraction has failed or stopped prematurely. */ 2107 SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile))); 2108- } 2109+ } 2110+# endif /* !(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 2111 #endif 2112 2113- /* Close the file and then re-open it using the Win32 2114- * CreateFile call, so that the file can be created 2115- * with GENERIC_WRITE access, otherwise the SetFileTime 2116- * call will fail. */ 2117- fclose(G.outfile); 2118- 2119- /* don't set the time stamp and attributes on standard output */ 2120- if (uO.cflag) 2121- return; 2122- 2123- /* skip restoring time stamps on user's request */ 2124- if (uO.D_flag <= 1) { 2125- gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft); 2126- 2127- /* open a handle to the file before processing extra fields; 2128- we do this in case new security on file prevents us from updating 2129- time stamps */ 2130- hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, 2131- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 2132- } else { 2133- gotTime = 0; 2134- } 2135- 2136- /* sfield@microsoft.com: set attributes before time in case we decide to 2137- support other filetime members later. This also allows us to apply 2138- attributes before the security is changed, which may prevent this 2139- from succeeding otherwise. Also, since most files don't have 2140- any interesting attributes, only change them if something other than 2141- FILE_ATTRIBUTE_ARCHIVE appears in the attributes. This works well 2142- as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the 2143- file anyway, when it's created new. */ 2144- if ((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) { 2145- if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F)) 2146- Info(slide, 1, ((char *)slide, 2147- "\nwarning (%d): could not set file attributes\n", 2148- (int)GetLastError())); 2149- } 2150+ /* Close the file and then re-open it using the Win32 2151+ * CreateFile call, so that the file can be created 2152+ * with GENERIC_WRITE access, otherwise the SetFileTime 2153+ * call will fail. */ 2154+ fclose(G.outfile); 2155+ 2156+ /* don't set the time stamp and attributes on standard output */ 2157+ if (uO.cflag) 2158+ return; 2159+ 2160+ gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft); 2161+ 2162+ /* open a handle to the file before processing extra fields; 2163+ we do this in case new security on file prevents us from updating 2164+ time stamps */ 2165+ hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, 2166+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 2167+ 2168+ /* sfield@microsoft.com: set attributes before time in case we decide to 2169+ support other filetime members later. This also allows us to apply 2170+ attributes before the security is changed, which may prevent this 2171+ from succeeding otherwise. Also, since most files don't have 2172+ any interesting attributes, only change them if something other than 2173+ FILE_ATTRIBUTE_ARCHIVE appears in the attributes. This works well 2174+ as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the 2175+ file anyway, when it's created new. */ 2176+ if((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) { 2177+ if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F)) 2178+ Info(slide, 1, ((char *)slide, 2179+ "\nwarning (%d): could not set file attributes\n", 2180+ (int)GetLastError())); 2181+ } 2182 2183 #ifdef NTSD_EAS 2184- /* set NTFS SD extra fields */ 2185- if (G.extra_field && /* zipfile extra field may have extended attribs */ 2186- FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length, 2187- &ebSDptr, &ebSDlen)) 2188- { 2189+ /* set NTFS SD extra fields */ 2190+ if (G.extra_field && /* zipfile extra field may have extended attribs */ 2191+ FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length, 2192+ &ebSDptr, &ebSDlen)) 2193+ { 2194+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2195+ /* no win32_wide implies "no NT SD support", so FindSDExtraField 2196+ * will never return "success". 2197+ */ 2198+# else /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 2199 int err = SetSD(__G__ Ansi_Fname, G.pInfo->file_attr, 2200 ebSDptr, ebSDlen); 2201@@ -1131,9 +1255,10 @@ 2202 ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":"")); 2203 } 2204- } 2205+# endif /* ? (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 2206+ } 2207 #endif /* NTSD_EAS */ 2208 2209- /* skip restoring time stamps on user's request */ 2210- if (uO.D_flag <= 1) { 2211+ /* skip restoring time stamps on user's request */ 2212+ if (uO.D_flag <= 1) { 2213 if ( hFile == INVALID_HANDLE_VALUE ) 2214 Info(slide, 1, ((char *)slide, 2215@@ -1152,10 +1277,101 @@ 2216 CloseHandle(hFile); 2217 } 2218- } 2219+ } 2220 2221- return; 2222+ return; 2223 2224 #undef Ansi_Fname 2225 2226+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2227+ } else { 2228+ /* wide version */ 2229+ 2230+#ifndef __RSXNT__ 2231+ if (IsWinNT()) { 2232+ /* Truncate the file to the current position. 2233+ * This is needed to remove excess allocation in case the 2234+ * extraction has failed or stopped prematurely. */ 2235+ SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile))); 2236+ } 2237+#endif 2238+ 2239+ /* Close the file and then re-open it using the Win32 2240+ * CreateFile call, so that the file can be created 2241+ * with GENERIC_WRITE access, otherwise the SetFileTime 2242+ * call will fail. */ 2243+ fclose(G.outfile); 2244+ 2245+ /* don't set the time stamp and attributes on standard output */ 2246+ if (uO.cflag) 2247+ return; 2248+ 2249+ gotTime = getNTfiletimeW(__G__ &Modft, &Accft, &Creft); 2250+ 2251+ /* open a handle to the file before processing extra fields; 2252+ we do this in case new security on file prevents us from updating 2253+ time stamps */ 2254+ hFile = CreateFileW(G.unipath_widefilename, 2255+ GENERIC_WRITE, FILE_SHARE_WRITE, NULL, 2256+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 2257+ 2258+ /* sfield@microsoft.com: set attributes before time in case we decide to 2259+ support other filetime members later. This also allows us to apply 2260+ attributes before the security is changed, which may prevent this 2261+ from succeeding otherwise. Also, since most files don't have 2262+ any interesting attributes, only change them if something other than 2263+ FILE_ATTRIBUTE_ARCHIVE appears in the attributes. This works well 2264+ as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the 2265+ file anyway, when it's created new. */ 2266+ if((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) { 2267+ if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F)) 2268+ Info(slide, 1, ((char *)slide, 2269+ "\nwarning (%d): could not set file attributes\n", 2270+ (int)GetLastError())); 2271+ } 2272+ 2273+#ifdef NTSD_EAS 2274+ /* set NTFS SD extra fields */ 2275+ if (G.extra_field && /* zipfile extra field may have extended attribs */ 2276+ FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length, 2277+ &ebSDptr, &ebSDlen)) 2278+ { 2279+ int err = SetSD(__G__ G.unipath_widefilename, G.pInfo->file_attr, 2280+ ebSDptr, ebSDlen); 2281+ 2282+ if (err == IZ_EF_TRUNC) { 2283+ if (uO.qflag) 2284+ Info(slide, 1, ((char *)slide, "%-22s ", 2285+ FnFilter1(G.filename))); 2286+ Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD), 2287+ ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":"")); 2288+ } 2289+ } 2290+#endif /* NTSD_EAS */ 2291+ 2292+ /* skip restoring time stamps on user's request */ 2293+ if (uO.D_flag <= 1) { 2294+ if ( hFile == INVALID_HANDLE_VALUE ) 2295+ Info(slide, 1, ((char *)slide, 2296+ "\nCreateFile() error %d when trying set file time\n", 2297+ (int)GetLastError())); 2298+ else { 2299+ if (gotTime) { 2300+ FILETIME *pModft = (gotTime & EB_UT_FL_MTIME) ? &Modft : NULL; 2301+ FILETIME *pAccft = (gotTime & EB_UT_FL_ATIME) ? &Accft : NULL; 2302+ FILETIME *pCreft = (gotTime & EB_UT_FL_CTIME) ? &Creft : NULL; 2303+ 2304+ if (!SetFileTime(hFile, pCreft, pAccft, pModft)) 2305+ Info(slide, 0, ((char *)slide, 2306+ "\nSetFileTime failed: %d\n", (int)GetLastError())); 2307+ } 2308+ CloseHandle(hFile); 2309+ } 2310+ } 2311+ 2312+ return; 2313+ 2314+ } 2315+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 2316+ 2317 } /* end function close_outfile() */ 2318 2319@@ -1225,8 +1441,76 @@ 2320 2321 2322+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2323+int defer_dir_attribsw(__G__ pdw) 2324+ __GDEF 2325+ direntryw **pdw; 2326+{ 2327+ NTdirattrw *d_entryw; 2328+#ifdef NTSD_EAS 2329+ uch *ebSDptr; 2330+ unsigned ebSDlen; 2331+#endif 2332+ 2333+ /* Win9x does not support setting directory time stamps. */ 2334+ if (!IsWinNT()) { 2335+ *pdw = (direntryw *)NULL; 2336+ return PK_OK; 2337+ } 2338+ 2339+#ifdef NTSD_EAS 2340+ /* set extended attributes from extra fields */ 2341+ if (G.extra_field && /* zipfile e.f. may have extended attribs */ 2342+ FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length, 2343+ &ebSDptr, &ebSDlen)) { 2344+ /* ebSDlen contains the payload size of the e.f. block, but 2345+ we store it including the e.b. header. */ 2346+ ebSDlen += EB_HEADSIZE; 2347+ } else { 2348+ /* no NTSD e.f. block -> no space needed to allocate */ 2349+ ebSDlen = 0; 2350+ } 2351+#endif /* NTSD_EAS */ 2352+ 2353+ d_entryw = (NTdirattrw *)malloc(sizeof(NTdirattrw) 2354+#ifdef NTSD_EAS 2355+ + ebSDlen 2356+#endif 2357+ + (wcslen(G.unipath_widefilename) 2358+ * sizeof(wchar_t))); 2359+ *pdw = (direntryw *)d_entryw; 2360+ if (d_entryw == (NTdirattrw *)NULL) { 2361+ return PK_MEM; 2362+ } 2363+#ifdef NTSD_EAS 2364+ if (ebSDlen > 0) 2365+ memcpy(d_entryw->buf, ebSDptr, ebSDlen); 2366+ d_entryw->SDlen = ebSDlen; 2367+ d_entryw->fnw = d_entryw->buf + ebSDlen; 2368+#else 2369+ d_entryw->fnw = d_entryw->buf; 2370+#endif 2371+ 2372+ wcscpy(d_entryw->fnw, G.unipath_widefilename); 2373+ 2374+ d_entryw->perms = G.pInfo->file_attr; 2375+ 2376+ d_entryw->gotTime = (uO.D_flag <= 0 2377+ ? getNTfiletimeW(__G__ &(d_entryw->Modft), 2378+ &(d_entryw->Accft), 2379+ &(d_entryw->Creft)) 2380+ : 0); 2381+ return PK_OK; 2382+} /* end function defer_dir_attribsw() */ 2383+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 2384+ 2385+ 2386 int set_direc_attribs(__G__ d) 2387 __GDEF 2388 direntry *d; 2389 { 2390+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2391+ /* Win9x does not support setting directory time stamps. */ 2392+ return PK_OK; 2393+#else /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 2394 int errval; 2395 HANDLE hFile = INVALID_HANDLE_VALUE; /* File handle defined in NT */ 2396@@ -1320,6 +1604,107 @@ 2397 2398 return errval; 2399+#endif /* ? (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */ 2400 } /* end function set_direc_attribs() */ 2401 2402+ 2403+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2404+int set_direc_attribsw(__G__ dw) 2405+ __GDEF 2406+ direntryw *dw; 2407+{ 2408+ int errval; 2409+ HANDLE hFile = INVALID_HANDLE_VALUE; /* File handle defined in NT */ 2410+ 2411+ /* Win9x does not support setting directory time stamps. */ 2412+ if (!IsWinNT()) 2413+ return PK_OK; 2414+ 2415+ errval = PK_OK; 2416+ 2417+ /* Skip restoring directory time stamps on user' request. */ 2418+ if (uO.D_flag <= 0) { 2419+ /* Open a handle to the directory before processing extra fields; 2420+ we do this in case new security on file prevents us from updating 2421+ time stamps. 2422+ Although the WIN32 documentation recommends to use GENERIC_WRITE 2423+ access flag to create the handle for SetFileTime(), this is too 2424+ demanding for directories with the "read-only" attribute bit set. 2425+ So we use the more specific flag FILE_WRITE_ATTRIBUTES here to 2426+ request the minimum required access rights. (This problem is a 2427+ Windows bug that has been silently fixed in Windows XP SP2.) */ 2428+ hFile = CreateFileW(dw->fnw, FILE_WRITE_ATTRIBUTES, 2429+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, 2430+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 2431+ } 2432+ 2433+#ifdef NTSD_EAS 2434+ if (NtAtt(dw)->SDlen > 0) { 2435+ int err; 2436+ 2437+ if (QCOND2) { 2438+ char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all); 2439+ Info(slide, 1, ((char *)slide, " set attrib: %-22s ", 2440+ FnFilter1(fn))); 2441+ free(fn); 2442+ } 2443+ 2444+ /* set NTFS SD extra fields */ 2445+ err = SetSD(__G__ dw->fnw, NtAtt(dw)->perms, 2446+ NtAtt(dw)->buf, NtAtt(dw)->SDlen - EB_HEADSIZE); 2447+ if (err == IZ_EF_TRUNC) { 2448+ if (!QCOND2) { 2449+ char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all); 2450+ Info(slide, 1, ((char *)slide, "%-22s ", 2451+ FnFilter1(fn))); 2452+ free(fn); 2453+ } 2454+ Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD), 2455+ NtAtt(dw)->SDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n")); 2456+ } else if (QCOND2) { 2457+ Info(slide, 0, ((char *)slide, "\n")); 2458+ } 2459+ if (errval < err) 2460+ errval = err; 2461+ } 2462+#endif /* NTSD_EAS */ 2463+ 2464+ /* Skip restoring directory time stamps on user' request. */ 2465+ if (uO.D_flag <= 0) { 2466+ if (hFile == INVALID_HANDLE_VALUE) { 2467+ char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all); 2468+ Info(slide, 1, ((char *)slide, 2469+ "warning: CreateFile() error %d (set file times for %s)\n", 2470+ (int)GetLastError(), FnFilter1(fn))); 2471+ free(fn); 2472+ if (!errval) 2473+ errval = PK_WARN; 2474+ } else { 2475+ if (NtAtt(dw)->gotTime) { 2476+ FILETIME *pModft = (NtAtt(dw)->gotTime & EB_UT_FL_MTIME) 2477+ ? &(NtAtt(dw)->Modft) : NULL; 2478+ FILETIME *pAccft = (NtAtt(dw)->gotTime & EB_UT_FL_ATIME) 2479+ ? &(NtAtt(dw)->Accft) : NULL; 2480+ FILETIME *pCreft = (NtAtt(dw)->gotTime & EB_UT_FL_CTIME) 2481+ ? &(NtAtt(dw)->Creft) : NULL; 2482+ 2483+ if (!SetFileTime(hFile, pCreft, pAccft, pModft)) { 2484+ char *fn = wchar_to_local_string(dw->fnw, 2485+ G.unicode_escape_all); 2486+ Info(slide, 0, ((char *)slide, 2487+ "warning: SetFileTime() for %s error %d\n", 2488+ FnFilter1(fn), (int)GetLastError())); 2489+ free(fn); 2490+ if (!errval) 2491+ errval = PK_WARN; 2492+ } 2493+ } 2494+ CloseHandle(hFile); 2495+ } 2496+ } 2497+ 2498+ return errval; 2499+} /* end function set_direc_attribsw() */ 2500+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 2501+ 2502 #endif /* SET_DIR_ATTRIB */ 2503 2504@@ -1419,5 +1804,5 @@ 2505 #endif 2506 2507- if ((!strncmp(name, "//", 2) || !strncmp(name, "\\\\", 2)) && 2508+ if ((!strncmp(name, "//", 2) || !strncmp(name,"\\\\", 2)) && 2509 (name[2] != '\0' && name[2] != '/' && name[2] != '\\')) { 2510 /* GetFullPathname() and GetVolumeInformation() do not work 2511@@ -1467,4 +1852,63 @@ 2512 2513 2514+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2515+static int NTQueryVolInfoW(__GPRO__ const wchar_t *namew) 2516+{ 2517+ /* static char lastRootPath[4] = ""; */ 2518+ /* static int lastVolOldFAT; */ 2519+ /* static int lastVolLocTim; */ 2520+ wchar_t *tmp0w; 2521+ wchar_t tmp1w[MAX_PATH], tmp2w[MAX_PATH]; 2522+ DWORD volSerNo, maxCompLen, fileSysFlags; 2523+ 2524+ if ((!wcsncmp(namew, L"//", 2) || !wcsncmp(namew, L"\\\\", 2)) && 2525+ (namew[2] != '\0' && namew[2] != '/' && namew[2] != '\\')) { 2526+ /* GetFullPathname() and GetVolumeInformation() do not work 2527+ * on UNC names. For now, we return "error". 2528+ * **FIXME**: check if UNC name is mapped to a drive letter 2529+ * and use mapped drive for volume info query. 2530+ */ 2531+ return FALSE; 2532+ } 2533+ if (iswalpha(namew[0]) && (namew[1] == ':')) 2534+ tmp0w = (wchar_t *)namew; 2535+ else 2536+ { 2537+ if (!GetFullPathNameW(namew, MAX_PATH, tmp1w, &tmp0w)) 2538+ return FALSE; 2539+ tmp0w = &tmp1w[0]; 2540+ } 2541+ if (wcsncmp(G.lastRootPathw, tmp0w, 2) != 0) { 2542+ /* For speed, we skip repeated queries for the same device */ 2543+ wcsncpy(G.lastRootPathw, tmp0w, 2); /* Build the root path name, */ 2544+ G.lastRootPathw[2] = '/'; /* e.g. "A:/" */ 2545+ G.lastRootPathw[3] = '\0'; 2546+ 2547+ if (!GetVolumeInformationW(G.lastRootPathw, 2548+ tmp1w, (DWORD)MAX_PATH, 2549+ &volSerNo, &maxCompLen, &fileSysFlags, 2550+ tmp2w, (DWORD)MAX_PATH)) { 2551+ G.lastRootPathw[0] = '\0'; 2552+ return FALSE; 2553+ } 2554+ 2555+ /* LFNs are available if the component length is > 12 */ 2556+ G.lastVolOldFAT = (maxCompLen <= 12); 2557+/* G.lastVolOldFAT = !strncmp(strupr(tmp2), "FAT", 3); old version */ 2558+ 2559+ /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in 2560+ * local time! 2561+ */ 2562+ G.lastVolLocTim = !wcsncmp(_wcsupr(tmp2w), L"VFAT", 4) || 2563+ !wcsncmp(tmp2w, L"HPFS", 4) || 2564+ !wcsncmp(tmp2w, L"FAT", 3); 2565+ } 2566+ 2567+ return TRUE; 2568+ 2569+} /* end function NTQueryVolInfoW() */ 2570+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 2571+ 2572+ 2573 2574 2575@@ -1478,4 +1922,11 @@ 2576 } 2577 2578+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2579+static int IsVolumeOldFATw(__GPRO__ const wchar_t *namew) 2580+{ 2581+ return (NTQueryVolInfoW(__G__ namew) ? G.lastVolOldFAT : FALSE); 2582+} 2583+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 2584+ 2585 2586 2587@@ -1931,13 +2382,253 @@ 2588 2589 2590+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2591 2592+/* Win32 wide version */ 2593 2594-/****************************/ 2595-/* Function maskDOSdevice() */ 2596-/****************************/ 2597- 2598-static void maskDOSdevice(__G__ pathcomp) 2599+int mapnamew(__G__ renamed) 2600 __GDEF 2601- char *pathcomp; 2602+ int renamed; 2603+/* 2604+ * returns: 2605+ * MPN_OK - no problem detected 2606+ * MPN_INF_TRUNC - caution (truncated filename) 2607+ * MPN_INF_SKIP - info "skip entry" (dir doesn't exist) 2608+ * MPN_ERR_SKIP - error -> skip entry 2609+ * MPN_ERR_TOOLONG - error -> path is too long 2610+ * MPN_NOMEM - error (memory allocation failed) -> skip entry 2611+ * [also MPN_VOL_LABEL, MPN_CREATED_DIR] 2612+ */ 2613+{ 2614+ wchar_t pathcompw[FILNAMSIZ]; /* path-component buffer */ 2615+ wchar_t *ppw, *cpw=NULL; /* character pointers */ 2616+ wchar_t *lastsemiw = NULL; /* pointer to last semi-colon in pathcomp */ 2617+ int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */ 2618+ int error; 2619+ register wchar_t workchw; /* hold the character being tested */ 2620+ 2621+ 2622+/*--------------------------------------------------------------------------- 2623+ Initialize various pointers and counters and stuff. 2624+ ---------------------------------------------------------------------------*/ 2625+ 2626+ /* can create path as long as not just freshening, or if user told us */ 2627+ G.create_dirs = (!uO.fflag || renamed); 2628+ 2629+ G.created_dir = FALSE; /* not yet */ 2630+ G.renamed_fullpath = FALSE; 2631+ G.fnlen = wcslen(G.unipath_widefilename); 2632+ 2633+ if (renamed) { 2634+ cpw = G.unipath_widefilename; /* point to beginning of renamed name... */ 2635+ if (*cpw) do { 2636+ if (*cpw == '\\') /* convert backslashes to forward */ 2637+ *cpw = '/'; 2638+ } while (*(++cpw)); 2639+ cpw = G.unipath_widefilename; 2640+ /* use temporary rootpath if user gave full pathname */ 2641+ if (G.unipath_widefilename[0] == '/') { 2642+ G.renamed_fullpath = TRUE; 2643+ pathcompw[0] = '/'; /* copy the '/' and terminate */ 2644+ pathcompw[1] = '\0'; 2645+ ++cpw; 2646+ } else if (iswalpha(G.unipath_widefilename[0]) && G.unipath_widefilename[1] == ':') { 2647+ G.renamed_fullpath = TRUE; 2648+ ppw = pathcompw; 2649+ *ppw++ = *cpw++; /* copy the "d:" (+ '/', possibly) */ 2650+ *ppw++ = *cpw++; 2651+ if (*cpw == '/') 2652+ *ppw++ = *cpw++; /* otherwise add "./"? */ 2653+ *ppw = '\0'; 2654+ } 2655+ } 2656+ 2657+ /* pathcomp is ignored unless renamed_fullpath is TRUE: */ 2658+ if ((error = checkdirw(__G__ pathcompw, INIT)) != 0) /* init path buffer */ 2659+ return error; /* ...unless no mem or vol label on hard disk */ 2660+ 2661+ *pathcompw = '\0'; /* initialize translation buffer */ 2662+ ppw = pathcompw; /* point to translation buffer */ 2663+ if (!renamed) { /* cp already set if renamed */ 2664+ if (uO.jflag) /* junking directories */ 2665+ cpw = wcschr(G.unipath_widefilename, '/'); 2666+ if (cpw == NULL) /* no '/' or not junking dirs */ 2667+ cpw = G.unipath_widefilename; /* point to internal zipfile-member pathname */ 2668+ else 2669+ ++cpw; /* point to start of last component of path */ 2670+ } 2671+ 2672+/*--------------------------------------------------------------------------- 2673+ Begin main loop through characters in filename. 2674+ ---------------------------------------------------------------------------*/ 2675+ 2676+ for (; (workchw = *cpw) != 0; cpw++) { 2677+ 2678+ switch (workchw) { 2679+ case '/': /* can assume -j flag not given */ 2680+ *ppw = '\0'; 2681+ maskDOSdevicew(__G__ pathcompw); 2682+ if (wcscmp(pathcompw, L".") == 0) { 2683+ /* don't botherw appending "./" to the path */ 2684+ *pathcompw = '\0'; 2685+ } else if (!uO.ddotflag && wcscmp(pathcompw, L"..") == 0) { 2686+ /* "../" dir traversal detected, skip over it */ 2687+ *pathcompw = '\0'; 2688+ killed_ddot = TRUE; /* set "show message" flag */ 2689+ } 2690+ /* when path component is not empty, append it now */ 2691+ if (*pathcompw != '\0' && 2692+ ((error = checkdirw(__G__ pathcompw, APPEND_DIR)) 2693+ & MPN_MASK) > MPN_INF_TRUNC) 2694+ return error; 2695+ ppw = pathcompw; /* reset conversion buffer for next piece */ 2696+ lastsemiw = (wchar_t *)NULL; /* leave direct. semi-colons alone */ 2697+ break; 2698+ 2699+ case ':': /* drive spec not stored, so no colon allowed */ 2700+ case '\\': /* '\\' may come as normal filename char (not */ 2701+ case '<': /* dir sep char!) from unix-like file system */ 2702+ case '>': /* no redirection symbols allowed either */ 2703+ case '|': /* no pipe signs allowed */ 2704+ case '"': /* no double quotes allowed */ 2705+ case '?': /* no wildcards allowed */ 2706+ case '*': 2707+ *ppw++ = '_'; /* these rules apply equally to FAT and NTFS */ 2708+ break; 2709+ case ';': /* start of VMS version? */ 2710+ lastsemiw = ppw; /* remove VMS version later... */ 2711+ *ppw++ = ';'; /* but keep semicolon for now */ 2712+ break; 2713+ 2714+ 2715+ case ' ': /* keep spaces unless specifically */ 2716+ /* NT cannot create filenames with spaces on FAT volumes */ 2717+ if (uO.sflag || IsVolumeOldFATw(__G__ G.unipath_widefilename)) 2718+ *ppw++ = '_'; 2719+ else 2720+ *ppw++ = ' '; 2721+ break; 2722+ 2723+ default: 2724+ /* allow European characters in filenames: */ 2725+ if (iswprint(workchw) || workchw >= 127) 2726+ *ppw++ = workchw; 2727+ } /* end switch */ 2728+ 2729+ } /* end while loop */ 2730+ 2731+ /* Show warning when stripping insecure "parent dir" path components */ 2732+ /* For now use standard path for output messages */ 2733+ if (killed_ddot && QCOND2) { 2734+ Info(slide, 0, ((char *)slide, 2735+ "warning: skipped \"../\" path component(s) in %s\n", 2736+ FnFilter1(G.filename))); 2737+ if (!(error & ~MPN_MASK)) 2738+ error = (error & MPN_MASK) | PK_WARN; 2739+ } 2740+ 2741+/*--------------------------------------------------------------------------- 2742+ Report if directory was created (and no file to create: filename ended 2743+ in '/'), check name to be sure it exists, and combine path and name be- 2744+ fore exiting. 2745+ ---------------------------------------------------------------------------*/ 2746+ 2747+ if (G.unipath_widefilename[wcslen(G.unipath_widefilename) - 1] == '/') { 2748+ checkdirw(__G__ G.unipath_widefilename, GETPATH); 2749+ if (G.created_dir) { 2750+ if (QCOND2) { 2751+ Info(slide, 0, ((char *)slide, " creating: %-22s\n", 2752+ FnFilter1(G.filename))); 2753+ } 2754+ 2755+ /* set file attributes: 2756+ The default for newly created directories is "DIR attribute 2757+ flags set", so there is no need to change attributes unless 2758+ one of the DOS style attribute flags is set. The readonly 2759+ attribute need not be masked, since it does not prevent 2760+ modifications in the new directory. */ 2761+ if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) { 2762+ if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F)) 2763+ Info(slide, 1, ((char *)slide, 2764+ "\nwarning (%d): could not set file attributes for %s\n", 2765+ (int)GetLastError(), FnFilter1(G.filename))); 2766+ } 2767+ 2768+ /* set dir time (note trailing '/') */ 2769+ return (error & ~MPN_MASK) | MPN_CREATED_DIR; 2770+ } else if (IS_OVERWRT_ALL) { 2771+ /* overwrite attributes of existing directory on user's request */ 2772+ 2773+ /* set file attributes: */ 2774+ if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) { 2775+ if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F)) 2776+ Info(slide, 1, ((char *)slide, 2777+ "\nwarning (%d): could not set file attributes for %s\n", 2778+ (int)GetLastError(), FnFilter1(G.filename))); 2779+ } 2780+ } 2781+ /* dir existed already; don't look for data to extract */ 2782+ return (error & ~MPN_MASK) | MPN_INF_SKIP; 2783+ } 2784+ 2785+ *ppw = '\0'; /* done with pathcomp: terminate it */ 2786+ 2787+ /* if not saving them, remove VMS version numbers (appended "###") */ 2788+ if (!uO.V_flag && lastsemiw) { 2789+ ppw = lastsemiw + 1; /* semi-colon was kept: expect #'s after */ 2790+ while (iswdigit(*ppw)) 2791+ ++ppw; 2792+ if (*ppw == '\0') /* only digits between ';' and end: nuke */ 2793+ *lastsemiw = '\0'; 2794+ } 2795+ 2796+ maskDOSdevicew(__G__ pathcompw); 2797+ 2798+ if (*pathcompw == '\0') { 2799+ Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n", 2800+ FnFilter1(G.filename))); 2801+ return (error & ~MPN_MASK) | MPN_ERR_SKIP; 2802+ } 2803+ 2804+ checkdirw(__G__ pathcompw, APPEND_NAME); /* returns 1 if truncated: care? */ 2805+ checkdirw(__G__ G.unipath_widefilename, GETPATH); 2806+ 2807+ if (G.pInfo->vollabel) { /* set the volume label now */ 2808+ char drive[4]; 2809+ wchar_t drivew[4]; 2810+ 2811+ /* Build a drive string, e.g. "b:" */ 2812+ drive[0] = (char)('a' + G.nLabelDrive - 1); 2813+ drivew[0] = (wchar_t)('a' + G.nLabelDrive - 1); 2814+ wcscpy(drivew + 1, L":\\"); 2815+ if (QCOND2) 2816+ Info(slide, 0, ((char *)slide, "labelling %s %-22s\n", drive, 2817+ FnFilter1(G.filename))); 2818+ if (!SetVolumeLabelW(drivew, G.unipath_widefilename)) { 2819+ Info(slide, 1, ((char *)slide, 2820+ "mapname: error setting volume label\n")); 2821+ return (error & ~MPN_MASK) | MPN_ERR_SKIP; 2822+ } 2823+ /* success: skip the "extraction" quietly */ 2824+ return (error & ~MPN_MASK) | MPN_INF_SKIP; 2825+ } 2826+ 2827+ Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n", 2828+ FnFilter1(G.filename), error)); 2829+ return error; 2830+ 2831+} /* end function mapnamew() */ 2832+ 2833+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 2834+ 2835+ 2836+ 2837+ 2838+/****************************/ 2839+/* Function maskDOSdevice() */ 2840+/****************************/ 2841+ 2842+static void maskDOSdevice(__G__ pathcomp) 2843+ __GDEF 2844+ char *pathcomp; 2845 { 2846 /*--------------------------------------------------------------------------- 2847@@ -1981,4 +2672,40 @@ 2848 2849 2850+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2851+ 2852+static void maskDOSdevicew(__G__ pathcompw) 2853+ __GDEF 2854+ wchar_t *pathcompw; 2855+{ 2856+/*--------------------------------------------------------------------------- 2857+ Put an underscore in front of the file name if the file name is a 2858+ DOS/WINDOWS device name like CON.*, AUX.*, PRN.*, etc. Trying to 2859+ extract such a file would fail at best and wedge us at worst. 2860+ ---------------------------------------------------------------------------*/ 2861+#if !defined(S_IFCHR) && defined(_S_IFCHR) 2862+# define S_IFCHR _S_IFCHR 2863+#endif 2864+#if !defined(S_ISCHR) 2865+# if defined(_S_ISCHR) 2866+# define S_ISCHR(m) _S_ISCHR(m) 2867+# elif defined(S_IFCHR) 2868+# define S_ISCHR(m) ((m) & S_IFCHR) 2869+# endif 2870+#endif 2871+ 2872+ if (zstatw(pathcompw, &G.statbuf) == 0 && S_ISCHR(G.statbuf.st_mode)) { 2873+ extent i; 2874+ 2875+ /* pathcomp contains a name of a DOS character device (builtin or 2876+ * installed device driver). 2877+ * Prepend a '_' to allow creation of the item in the file system. 2878+ */ 2879+ for (i = wcslen(pathcompw) + 1; i > 0; --i) 2880+ pathcompw[i] = pathcompw[i - 1]; 2881+ pathcompw[0] = '_'; 2882+ } 2883+} /* end function maskDOSdevicew() */ 2884+ 2885+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 2886 2887 2888@@ -2080,19 +2807,511 @@ 2889 *pEndFAT = pEnd; /* filename is fine; point at terminating zero */ 2890 2891- if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ') 2892- last_dot[-1] = '_'; /* NO blank in front of '.'! */ 2893+ if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ') 2894+ last_dot[-1] = '_'; /* NO blank in front of '.'! */ 2895+ } 2896+} /* end function map2fat() */ 2897+ 2898+ 2899+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 2900+ 2901+static void map2fatw(pathcompw, pEndFATw) 2902+ wchar_t *pathcompw, **pEndFATw; 2903+{ 2904+ wchar_t *ppcw = pathcompw; /* variable pointer to pathcomp */ 2905+ wchar_t *pEndw = *pEndFATw; /* variable pointer to buildpathFAT */ 2906+ wchar_t *pBeginw = *pEndFATw; /* constant pointer to start of this comp. */ 2907+ wchar_t *last_dotw = NULL; /* last dot not converted to underscore */ 2908+ register wchar_t workchw; /* hold the character being tested */ 2909+ 2910+ 2911+ /* Only need check those characters which are legal in NTFS but not 2912+ * in FAT: to get here, must already have passed through mapname. 2913+ * Also must truncate path component to ensure 8.3 compliance. 2914+ */ 2915+ while ((workchw = *ppcw++) != 0) { 2916+ switch (workchw) { 2917+ case '[': 2918+ case ']': 2919+ case '+': 2920+ case ',': 2921+ case ';': 2922+ case '=': 2923+ *pEndw++ = '_'; /* convert brackets to underscores */ 2924+ break; 2925+ 2926+ case '.': 2927+ if (pEndw == *pEndFATw) { /* nothing appended yet... */ 2928+ if (*ppcw == '\0') /* don't bother appending a */ 2929+ break; /* "./" component to the path */ 2930+ else if (*ppcw == '.' && ppcw[1] == '\0') { /* "../" */ 2931+ *pEndw++ = '.'; /* add first dot, */ 2932+ *pEndw++ = '.'; /* add second dot, and */ 2933+ ++ppcw; /* skip over to pathcomp's end */ 2934+ } else { /* FAT doesn't allow null filename */ 2935+ *pEndw++ = '_'; /* bodies, so map .exrc -> _exrc */ 2936+ } /* (_.exr would keep max 3 chars) */ 2937+ } else { /* found dot within path component */ 2938+ last_dotw = pEndw; /* point at last dot so far... */ 2939+ *pEndw++ = '_'; /* convert to underscore for now */ 2940+ } 2941+ break; 2942+ 2943+ default: 2944+ *pEndw++ = workchw; 2945+ 2946+ } /* end switch */ 2947+ } /* end while loop */ 2948+ 2949+ *pEndw = '\0'; /* terminate buildpathFAT */ 2950+ 2951+ /* NOTE: keep in mind that pEnd points to the end of the path 2952+ * component, and *pEndFAT still points to the *beginning* of it... 2953+ * Also note that the algorithm does not try to get too fancy: 2954+ * if there are no dots already, the name either gets truncated 2955+ * at 8 characters or the last underscore is converted to a dot 2956+ * (only if more characters are saved that way). In no case is 2957+ * a dot inserted between existing characters. 2958+ */ 2959+ if (last_dotw == NULL) { /* no dots: check for underscores... */ 2960+ wchar_t *pluw = wcschr(pBeginw, '_'); /* pointer to last underscore */ 2961+ 2962+ if ((pluw != NULL) && /* found underscore: convert to dot? */ 2963+ (MIN(pluw - pBeginw, 8) + MIN(pEndw - pluw - 1, 3) > 8)) { 2964+ last_dotw = pluw; /* be lazy: drop through to next if-blk */ 2965+ } else if ((pEndw - *pEndFATw) > 8) { 2966+ /* no underscore; or converting underscore to dot would save less 2967+ chars than leaving everything in the basename */ 2968+ *pEndFATw += 8; /* truncate at 8 chars */ 2969+ **pEndFATw = '\0'; 2970+ } else 2971+ *pEndFATw = pEndw; /* whole thing fits into 8 chars or less */ 2972+ } 2973+ 2974+ if (last_dotw != NULL) { /* one dot is OK: */ 2975+ *last_dotw = '.'; /* put it back in */ 2976+ 2977+ if ((last_dotw - pBeginw) > 8) { 2978+ wchar_t *pw, *qw; 2979+ int i; 2980+ 2981+ pw = last_dotw; 2982+ qw = last_dotw = pBeginw + 8; 2983+ for (i = 0; (i < 4) && *pw; ++i) /* too many chars in basename: */ 2984+ *qw++ = *pw++; /* shift .ext left and trun- */ 2985+ *qw = '\0'; /* cate/terminate it */ 2986+ *pEndFATw = qw; 2987+ } else if ((pEndw - last_dotw) > 4) { /* too many chars in extension */ 2988+ *pEndFATw = last_dotw + 4; 2989+ **pEndFATw = '\0'; 2990+ } else 2991+ *pEndFATw = pEndw; /* filename is fine; point at terminating zero */ 2992+ 2993+ if ((last_dotw - pBeginw) > 0 && last_dotw[-1] == ' ') 2994+ last_dotw[-1] = '_'; /* NO blank in front of '.'! */ 2995+ } 2996+} /* end function map2fatw() */ 2997+ 2998+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 2999+ 3000+ 3001+ 3002+/***********************/ /* Borrowed from os2.c for UnZip 5.1. */ 3003+/* Function checkdir() */ /* Difference: no EA stuff */ 3004+/***********************/ /* HPFS stuff works on NTFS too */ 3005+ 3006+int checkdir(__G__ pathcomp, flag) 3007+ __GDEF 3008+ char *pathcomp; 3009+ int flag; 3010+/* 3011+ * returns: 3012+ * MPN_OK - no problem detected 3013+ * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename 3014+ * MPN_INF_SKIP - path doesn't exist, not allowed to create 3015+ * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path 3016+ * exists and is not a directory, but is supposed to be 3017+ * MPN_ERR_TOOLONG - path is too long 3018+ * MPN_NOMEM - can't allocate memory for filename buffers 3019+ */ 3020+{ 3021+ /* static int rootlen = 0; */ /* length of rootpath */ 3022+ /* static char *rootpath; */ /* user's "extract-to" directory */ 3023+ /* static char *buildpathHPFS; */ /* full path (so far) to extracted file, */ 3024+ /* static char *buildpathFAT; */ /* both HPFS/EA (main) and FAT versions */ 3025+ /* static char *endHPFS; */ /* corresponding pointers to end of */ 3026+ /* static char *endFAT; */ /* buildpath ('\0') */ 3027+ 3028+# define FN_MASK 7 3029+# define FUNCTION (flag & FN_MASK) 3030+ 3031+ 3032+ 3033+/*--------------------------------------------------------------------------- 3034+ APPEND_DIR: append the path component to the path being built and check 3035+ for its existence. If doesn't exist and we are creating directories, do 3036+ so for this one; else signal success or error as appropriate. 3037+ ---------------------------------------------------------------------------*/ 3038+ 3039+ if (FUNCTION == APPEND_DIR) { 3040+ char *p = pathcomp; 3041+ int too_long = FALSE; 3042+ 3043+ Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp))); 3044+ while ((*G.endHPFS = *p++) != '\0') /* copy to HPFS filename */ 3045+ ++G.endHPFS; 3046+ if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) { 3047+ p = pathcomp; 3048+ while ((*G.endFAT = *p++) != '\0') /* copy to FAT filename, too */ 3049+ ++G.endFAT; 3050+ } else 3051+ map2fat(pathcomp, &G.endFAT); /* map into FAT fn, update endFAT */ 3052+ 3053+ /* GRR: could do better check, see if overrunning buffer as we go: 3054+ * check endHPFS-buildpathHPFS after each append, set warning variable 3055+ * if within 20 of FILNAMSIZ; then if var set, do careful check when 3056+ * appending. Clear variable when begin new path. */ 3057+ 3058+ /* next check: need to append '/', at least one-char name, '\0' */ 3059+ if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3) 3060+ too_long = TRUE; /* check if extracting dir? */ 3061+#ifdef FIX_STAT_BUG 3062+ /* Borland C++ 5.0 does not handle a call to stat() well if the 3063+ * directory does not exist (it tends to crash in strange places.) 3064+ * This is apparently a problem only when compiling for GUI rather 3065+ * than console. The code below attempts to work around this problem. 3066+ */ 3067+ if (access(G.buildpathFAT, 0) != 0) { 3068+ if (!G.create_dirs) { /* told not to create (freshening) */ 3069+ free(G.buildpathHPFS); 3070+ free(G.buildpathFAT); 3071+ /* path doesn't exist: nothing to do */ 3072+ return MPN_INF_SKIP; 3073+ } 3074+ if (too_long) { /* GRR: should allow FAT extraction w/o EAs */ 3075+ Info(slide, 1, ((char *)slide, 3076+ "checkdir error: path too long: %s\n", 3077+ FnFilter1(G.buildpathHPFS))); 3078+ free(G.buildpathHPFS); 3079+ free(G.buildpathFAT); 3080+ /* no room for filenames: fatal */ 3081+ return MPN_ERR_TOOLONG; 3082+ } 3083+ if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */ 3084+ Info(slide, 1, ((char *)slide, 3085+ "checkdir error: cannot create %s\n\ 3086+ unable to process %s.\n", 3087+ FnFilter2(G.buildpathFAT), FnFilter1(G.filename))); 3088+ free(G.buildpathHPFS); 3089+ free(G.buildpathFAT); 3090+ /* path didn't exist, tried to create, failed */ 3091+ return MPN_ERR_SKIP; 3092+ } 3093+ G.created_dir = TRUE; 3094+ } 3095+#endif /* FIX_STAT_BUG */ 3096+ if (SSTAT(G.buildpathFAT, &G.statbuf)) /* path doesn't exist */ 3097+ { 3098+ if (!G.create_dirs) { /* told not to create (freshening) */ 3099+ free(G.buildpathHPFS); 3100+ free(G.buildpathFAT); 3101+ /* path doesn't exist: nothing to do */ 3102+ return MPN_INF_SKIP; 3103+ } 3104+ if (too_long) { /* GRR: should allow FAT extraction w/o EAs */ 3105+ Info(slide, 1, ((char *)slide, 3106+ "checkdir error: path too long: %s\n", 3107+ FnFilter1(G.buildpathHPFS))); 3108+ free(G.buildpathHPFS); 3109+ free(G.buildpathFAT); 3110+ /* no room for filenames: fatal */ 3111+ return MPN_ERR_TOOLONG; 3112+ } 3113+ if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */ 3114+ Info(slide, 1, ((char *)slide, 3115+ "checkdir error: cannot create %s\n\ 3116+ unable to process %s.\n", 3117+ FnFilter2(G.buildpathFAT), FnFilter1(G.filename))); 3118+ free(G.buildpathHPFS); 3119+ free(G.buildpathFAT); 3120+ /* path didn't exist, tried to create, failed */ 3121+ return MPN_ERR_SKIP; 3122+ } 3123+ G.created_dir = TRUE; 3124+ } else if (!S_ISDIR(G.statbuf.st_mode)) { 3125+ Info(slide, 1, ((char *)slide, 3126+ "checkdir error: %s exists but is not directory\n \ 3127+ unable to process %s.\n", 3128+ FnFilter2(G.buildpathFAT), FnFilter1(G.filename))); 3129+ free(G.buildpathHPFS); 3130+ free(G.buildpathFAT); 3131+ /* path existed but wasn't dir */ 3132+ return MPN_ERR_SKIP; 3133+ } 3134+ if (too_long) { 3135+ Info(slide, 1, ((char *)slide, 3136+ "checkdir error: path too long: %s\n", 3137+ FnFilter1(G.buildpathHPFS))); 3138+ free(G.buildpathHPFS); 3139+ free(G.buildpathFAT); 3140+ /* no room for filenames: fatal */ 3141+ return MPN_ERR_TOOLONG; 3142+ } 3143+ *G.endHPFS++ = '/'; 3144+ *G.endFAT++ = '/'; 3145+ *G.endHPFS = *G.endFAT = '\0'; 3146+ Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now = [%s]\n", 3147+ FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT))); 3148+ return MPN_OK; 3149+ 3150+ } /* end if (FUNCTION == APPEND_DIR) */ 3151+ 3152+/*--------------------------------------------------------------------------- 3153+ GETPATH: copy full FAT path to the string pointed at by pathcomp (want 3154+ filename to reflect name used on disk, not EAs; if full path is HPFS, 3155+ buildpathFAT and buildpathHPFS will be identical). Also free both paths. 3156+ ---------------------------------------------------------------------------*/ 3157+ 3158+ if (FUNCTION == GETPATH) { 3159+ Trace((stderr, "getting and freeing FAT path [%s]\n", 3160+ FnFilter1(G.buildpathFAT))); 3161+ Trace((stderr, "freeing HPFS path [%s]\n", 3162+ FnFilter1(G.buildpathHPFS))); 3163+ strcpy(pathcomp, G.buildpathFAT); 3164+ free(G.buildpathFAT); 3165+ free(G.buildpathHPFS); 3166+ G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL; 3167+ return MPN_OK; 3168+ } 3169+ 3170+/*--------------------------------------------------------------------------- 3171+ APPEND_NAME: assume the path component is the filename; append it and 3172+ return without checking for existence. 3173+ ---------------------------------------------------------------------------*/ 3174+ 3175+ if (FUNCTION == APPEND_NAME) { 3176+ char *p = pathcomp; 3177+ int error = MPN_OK; 3178+ 3179+ Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp))); 3180+ /* The buildpathHPFS buffer has been allocated large enough to 3181+ * hold the complete combined name, so there is no need to check 3182+ * for OS filename size limit overflow within the copy loop. 3183+ */ 3184+ while ((*G.endHPFS = *p++) != '\0') { /* copy to HPFS filename */ 3185+ ++G.endHPFS; 3186+ } 3187+ /* Now, check for OS filename size overflow. When detected, the 3188+ * mapped HPFS name is truncated and a warning message is shown. 3189+ */ 3190+ if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) { 3191+ G.buildpathHPFS[FILNAMSIZ-1] = '\0'; 3192+ Info(slide, 1, ((char *)slide, 3193+ "checkdir warning: path too long; truncating\n \ 3194+ %s\n -> %s\n", 3195+ FnFilter1(G.filename), FnFilter2(G.buildpathHPFS))); 3196+ error = MPN_INF_TRUNC; /* filename truncated */ 3197+ } 3198+ 3199+ /* The buildpathFAT buffer has the same allocated size as the 3200+ * buildpathHPFS buffer, so there is no need for an overflow check 3201+ * within the following copy loop, either. 3202+ */ 3203+ if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) { 3204+ /* copy to FAT filename, too */ 3205+ p = pathcomp; 3206+ while ((*G.endFAT = *p++) != '\0') 3207+ ++G.endFAT; 3208+ } else 3209+ /* map into FAT fn, update endFAT */ 3210+ map2fat(pathcomp, &G.endFAT); 3211+ 3212+ /* Check that the FAT path does not exceed the FILNAMSIZ limit, and 3213+ * truncate when neccessary. 3214+ * Note that truncation can only happen when the HPFS path (which is 3215+ * never shorter than the FAT path) has been already truncated. 3216+ * So, emission of the warning message and setting the error code 3217+ * has already happened. 3218+ */ 3219+ if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ) 3220+ G.buildpathFAT[FILNAMSIZ-1] = '\0'; 3221+ Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT: %s\n", 3222+ FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT))); 3223+ 3224+ return error; /* could check for existence, prompt for new name... */ 3225+ 3226+ } /* end if (FUNCTION == APPEND_NAME) */ 3227+ 3228+/*--------------------------------------------------------------------------- 3229+ INIT: allocate and initialize buffer space for the file currently being 3230+ extracted. If file was renamed with an absolute path, don't prepend the 3231+ extract-to path. 3232+ ---------------------------------------------------------------------------*/ 3233+ 3234+ if (FUNCTION == INIT) { 3235+ Trace((stderr, "initializing buildpathHPFS and buildpathFAT to ")); 3236+#ifdef ACORN_FTYPE_NFS 3237+ if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+ 3238+ (uO.acorn_nfs_ext ? 5 : 1))) 3239+#else 3240+ if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1)) 3241+#endif 3242+ == NULL) 3243+ return MPN_NOMEM; 3244+#ifdef ACORN_FTYPE_NFS 3245+ if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+ 3246+ (uO.acorn_nfs_ext ? 5 : 1))) 3247+#else 3248+ if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1)) 3249+#endif 3250+ == NULL) { 3251+ free(G.buildpathHPFS); 3252+ return MPN_NOMEM; 3253+ } 3254+ if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */ 3255+/* GRR: for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */ 3256+ if (G.renamed_fullpath && pathcomp[1] == ':') 3257+ *G.buildpathHPFS = (char)ToLower(*pathcomp); 3258+ else if (!G.renamed_fullpath && G.rootlen > 1 && 3259+ G.rootpath[1] == ':') 3260+ *G.buildpathHPFS = (char)ToLower(*G.rootpath); 3261+ else { 3262+ char tmpN[MAX_PATH], *tmpP; 3263+ if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH) 3264+ { /* by definition of MAX_PATH we should never get here */ 3265+ Info(slide, 1, ((char *)slide, 3266+ "checkdir warning: current dir path too long\n")); 3267+ return MPN_INF_TRUNC; /* can't get drive letter */ 3268+ } 3269+ G.nLabelDrive = *tmpN - 'a' + 1; 3270+ *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a'); 3271+ } 3272+ G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */ 3273+ if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */ 3274+ || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */ 3275+ free(G.buildpathHPFS); 3276+ free(G.buildpathFAT); 3277+ return MPN_VOL_LABEL; /* skipping with message */ 3278+ } 3279+ *G.buildpathHPFS = '\0'; 3280+ } else if (G.renamed_fullpath) /* pathcomp = valid data */ 3281+ strcpy(G.buildpathHPFS, pathcomp); 3282+ else if (G.rootlen > 0) 3283+ strcpy(G.buildpathHPFS, G.rootpath); 3284+ else 3285+ *G.buildpathHPFS = '\0'; 3286+ G.endHPFS = G.buildpathHPFS; 3287+ G.endFAT = G.buildpathFAT; 3288+ while ((*G.endFAT = *G.endHPFS) != '\0') { 3289+ ++G.endFAT; 3290+ ++G.endHPFS; 3291+ } 3292+ Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS))); 3293+ return MPN_OK; 3294+ } 3295+ 3296+/*--------------------------------------------------------------------------- 3297+ ROOT: if appropriate, store the path in rootpath and create it if neces- 3298+ sary; else assume it's a zipfile member and return. This path segment 3299+ gets used in extracting all members from every zipfile specified on the 3300+ command line. Note that under OS/2 and MS-DOS, if a candidate extract-to 3301+ directory specification includes a drive letter (leading "x:"), it is 3302+ treated just as if it had a trailing '/'--that is, one directory level 3303+ will be created if the path doesn't exist, unless this is otherwise pro- 3304+ hibited (e.g., freshening). 3305+ ---------------------------------------------------------------------------*/ 3306+ 3307+#if (!defined(SFX) || defined(SFX_EXDIR)) 3308+ if (FUNCTION == ROOT) { 3309+ Trace((stderr, "initializing root path to [%s]\n", 3310+ FnFilter1(pathcomp))); 3311+ if (pathcomp == NULL) { 3312+ G.rootlen = 0; 3313+ return MPN_OK; 3314+ } 3315+ if (G.rootlen > 0) /* rootpath was already set, nothing to do */ 3316+ return MPN_OK; 3317+ if ((G.rootlen = strlen(pathcomp)) > 0) { 3318+ int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE; 3319+ char *tmproot; 3320+ 3321+ if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) { 3322+ G.rootlen = 0; 3323+ return MPN_NOMEM; 3324+ } 3325+ strcpy(tmproot, pathcomp); 3326+ if (isalpha((uch)tmproot[0]) && tmproot[1] == ':') 3327+ has_drive = TRUE; /* drive designator */ 3328+ if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') { 3329+ tmproot[--G.rootlen] = '\0'; 3330+ had_trailing_pathsep = TRUE; 3331+ } 3332+ if (has_drive && (G.rootlen == 2)) { 3333+ if (!had_trailing_pathsep) /* i.e., original wasn't "x:/" */ 3334+ add_dot = TRUE; /* relative path: add '.' before '/' */ 3335+ } else if (G.rootlen > 0) { /* need not check "x:." and "x:/" */ 3336+ if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) 3337+ { 3338+ /* path does not exist */ 3339+ if (!G.create_dirs /* || iswild(tmproot) */ ) { 3340+ free(tmproot); 3341+ G.rootlen = 0; 3342+ /* treat as stored file */ 3343+ return MPN_INF_SKIP; 3344+ } 3345+ /* create directory (could add loop here scanning tmproot 3346+ * to create more than one level, but really necessary?) */ 3347+ if (MKDIR(tmproot, 0777) == -1) { 3348+ Info(slide, 1, ((char *)slide, 3349+ "checkdir: cannot create extraction directory: %s\n", 3350+ FnFilter1(tmproot))); 3351+ free(tmproot); 3352+ G.rootlen = 0; 3353+ /* path didn't exist, tried to create, failed: */ 3354+ /* file exists, or need 2+ subdir levels */ 3355+ return MPN_ERR_SKIP; 3356+ } 3357+ } 3358+ } 3359+ if (add_dot) /* had just "x:", make "x:." */ 3360+ tmproot[G.rootlen++] = '.'; 3361+ tmproot[G.rootlen++] = '/'; 3362+ tmproot[G.rootlen] = '\0'; 3363+ if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) { 3364+ free(tmproot); 3365+ G.rootlen = 0; 3366+ return MPN_NOMEM; 3367+ } 3368+ Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath))); 3369+ } 3370+ return MPN_OK; 3371+ } 3372+#endif /* !SFX || SFX_EXDIR */ 3373+ 3374+/*--------------------------------------------------------------------------- 3375+ END: free rootpath, immediately prior to program exit. 3376+ ---------------------------------------------------------------------------*/ 3377+ 3378+ if (FUNCTION == END) { 3379+ Trace((stderr, "freeing rootpath\n")); 3380+ if (G.rootlen > 0) { 3381+ free(G.rootpath); 3382+ G.rootlen = 0; 3383+ } 3384+ return MPN_OK; 3385 } 3386-} /* end function map2fat() */ 3387 3388+ return MPN_INVALID; /* should never reach */ 3389+ 3390+} /* end function checkdir() */ 3391 3392 3393 3394-/***********************/ /* Borrowed from os2.c for UnZip 5.1. */ 3395-/* Function checkdir() */ /* Difference: no EA stuff */ 3396-/***********************/ /* HPFS stuff works on NTFS too */ 3397+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 3398 3399-int checkdir(__G__ pathcomp, flag) 3400+/* WIN32 wide version */ 3401+ 3402+int checkdirw(__G__ pathcompw, flag) 3403 __GDEF 3404- char *pathcomp; 3405+ wchar_t *pathcompw; 3406 int flag; 3407 /* 3408@@ -2126,16 +3345,20 @@ 3409 3410 if (FUNCTION == APPEND_DIR) { 3411- char *p = pathcomp; 3412+ wchar_t *pw = pathcompw; 3413 int too_long = FALSE; 3414- 3415- Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp))); 3416- while ((*G.endHPFS = *p++) != '\0') /* copy to HPFS filename */ 3417- ++G.endHPFS; 3418- if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) { 3419- p = pathcomp; 3420- while ((*G.endFAT = *p++) != '\0') /* copy to FAT filename, too */ 3421- ++G.endFAT; 3422+ char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all); 3423+ char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all); 3424+ /* Could use G.filename from the standard path, but may 3425+ not work well on this port */ 3426+ char *fn = wchar_to_local_string(G.unipath_widefilename, G.unicode_escape_all); 3427+ 3428+ while ((*G.endHPFSw = *pw++) != '\0') /* copy to HPFS filename */ 3429+ ++G.endHPFSw; 3430+ if (!IsVolumeOldFATw(__G__ G.buildpathHPFSw)) { 3431+ pw = pathcompw; 3432+ while ((*G.endFATw = *pw++) != '\0') /* copy to FAT filename, too */ 3433+ ++G.endFATw; 3434 } else 3435- map2fat(pathcomp, &G.endFAT); /* map into FAT fn, update endFAT */ 3436+ map2fatw(pathcompw, &G.endFATw); /* map into FAT fn, update endFAT */ 3437 3438 /* GRR: could do better check, see if overrunning buffer as we go: 3439@@ -2145,5 +3368,5 @@ 3440 3441 /* next check: need to append '/', at least one-char name, '\0' */ 3442- if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3) 3443+ if ((G.endHPFSw-G.buildpathHPFSw) > FILNAMSIZ-3) 3444 too_long = TRUE; /* check if extracting dir? */ 3445 #ifdef FIX_STAT_BUG 3446@@ -2153,8 +3376,11 @@ 3447 * than console. The code below attempts to work around this problem. 3448 */ 3449- if (access(G.buildpathFAT, 0) != 0) { 3450+ if (_waccess(G.buildpathFATw, 0) != 0) { 3451 if (!G.create_dirs) { /* told not to create (freshening) */ 3452- free(G.buildpathHPFS); 3453- free(G.buildpathFAT); 3454+ free(buildpathHPFS); 3455+ free(buildpathFAT); 3456+ free(fn); 3457+ free(G.buildpathHPFSw); 3458+ free(G.buildpathFATw); 3459 /* path doesn't exist: nothing to do */ 3460 return MPN_INF_SKIP; 3461@@ -2163,28 +3389,40 @@ 3462 Info(slide, 1, ((char *)slide, 3463 "checkdir error: path too long: %s\n", 3464- FnFilter1(G.buildpathHPFS))); 3465- free(G.buildpathHPFS); 3466- free(G.buildpathFAT); 3467+ FnFilter1(fn))); 3468+ free(buildpathHPFS); 3469+ free(buildpathFAT); 3470+ free(fn); 3471+ free(G.buildpathHPFSw); 3472+ free(G.buildpathFATw); 3473 /* no room for filenames: fatal */ 3474 return MPN_ERR_TOOLONG; 3475 } 3476- if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */ 3477- Info(slide, 1, ((char *)slide, 3478- "checkdir error: cannot create %s\n\ 3479- unable to process %s.\n", 3480- FnFilter2(G.buildpathFAT), FnFilter1(G.filename))); 3481- free(G.buildpathHPFS); 3482- free(G.buildpathFAT); 3483- /* path didn't exist, tried to create, failed */ 3484- return MPN_ERR_SKIP; 3485- } 3486- G.created_dir = TRUE; 3487+ { 3488+ int i = MKDIRW(G.buildpathFATw, 0777); 3489+ if (i == -1) { /* create the directory */ 3490+ Info(slide, 1, ((char *)slide, 3491+ "checkdir error: cannot create %s\n\ 3492+ unable to process %s.\n", 3493+ FnFilter2(buildpathFAT), FnFilter1(fn))); 3494+ free(buildpathHPFS); 3495+ free(buildpathFAT); 3496+ free(fn); 3497+ free(G.buildpathHPFSw); 3498+ free(G.buildpathFATw); 3499+ /* path didn't exist, tried to create, failed */ 3500+ return MPN_ERR_SKIP; 3501+ } 3502+ G.created_dir = TRUE; 3503+ } 3504 } 3505 #endif /* FIX_STAT_BUG */ 3506- if (SSTAT(G.buildpathFAT, &G.statbuf)) /* path doesn't exist */ 3507+ if (SSTATW(G.buildpathFATw, &G.statbuf)) /* path doesn't exist */ 3508 { 3509 if (!G.create_dirs) { /* told not to create (freshening) */ 3510- free(G.buildpathHPFS); 3511- free(G.buildpathFAT); 3512+ free(buildpathHPFS); 3513+ free(buildpathFAT); 3514+ free(fn); 3515+ free(G.buildpathHPFSw); 3516+ free(G.buildpathFATw); 3517 /* path doesn't exist: nothing to do */ 3518 return MPN_INF_SKIP; 3519@@ -2193,28 +3431,41 @@ 3520 Info(slide, 1, ((char *)slide, 3521 "checkdir error: path too long: %s\n", 3522- FnFilter1(G.buildpathHPFS))); 3523- free(G.buildpathHPFS); 3524- free(G.buildpathFAT); 3525+ FnFilter1(buildpathHPFS))); 3526+ free(buildpathHPFS); 3527+ free(buildpathFAT); 3528+ free(fn); 3529+ free(G.buildpathHPFSw); 3530+ free(G.buildpathFATw); 3531 /* no room for filenames: fatal */ 3532 return MPN_ERR_TOOLONG; 3533 } 3534- if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */ 3535- Info(slide, 1, ((char *)slide, 3536- "checkdir error: cannot create %s\n\ 3537- unable to process %s.\n", 3538- FnFilter2(G.buildpathFAT), FnFilter1(G.filename))); 3539- free(G.buildpathHPFS); 3540- free(G.buildpathFAT); 3541- /* path didn't exist, tried to create, failed */ 3542- return MPN_ERR_SKIP; 3543- } 3544- G.created_dir = TRUE; 3545+ { 3546+ char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all); 3547+ int i = MKDIRW(G.buildpathFATw, 0777); 3548+ if (i == -1) { /* create the directory */ 3549+ Info(slide, 1, ((char *)slide, 3550+ "checkdir error: cannot create %s\n\ 3551+ unable to process %s.\n", 3552+ FnFilter2(buildpathFAT), FnFilter1(fn))); 3553+ free(buildpathHPFS); 3554+ free(buildpathFAT); 3555+ free(fn); 3556+ free(G.buildpathHPFSw); 3557+ free(G.buildpathFATw); 3558+ /* path didn't exist, tried to create, failed */ 3559+ return MPN_ERR_SKIP; 3560+ } 3561+ G.created_dir = TRUE; 3562+ } 3563 } else if (!S_ISDIR(G.statbuf.st_mode)) { 3564 Info(slide, 1, ((char *)slide, 3565 "checkdir error: %s exists but is not directory\n \ 3566 unable to process %s.\n", 3567- FnFilter2(G.buildpathFAT), FnFilter1(G.filename))); 3568- free(G.buildpathHPFS); 3569- free(G.buildpathFAT); 3570+ FnFilter2(buildpathFAT), FnFilter1(fn))); 3571+ free(buildpathHPFS); 3572+ free(buildpathFAT); 3573+ free(fn); 3574+ free(G.buildpathHPFSw); 3575+ free(G.buildpathFATw); 3576 /* path existed but wasn't dir */ 3577 return MPN_ERR_SKIP; 3578@@ -2223,15 +3474,23 @@ 3579 Info(slide, 1, ((char *)slide, 3580 "checkdir error: path too long: %s\n", 3581- FnFilter1(G.buildpathHPFS))); 3582- free(G.buildpathHPFS); 3583- free(G.buildpathFAT); 3584+ FnFilter1(buildpathHPFS))); 3585+ free(buildpathHPFS); 3586+ free(buildpathFAT); 3587+ free(fn); 3588+ free(G.buildpathHPFSw); 3589+ free(G.buildpathFATw); 3590 /* no room for filenames: fatal */ 3591 return MPN_ERR_TOOLONG; 3592 } 3593- *G.endHPFS++ = '/'; 3594- *G.endFAT++ = '/'; 3595- *G.endHPFS = *G.endFAT = '\0'; 3596+ *G.endHPFSw++ = '/'; 3597+ *G.endFATw++ = '/'; 3598+ *G.endHPFSw = *G.endFATw = '\0'; 3599 Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now = [%s]\n", 3600- FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT))); 3601+ FnFilter1(buildpathHPFS), FnFilter2(buildpathFAT))); 3602+ free(buildpathHPFS); 3603+ free(buildpathFAT); 3604+ free(fn); 3605+ //free(G.buildpathHPFSw); 3606+ //free(G.buildpathFATw); 3607 return MPN_OK; 3608 3609@@ -2245,12 +3504,16 @@ 3610 3611 if (FUNCTION == GETPATH) { 3612+ char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all); 3613+ char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all); 3614 Trace((stderr, "getting and freeing FAT path [%s]\n", 3615- FnFilter1(G.buildpathFAT))); 3616+ FnFilter1(buildpathFAT))); 3617 Trace((stderr, "freeing HPFS path [%s]\n", 3618- FnFilter1(G.buildpathHPFS))); 3619- strcpy(pathcomp, G.buildpathFAT); 3620- free(G.buildpathFAT); 3621- free(G.buildpathHPFS); 3622- G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL; 3623+ FnFilter1(buildpathHPFS))); 3624+ wcscpy(pathcompw, G.buildpathFATw); 3625+ free(buildpathFAT); 3626+ free(buildpathHPFS); 3627+ free(G.buildpathFATw); 3628+ free(G.buildpathHPFSw); 3629+ G.buildpathHPFSw = G.buildpathFATw = G.endHPFSw = G.endFATw = NULL; 3630 return MPN_OK; 3631 } 3632@@ -2262,6 +3525,8 @@ 3633 3634 if (FUNCTION == APPEND_NAME) { 3635- char *p = pathcomp; 3636+ wchar_t *pw = pathcompw; 3637 int error = MPN_OK; 3638+ char *pathcomp = wchar_to_local_string(pathcompw, G.unicode_escape_all); 3639+ char *fn = wchar_to_local_string(G.unipath_widefilename, G.unicode_escape_all); 3640 3641 Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp))); 3642@@ -2270,16 +3535,19 @@ 3643 * for OS filename size limit overflow within the copy loop. 3644 */ 3645- while ((*G.endHPFS = *p++) != '\0') { /* copy to HPFS filename */ 3646- ++G.endHPFS; 3647+ while ((*G.endHPFSw = *pw++) != '\0') { /* copy to HPFS filename */ 3648+ ++G.endHPFSw; 3649 } 3650 /* Now, check for OS filename size overflow. When detected, the 3651 * mapped HPFS name is truncated and a warning message is shown. 3652 */ 3653- if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) { 3654- G.buildpathHPFS[FILNAMSIZ-1] = '\0'; 3655+ if ((G.endHPFSw-G.buildpathHPFSw) >= FILNAMSIZ) { 3656+ char *buildpathHPFS; 3657+ G.buildpathHPFSw[FILNAMSIZ-1] = '\0'; 3658+ buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all); 3659 Info(slide, 1, ((char *)slide, 3660 "checkdir warning: path too long; truncating\n \ 3661 %s\n -> %s\n", 3662- FnFilter1(G.filename), FnFilter2(G.buildpathHPFS))); 3663+ FnFilter1(fn), FnFilter2(buildpathHPFS))); 3664+ free(buildpathHPFS); 3665 error = MPN_INF_TRUNC; /* filename truncated */ 3666 } 3667@@ -2289,12 +3557,12 @@ 3668 * within the following copy loop, either. 3669 */ 3670- if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) { 3671+ if (G.pInfo->vollabel || !IsVolumeOldFATw(__G__ G.buildpathHPFSw)) { 3672 /* copy to FAT filename, too */ 3673- p = pathcomp; 3674- while ((*G.endFAT = *p++) != '\0') 3675- ++G.endFAT; 3676+ pw = pathcompw; 3677+ while ((*G.endFATw = *pw++) != '\0') 3678+ ++G.endFATw; 3679 } else 3680 /* map into FAT fn, update endFAT */ 3681- map2fat(pathcomp, &G.endFAT); 3682+ map2fatw(pathcompw, &G.endFATw); 3683 3684 /* Check that the FAT path does not exceed the FILNAMSIZ limit, and 3685@@ -2305,8 +3573,16 @@ 3686 * has already happened. 3687 */ 3688- if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ) 3689- G.buildpathFAT[FILNAMSIZ-1] = '\0'; 3690- Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT: %s\n", 3691- FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT))); 3692+ if ((G.endFATw-G.buildpathFATw) >= FILNAMSIZ) 3693+ G.buildpathFATw[FILNAMSIZ-1] = '\0'; 3694+ { 3695+ char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all); 3696+ char *buildpathFAT = wchar_to_local_string(G.buildpathFATw,G.unicode_escape_all); 3697+ Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT: %s\n", 3698+ FnFilter1(buildpathHPFS), FnFilter2(buildpathFAT))); 3699+ free(buildpathHPFS); 3700+ free(buildpathFAT); 3701+ } 3702+ free(fn); 3703+ free(pathcomp); 3704 3705 return error; /* could check for existence, prompt for new name... */ 3706@@ -2321,33 +3597,23 @@ 3707 3708 if (FUNCTION == INIT) { 3709- Trace((stderr, "initializing buildpathHPFS and buildpathFAT to ")); 3710-#ifdef ACORN_FTYPE_NFS 3711- if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+ 3712- (uO.acorn_nfs_ext ? 5 : 1))) 3713-#else 3714- if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1)) 3715-#endif 3716+ Trace((stderr, "initializing buildpathHPFSw and buildpathFATw to ")); 3717+ if ((G.buildpathHPFSw = (wchar_t *)malloc((G.fnlen+G.rootlen+1) * sizeof(wchar_t))) 3718 == NULL) 3719 return MPN_NOMEM; 3720-#ifdef ACORN_FTYPE_NFS 3721- if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+ 3722- (uO.acorn_nfs_ext ? 5 : 1))) 3723-#else 3724- if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1)) 3725-#endif 3726+ if ((G.buildpathFATw = (wchar_t *)malloc((G.fnlen+G.rootlen+1) * sizeof(wchar_t))) 3727 == NULL) { 3728- free(G.buildpathHPFS); 3729+ free(G.buildpathHPFSw); 3730 return MPN_NOMEM; 3731 } 3732 if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */ 3733 /* GRR: for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */ 3734- if (G.renamed_fullpath && pathcomp[1] == ':') 3735- *G.buildpathHPFS = (char)ToLower(*pathcomp); 3736+ if (G.renamed_fullpath && pathcompw[1] == ':') 3737+ *G.buildpathHPFSw = (wchar_t)towlower(*pathcompw); 3738 else if (!G.renamed_fullpath && G.rootlen > 1 && 3739- G.rootpath[1] == ':') 3740- *G.buildpathHPFS = (char)ToLower(*G.rootpath); 3741+ G.rootpathw[1] == ':') 3742+ *G.buildpathHPFSw = (wchar_t)towlower(*G.rootpathw); 3743 else { 3744- char tmpN[MAX_PATH], *tmpP; 3745- if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH) 3746+ wchar_t tmpNw[MAX_PATH], *tmpPw; 3747+ if (GetFullPathNameW(L".", MAX_PATH, tmpNw, &tmpPw) > MAX_PATH) 3748 { /* by definition of MAX_PATH we should never get here */ 3749 Info(slide, 1, ((char *)slide, 3750@@ -2355,28 +3621,33 @@ 3751 return MPN_INF_TRUNC; /* can't get drive letter */ 3752 } 3753- G.nLabelDrive = *tmpN - 'a' + 1; 3754- *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a'); 3755+ G.nLabelDrive = (char)(*tmpNw - 'a' + 1); 3756+ *G.buildpathHPFSw = (wchar_t)(G.nLabelDrive - 1 + 'a'); 3757 } 3758- G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */ 3759- if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */ 3760+ G.nLabelDrive = (char)(*G.buildpathHPFSw - 'a' + 1); /* save for mapname() */ 3761+ if (uO.volflag == 0 || *G.buildpathHPFSw < 'a' /* no labels/bogus? */ 3762 || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */ 3763- free(G.buildpathHPFS); 3764- free(G.buildpathFAT); 3765+ free(G.buildpathHPFSw); 3766+ free(G.buildpathFATw); 3767 return MPN_VOL_LABEL; /* skipping with message */ 3768 } 3769- *G.buildpathHPFS = '\0'; 3770+ *G.buildpathHPFSw = '\0'; 3771 } else if (G.renamed_fullpath) /* pathcomp = valid data */ 3772- strcpy(G.buildpathHPFS, pathcomp); 3773+ wcscpy(G.buildpathHPFSw, pathcompw); 3774 else if (G.rootlen > 0) 3775- strcpy(G.buildpathHPFS, G.rootpath); 3776+ wcscpy(G.buildpathHPFSw, G.rootpathw); 3777 else 3778- *G.buildpathHPFS = '\0'; 3779- G.endHPFS = G.buildpathHPFS; 3780- G.endFAT = G.buildpathFAT; 3781- while ((*G.endFAT = *G.endHPFS) != '\0') { 3782- ++G.endFAT; 3783- ++G.endHPFS; 3784+ *G.buildpathHPFSw = '\0'; 3785+ G.endHPFSw = G.buildpathHPFSw; 3786+ G.endFATw = G.buildpathFATw; 3787+ while ((*G.endFATw = *G.endHPFSw) != '\0') { 3788+ ++G.endFATw; 3789+ ++G.endHPFSw; 3790 } 3791- Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS))); 3792+ { 3793+ char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all); 3794+ Trace((stderr, "[%s]\n", FnFilter1(buildpathHPFS))); 3795+ free(buildpathHPFS); 3796+ } 3797+ 3798 return MPN_OK; 3799 } 3800@@ -2395,7 +3666,9 @@ 3801 #if (!defined(SFX) || defined(SFX_EXDIR)) 3802 if (FUNCTION == ROOT) { 3803+ char *pathcomp = wchar_to_local_string(pathcompw, G.unicode_escape_all); 3804 Trace((stderr, "initializing root path to [%s]\n", 3805 FnFilter1(pathcomp))); 3806- if (pathcomp == NULL) { 3807+ free(pathcomp); 3808+ if (pathcompw == NULL) { 3809 G.rootlen = 0; 3810 return MPN_OK; 3811@@ -2403,17 +3676,17 @@ 3812 if (G.rootlen > 0) /* rootpath was already set, nothing to do */ 3813 return MPN_OK; 3814- if ((G.rootlen = strlen(pathcomp)) > 0) { 3815+ if ((G.rootlen = wcslen(pathcompw)) > 0) { 3816 int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE; 3817- char *tmproot; 3818+ wchar_t *tmprootw; 3819 3820- if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) { 3821+ if ((tmprootw = (wchar_t *)malloc((G.rootlen+3) * sizeof(wchar_t))) == (wchar_t *)NULL) { 3822 G.rootlen = 0; 3823 return MPN_NOMEM; 3824 } 3825- strcpy(tmproot, pathcomp); 3826- if (isalpha((uch)tmproot[0]) && tmproot[1] == ':') 3827+ wcscpy(tmprootw, pathcompw); 3828+ if (iswalpha(tmprootw[0]) && tmprootw[1] == ':') 3829 has_drive = TRUE; /* drive designator */ 3830- if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') { 3831- tmproot[--G.rootlen] = '\0'; 3832+ if (tmprootw[G.rootlen-1] == '/' || tmprootw[G.rootlen-1] == '\\') { 3833+ tmprootw[--G.rootlen] = '\0'; 3834 had_trailing_pathsep = TRUE; 3835 } 3836@@ -2422,9 +3695,9 @@ 3837 add_dot = TRUE; /* relative path: add '.' before '/' */ 3838 } else if (G.rootlen > 0) { /* need not check "x:." and "x:/" */ 3839- if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) 3840+ if (SSTATW(tmprootw, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) 3841 { 3842 /* path does not exist */ 3843 if (!G.create_dirs /* || iswild(tmproot) */ ) { 3844- free(tmproot); 3845+ free(tmprootw); 3846 G.rootlen = 0; 3847 /* treat as stored file */ 3848@@ -2433,12 +3706,15 @@ 3849 /* create directory (could add loop here scanning tmproot 3850 * to create more than one level, but really necessary?) */ 3851- if (MKDIR(tmproot, 0777) == -1) { 3852+ if (MKDIRW(tmprootw, 0777) == -1) { 3853+ char *tmproot = wchar_to_local_string(tmprootw, G.unicode_escape_all); 3854 Info(slide, 1, ((char *)slide, 3855 "checkdir: cannot create extraction directory: %s\n", 3856 FnFilter1(tmproot))); 3857 free(tmproot); 3858+ free(tmprootw); 3859 G.rootlen = 0; 3860 /* path didn't exist, tried to create, failed: */ 3861 /* file exists, or need 2+ subdir levels */ 3862+ free(pathcomp); 3863 return MPN_ERR_SKIP; 3864 } 3865@@ -2446,13 +3722,17 @@ 3866 } 3867 if (add_dot) /* had just "x:", make "x:." */ 3868- tmproot[G.rootlen++] = '.'; 3869- tmproot[G.rootlen++] = '/'; 3870- tmproot[G.rootlen] = '\0'; 3871- if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) { 3872- free(tmproot); 3873+ tmprootw[G.rootlen++] = '.'; 3874+ tmprootw[G.rootlen++] = '/'; 3875+ tmprootw[G.rootlen] = '\0'; 3876+ if ((G.rootpathw = (wchar_t *)realloc(tmprootw, (G.rootlen+1) * sizeof(wchar_t))) == NULL) { 3877+ free(tmprootw); 3878 G.rootlen = 0; 3879 return MPN_NOMEM; 3880 } 3881- Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath))); 3882+ { 3883+ char *rootpath = wchar_to_local_string(G.rootpathw, G.unicode_escape_all); 3884+ Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath))); 3885+ free(rootpath); 3886+ } 3887 } 3888 return MPN_OK; 3889@@ -2467,5 +3747,5 @@ 3890 Trace((stderr, "freeing rootpath\n")); 3891 if (G.rootlen > 0) { 3892- free(G.rootpath); 3893+ free(G.rootpathw); 3894 G.rootlen = 0; 3895 } 3896@@ -2475,6 +3755,7 @@ 3897 return MPN_INVALID; /* should never reach */ 3898 3899-} /* end function checkdir() */ 3900+} /* end function checkdirw() */ 3901 3902+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 3903 3904 3905@@ -2809,4 +4090,99 @@ 3906 } 3907 3908+ 3909+ 3910+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 3911+ 3912+int zstat_win32w(__W32STAT_GLOBALS__ const wchar_t *pathw, z_stat *buf) 3913+{ 3914+ if (!zstatw(pathw, buf)) 3915+ { 3916+ char *path = wchar_to_local_string((wchar_t *)pathw, G.unicode_escape_all); 3917+ /* stat was successful, now redo the time-stamp fetches */ 3918+#ifndef NO_W32TIMES_IZFIX 3919+ int fs_uses_loctime = FStampIsLocTimeW(__G__ pathw); 3920+#endif 3921+ HANDLE h; 3922+ FILETIME Modft, Accft, Creft; 3923+ 3924+ TTrace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime)); 3925+ h = CreateFileW(pathw, GENERIC_READ, 3926+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 3927+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 3928+ if (h != INVALID_HANDLE_VALUE) { 3929+ BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft); 3930+ CloseHandle(h); 3931+ 3932+ if (ftOK) { 3933+ FTTrace((stdout, "GetFileTime returned Modft", 0, &Modft)); 3934+ FTTrace((stdout, "GetFileTime returned Creft", 0, &Creft)); 3935+#ifndef NO_W32TIMES_IZFIX 3936+ if (!fs_uses_loctime) { 3937+ /* On a filesystem that stores UTC timestamps, we refill 3938+ * the time fields of the struct stat buffer by directly 3939+ * using the UTC values as returned by the Win32 3940+ * GetFileTime() API call. 3941+ */ 3942+ NtfsFileTime2utime(&Modft, &(buf->st_mtime)); 3943+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0) 3944+ NtfsFileTime2utime(&Accft, &(buf->st_atime)); 3945+ else 3946+ buf->st_atime = buf->st_mtime; 3947+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0) 3948+ NtfsFileTime2utime(&Creft, &(buf->st_ctime)); 3949+ else 3950+ buf->st_ctime = buf->st_mtime; 3951+ TTrace((stdout,"NTFS, recalculated modtime %08lx\n", 3952+ buf->st_mtime)); 3953+ } else 3954+#endif /* NO_W32TIMES_IZFIX */ 3955+ { 3956+ /* On VFAT and FAT-like filesystems, the FILETIME values 3957+ * are converted back to the stable local time before 3958+ * converting them to UTC unix time-stamps. 3959+ */ 3960+ VFatFileTime2utime(&Modft, &(buf->st_mtime)); 3961+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0) 3962+ VFatFileTime2utime(&Accft, &(buf->st_atime)); 3963+ else 3964+ buf->st_atime = buf->st_mtime; 3965+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0) 3966+ VFatFileTime2utime(&Creft, &(buf->st_ctime)); 3967+ else 3968+ buf->st_ctime = buf->st_mtime; 3969+ TTrace((stdout, "VFAT, recalculated modtime %08lx\n", 3970+ buf->st_mtime)); 3971+ } 3972+ } 3973+ } 3974+ free(path); 3975+ 3976+ return 0; 3977+ } 3978+#ifdef W32_STATROOT_FIX 3979+ else 3980+ { 3981+ DWORD flags; 3982+ 3983+ flags = GetFileAttributesW(pathw); 3984+ if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) { 3985+ char *path = wchar_to_local_string((wchar_t *)pathw, G.unicode_escape_all); 3986+ Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n", 3987+ FnFilter1(path))); 3988+ free(path); 3989+ memset(buf, 0, sizeof(z_stat)); 3990+ buf->st_atime = buf->st_ctime = buf->st_mtime = 3991+ dos_to_unix_time(DOSTIME_MINIMUM); /* 1-1-80 */ 3992+ buf->st_mode = S_IFDIR | S_IREAD | 3993+ ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE); 3994+ return 0; 3995+ } /* assumes: stat() won't fail on non-dirs without good reason */ 3996+ } 3997+#endif /* W32_STATROOT_FIX */ 3998+ return -1; 3999+} 4000+ 4001+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 4002+ 4003 #endif /* W32_STAT_BANDAID */ 4004 4005@@ -2939,6 +4315,5 @@ 4006 4007 4008-#if 0 4009-#ifdef UNICODE_SUPPORT 4010+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) 4011 wchar_t *utf8_to_wchar_string(utf8_string) 4012 char *utf8_string; /* path to get utf-8 name for */ 4013@@ -3030,22 +4405,40 @@ 4014 return qw; 4015 } 4016-#endif /* UNICODE_SUPPORT */ 4017-#endif /* 0 */ 4018 4019+int has_win32_wide() 4020+{ 4021+ int is_win32_wide; 4022 4023+ /* test if we have wide function support */ 4024 4025-/* --------------------------------------------------- */ 4026-/* Large File Support 4027- * 4028- * Initial functions by E. Gordon and R. Nausedat 4029- * 9/10/2003 4030- * Lifted from Zip 3b, win32.c and place here by Myles Bennett 4031- * 7/6/2004 4032- * 4033- * These implement 64-bit file support for Windows. The 4034- * defines and headers are in win32/w32cfg.h. 4035- * 4036- * Moved to win32i64.c by Mike White to avoid conflicts in 4037- * same name functions in WiZ using UnZip and Zip libraries. 4038- * 9/25/2003 4039- */ 4040+ /* first guess: On "real" WinNT, the WIN32 wide API >>is<< supported. */ 4041+ is_win32_wide = IsWinNT(); 4042+ 4043+ if (!is_win32_wide) 4044+ { 4045+ /* On a non-WinNT environment (Win9x or Win32s), wide functions 4046+ * might although supported when program is linked against the 4047+ * Win9x Unicode support library. 4048+ * => run a check whether a needed API function is supported. 4049+ */ 4050+ DWORD r; 4051+ /* get attributes for this directory */ 4052+ r = GetFileAttributesA("."); 4053+ 4054+ /* r should be 16 = FILE_ATTRIBUTE_DIRECTORY */ 4055+ if (r == FILE_ATTRIBUTE_DIRECTORY) { 4056+ /* now see if it works for the wide version */ 4057+ r = GetFileAttributesW(L"."); 4058+ /* if this fails then we probably don't have wide functions */ 4059+ if (r == 0xFFFFFFFF) { 4060+ /* error is probably "This function is only valid in Win32 mode." */ 4061+ } else if (r == FILE_ATTRIBUTE_DIRECTORY) { 4062+ /* worked, so assume we have wide support */ 4063+ is_win32_wide = TRUE; 4064+ } 4065+ } 4066+ } 4067+ return is_win32_wide; 4068+} 4069+ 4070+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */ 4071diff -ru2 unz60d10/windll/vc6/dll/unz32dll.dsp unz60d10_w32w/windll/vc6/dll/unz32dll.dsp 4072--- unz60d10/windll/vc6/dll/unz32dll.dsp Wed Dec 27 23:25:00 2006 4073+++ unz60d10_w32w/windll/vc6/dll/unz32dll.dsp Mon Feb 11 02:38:32 2008 4074@@ -46,5 +46,5 @@ 4075 # PROP Target_Dir "" 4076 # ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c 4077-# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../.." /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /YX /FD /c 4078+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../.." /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /YX /FD /c 4079 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 4080 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 4081@@ -72,5 +72,5 @@ 4082 # PROP Target_Dir "" 4083 # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c 4084-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../../.." /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /YX /FD /c 4085+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../../.." /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /YX /FD /c 4086 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 4087 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 4088@@ -98,5 +98,5 @@ 4089 # PROP Target_Dir "" 4090 # ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c 4091-# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../.." /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "ASM_CRC" /YX /FD /c 4092+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../.." /D "NDEBUG" /D "ASM_CRC" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /YX /FD /c 4093 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 4094 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 4095@@ -124,5 +124,5 @@ 4096 # PROP Target_Dir "" 4097 # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c 4098-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../../.." /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "ASM_CRC" /YX /FD /c 4099+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../../.." /D "_DEBUG" /D "ASM_CRC" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FR /YX /FD /c 4100 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 4101 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 4102