unzip/win32-experimental/unz60d10_w32wide-Unicode_pa...

4102 lines
163 KiB
Plaintext

diff -ru2 unz60d10/extract.c unz60d10_w32w/extract.c
--- unz60d10/extract.c Thu Dec 27 21:41:40 2007
+++ unz60d10_w32w/extract.c Mon Feb 11 02:22:00 2008
@@ -87,4 +87,11 @@
static int store_info OF((__GPRO));
#ifdef SET_DIR_ATTRIB
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static int extract_or_test_entrylistw OF((__GPRO__ unsigned numchunk,
+ ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes,
+ unsigned *pnum_dirs,
+ direntryw **pdirlistw,
+ int error_in_archive));
+# endif
static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes,
@@ -112,4 +119,7 @@
#endif
#ifdef SET_DIR_ATTRIB
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ static int Cdecl dircompw OF((ZCONST zvoid *a, ZCONST zvoid *b));
+# endif
static int Cdecl dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b));
#endif
@@ -336,4 +346,7 @@
#ifdef SET_DIR_ATTRIB
unsigned num_dirs=0;
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ direntryw *dirlistw=(direntryw *)NULL, **sorted_dirlistw=(direntryw **)NULL;
+#endif
direntry *dirlist=(direntry *)NULL, **sorted_dirlist=(direntry **)NULL;
#endif
@@ -356,8 +369,25 @@
if (uO.exdir != (char *)NULL && G.extract_flag) {
G.create_dirs = !uO.fflag;
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ if (G.has_win32_wide) {
+ wchar_t *exdirw = local_to_wchar_string(uO.exdir);
+ if ((error = checkdirw(exdirw, ROOT)) > MPN_INF_SKIP) {
+ /* out of memory, or file in way */
+ free(exdirw);
+ return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
+ }
+ free(exdirw);
+ } else {
+ if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) {
+ /* out of memory, or file in way */
+ return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
+ }
+ }
+# else /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) {
/* out of memory, or file in way */
return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
}
+# endif /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
}
#endif /* !SFX || SFX_EXDIR */
@@ -570,5 +600,18 @@
-----------------------------------------------------------------------*/
- error = extract_or_test_entrylist(__G__ j,
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ if (G.has_win32_wide)
+ {
+ error = extract_or_test_entrylistw(__G__ j,
+ &filnum, &num_bad_pwd, &old_extra_bytes,
+# ifdef SET_DIR_ATTRIB
+ &num_dirs, &dirlistw,
+# endif
+ error_in_archive);
+ }
+ else
+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
+ {
+ error = extract_or_test_entrylist(__G__ j,
&filnum, &num_bad_pwd, &old_extra_bytes,
#ifdef SET_DIR_ATTRIB
@@ -576,4 +619,5 @@
#endif
error_in_archive);
+ }
if (error != PK_COOL) {
if (error > error_in_archive)
@@ -643,4 +687,55 @@
#ifdef SET_DIR_ATTRIB
if (num_dirs > 0) {
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ if (G.has_win32_wide) {
+ sorted_dirlistw = (direntryw **)malloc(num_dirs*sizeof(direntryw *));
+ if (sorted_dirlistw == (direntryw **)NULL) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(DirlistSortNoMem)));
+ while (dirlistw != (direntryw *)NULL) {
+ direntryw *dw = dirlistw;
+
+ dirlistw = dirlistw->next;
+ free(dw);
+ }
+ } else {
+ ulg ndirs_fail = 0;
+
+ if (num_dirs == 1)
+ sorted_dirlistw[0] = dirlistw;
+ else {
+ for (i = 0; i < num_dirs; ++i) {
+ sorted_dirlistw[i] = dirlistw;
+ dirlistw = dirlistw->next;
+ }
+ qsort((char *)sorted_dirlistw, num_dirs, sizeof(direntryw *),
+ dircompw);
+ }
+
+ Trace((stderr, "setting directory times/perms/attributes\n"));
+ for (i = 0; i < num_dirs; ++i) {
+ direntryw *dw = sorted_dirlistw[i];
+
+ Trace((stderr, "dir = %s\n", dw->fn));
+ if ((error = set_direc_attribsw(__G__ dw)) != PK_OK) {
+ ndirs_fail++;
+ Info(slide, 0x201, ((char *)slide,
+ LoadFarString(DirlistSetAttrFailed), dw->fnw));
+ if (!error_in_archive)
+ error_in_archive = error;
+ }
+ free(dw);
+ }
+ free(sorted_dirlistw);
+ if (!uO.tflag && QCOND2) {
+ if (ndirs_fail > 0)
+ Info(slide, 0, ((char *)slide,
+ LoadFarString(DirlistFailAttrSum), ndirs_fail));
+ }
+ }
+ }
+ else
+# endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
+ {
sorted_dirlist = (direntry **)malloc(num_dirs*sizeof(direntry *));
if (sorted_dirlist == (direntry **)NULL) {
@@ -688,4 +783,5 @@
}
}
+ }
}
#endif /* SET_DIR_ATTRIB */
@@ -821,190 +917,731 @@
#endif
-#ifdef USE_WAVP
-# define UNKN_WAVP (G.crec.compression_method!=WAVPACKED)
-#else
-# define UNKN_WAVP TRUE /* WavPack unknown */
+#ifdef USE_WAVP
+# define UNKN_WAVP (G.crec.compression_method!=WAVPACKED)
+#else
+# define UNKN_WAVP TRUE /* WavPack unknown */
+#endif
+
+#ifdef USE_PPMD
+# define UNKN_PPMD (G.crec.compression_method!=PPMDED)
+#else
+# define UNKN_PPMD TRUE /* PPMd unknown */
+#endif
+
+#ifdef SFX
+# ifdef USE_DEFLATE64
+# define UNKN_COMPR \
+ (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \
+ && G.crec.compression_method>ENHDEFLATED \
+ && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
+# else
+# define UNKN_COMPR \
+ (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\
+ && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
+# endif
+#else
+# ifdef COPYRIGHT_CLEAN /* no reduced files */
+# define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
+ G.crec.compression_method <= REDUCED4)
+# else
+# define UNKN_RED FALSE /* reducing not unknown */
+# endif
+# ifdef LZW_CLEAN /* no shrunk files */
+# define UNKN_SHR (G.crec.compression_method == SHRUNK)
+# else
+# define UNKN_SHR FALSE /* unshrinking not unknown */
+# endif
+# ifdef USE_DEFLATE64
+# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
+ G.crec.compression_method==TOKENIZED || \
+ (G.crec.compression_method>ENHDEFLATED && UNKN_BZ2 && UNKN_LZMA \
+ && UNKN_WAVP && UNKN_PPMD))
+# else
+# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
+ G.crec.compression_method==TOKENIZED || \
+ (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \
+ && UNKN_WAVP && UNKN_PPMD))
+# endif
+#endif
+
+#if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS))
+ int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS);
+# define UNZVERS_SUPPORT unzvers_support
+#else
+# define UNZVERS_SUPPORT UNZIP_VERSION
+#endif
+
+/*---------------------------------------------------------------------------
+ Check central directory info for version/compatibility requirements.
+ ---------------------------------------------------------------------------*/
+
+ G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1; /* bit field */
+ G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8; /* bit */
+ G.pInfo->textfile = G.crec.internal_file_attributes & 1; /* bit field */
+ G.pInfo->crc = G.crec.crc32;
+ G.pInfo->compr_size = G.crec.csize;
+ G.pInfo->uncompr_size = G.crec.ucsize;
+
+ switch (uO.aflag) {
+ case 0:
+ G.pInfo->textmode = FALSE; /* bit field */
+ break;
+ case 1:
+ G.pInfo->textmode = G.pInfo->textfile; /* auto-convert mode */
+ break;
+ default: /* case 2: */
+ G.pInfo->textmode = TRUE;
+ break;
+ }
+
+ if (G.crec.version_needed_to_extract[1] == VMS_) {
+ if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
+ Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
+ FnFilter1(G.filename), "VMS",
+ G.crec.version_needed_to_extract[0] / 10,
+ G.crec.version_needed_to_extract[0] % 10,
+ VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10));
+ return 0;
+ }
+#ifndef VMS /* won't be able to use extra field, but still have data */
+ else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */
+ Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery),
+ FnFilter1(G.filename)));
+ fgets(G.answerbuf, 9, stdin);
+ if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y'))
+ return 0;
+ }
+#endif /* !VMS */
+ /* usual file type: don't need VMS to extract */
+ } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
+ Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
+ FnFilter1(G.filename), "PK",
+ G.crec.version_needed_to_extract[0] / 10,
+ G.crec.version_needed_to_extract[0] % 10,
+ UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10));
+ return 0;
+ }
+
+ if (UNKN_COMPR) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) {
+#ifndef SFX
+ unsigned cmpridx;
+
+ if ((cmpridx = find_compr_idx(G.crec.compression_method))
+ < NUM_METHODS)
+ Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName),
+ FnFilter1(G.filename),
+ LoadFarStringSmall(ComprNames[cmpridx])));
+ else
+#endif
+ Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum),
+ FnFilter1(G.filename),
+ G.crec.compression_method));
+ }
+ return 0;
+ }
+#if (!CRYPT)
+ if (G.pInfo->encrypted) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
+ Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted),
+ FnFilter1(G.filename)));
+ return 0;
+ }
+#endif /* !CRYPT */
+
+#ifndef SFX
+ /* store a copy of the central header filename for later comparison */
+ if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName),
+ FnFilter1(G.filename)));
+ } else
+ zfstrcpy(G.pInfo->cfilname, G.filename);
+#endif /* !SFX */
+
+ /* map whatever file attributes we have into the local format */
+ mapattr(__G); /* GRR: worry about return value later */
+
+ G.pInfo->diskstart = G.crec.disk_number_start;
+ G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header;
+ return 1;
+
+} /* end function store_info() */
+
+
+
+
+
+#ifndef SFX
+/*******************************/
+/* Function find_compr_idx() */
+/*******************************/
+
+unsigned find_compr_idx(compr_methodnum)
+ unsigned compr_methodnum;
+{
+ unsigned i;
+
+ for (i = 0; i < NUM_METHODS; i++) {
+ if (ComprIDs[i] == compr_methodnum) break;
+ }
+ return i;
+}
+#endif /* !SFX */
+
+
+
+
+
+/******************************************/
+/* Function extract_or_test_entrylist() */
+/******************************************/
+
+static int extract_or_test_entrylist(__G__ numchunk,
+ pfilnum, pnum_bad_pwd, pold_extra_bytes,
+#ifdef SET_DIR_ATTRIB
+ pnum_dirs, pdirlist,
+#endif
+ error_in_archive) /* return PK-type error code */
+ __GDEF
+ unsigned numchunk;
+ ulg *pfilnum;
+ ulg *pnum_bad_pwd;
+ zoff_t *pold_extra_bytes;
+#ifdef SET_DIR_ATTRIB
+ unsigned *pnum_dirs;
+ direntry **pdirlist;
+#endif
+ int error_in_archive;
+{
+ unsigned i;
+ int renamed, query;
+ int skip_entry;
+ zoff_t bufstart, inbuf_offset, request;
+ int error, errcode;
+
+/* possible values for local skip_entry flag: */
+#define SKIP_NO 0 /* do not skip this entry */
+#define SKIP_Y_EXISTING 1 /* skip this entry, do not overwrite file */
+#define SKIP_Y_NONEXIST 2 /* skip this entry, do not create new file */
+
+ /*-----------------------------------------------------------------------
+ Second loop: process files in current block, extracting or testing
+ each one.
+ -----------------------------------------------------------------------*/
+
+ for (i = 0; i < numchunk; ++i) {
+ (*pfilnum)++; /* *pfilnum = i + blknum*DIR_BLKSIZ + 1; */
+ G.pInfo = &G.info[i];
+#ifdef NOVELL_BUG_FAILSAFE
+ G.dne = FALSE; /* assume file exists until stat() says otherwise */
+#endif
+
+ /* if the target position is not within the current input buffer
+ * (either haven't yet read far enough, or (maybe) skipping back-
+ * ward), skip to the target position and reset readbuf(). */
+
+ /* seek_zipf(__G__ pInfo->offset); */
+ request = G.pInfo->offset + G.extra_bytes;
+ inbuf_offset = request % INBUFSIZ;
+ bufstart = request - inbuf_offset;
+
+ Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n",
+ (long)request, (long)inbuf_offset));
+ Trace((stderr,
+ "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
+ (long)bufstart, (long)G.cur_zipfile_bufstart));
+ if (request < 0) {
+ Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg),
+ G.zipfn, LoadFarString(ReportMsg)));
+ error_in_archive = PK_ERR;
+ if (*pfilnum == 1 && G.extra_bytes != 0L) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(AttemptRecompensate)));
+ *pold_extra_bytes = G.extra_bytes;
+ G.extra_bytes = 0L;
+ request = G.pInfo->offset; /* could also check if != 0 */
+ inbuf_offset = request % INBUFSIZ;
+ bufstart = request - inbuf_offset;
+ Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n",
+ (long)request, (long)inbuf_offset));
+ Trace((stderr,
+ "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
+ (long)bufstart, (long)G.cur_zipfile_bufstart));
+ /* try again */
+ if (request < 0) {
+ Trace((stderr,
+ "debug: recompensated request still < 0\n"));
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall(SeekMsg),
+ G.zipfn, LoadFarString(ReportMsg)));
+ error_in_archive = PK_BADERR;
+ continue;
+ }
+ } else {
+ error_in_archive = PK_BADERR;
+ continue; /* this one hosed; try next */
+ }
+ }
+
+ if (bufstart != G.cur_zipfile_bufstart) {
+ Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n"));
+#ifdef USE_STRM_INPUT
+ zfseeko(G.zipfd, bufstart, SEEK_SET);
+ G.cur_zipfile_bufstart = zftello(G.zipfd);
+#else /* !USE_STRM_INPUT */
+ G.cur_zipfile_bufstart =
+ zlseek(G.zipfd, bufstart, SEEK_SET);
+#endif /* ?USE_STRM_INPUT */
+ if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
+ {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
+ *pfilnum, "lseek", (long)bufstart));
+ error_in_archive = PK_BADERR;
+ continue; /* can still do next file */
+ }
+ G.inptr = G.inbuf + (int)inbuf_offset;
+ G.incnt -= (int)inbuf_offset;
+ } else {
+ G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset;
+ G.inptr = G.inbuf + (int)inbuf_offset;
+ }
+
+ /* should be in proper position now, so check for sig */
+ if (readbuf(__G__ G.sig, 4) == 0) { /* bad offset */
+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
+ *pfilnum, "EOF", (long)request));
+ error_in_archive = PK_BADERR;
+ continue; /* but can still try next one */
+ }
+ if (strncmp(G.sig, local_hdr_sig, 4)) {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
+ *pfilnum, LoadFarStringSmall(LocalHdrSig), (long)request));
+ /*
+ GRRDUMP(G.sig, 4)
+ GRRDUMP(local_hdr_sig, 4)
+ */
+ error_in_archive = PK_ERR;
+ if ((*pfilnum == 1 && G.extra_bytes != 0L) ||
+ (G.extra_bytes == 0L && *pold_extra_bytes != 0L)) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(AttemptRecompensate)));
+ if (G.extra_bytes) {
+ *pold_extra_bytes = G.extra_bytes;
+ G.extra_bytes = 0L;
+ } else
+ G.extra_bytes = *pold_extra_bytes; /* third attempt */
+ if (((error = seek_zipf(__G__ G.pInfo->offset)) != PK_OK) ||
+ (readbuf(__G__ G.sig, 4) == 0)) { /* bad offset */
+ if (error != PK_BADERR)
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OffsetMsg), *pfilnum, "EOF",
+ (long)request));
+ error_in_archive = PK_BADERR;
+ continue; /* but can still try next one */
+ }
+ if (strncmp(G.sig, local_hdr_sig, 4)) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OffsetMsg), *pfilnum,
+ LoadFarStringSmall(LocalHdrSig), (long)request));
+ error_in_archive = PK_BADERR;
+ continue;
+ }
+ } else
+ continue; /* this one hosed; try next */
+ }
+ if ((error = process_local_file_hdr(__G)) != PK_COOL) {
+ Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr),
+ *pfilnum));
+ error_in_archive = error; /* only PK_EOF defined */
+ continue; /* can still try next one */
+ }
+ if ((error = do_string(__G__ G.lrec.filename_length, DS_FN_L)) !=
+ PK_COOL)
+ {
+ if (error > error_in_archive)
+ error_in_archive = error;
+ if (error > PK_WARN) {
+ Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg),
+ FnFilter1(G.filename), "local"));
+ continue; /* go on to next one */
+ }
+ }
+ if (G.extra_field != (uch *)NULL) {
+ free(G.extra_field);
+ G.extra_field = (uch *)NULL;
+ }
+ if ((error =
+ do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0)
+ {
+ if (error > error_in_archive)
+ error_in_archive = error;
+ if (error > PK_WARN) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(ExtFieldMsg),
+ FnFilter1(G.filename), "local"));
+ continue; /* go on */
+ }
+ }
+#ifndef SFX
+ /* Filename consistency checks must come after reading in the local
+ * extra field, so that a UTF-8 entry name e.f. block has already
+ * been processed.
+ */
+ if (G.pInfo->cfilname != (char Far *)NULL) {
+ if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) {
+# ifdef SMALL_MEM
+ char *temp_cfilnam = slide + (7 * (WSIZE>>3));
+
+ zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname);
+# define cFile_PrintBuf temp_cfilnam
+# else
+# define cFile_PrintBuf G.pInfo->cfilname
+# endif
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall2(LvsCFNamMsg),
+ FnFilter2(cFile_PrintBuf), FnFilter1(G.filename)));
+# undef cFile_PrintBuf
+ zfstrcpy(G.filename, G.pInfo->cfilname);
+ if (error_in_archive < PK_WARN)
+ error_in_archive = PK_WARN;
+ }
+ zffree(G.pInfo->cfilname);
+ G.pInfo->cfilname = (char Far *)NULL;
+ }
+#endif /* !SFX */
+ /* Size consistency checks must come after reading in the local extra
+ * field, so that any Zip64 extension local e.f. block has already
+ * been processed.
+ */
+ if (G.lrec.compression_method == STORED) {
+ zusz_t csiz_decrypted = G.lrec.csize;
+
+ if (G.pInfo->encrypted)
+ csiz_decrypted -= 12;
+ if (G.lrec.ucsize != csiz_decrypted) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarStringSmall2(WrnStorUCSizCSizDiff),
+ FnFilter1(G.filename),
+ FmZofft(G.lrec.ucsize, NULL, "u"),
+ FmZofft(csiz_decrypted, NULL, "u")));
+ G.lrec.ucsize = csiz_decrypted;
+ if (error_in_archive < PK_WARN)
+ error_in_archive = PK_WARN;
+ }
+ }
+
+#if CRYPT
+ if (G.pInfo->encrypted &&
+ (error = decrypt(__G__ uO.pwdarg)) != PK_COOL) {
+ if (error == PK_WARN) {
+ if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(SkipIncorrectPasswd),
+ FnFilter1(G.filename)));
+ ++(*pnum_bad_pwd);
+ } else { /* (error > PK_WARN) */
+ if (error > error_in_archive)
+ error_in_archive = error;
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(SkipCannotGetPasswd),
+ FnFilter1(G.filename)));
+ }
+ continue; /* go on to next file */
+ }
+#endif /* CRYPT */
+
+ /*
+ * just about to extract file: if extracting to disk, check if
+ * already exists, and if so, take appropriate action according to
+ * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
+ * loop because we don't store the possibly renamed filename[] in
+ * info[])
+ */
+#ifdef DLL
+ if (!uO.tflag && !uO.cflag && !G.redirect_data)
+#else
+ if (!uO.tflag && !uO.cflag)
+#endif
+ {
+ renamed = FALSE; /* user hasn't renamed output file yet */
+
+startover:
+ query = FALSE;
+ skip_entry = SKIP_NO;
+ /* for files from DOS FAT, check for use of backslash instead
+ * of slash as directory separator (bug in some zipper(s); so
+ * far, not a problem in HPFS, NTFS or VFAT systems)
+ */
+#ifndef SFX
+ if (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/')) {
+ char *p=G.filename;
+
+ if (*p) do {
+ if (*p == '\\') {
+ if (!G.reported_backslash) {
+ Info(slide, 0x21, ((char *)slide,
+ LoadFarString(BackslashPathSep), G.zipfn));
+ G.reported_backslash = TRUE;
+ if (!error_in_archive)
+ error_in_archive = PK_WARN;
+ }
+ *p = '/';
+ }
+ } while (*PREINCSTR(p));
+ }
+#endif /* !SFX */
+
+ if (!renamed) {
+ /* remove absolute path specs */
+ if (G.filename[0] == '/') {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(AbsolutePathWarning),
+ FnFilter1(G.filename)));
+ if (!error_in_archive)
+ error_in_archive = PK_WARN;
+ do {
+ char *p = G.filename + 1;
+ do {
+ *(p-1) = *p;
+ } while (*p++ != '\0');
+ } while (G.filename[0] == '/');
+ }
+ }
+
+ /* mapname can create dirs if not freshening or if renamed */
+ error = mapname(__G__ renamed);
+ if ((errcode = error & ~MPN_MASK) != PK_OK &&
+ error_in_archive < errcode)
+ error_in_archive = errcode;
+ if ((errcode = error & MPN_MASK) > MPN_INF_TRUNC) {
+ if (errcode == MPN_CREATED_DIR) {
+#ifdef SET_DIR_ATTRIB
+ direntry *d_entry;
+
+ error = defer_dir_attribs(__G__ &d_entry);
+ if (d_entry == (direntry *)NULL) {
+ /* There may be no dir_attribs info available, or
+ * we have encountered a mem allocation error.
+ * In case of an error, report it and set program
+ * error state to warning level.
+ */
+ if (error) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(DirlistEntryNoMem)));
+ if (!error_in_archive)
+ error_in_archive = PK_WARN;
+ }
+ } else {
+ d_entry->next = (*pdirlist);
+ (*pdirlist) = d_entry;
+ ++(*pnum_dirs);
+ }
+#endif /* SET_DIR_ATTRIB */
+ } else if (errcode == MPN_VOL_LABEL) {
+#ifdef DOS_OS2_W32
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(SkipVolumeLabel),
+ FnFilter1(G.filename),
+ uO.volflag? "hard disk " : ""));
+#else
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(SkipVolumeLabel),
+ FnFilter1(G.filename), ""));
+#endif
+ } else if (errcode > MPN_INF_SKIP &&
+ error_in_archive < PK_ERR)
+ error_in_archive = PK_ERR;
+ Trace((stderr, "mapname(%s) returns error code = %d\n",
+ FnFilter1(G.filename), error));
+ continue; /* go on to next file */
+ }
+
+#ifdef QDOS
+ QFilename(__G__ G.filename);
+#endif
+ switch (check_for_newer(__G__ G.filename)) {
+ case DOES_NOT_EXIST:
+#ifdef NOVELL_BUG_FAILSAFE
+ G.dne = TRUE; /* stat() says file DOES NOT EXIST */
+#endif
+ /* freshen (no new files): skip unless just renamed */
+ if (uO.fflag && !renamed)
+ skip_entry = SKIP_Y_NONEXIST;
+ break;
+ case EXISTS_AND_OLDER:
+#ifdef UNIXBACKUP
+ if (!uO.B_flag)
+#endif
+ {
+ if (IS_OVERWRT_NONE)
+ /* never overwrite: skip file */
+ skip_entry = SKIP_Y_EXISTING;
+ else if (!IS_OVERWRT_ALL)
+ query = TRUE;
+ }
+ break;
+ case EXISTS_AND_NEWER: /* (or equal) */
+#ifdef UNIXBACKUP
+ if ((!uO.B_flag && IS_OVERWRT_NONE) ||
+#else
+ if (IS_OVERWRT_NONE ||
+#endif
+ (uO.uflag && !renamed)) {
+ /* skip if update/freshen & orig name */
+ skip_entry = SKIP_Y_EXISTING;
+ } else {
+#ifdef UNIXBACKUP
+ if (!IS_OVERWRT_ALL && !uO.B_flag)
+#else
+ if (!IS_OVERWRT_ALL)
+#endif
+ query = TRUE;
+ }
+ break;
+ }
+ if (query) {
+#ifdef WINDLL
+ switch (G.lpUserFunctions->replace != NULL ?
+ (*G.lpUserFunctions->replace)(G.filename) :
+ IDM_REPLACE_NONE) {
+ case IDM_REPLACE_RENAME:
+ _ISO_INTERN(G.filename);
+ renamed = TRUE;
+ goto startover;
+ case IDM_REPLACE_ALL:
+ G.overwrite_mode = OVERWRT_ALWAYS;
+ /* FALL THROUGH, extract */
+ case IDM_REPLACE_YES:
+ break;
+ case IDM_REPLACE_NONE:
+ G.overwrite_mode = OVERWRT_NEVER;
+ /* FALL THROUGH, skip */
+ case IDM_REPLACE_NO:
+ skip_entry = SKIP_Y_EXISTING;
+ break;
+ }
+#else /* !WINDLL */
+ extent fnlen;
+reprompt:
+ Info(slide, 0x81, ((char *)slide,
+ LoadFarString(ReplaceQuery),
+ FnFilter1(G.filename)));
+ if (fgets(G.answerbuf, 9, stdin) == (char *)NULL) {
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(AssumeNone)));
+ *G.answerbuf = 'N';
+ if (!error_in_archive)
+ error_in_archive = 1; /* not extracted: warning */
+ }
+ switch (*G.answerbuf) {
+ case 'r':
+ case 'R':
+ do {
+ Info(slide, 0x81, ((char *)slide,
+ LoadFarString(NewNameQuery)));
+ fgets(G.filename, FILNAMSIZ, stdin);
+ /* usually get \n here: better check for it */
+ fnlen = strlen(G.filename);
+ if (lastchar(G.filename, fnlen) == '\n')
+ G.filename[--fnlen] = '\0';
+ } while (fnlen == 0);
+#ifdef WIN32 /* WIN32 fgets( ... , stdin) returns OEM coded strings */
+ _OEM_INTERN(G.filename);
+#endif
+ renamed = TRUE;
+ goto startover; /* sorry for a goto */
+ case 'A': /* dangerous option: force caps */
+ G.overwrite_mode = OVERWRT_ALWAYS;
+ /* FALL THROUGH, extract */
+ case 'y':
+ case 'Y':
+ break;
+ case 'N':
+ G.overwrite_mode = OVERWRT_NEVER;
+ /* FALL THROUGH, skip */
+ case 'n':
+ /* skip file */
+ skip_entry = SKIP_Y_EXISTING;
+ break;
+ case '\n':
+ case '\r':
+ /* Improve echo of '\n' and/or '\r'
+ (sizeof(G.answerbuf) == 10 (see globals.h), so
+ there is enough space for the provided text...) */
+ strcpy(G.answerbuf, "{ENTER}");
+ /* fall through ... */
+ default:
+ Info(slide, 1, ((char *)slide,
+ LoadFarString(InvalidResponse), *G.answerbuf));
+ goto reprompt; /* yet another goto? */
+ } /* end switch (*answerbuf) */
+#endif /* ?WINDLL */
+ } /* end if (query) */
+ if (skip_entry != SKIP_NO) {
+#ifdef WINDLL
+ if (skip_entry == SKIP_Y_EXISTING) {
+ /* report skipping of an existing entry */
+ Info(slide, 0, ((char *)slide,
+ ((IS_OVERWRT_NONE || !uO.uflag || renamed) ?
+ "Target file exists.\nSkipping %s\n" :
+ "Target file newer.\nSkipping %s\n"),
+ FnFilter1(G.filename)));
+ }
+#endif /* WINDLL */
+ continue;
+ }
+ } /* end if (extracting to disk) */
+
+#ifdef DLL
+ if ((G.statreportcb != NULL) &&
+ (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn,
+ G.filename, NULL)) {
+ return IZ_CTRLC; /* cancel operation by user request */
+ }
#endif
-
-#ifdef USE_PPMD
-# define UNKN_PPMD (G.crec.compression_method!=PPMDED)
-#else
-# define UNKN_PPMD TRUE /* PPMd unknown */
+#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
+ UserStop();
#endif
-
-#ifdef SFX
-# ifdef USE_DEFLATE64
-# define UNKN_COMPR \
- (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \
- && G.crec.compression_method>ENHDEFLATED \
- && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
-# else
-# define UNKN_COMPR \
- (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\
- && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
-# endif
-#else
-# ifdef COPYRIGHT_CLEAN /* no reduced files */
-# define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
- G.crec.compression_method <= REDUCED4)
-# else
-# define UNKN_RED FALSE /* reducing not unknown */
-# endif
-# ifdef LZW_CLEAN /* no shrunk files */
-# define UNKN_SHR (G.crec.compression_method == SHRUNK)
-# else
-# define UNKN_SHR FALSE /* unshrinking not unknown */
-# endif
-# ifdef USE_DEFLATE64
-# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
- G.crec.compression_method==TOKENIZED || \
- (G.crec.compression_method>ENHDEFLATED && UNKN_BZ2 && UNKN_LZMA \
- && UNKN_WAVP && UNKN_PPMD))
-# else
-# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
- G.crec.compression_method==TOKENIZED || \
- (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \
- && UNKN_WAVP && UNKN_PPMD))
-# endif
+#ifdef AMIGA
+ G.filenote_slot = i;
#endif
-
-#if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS))
- int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS);
-# define UNZVERS_SUPPORT unzvers_support
+ G.disk_full = 0;
+ if ((error = extract_or_test_member(__G)) != PK_COOL) {
+ if (error > error_in_archive)
+ error_in_archive = error; /* ...and keep going */
+#ifdef DLL
+ if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
#else
-# define UNZVERS_SUPPORT UNZIP_VERSION
+ if (G.disk_full > 1) {
#endif
-
-/*---------------------------------------------------------------------------
- Check central directory info for version/compatibility requirements.
- ---------------------------------------------------------------------------*/
-
- G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1; /* bit field */
- G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8; /* bit */
- G.pInfo->textfile = G.crec.internal_file_attributes & 1; /* bit field */
- G.pInfo->crc = G.crec.crc32;
- G.pInfo->compr_size = G.crec.csize;
- G.pInfo->uncompr_size = G.crec.ucsize;
-
- switch (uO.aflag) {
- case 0:
- G.pInfo->textmode = FALSE; /* bit field */
- break;
- case 1:
- G.pInfo->textmode = G.pInfo->textfile; /* auto-convert mode */
- break;
- default: /* case 2: */
- G.pInfo->textmode = TRUE;
- break;
- }
-
- if (G.crec.version_needed_to_extract[1] == VMS_) {
- if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) {
- if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
- Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
- FnFilter1(G.filename), "VMS",
- G.crec.version_needed_to_extract[0] / 10,
- G.crec.version_needed_to_extract[0] % 10,
- VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10));
- return 0;
+ return error_in_archive; /* (unless disk full) */
+ }
}
-#ifndef VMS /* won't be able to use extra field, but still have data */
- else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */
- Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery),
- FnFilter1(G.filename)));
- fgets(G.answerbuf, 9, stdin);
- if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y'))
- return 0;
+#ifdef DLL
+ if ((G.statreportcb != NULL) &&
+ (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn,
+ G.filename, (zvoid *)&G.lrec.ucsize)) {
+ return IZ_CTRLC; /* cancel operation by user request */
}
-#endif /* !VMS */
- /* usual file type: don't need VMS to extract */
- } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) {
- if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
- Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
- FnFilter1(G.filename), "PK",
- G.crec.version_needed_to_extract[0] / 10,
- G.crec.version_needed_to_extract[0] % 10,
- UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10));
- return 0;
- }
-
- if (UNKN_COMPR) {
- if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) {
-#ifndef SFX
- unsigned cmpridx;
-
- if ((cmpridx = find_compr_idx(G.crec.compression_method))
- < NUM_METHODS)
- Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName),
- FnFilter1(G.filename),
- LoadFarStringSmall(ComprNames[cmpridx])));
- else
#endif
- Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum),
- FnFilter1(G.filename),
- G.crec.compression_method));
- }
- return 0;
- }
-#if (!CRYPT)
- if (G.pInfo->encrypted) {
- if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
- Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted),
- FnFilter1(G.filename)));
- return 0;
- }
-#endif /* !CRYPT */
-
-#ifndef SFX
- /* store a copy of the central header filename for later comparison */
- if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) {
- Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName),
- FnFilter1(G.filename)));
- } else
- zfstrcpy(G.pInfo->cfilname, G.filename);
-#endif /* !SFX */
-
- /* map whatever file attributes we have into the local format */
- mapattr(__G); /* GRR: worry about return value later */
-
- G.pInfo->diskstart = G.crec.disk_number_start;
- G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header;
- return 1;
-
-} /* end function store_info() */
-
-
-
-
-
-#ifndef SFX
-/*******************************/
-/* Function find_compr_idx() */
-/*******************************/
-
-unsigned find_compr_idx(compr_methodnum)
- unsigned compr_methodnum;
-{
- unsigned i;
-
- for (i = 0; i < NUM_METHODS; i++) {
- if (ComprIDs[i] == compr_methodnum) break;
- }
- return i;
-}
-#endif /* !SFX */
+#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
+ UserStop();
+#endif
+ } /* end for-loop (i: files in current block) */
+ return error_in_archive;
+} /* end function extract_or_test_entrylist() */
-/******************************************/
-/* Function extract_or_test_entrylist() */
-/******************************************/
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
-static int extract_or_test_entrylist(__G__ numchunk,
+static int extract_or_test_entrylistw(__G__ numchunk,
pfilnum, pnum_bad_pwd, pold_extra_bytes,
#ifdef SET_DIR_ATTRIB
- pnum_dirs, pdirlist,
+ pnum_dirs, pdirlistw,
#endif
error_in_archive) /* return PK-type error code */
@@ -1016,5 +1653,5 @@
#ifdef SET_DIR_ATTRIB
unsigned *pnum_dirs;
- direntry **pdirlist;
+ direntryw **pdirlistw;
#endif
int error_in_archive;
@@ -1190,8 +1827,4 @@
}
#ifndef SFX
- /* Filename consistency checks must come after reading in the local
- * extra field, so that a UTF-8 entry name e.f. block has already
- * been processed.
- */
if (G.pInfo->cfilname != (char Far *)NULL) {
if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) {
@@ -1316,5 +1949,8 @@
/* mapname can create dirs if not freshening or if renamed */
- error = mapname(__G__ renamed);
+ if (G.has_win32_wide)
+ error = mapnamew(__G__ renamed);
+ else
+ error = mapname(__G__ renamed);
if ((errcode = error & ~MPN_MASK) != PK_OK &&
error_in_archive < errcode)
@@ -1323,24 +1959,24 @@
if (errcode == MPN_CREATED_DIR) {
#ifdef SET_DIR_ATTRIB
- direntry *d_entry;
+ direntryw *d_entryw;
- error = defer_dir_attribs(__G__ &d_entry);
- if (d_entry == (direntry *)NULL) {
- /* There may be no dir_attribs info available, or
- * we have encountered a mem allocation error.
- * In case of an error, report it and set program
- * error state to warning level.
- */
- if (error) {
- Info(slide, 0x401, ((char *)slide,
- LoadFarString(DirlistEntryNoMem)));
- if (!error_in_archive)
- error_in_archive = PK_WARN;
- }
- } else {
- d_entry->next = (*pdirlist);
- (*pdirlist) = d_entry;
- ++(*pnum_dirs);
- }
+ error = defer_dir_attribsw(__G__ &d_entryw);
+ if (d_entryw == (direntryw *)NULL) {
+ /* There may be no dir_attribs info available, or
+ * we have encountered a mem allocation error.
+ * In case of an error, report it and set program
+ * error state to warning level.
+ */
+ if (error) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(DirlistEntryNoMem)));
+ if (!error_in_archive)
+ error_in_archive = PK_WARN;
+ }
+ } else {
+ d_entryw->next = (*pdirlistw);
+ (*pdirlistw) = d_entryw;
+ ++(*pnum_dirs);
+ }
#endif /* SET_DIR_ATTRIB */
} else if (errcode == MPN_VOL_LABEL) {
@@ -1366,5 +2002,5 @@
QFilename(__G__ G.filename);
#endif
- switch (check_for_newer(__G__ G.filename)) {
+ switch (check_for_newerw(__G__ G.unipath_widefilename)) {
case DOES_NOT_EXIST:
#ifdef NOVELL_BUG_FAILSAFE
@@ -1538,5 +2174,7 @@
return error_in_archive;
-} /* end function extract_or_test_entrylist() */
+} /* end function extract_or_test_entrylistw() */
+
+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
@@ -2565,4 +3203,14 @@
/* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */
}
+
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static int Cdecl dircompw(a, b) /* used by qsort(); swiped from Zip */
+ ZCONST zvoid *a, *b;
+{
+ /* order is significant: this sorts in reverse order (deepest first) */
+ return wcscmp((*(direntryw **)b)->fnw, (*(direntryw **)a)->fnw);
+ /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */
+}
+# endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
#endif /* SET_DIR_ATTRIB */
diff -ru2 unz60d10/fileio.c unz60d10_w32w/fileio.c
--- unz60d10/fileio.c Sun Jan 27 16:39:14 2008
+++ unz60d10_w32w/fileio.c Mon Feb 11 01:09:22 2008
@@ -294,5 +294,12 @@
zlstat(G.filename, &G.statbuf) == 0)
#else
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ if ((G.has_win32_wide
+ ? SSTATW(G.unipath_widefilename, &G.statbuf)
+ : SSTAT(G.filename, &G.statbuf)
+ ) == 0)
+#else
if (SSTAT(G.filename, &G.statbuf) == 0)
+#endif
#endif /* ?SYMLINKS */
{
@@ -378,5 +385,13 @@
chmod(G.filename, 0);
#endif /* NLM */
- if (unlink(G.filename) != 0) {
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ if ((G.has_win32_wide
+ ? _wunlink(G.unipath_widefilename)
+ : unlink(G.filename)
+ ) != 0)
+#else
+ if (unlink(G.filename) != 0)
+#endif
+ {
Info(slide, 0x401, ((char *)slide,
LoadFarString(CannotDeleteOldFile), FnFilter1(G.filename)));
@@ -456,5 +471,12 @@
G.outfile = zfopen(G.filename, FOPWR);
#else
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ G.outfile = (G.has_win32_wide
+ ? zfopenw(G.unipath_widefilename, L"wb")
+ : zfopen(G.filename, FOPW)
+ );
+#else /* (UNICODE_SUPPORT && WIN32_WIDE) */
G.outfile = zfopen(G.filename, FOPW);
+#endif /* ?(UNICODE_SUPPORT && WIN32_WIDE) */
#endif
#if defined(ATH_BE_UNX) || defined(AOS_VS) || defined(QDOS) || defined(TANDEM)
@@ -1984,4 +2006,115 @@
} /* end function check_for_newer() */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+int check_for_newerw(__G__ filenamew) /* return 1 if existing file is newer */
+ __GDEF /* or equal; 0 if older; -1 if doesn't */
+ wchar_t *filenamew; /* exist yet */
+{
+ time_t existing, archive;
+#ifdef USE_EF_UT_TIME
+ iztimes z_utime;
+#endif
+#ifdef AOS_VS
+ long dyy, dmm, ddd, dhh, dmin, dss;
+
+
+ dyy = (lrec.last_mod_dos_datetime >> 25) + 1980;
+ dmm = (lrec.last_mod_dos_datetime >> 21) & 0x0f;
+ ddd = (lrec.last_mod_dos_datetime >> 16) & 0x1f;
+ dhh = (lrec.last_mod_dos_datetime >> 11) & 0x1f;
+ dmin = (lrec.last_mod_dos_datetime >> 5) & 0x3f;
+ dss = (lrec.last_mod_dos_datetime & 0x1f) * 2;
+
+ /* under AOS/VS, file times can only be set at creation time,
+ * with the info in a special DG format. Make sure we can create
+ * it here - we delete it later & re-create it, whether or not
+ * it exists now.
+ */
+ if (!zvs_create(filenamew, (((ulg)dgdate(dmm, ddd, dyy)) << 16) |
+ (dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1))
+ return DOES_NOT_EXIST;
+#endif /* AOS_VS */
+
+ Trace((stderr, "check_for_newer: doing stat(%s)\n", FnFilter1(filename)));
+ if (SSTATW(filenamew, &G.statbuf)) {
+ Trace((stderr,
+ "check_for_newer: stat(%s) returns %d: file does not exist\n",
+ FnFilter1(filename), SSTAT(filename, &G.statbuf)));
+#ifdef SYMLINKS
+ Trace((stderr, "check_for_newer: doing lstat(%s)\n",
+ FnFilter1(filename)));
+ /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */
+ if (zlstat(filename, &G.statbuf) == 0) {
+ Trace((stderr,
+ "check_for_newer: lstat(%s) returns 0: symlink does exist\n",
+ FnFilter1(filename)));
+ if (QCOND2 && !IS_OVERWRT_ALL)
+ Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
+ FnFilter1(filename), " with no real file"));
+ return EXISTS_AND_OLDER; /* symlink dates are meaningless */
+ }
+#endif /* SYMLINKS */
+ return DOES_NOT_EXIST;
+ }
+ Trace((stderr, "check_for_newer: stat(%s) returns 0: file exists\n",
+ FnFilter1(filename)));
+
+#ifdef SYMLINKS
+ /* GRR OPTION: could instead do this test ONLY if G.symlnk is true */
+ if (zlstat(filename, &G.statbuf) == 0 && S_ISLNK(G.statbuf.st_mode)) {
+ Trace((stderr, "check_for_newer: %s is a symbolic link\n",
+ FnFilter1(filename)));
+ if (QCOND2 && !IS_OVERWRT_ALL)
+ Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
+ FnFilter1(filename), ""));
+ return EXISTS_AND_OLDER; /* symlink dates are meaningless */
+ }
+#endif /* SYMLINKS */
+
+ NATIVE_TO_TIMET(G.statbuf.st_mtime) /* NOP unless MSC 7.0 or Macintosh */
+
+#ifdef USE_EF_UT_TIME
+ /* The `Unix extra field mtime' should be used for comparison with the
+ * time stamp of the existing file >>>ONLY<<< when the EF info is also
+ * used to set the modification time of the extracted file.
+ */
+ if (G.extra_field &&
+#ifdef IZ_CHECK_TZ
+ G.tz_is_valid &&
+#endif
+ (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
+ G.lrec.last_mod_dos_datetime, &z_utime, NULL)
+ & EB_UT_FL_MTIME))
+ {
+ TTrace((stderr, "check_for_newer: using Unix extra field mtime\n"));
+ existing = G.statbuf.st_mtime;
+ archive = z_utime.mtime;
+ } else {
+ /* round up existing filetime to nearest 2 seconds for comparison,
+ * but saturate in case of arithmetic overflow
+ */
+ existing = ((G.statbuf.st_mtime & 1) &&
+ (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
+ G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
+ archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
+ }
+#else /* !USE_EF_UT_TIME */
+ /* round up existing filetime to nearest 2 seconds for comparison,
+ * but saturate in case of arithmetic overflow
+ */
+ existing = ((G.statbuf.st_mtime & 1) &&
+ (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
+ G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
+ archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
+#endif /* ?USE_EF_UT_TIME */
+
+ TTrace((stderr, "check_for_newer: existing %lu, archive %lu, e-a %ld\n",
+ (ulg)existing, (ulg)archive, (long)(existing-archive)));
+
+ return (existing >= archive);
+
+} /* end function check_for_newerw() */
+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
+
#endif /* !VMS && !OS2 && !CMS_MVS */
@@ -2319,4 +2452,23 @@
free(fn);
}
+# ifdef WIN32_WIDE
+ G.unipath_widefilename = NULL;
+ if (G.has_win32_wide) {
+ if (G.unipath_filename)
+ /* Get wide path from UTF-8 */
+ G.unipath_widefilename = utf8_to_wchar_string(G.unipath_filename);
+ else
+ G.unipath_widefilename = utf8_to_wchar_string(G.filename);
+
+ if (G.pInfo->lcflag) /* replace with lowercase filename */
+ wcslwr(G.unipath_widefilename);
+
+ if (G.pInfo->vollabel && length > 8 && G.unipath_widefilename[8] == '.') {
+ wchar_t *p = G.unipath_widefilename+8;
+ while (*p++)
+ p[-1] = *p; /* disk label, and 8th char is dot: remove dot */
+ }
+ }
+# endif /* WIN32_WIDE */
}
#endif /* UNICODE_SUPPORT */
diff -ru2 unz60d10/globals.h unz60d10_w32w/globals.h
--- unz60d10/globals.h Sun Jan 27 16:31:56 2008
+++ unz60d10_w32w/globals.h Mon Feb 11 01:09:22 2008
@@ -302,4 +302,8 @@
ulg unipath_checksum; /* Unicode field checksum */
char *unipath_filename; /* UTF-8 path */
+# ifdef WIN32_WIDE
+ wchar_t *unipath_widefilename; /* wide character filename */
+ int has_win32_wide; /* true if Win32 W calls work */
+# endif
char *unipath_escapedfilename;
#endif /* UNICODE_SUPPORT */
diff -ru2 unz60d10/match.c unz60d10_w32w/match.c
--- unz60d10/match.c Sun Aug 14 20:00:36 2005
+++ unz60d10_w32w/match.c Sun Jan 6 18:19:46 2008
@@ -1,4 +1,4 @@
/*
- Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
See the accompanying file LICENSE, version 2000-Apr-09 or later
@@ -407,5 +407,18 @@
} /* end function iswild() */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+int iswildw(pw) /* originally only used for stat()-bug workaround in */
+ ZCONST wchar_t *pw; /* VAX C, Turbo/Borland C, Watcom C, Atari MiNT libs; */
+{ /* now used in process_zipfiles() as well */
+ for (; *pw; pw++)
+ if (*pw == '\\' && *(pw+1))
+ ++pw;
+ else if (*pw == '?' || *pw == '*' || *pw == '[')
+ return TRUE;
+
+ return FALSE;
+} /* end function iswildw() */
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
diff -ru2 unz60d10/process.c unz60d10_w32w/process.c
--- unz60d10/process.c Sun Feb 3 00:03:34 2008
+++ unz60d10_w32w/process.c Mon Feb 11 01:09:22 2008
@@ -43,4 +43,7 @@
# include "crc32.h"
#endif
+#ifdef UNICODE_SUPPORT
+# include <wchar.h>
+#endif /* def UNICODE_SUPPORT */
static int do_seekable OF((__GPRO__ int lastchance));
@@ -552,5 +555,12 @@
inflate_free(__G);
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ if (G.has_win32_wide)
+ checkdirw(__G__ (wchar_t *)NULL, END);
+ else
+ checkdir(__G__ (char *)NULL, END);
+#else
checkdir(__G__ (char *)NULL, END);
+#endif
#ifdef DYNALLOC_CRCTAB
@@ -1507,26 +1517,4 @@
*/
- /* This is an internal comment. Remove before the next public beta.
-
- Below check does not catch when an entry requires Zip64, as
- when the uncompressed size is larger than 4 GB, but the
- standard fields in ecrec (called EOCDR in the Zip source)
- are sufficient, as when the file compresses under the Zip64
- limit. In such cases ecrec64 (called Zip64 EOCDR in Zip)
- will exist to flag the archive as Zip64, even though none
- of the ecrec values are set to the FFFF or FFFFFFFF flag
- values.
-
- if(check_ecrec_zip64(__G)){
- need_zip64 = TRUE;
- }
-
- In fact, this check is not needed, as ecrec64 will ALWAYS
- exist for a proper Zip64 archive, as the Version Needed To Extract
- field is required to be set to 4.5 or higher.
-
- End of internal comment.
- */
-
/* The ecrec64 will ALWAYS exist for a proper Zip64 archive, as
the Version Needed To Extract field is required to be set to
@@ -1954,7 +1942,4 @@
G.unipath_filename[ULen] = '\0';
}
-# if 0
- G.unipath_escapedfilename = utf8_to_escaped_string(G.unipath_filename);
-# endif
}
@@ -2324,4 +2309,37 @@
return w;
}
+
+char *wchar_to_local_string(wchar_string, escape_all)
+ wchar_t *wchar_string;
+ int escape_all;
+{
+ zwchar *wide_string = wchar_to_wide_string(wchar_string);
+ char *local_string = wide_to_local_string(wide_string, escape_all);
+
+ free(wide_string);
+
+ return local_string;
+}
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+zwchar *wchar_to_wide_string(wchar_string)
+ wchar_t *wchar_string;
+{
+ int i;
+ int wchar_len;
+ zwchar *wide_string;
+
+ wchar_len = wcslen(wchar_string);
+
+ if ((wide_string = malloc((wchar_len + 1) * sizeof(zwchar))) == NULL) {
+ return NULL;
+ }
+ for (i = 0; i <= wchar_len; i++) {
+ wide_string[i] = wchar_string[i];
+ }
+
+ return wide_string;
+}
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
char *utf8_to_escaped_string(utf8_string, escape_all)
diff -ru2 unz60d10/unzpriv.h unz60d10_w32w/unzpriv.h
--- unz60d10/unzpriv.h Sun Feb 3 15:50:52 2008
+++ unz60d10_w32w/unzpriv.h Mon Feb 11 02:05:46 2008
@@ -1318,4 +1318,7 @@
# define zstat _stati64
# define zfstat _fstati64
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+# define zstatw _wstati64
+# endif
/* 64-bit lseek */
@@ -1332,4 +1335,7 @@
/* 64-bit fopen */
# define zfopen fopen
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+# define zfopenw _wfopen
+# endif
# define zfdopen fdopen
@@ -1904,4 +1910,11 @@
char buf[1]; /* start of system-specific internal data */
} direntry;
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ typedef struct direntryw { /* head of system-specific struct holding */
+ struct direntryw *next; /* defered directory attributes info */
+ wchar_t *fnw; /* filename of directory */
+ wchar_t buf[1]; /* start of system-specific internal data */
+ } direntryw;
+# endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
#endif /* SET_DIR_ATTRIB */
@@ -2225,4 +2238,7 @@
time_t dos_to_unix_time OF((ulg dos_datetime));
int check_for_newer OF((__GPRO__ char *filename)); /* os2,vmcms,vms */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+int check_for_newerw OF((__GPRO__ wchar_t *filenamew)); /* os2,vmcms,vms */
+#endif
int do_string OF((__GPRO__ unsigned int length, int option));
ush makeword OF((ZCONST uch *b));
@@ -2468,4 +2484,8 @@
int zstat_win32 OF((__W32STAT_GLOBALS__
const char *path, z_stat *buf)); /* win32.c */
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ int zstat_win32w OF((__W32STAT_GLOBALS__
+ const wchar_t *pathw, z_stat *buf)); /* win32.c */
+# endif
#endif
#endif
@@ -2485,4 +2505,7 @@
int ic __WDLPRO)); /* match.c */
int iswild OF((ZCONST char *p)); /* match.c */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+int iswildw OF((ZCONST wchar_t *pw)); /* match.c */
+#endif
/* declarations of public CRC-32 functions have been moved into crc32.h
@@ -2497,4 +2520,8 @@
int mapname OF((__GPRO__ int renamed)); /* local */
int checkdir OF((__GPRO__ char *pathcomp, int flag)); /* local */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ int mapnamew OF((__GPRO__ int renamed)); /* local */
+ int checkdirw OF((__GPRO__ wchar_t *pathcomp, int flag)); /* local */
+#endif
char *do_wild OF((__GPRO__ ZCONST char *wildzipfn)); /* local */
char *GetLoadPath OF((__GPRO)); /* local */
@@ -2517,4 +2544,8 @@
int defer_dir_attribs OF((__GPRO__ direntry **pd)); /* local */
int set_direc_attribs OF((__GPRO__ direntry *d)); /* local */
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ int defer_dir_attribsw OF((__GPRO__ direntryw **pd)); /* local */
+ int set_direc_attribsw OF((__GPRO__ direntryw *d)); /* local */
+# endif
#endif
#ifdef TIMESTAMP
@@ -2980,4 +3011,8 @@
/* convert UTF-8 string to wide string */
zwchar *utf8_to_wide_string OF((char *));
+
+ char *wchar_to_local_string OF((wchar_t *, int));
+
+ zwchar *wchar_to_wide_string OF((wchar_t *));
/* convert wide string to multi-byte string */
diff -ru2 unz60d10/win32/nt.c unz60d10_w32w/win32/nt.c
--- unz60d10/win32/nt.c Tue Dec 25 12:34:50 2007
+++ unz60d10_w32w/win32/nt.c Mon Feb 11 02:09:20 2008
@@ -1,6 +1,6 @@
/*
- Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
- See the accompanying file LICENSE, version 2000-Apr-09 or later
+ See the accompanying file LICENSE, version 2007-Mar-04 or later
(the contents of which are also included in unzip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
@@ -63,5 +63,10 @@
static BOOL Initialize(VOID);
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static VOID GetRemotePrivilegesSet(wchar_t *FileName,
+ PDWORD dwRemotePrivileges);
+#else
static VOID GetRemotePrivilegesSet(CHAR *FileName, PDWORD dwRemotePrivileges);
+#endif
static VOID InitLocalPrivileges(VOID);
@@ -191,5 +196,10 @@
}
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static VOID GetRemotePrivilegesSet(wchar_t *FileName,
+ PDWORD dwRemotePrivileges)
+#else
static VOID GetRemotePrivilegesSet(char *FileName, PDWORD dwRemotePrivileges)
+#endif
{
HANDLE hFile;
@@ -199,5 +209,9 @@
/* see if we have the SeRestorePrivilege */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ hFile = CreateFileW(
+#else
hFile = CreateFileA(
+#endif
FileName,
ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER | READ_CONTROL,
@@ -236,5 +250,9 @@
/* note we don't need this if we have SeRestorePrivilege */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ hFile = CreateFileW(
+#else
hFile = CreateFileA(
+#endif
FileName,
ACCESS_SYSTEM_SECURITY,
@@ -255,10 +273,19 @@
BOOL GetVolumeCaps(
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ wchar_t *rootpath, /* filepath, or NULL */
+ wchar_t *name, /* filename associated with rootpath */
+#else
char *rootpath, /* filepath, or NULL */
char *name, /* filename associated with rootpath */
+#endif
PVOLUMECAPS VolumeCaps /* result structure describing capabilities */
)
{
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ wchar_t TempRootPath[MAX_PATH + 1];
+#else
char TempRootPath[MAX_PATH + 1];
+#endif
DWORD cchTempRootPath = 0;
BOOL bSuccess = TRUE; /* assume success until told otherwise */
@@ -273,5 +300,9 @@
DWORD i;
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ cchTempRootPath = lstrlenW(rootpath);
+#else
cchTempRootPath = lstrlenA(rootpath);
+#endif
if(cchTempRootPath > MAX_PATH) return FALSE;
@@ -345,5 +376,9 @@
if(!g_VolumeCaps.bValid ||
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ lstrcmpiW(g_VolumeCaps.RootPath, TempRootPath) != 0)
+#else
lstrcmpiA(g_VolumeCaps.RootPath, TempRootPath) != 0)
+#endif
{
@@ -357,5 +392,9 @@
LeaveCriticalSection( &VolumeCapsLock );
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ bSuccess = GetVolumeInformationW(
+#else
bSuccess = GetVolumeInformationA(
+#endif
(TempRootPath[0] == '\0') ? NULL : TempRootPath,
NULL, 0,
@@ -371,5 +410,9 @@
VolumeCaps->bUsePrivileges)
{
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ if(GetDriveTypeW( (TempRootPath[0] == '\0') ? NULL : TempRootPath )
+#else
if(GetDriveTypeA( (TempRootPath[0] == '\0') ? NULL : TempRootPath )
+#endif
== DRIVE_REMOTE)
{
@@ -388,5 +431,9 @@
if(bSuccess) {
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ lstrcpynW(g_VolumeCaps.RootPath, TempRootPath, cchTempRootPath+1);
+#else
lstrcpynA(g_VolumeCaps.RootPath, TempRootPath, cchTempRootPath+1);
+#endif
g_VolumeCaps.dwFileSystemFlags = dwFileSystemFlags;
g_VolumeCaps.bRemote = bRemote;
@@ -413,5 +460,9 @@
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+BOOL SecuritySet(wchar_t *resource, PVOLUMECAPS VolumeCaps, uch *securitydata)
+#else
BOOL SecuritySet(char *resource, PVOLUMECAPS VolumeCaps, uch *securitydata)
+#endif
{
HANDLE hFile;
@@ -491,5 +542,9 @@
dwFlags |= FILE_FLAG_BACKUP_SEMANTICS;
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ hFile = CreateFileW(
+#else
hFile = CreateFileA(
+#endif
resource,
dwDesiredAccess,
diff -ru2 unz60d10/win32/nt.h unz60d10_w32w/win32/nt.h
--- unz60d10/win32/nt.h Mon Jan 24 02:46:38 2005
+++ unz60d10_w32w/win32/nt.h Mon Feb 11 02:07:20 2008
@@ -1,4 +1,4 @@
/*
- Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
See the accompanying file LICENSE, version 2000-Apr-09 or later
@@ -24,9 +24,18 @@
DWORD dwRemotePrivileges; /* relevant only on remote volumes */
DWORD dwFileAttributes;
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ wchar_t RootPath[MAX_PATH+1]; /* path to network / filesystem */
+#else
char RootPath[MAX_PATH+1]; /* path to network / filesystem */
+#endif
} VOLUMECAPS, *PVOLUMECAPS, *LPVOLUMECAPS;
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+BOOL SecuritySet(wchar_t *resource, PVOLUMECAPS VolumeCaps, uch *securitydata);
+BOOL GetVolumeCaps(wchar_t *rootpath, wchar_t *name, PVOLUMECAPS VolumeCaps);
+#else
BOOL SecuritySet(char *resource, PVOLUMECAPS VolumeCaps, uch *securitydata);
BOOL GetVolumeCaps(char *rootpath, char *name, PVOLUMECAPS VolumeCaps);
+#endif
BOOL ValidateSecurity(uch *securitydata);
diff -ru2 unz60d10/win32/vc6/funzip.dsp unz60d10_w32w/win32/vc6/funzip.dsp
--- unz60d10/win32/vc6/funzip.dsp Mon Feb 11 02:55:18 2008
+++ unz60d10_w32w/win32/vc6/funzip.dsp Mon Feb 11 02:55:38 2008
@@ -45,5 +45,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "_MBCS" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -69,5 +69,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
+# 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
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@@ -93,5 +93,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c
+# 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
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -117,5 +117,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "FUNZIP" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
+# 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
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
diff -ru2 unz60d10/win32/vc6/unzip.dsp unz60d10_w32w/win32/vc6/unzip.dsp
--- unz60d10/win32/vc6/unzip.dsp Sat Mar 24 19:51:24 2007
+++ unz60d10_w32w/win32/vc6/unzip.dsp Mon Feb 11 02:52:48 2008
@@ -45,5 +45,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -69,5 +69,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
+# 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
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@@ -93,5 +93,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c
+# 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
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -118,5 +118,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
+# 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
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
diff -ru2 unz60d10/win32/vc6/unzipbz2.dsp unz60d10_w32w/win32/vc6/unzipbz2.dsp
--- unz60d10/win32/vc6/unzipbz2.dsp Sun Jan 6 19:14:44 2008
+++ unz60d10_w32w/win32/vc6/unzipbz2.dsp Mon Feb 11 02:52:48 2008
@@ -45,5 +45,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /c
+# 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
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -69,5 +69,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
+# 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
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@@ -93,5 +93,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /c
+# 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
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -118,5 +118,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c
-# 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
+# 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
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
diff -ru2 unz60d10/win32/vc6/unzipsfx.dsp unz60d10_w32w/win32/vc6/unzipsfx.dsp
--- unz60d10/win32/vc6/unzipsfx.dsp Sun Jan 6 19:13:46 2008
+++ unz60d10_w32w/win32/vc6/unzipsfx.dsp Mon Feb 11 02:52:48 2008
@@ -45,5 +45,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
-# ADD CPP /nologo /W3 /GX /O1 /D "WIN32" /D "SFX" /D "_CONSOLE" /D "_MBCS" /FD /c
+# ADD CPP /nologo /W3 /GX /O1 /D "WIN32" /D "SFX" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -69,5 +69,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
+# 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
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@@ -93,5 +93,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "SFX" /FD /c
-# ADD CPP /nologo /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c
+# 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
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -117,5 +117,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "SFX" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
+# 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
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
diff -ru2 unz60d10/win32/w32cfg.h unz60d10_w32w/win32/w32cfg.h
--- unz60d10/win32/w32cfg.h Thu Oct 4 02:05:42 2007
+++ unz60d10_w32w/win32/w32cfg.h Tue Jan 1 18:34:48 2008
@@ -271,15 +271,38 @@
#define STR_TO_ISO
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ wchar_t *utf8_to_wchar_string OF((char *));
+ wchar_t *local_to_wchar_string OF((char *));
+ int has_win32_wide();
+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
+
/* Static variables that we have to add to Uz_Globs: */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
#define SYSTEM_SPECIFIC_GLOBALS \
int created_dir, renamed_fullpath, fnlen;\
unsigned nLabelDrive;\
char lastRootPath[4];\
+ wchar_t lastRootPathw[4];\
int lastVolOldFAT, lastVolLocTim;\
char *rootpath, *buildpathHPFS, *buildpathFAT, *endHPFS, *endFAT;\
+ wchar_t *rootpathw, *buildpathHPFSw, *buildpathFATw, *endHPFSw, *endFATw;\
ZCONST char *wildname;\
+ ZCONST wchar_t *wildnamew;\
char *dirname, matchname[FILNAMSIZ];\
+ wchar_t *dirnamew, matchnamew[FILNAMSIZ];\
int rootlen, have_dirname, dirnamelen, notfirstcall;\
zvoid *wild_dir;
+#else /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
+#define SYSTEM_SPECIFIC_GLOBALS \
+ int created_dir, renamed_fullpath, fnlen;\
+ unsigned nLabelDrive;\
+ char lastRootPath[4];\
+ int lastVolOldFAT, lastVolLocTim;\
+ char *rootpath, *buildpathHPFS, *buildpathFAT, *endHPFS, *endFAT;\
+ ZCONST char *wildname;\
+ char *dirname, matchname[FILNAMSIZ];\
+ int rootlen, have_dirname, dirnamelen, notfirstcall;\
+ zvoid *wild_dir;
+#endif /* ?(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
/* created_dir, renamed_fullpath, fnlen, and nLabelDrive are used by */
@@ -342,4 +365,13 @@
# define SSTAT(path, pbuf) zstat_win32(__W32STAT_G__ path, pbuf)
#endif
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+# ifdef WILD_STAT_BUG
+# define SSTATW(pathw, pbuf) (iswildw(pathw) || zstat_win32w(__W32STAT_G__ pathw, pbuf))
+# else
+# define SSTATW(pathw, pbuf) zstat_win32w(__W32STAT_G__ pathw, pbuf)
+# endif
+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
+
#ifdef __WATCOMC__
diff -ru2 unz60d10/win32/win32.c unz60d10_w32w/win32/win32.c
--- unz60d10/win32/win32.c Tue Jan 1 21:26:22 2008
+++ unz60d10_w32w/win32/win32.c Tue Jan 1 21:26:24 2008
@@ -75,4 +75,12 @@
#endif
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+# if (defined(__EMX__) || defined(__CYGWIN__))
+# define MKDIRW(pathw,mode) _wmkdir(pathw,mode)
+# else
+# define MKDIRW(pathw,mode) _wmkdir(pathw)
+# endif
+#endif
+
#ifdef HAVE_WORKING_DIRENT_H
# undef HAVE_WORKING_DIRENT_H
@@ -124,4 +132,22 @@
} NTdirattr;
#define NtAtt(d) ((NTdirattr *)d) /* typecast shortcut */
+
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ typedef struct NTdirattrw { /* struct for holding unix style directory */
+ struct NTdirattrw *next; /* info until can be sorted and set at end */
+ wchar_t *fnw; /* filename of directory */
+ FILETIME Modft; /* File time type defined in NT, `last modified' time */
+ FILETIME Accft; /* NT file time type, `last access' time */
+ FILETIME Creft; /* NT file time type, `file creation' time */
+ int gotTime;
+ unsigned perms; /* same as min_info.file_attr */
+# ifdef NTSD_EAS
+ unsigned SDlen; /* length of SD data in buf */
+# endif
+ wchar_t buf[1]; /* buffer stub for directory SD and name */
+ } NTdirattrw;
+# define NtAttw(dw) ((NTdirattrw *)dw) /* typecast shortcut */
+# endif
+
#endif /* SET_DIR_ATTRIB */
@@ -129,10 +155,15 @@
/* Function prototypes */
#ifdef NTSD_EAS
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ static int SetSD(__GPRO__ wchar_t *path, unsigned fperms,
+ uch *eb_ptr, unsigned eb_len);
+# else
static int SetSD(__GPRO__ char *path, unsigned fperms,
uch *eb_ptr, unsigned eb_len);
+# endif
static int FindSDExtraField(__GPRO__
uch *ef_ptr, unsigned ef_len,
uch **p_ebSD_ptr, unsigned *p_ebSD_len);
-#endif
+#endif /* NTSD_EAS */
#ifndef NO_W32TIMES_IZFIX
@@ -147,13 +178,27 @@
#endif
static int FStampIsLocTime(__GPRO__ const char *path);
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ static int FStampIsLocTimeW(__GPRO__ const wchar_t *pathw);
+#endif
static int getNTfiletime (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT,
FILETIME *pCreFT);
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static int getNTfiletimeW (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT,
+ FILETIME *pCreFT);
+#endif
static int isfloppy (int nDrive);
static int NTQueryVolInfo (__GPRO__ const char *name);
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ static int NTQueryVolInfoW (__GPRO__ const wchar_t *namew);
+#endif
static int IsVolumeOldFAT (__GPRO__ const char *name);
static void maskDOSdevice (__GPRO__ char *pathcomp);
static void map2fat (char *pathcomp, char **pEndFAT);
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ static void maskDOSdevicew (__GPRO__ wchar_t *pathcompw);
+ static void map2fatw (wchar_t *pathcompw, wchar_t **pEndFATw);
+#endif
@@ -309,7 +354,13 @@
/**********************/
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static int SetSD(__G__ path, fperms, eb_ptr, eb_len)
+ __GDEF
+ wchar_t *path;
+#else
static int SetSD(__G__ path, fperms, eb_ptr, eb_len)
__GDEF
char *path;
+#endif
unsigned fperms;
uch *eb_ptr;
@@ -918,4 +969,12 @@
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static int FStampIsLocTimeW(__GPRO__ const wchar_t *pathw)
+{
+ return (NTQueryVolInfoW(__G__ pathw) ? G.lastVolLocTim : FALSE);
+}
+#endif
+
+
#ifndef NO_W32TIMES_IZFIX
@@ -991,4 +1050,63 @@
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ static int getNTfiletimeW(__G__ pModFT, pAccFT, pCreFT)
+ __GDEF
+ FILETIME *pModFT;
+ FILETIME *pAccFT;
+ FILETIME *pCreFT;
+ {
+# ifdef USE_EF_UT_TIME
+ unsigned eb_izux_flg;
+ iztimes z_utime; /* struct for Unix-style actime & modtime, + creatime */
+# endif
+ int fs_uses_loctime = FStampIsLocTimeW(__G__ G.unipath_widefilename);
+
+ /* Copy and/or convert time and date variables, if necessary;
+ * return a flag indicating which time stamps are available. */
+# ifdef USE_EF_UT_TIME
+ if (G.extra_field &&
+# ifdef IZ_CHECK_TZ
+ G.tz_is_valid &&
+# endif
+ ((eb_izux_flg = ef_scan_for_izux(G.extra_field,
+ G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
+ &z_utime, NULL)) & EB_UT_FL_MTIME))
+ {
+ TTrace((stderr, "getNTfiletime: Unix e.f. modif. time = %lu\n",
+ z_utime.mtime));
+ UTIME_2_IZFILETIME(z_utime.mtime, pModFT)
+ if (eb_izux_flg & EB_UT_FL_ATIME) {
+ UTIME_2_IZFILETIME(z_utime.atime, pAccFT)
+ }
+ if (eb_izux_flg & EB_UT_FL_CTIME) {
+ UTIME_2_IZFILETIME(z_utime.ctime, pCreFT)
+ }
+ return (int)eb_izux_flg;
+ }
+# endif /* USE_EF_UT_TIME */
+# ifndef NO_W32TIMES_IZFIX
+ if (!fs_uses_loctime) {
+ time_t ux_modtime;
+
+ ux_modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
+ utime2NtfsFileTime(ux_modtime, pModFT);
+ } else
+#endif /* NO_W32TIMES_IZFIX */
+ {
+ FILETIME lft;
+
+ DosDateTimeToFileTime((WORD)(G.lrec.last_mod_dos_datetime >> 16),
+ (WORD)(G.lrec.last_mod_dos_datetime & 0xFFFFL),
+ &lft);
+ LocalFileTimeToFileTime(&lft, pModFT);
+ }
+ *pAccFT = *pModFT;
+ return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
+
+ } /* end function getNTfiletime() */
+#endif /* (UNICODE_SUPPORT && WIN32_WIDE) */
+
+
@@ -1059,66 +1177,72 @@
unsigned ebSDlen;
#endif
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ if (!G.has_win32_wide) {
+#endif
#ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
- char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
+ char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
- INTERN_TO_ISO(G.filename, ansi_name);
-# define Ansi_Fname ansi_name
+ INTERN_TO_ISO(G.filename, ansi_name);
+# define Ansi_Fname ansi_name
#else
-# define Ansi_Fname G.filename
+# define Ansi_Fname G.filename
#endif
#ifndef __RSXNT__
- if (IsWinNT()) {
+# if !(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE))
+ if (IsWinNT()) {
/* Truncate the file to the current position.
* This is needed to remove excess allocation in case the
* extraction has failed or stopped prematurely. */
SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile)));
- }
+ }
+# endif /* !(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
#endif
- /* Close the file and then re-open it using the Win32
- * CreateFile call, so that the file can be created
- * with GENERIC_WRITE access, otherwise the SetFileTime
- * call will fail. */
- fclose(G.outfile);
-
- /* don't set the time stamp and attributes on standard output */
- if (uO.cflag)
- return;
-
- /* skip restoring time stamps on user's request */
- if (uO.D_flag <= 1) {
- gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft);
-
- /* open a handle to the file before processing extra fields;
- we do this in case new security on file prevents us from updating
- time stamps */
- hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- } else {
- gotTime = 0;
- }
-
- /* sfield@microsoft.com: set attributes before time in case we decide to
- support other filetime members later. This also allows us to apply
- attributes before the security is changed, which may prevent this
- from succeeding otherwise. Also, since most files don't have
- any interesting attributes, only change them if something other than
- FILE_ATTRIBUTE_ARCHIVE appears in the attributes. This works well
- as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
- file anyway, when it's created new. */
- if ((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
- if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
- Info(slide, 1, ((char *)slide,
- "\nwarning (%d): could not set file attributes\n",
- (int)GetLastError()));
- }
+ /* Close the file and then re-open it using the Win32
+ * CreateFile call, so that the file can be created
+ * with GENERIC_WRITE access, otherwise the SetFileTime
+ * call will fail. */
+ fclose(G.outfile);
+
+ /* don't set the time stamp and attributes on standard output */
+ if (uO.cflag)
+ return;
+
+ gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft);
+
+ /* open a handle to the file before processing extra fields;
+ we do this in case new security on file prevents us from updating
+ time stamps */
+ hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ /* sfield@microsoft.com: set attributes before time in case we decide to
+ support other filetime members later. This also allows us to apply
+ attributes before the security is changed, which may prevent this
+ from succeeding otherwise. Also, since most files don't have
+ any interesting attributes, only change them if something other than
+ FILE_ATTRIBUTE_ARCHIVE appears in the attributes. This works well
+ as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
+ file anyway, when it's created new. */
+ if((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
+ if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
+ Info(slide, 1, ((char *)slide,
+ "\nwarning (%d): could not set file attributes\n",
+ (int)GetLastError()));
+ }
#ifdef NTSD_EAS
- /* set NTFS SD extra fields */
- if (G.extra_field && /* zipfile extra field may have extended attribs */
- FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
- &ebSDptr, &ebSDlen))
- {
+ /* set NTFS SD extra fields */
+ if (G.extra_field && /* zipfile extra field may have extended attribs */
+ FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
+ &ebSDptr, &ebSDlen))
+ {
+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ /* no win32_wide implies "no NT SD support", so FindSDExtraField
+ * will never return "success".
+ */
+# else /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
int err = SetSD(__G__ Ansi_Fname, G.pInfo->file_attr,
ebSDptr, ebSDlen);
@@ -1131,9 +1255,10 @@
ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":""));
}
- }
+# endif /* ? (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
+ }
#endif /* NTSD_EAS */
- /* skip restoring time stamps on user's request */
- if (uO.D_flag <= 1) {
+ /* skip restoring time stamps on user's request */
+ if (uO.D_flag <= 1) {
if ( hFile == INVALID_HANDLE_VALUE )
Info(slide, 1, ((char *)slide,
@@ -1152,10 +1277,101 @@
CloseHandle(hFile);
}
- }
+ }
- return;
+ return;
#undef Ansi_Fname
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ } else {
+ /* wide version */
+
+#ifndef __RSXNT__
+ if (IsWinNT()) {
+ /* Truncate the file to the current position.
+ * This is needed to remove excess allocation in case the
+ * extraction has failed or stopped prematurely. */
+ SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile)));
+ }
+#endif
+
+ /* Close the file and then re-open it using the Win32
+ * CreateFile call, so that the file can be created
+ * with GENERIC_WRITE access, otherwise the SetFileTime
+ * call will fail. */
+ fclose(G.outfile);
+
+ /* don't set the time stamp and attributes on standard output */
+ if (uO.cflag)
+ return;
+
+ gotTime = getNTfiletimeW(__G__ &Modft, &Accft, &Creft);
+
+ /* open a handle to the file before processing extra fields;
+ we do this in case new security on file prevents us from updating
+ time stamps */
+ hFile = CreateFileW(G.unipath_widefilename,
+ GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ /* sfield@microsoft.com: set attributes before time in case we decide to
+ support other filetime members later. This also allows us to apply
+ attributes before the security is changed, which may prevent this
+ from succeeding otherwise. Also, since most files don't have
+ any interesting attributes, only change them if something other than
+ FILE_ATTRIBUTE_ARCHIVE appears in the attributes. This works well
+ as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
+ file anyway, when it's created new. */
+ if((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
+ if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F))
+ Info(slide, 1, ((char *)slide,
+ "\nwarning (%d): could not set file attributes\n",
+ (int)GetLastError()));
+ }
+
+#ifdef NTSD_EAS
+ /* set NTFS SD extra fields */
+ if (G.extra_field && /* zipfile extra field may have extended attribs */
+ FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
+ &ebSDptr, &ebSDlen))
+ {
+ int err = SetSD(__G__ G.unipath_widefilename, G.pInfo->file_attr,
+ ebSDptr, ebSDlen);
+
+ if (err == IZ_EF_TRUNC) {
+ if (uO.qflag)
+ Info(slide, 1, ((char *)slide, "%-22s ",
+ FnFilter1(G.filename)));
+ Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
+ ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":""));
+ }
+ }
+#endif /* NTSD_EAS */
+
+ /* skip restoring time stamps on user's request */
+ if (uO.D_flag <= 1) {
+ if ( hFile == INVALID_HANDLE_VALUE )
+ Info(slide, 1, ((char *)slide,
+ "\nCreateFile() error %d when trying set file time\n",
+ (int)GetLastError()));
+ else {
+ if (gotTime) {
+ FILETIME *pModft = (gotTime & EB_UT_FL_MTIME) ? &Modft : NULL;
+ FILETIME *pAccft = (gotTime & EB_UT_FL_ATIME) ? &Accft : NULL;
+ FILETIME *pCreft = (gotTime & EB_UT_FL_CTIME) ? &Creft : NULL;
+
+ if (!SetFileTime(hFile, pCreft, pAccft, pModft))
+ Info(slide, 0, ((char *)slide,
+ "\nSetFileTime failed: %d\n", (int)GetLastError()));
+ }
+ CloseHandle(hFile);
+ }
+ }
+
+ return;
+
+ }
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
+
} /* end function close_outfile() */
@@ -1225,8 +1441,76 @@
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+int defer_dir_attribsw(__G__ pdw)
+ __GDEF
+ direntryw **pdw;
+{
+ NTdirattrw *d_entryw;
+#ifdef NTSD_EAS
+ uch *ebSDptr;
+ unsigned ebSDlen;
+#endif
+
+ /* Win9x does not support setting directory time stamps. */
+ if (!IsWinNT()) {
+ *pdw = (direntryw *)NULL;
+ return PK_OK;
+ }
+
+#ifdef NTSD_EAS
+ /* set extended attributes from extra fields */
+ if (G.extra_field && /* zipfile e.f. may have extended attribs */
+ FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
+ &ebSDptr, &ebSDlen)) {
+ /* ebSDlen contains the payload size of the e.f. block, but
+ we store it including the e.b. header. */
+ ebSDlen += EB_HEADSIZE;
+ } else {
+ /* no NTSD e.f. block -> no space needed to allocate */
+ ebSDlen = 0;
+ }
+#endif /* NTSD_EAS */
+
+ d_entryw = (NTdirattrw *)malloc(sizeof(NTdirattrw)
+#ifdef NTSD_EAS
+ + ebSDlen
+#endif
+ + (wcslen(G.unipath_widefilename)
+ * sizeof(wchar_t)));
+ *pdw = (direntryw *)d_entryw;
+ if (d_entryw == (NTdirattrw *)NULL) {
+ return PK_MEM;
+ }
+#ifdef NTSD_EAS
+ if (ebSDlen > 0)
+ memcpy(d_entryw->buf, ebSDptr, ebSDlen);
+ d_entryw->SDlen = ebSDlen;
+ d_entryw->fnw = d_entryw->buf + ebSDlen;
+#else
+ d_entryw->fnw = d_entryw->buf;
+#endif
+
+ wcscpy(d_entryw->fnw, G.unipath_widefilename);
+
+ d_entryw->perms = G.pInfo->file_attr;
+
+ d_entryw->gotTime = (uO.D_flag <= 0
+ ? getNTfiletimeW(__G__ &(d_entryw->Modft),
+ &(d_entryw->Accft),
+ &(d_entryw->Creft))
+ : 0);
+ return PK_OK;
+} /* end function defer_dir_attribsw() */
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
+
+
int set_direc_attribs(__G__ d)
__GDEF
direntry *d;
{
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+ /* Win9x does not support setting directory time stamps. */
+ return PK_OK;
+#else /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
int errval;
HANDLE hFile = INVALID_HANDLE_VALUE; /* File handle defined in NT */
@@ -1320,6 +1604,107 @@
return errval;
+#endif /* ? (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
} /* end function set_direc_attribs() */
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+int set_direc_attribsw(__G__ dw)
+ __GDEF
+ direntryw *dw;
+{
+ int errval;
+ HANDLE hFile = INVALID_HANDLE_VALUE; /* File handle defined in NT */
+
+ /* Win9x does not support setting directory time stamps. */
+ if (!IsWinNT())
+ return PK_OK;
+
+ errval = PK_OK;
+
+ /* Skip restoring directory time stamps on user' request. */
+ if (uO.D_flag <= 0) {
+ /* Open a handle to the directory before processing extra fields;
+ we do this in case new security on file prevents us from updating
+ time stamps.
+ Although the WIN32 documentation recommends to use GENERIC_WRITE
+ access flag to create the handle for SetFileTime(), this is too
+ demanding for directories with the "read-only" attribute bit set.
+ So we use the more specific flag FILE_WRITE_ATTRIBUTES here to
+ request the minimum required access rights. (This problem is a
+ Windows bug that has been silently fixed in Windows XP SP2.) */
+ hFile = CreateFileW(dw->fnw, FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
+
+#ifdef NTSD_EAS
+ if (NtAtt(dw)->SDlen > 0) {
+ int err;
+
+ if (QCOND2) {
+ char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all);
+ Info(slide, 1, ((char *)slide, " set attrib: %-22s ",
+ FnFilter1(fn)));
+ free(fn);
+ }
+
+ /* set NTFS SD extra fields */
+ err = SetSD(__G__ dw->fnw, NtAtt(dw)->perms,
+ NtAtt(dw)->buf, NtAtt(dw)->SDlen - EB_HEADSIZE);
+ if (err == IZ_EF_TRUNC) {
+ if (!QCOND2) {
+ char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all);
+ Info(slide, 1, ((char *)slide, "%-22s ",
+ FnFilter1(fn)));
+ free(fn);
+ }
+ Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
+ NtAtt(dw)->SDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
+ } else if (QCOND2) {
+ Info(slide, 0, ((char *)slide, "\n"));
+ }
+ if (errval < err)
+ errval = err;
+ }
+#endif /* NTSD_EAS */
+
+ /* Skip restoring directory time stamps on user' request. */
+ if (uO.D_flag <= 0) {
+ if (hFile == INVALID_HANDLE_VALUE) {
+ char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all);
+ Info(slide, 1, ((char *)slide,
+ "warning: CreateFile() error %d (set file times for %s)\n",
+ (int)GetLastError(), FnFilter1(fn)));
+ free(fn);
+ if (!errval)
+ errval = PK_WARN;
+ } else {
+ if (NtAtt(dw)->gotTime) {
+ FILETIME *pModft = (NtAtt(dw)->gotTime & EB_UT_FL_MTIME)
+ ? &(NtAtt(dw)->Modft) : NULL;
+ FILETIME *pAccft = (NtAtt(dw)->gotTime & EB_UT_FL_ATIME)
+ ? &(NtAtt(dw)->Accft) : NULL;
+ FILETIME *pCreft = (NtAtt(dw)->gotTime & EB_UT_FL_CTIME)
+ ? &(NtAtt(dw)->Creft) : NULL;
+
+ if (!SetFileTime(hFile, pCreft, pAccft, pModft)) {
+ char *fn = wchar_to_local_string(dw->fnw,
+ G.unicode_escape_all);
+ Info(slide, 0, ((char *)slide,
+ "warning: SetFileTime() for %s error %d\n",
+ FnFilter1(fn), (int)GetLastError()));
+ free(fn);
+ if (!errval)
+ errval = PK_WARN;
+ }
+ }
+ CloseHandle(hFile);
+ }
+ }
+
+ return errval;
+} /* end function set_direc_attribsw() */
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
+
#endif /* SET_DIR_ATTRIB */
@@ -1419,5 +1804,5 @@
#endif
- if ((!strncmp(name, "//", 2) || !strncmp(name, "\\\\", 2)) &&
+ if ((!strncmp(name, "//", 2) || !strncmp(name,"\\\\", 2)) &&
(name[2] != '\0' && name[2] != '/' && name[2] != '\\')) {
/* GetFullPathname() and GetVolumeInformation() do not work
@@ -1467,4 +1852,63 @@
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static int NTQueryVolInfoW(__GPRO__ const wchar_t *namew)
+{
+ /* static char lastRootPath[4] = ""; */
+ /* static int lastVolOldFAT; */
+ /* static int lastVolLocTim; */
+ wchar_t *tmp0w;
+ wchar_t tmp1w[MAX_PATH], tmp2w[MAX_PATH];
+ DWORD volSerNo, maxCompLen, fileSysFlags;
+
+ if ((!wcsncmp(namew, L"//", 2) || !wcsncmp(namew, L"\\\\", 2)) &&
+ (namew[2] != '\0' && namew[2] != '/' && namew[2] != '\\')) {
+ /* GetFullPathname() and GetVolumeInformation() do not work
+ * on UNC names. For now, we return "error".
+ * **FIXME**: check if UNC name is mapped to a drive letter
+ * and use mapped drive for volume info query.
+ */
+ return FALSE;
+ }
+ if (iswalpha(namew[0]) && (namew[1] == ':'))
+ tmp0w = (wchar_t *)namew;
+ else
+ {
+ if (!GetFullPathNameW(namew, MAX_PATH, tmp1w, &tmp0w))
+ return FALSE;
+ tmp0w = &tmp1w[0];
+ }
+ if (wcsncmp(G.lastRootPathw, tmp0w, 2) != 0) {
+ /* For speed, we skip repeated queries for the same device */
+ wcsncpy(G.lastRootPathw, tmp0w, 2); /* Build the root path name, */
+ G.lastRootPathw[2] = '/'; /* e.g. "A:/" */
+ G.lastRootPathw[3] = '\0';
+
+ if (!GetVolumeInformationW(G.lastRootPathw,
+ tmp1w, (DWORD)MAX_PATH,
+ &volSerNo, &maxCompLen, &fileSysFlags,
+ tmp2w, (DWORD)MAX_PATH)) {
+ G.lastRootPathw[0] = '\0';
+ return FALSE;
+ }
+
+ /* LFNs are available if the component length is > 12 */
+ G.lastVolOldFAT = (maxCompLen <= 12);
+/* G.lastVolOldFAT = !strncmp(strupr(tmp2), "FAT", 3); old version */
+
+ /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
+ * local time!
+ */
+ G.lastVolLocTim = !wcsncmp(_wcsupr(tmp2w), L"VFAT", 4) ||
+ !wcsncmp(tmp2w, L"HPFS", 4) ||
+ !wcsncmp(tmp2w, L"FAT", 3);
+ }
+
+ return TRUE;
+
+} /* end function NTQueryVolInfoW() */
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
+
+
@@ -1478,4 +1922,11 @@
}
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+static int IsVolumeOldFATw(__GPRO__ const wchar_t *namew)
+{
+ return (NTQueryVolInfoW(__G__ namew) ? G.lastVolOldFAT : FALSE);
+}
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
+
@@ -1931,13 +2382,253 @@
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+/* Win32 wide version */
-/****************************/
-/* Function maskDOSdevice() */
-/****************************/
-
-static void maskDOSdevice(__G__ pathcomp)
+int mapnamew(__G__ renamed)
__GDEF
- char *pathcomp;
+ int renamed;
+/*
+ * returns:
+ * MPN_OK - no problem detected
+ * MPN_INF_TRUNC - caution (truncated filename)
+ * MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
+ * MPN_ERR_SKIP - error -> skip entry
+ * MPN_ERR_TOOLONG - error -> path is too long
+ * MPN_NOMEM - error (memory allocation failed) -> skip entry
+ * [also MPN_VOL_LABEL, MPN_CREATED_DIR]
+ */
+{
+ wchar_t pathcompw[FILNAMSIZ]; /* path-component buffer */
+ wchar_t *ppw, *cpw=NULL; /* character pointers */
+ wchar_t *lastsemiw = NULL; /* pointer to last semi-colon in pathcomp */
+ int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
+ int error;
+ register wchar_t workchw; /* hold the character being tested */
+
+
+/*---------------------------------------------------------------------------
+ Initialize various pointers and counters and stuff.
+ ---------------------------------------------------------------------------*/
+
+ /* can create path as long as not just freshening, or if user told us */
+ G.create_dirs = (!uO.fflag || renamed);
+
+ G.created_dir = FALSE; /* not yet */
+ G.renamed_fullpath = FALSE;
+ G.fnlen = wcslen(G.unipath_widefilename);
+
+ if (renamed) {
+ cpw = G.unipath_widefilename; /* point to beginning of renamed name... */
+ if (*cpw) do {
+ if (*cpw == '\\') /* convert backslashes to forward */
+ *cpw = '/';
+ } while (*(++cpw));
+ cpw = G.unipath_widefilename;
+ /* use temporary rootpath if user gave full pathname */
+ if (G.unipath_widefilename[0] == '/') {
+ G.renamed_fullpath = TRUE;
+ pathcompw[0] = '/'; /* copy the '/' and terminate */
+ pathcompw[1] = '\0';
+ ++cpw;
+ } else if (iswalpha(G.unipath_widefilename[0]) && G.unipath_widefilename[1] == ':') {
+ G.renamed_fullpath = TRUE;
+ ppw = pathcompw;
+ *ppw++ = *cpw++; /* copy the "d:" (+ '/', possibly) */
+ *ppw++ = *cpw++;
+ if (*cpw == '/')
+ *ppw++ = *cpw++; /* otherwise add "./"? */
+ *ppw = '\0';
+ }
+ }
+
+ /* pathcomp is ignored unless renamed_fullpath is TRUE: */
+ if ((error = checkdirw(__G__ pathcompw, INIT)) != 0) /* init path buffer */
+ return error; /* ...unless no mem or vol label on hard disk */
+
+ *pathcompw = '\0'; /* initialize translation buffer */
+ ppw = pathcompw; /* point to translation buffer */
+ if (!renamed) { /* cp already set if renamed */
+ if (uO.jflag) /* junking directories */
+ cpw = wcschr(G.unipath_widefilename, '/');
+ if (cpw == NULL) /* no '/' or not junking dirs */
+ cpw = G.unipath_widefilename; /* point to internal zipfile-member pathname */
+ else
+ ++cpw; /* point to start of last component of path */
+ }
+
+/*---------------------------------------------------------------------------
+ Begin main loop through characters in filename.
+ ---------------------------------------------------------------------------*/
+
+ for (; (workchw = *cpw) != 0; cpw++) {
+
+ switch (workchw) {
+ case '/': /* can assume -j flag not given */
+ *ppw = '\0';
+ maskDOSdevicew(__G__ pathcompw);
+ if (wcscmp(pathcompw, L".") == 0) {
+ /* don't botherw appending "./" to the path */
+ *pathcompw = '\0';
+ } else if (!uO.ddotflag && wcscmp(pathcompw, L"..") == 0) {
+ /* "../" dir traversal detected, skip over it */
+ *pathcompw = '\0';
+ killed_ddot = TRUE; /* set "show message" flag */
+ }
+ /* when path component is not empty, append it now */
+ if (*pathcompw != '\0' &&
+ ((error = checkdirw(__G__ pathcompw, APPEND_DIR))
+ & MPN_MASK) > MPN_INF_TRUNC)
+ return error;
+ ppw = pathcompw; /* reset conversion buffer for next piece */
+ lastsemiw = (wchar_t *)NULL; /* leave direct. semi-colons alone */
+ break;
+
+ case ':': /* drive spec not stored, so no colon allowed */
+ case '\\': /* '\\' may come as normal filename char (not */
+ case '<': /* dir sep char!) from unix-like file system */
+ case '>': /* no redirection symbols allowed either */
+ case '|': /* no pipe signs allowed */
+ case '"': /* no double quotes allowed */
+ case '?': /* no wildcards allowed */
+ case '*':
+ *ppw++ = '_'; /* these rules apply equally to FAT and NTFS */
+ break;
+ case ';': /* start of VMS version? */
+ lastsemiw = ppw; /* remove VMS version later... */
+ *ppw++ = ';'; /* but keep semicolon for now */
+ break;
+
+
+ case ' ': /* keep spaces unless specifically */
+ /* NT cannot create filenames with spaces on FAT volumes */
+ if (uO.sflag || IsVolumeOldFATw(__G__ G.unipath_widefilename))
+ *ppw++ = '_';
+ else
+ *ppw++ = ' ';
+ break;
+
+ default:
+ /* allow European characters in filenames: */
+ if (iswprint(workchw) || workchw >= 127)
+ *ppw++ = workchw;
+ } /* end switch */
+
+ } /* end while loop */
+
+ /* Show warning when stripping insecure "parent dir" path components */
+ /* For now use standard path for output messages */
+ if (killed_ddot && QCOND2) {
+ Info(slide, 0, ((char *)slide,
+ "warning: skipped \"../\" path component(s) in %s\n",
+ FnFilter1(G.filename)));
+ if (!(error & ~MPN_MASK))
+ error = (error & MPN_MASK) | PK_WARN;
+ }
+
+/*---------------------------------------------------------------------------
+ Report if directory was created (and no file to create: filename ended
+ in '/'), check name to be sure it exists, and combine path and name be-
+ fore exiting.
+ ---------------------------------------------------------------------------*/
+
+ if (G.unipath_widefilename[wcslen(G.unipath_widefilename) - 1] == '/') {
+ checkdirw(__G__ G.unipath_widefilename, GETPATH);
+ if (G.created_dir) {
+ if (QCOND2) {
+ Info(slide, 0, ((char *)slide, " creating: %-22s\n",
+ FnFilter1(G.filename)));
+ }
+
+ /* set file attributes:
+ The default for newly created directories is "DIR attribute
+ flags set", so there is no need to change attributes unless
+ one of the DOS style attribute flags is set. The readonly
+ attribute need not be masked, since it does not prevent
+ modifications in the new directory. */
+ if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
+ if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F))
+ Info(slide, 1, ((char *)slide,
+ "\nwarning (%d): could not set file attributes for %s\n",
+ (int)GetLastError(), FnFilter1(G.filename)));
+ }
+
+ /* set dir time (note trailing '/') */
+ return (error & ~MPN_MASK) | MPN_CREATED_DIR;
+ } else if (IS_OVERWRT_ALL) {
+ /* overwrite attributes of existing directory on user's request */
+
+ /* set file attributes: */
+ if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
+ if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F))
+ Info(slide, 1, ((char *)slide,
+ "\nwarning (%d): could not set file attributes for %s\n",
+ (int)GetLastError(), FnFilter1(G.filename)));
+ }
+ }
+ /* dir existed already; don't look for data to extract */
+ return (error & ~MPN_MASK) | MPN_INF_SKIP;
+ }
+
+ *ppw = '\0'; /* done with pathcomp: terminate it */
+
+ /* if not saving them, remove VMS version numbers (appended "###") */
+ if (!uO.V_flag && lastsemiw) {
+ ppw = lastsemiw + 1; /* semi-colon was kept: expect #'s after */
+ while (iswdigit(*ppw))
+ ++ppw;
+ if (*ppw == '\0') /* only digits between ';' and end: nuke */
+ *lastsemiw = '\0';
+ }
+
+ maskDOSdevicew(__G__ pathcompw);
+
+ if (*pathcompw == '\0') {
+ Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
+ FnFilter1(G.filename)));
+ return (error & ~MPN_MASK) | MPN_ERR_SKIP;
+ }
+
+ checkdirw(__G__ pathcompw, APPEND_NAME); /* returns 1 if truncated: care? */
+ checkdirw(__G__ G.unipath_widefilename, GETPATH);
+
+ if (G.pInfo->vollabel) { /* set the volume label now */
+ char drive[4];
+ wchar_t drivew[4];
+
+ /* Build a drive string, e.g. "b:" */
+ drive[0] = (char)('a' + G.nLabelDrive - 1);
+ drivew[0] = (wchar_t)('a' + G.nLabelDrive - 1);
+ wcscpy(drivew + 1, L":\\");
+ if (QCOND2)
+ Info(slide, 0, ((char *)slide, "labelling %s %-22s\n", drive,
+ FnFilter1(G.filename)));
+ if (!SetVolumeLabelW(drivew, G.unipath_widefilename)) {
+ Info(slide, 1, ((char *)slide,
+ "mapname: error setting volume label\n"));
+ return (error & ~MPN_MASK) | MPN_ERR_SKIP;
+ }
+ /* success: skip the "extraction" quietly */
+ return (error & ~MPN_MASK) | MPN_INF_SKIP;
+ }
+
+ Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n",
+ FnFilter1(G.filename), error));
+ return error;
+
+} /* end function mapnamew() */
+
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
+
+
+
+
+/****************************/
+/* Function maskDOSdevice() */
+/****************************/
+
+static void maskDOSdevice(__G__ pathcomp)
+ __GDEF
+ char *pathcomp;
{
/*---------------------------------------------------------------------------
@@ -1981,4 +2672,40 @@
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+
+static void maskDOSdevicew(__G__ pathcompw)
+ __GDEF
+ wchar_t *pathcompw;
+{
+/*---------------------------------------------------------------------------
+ Put an underscore in front of the file name if the file name is a
+ DOS/WINDOWS device name like CON.*, AUX.*, PRN.*, etc. Trying to
+ extract such a file would fail at best and wedge us at worst.
+ ---------------------------------------------------------------------------*/
+#if !defined(S_IFCHR) && defined(_S_IFCHR)
+# define S_IFCHR _S_IFCHR
+#endif
+#if !defined(S_ISCHR)
+# if defined(_S_ISCHR)
+# define S_ISCHR(m) _S_ISCHR(m)
+# elif defined(S_IFCHR)
+# define S_ISCHR(m) ((m) & S_IFCHR)
+# endif
+#endif
+
+ if (zstatw(pathcompw, &G.statbuf) == 0 && S_ISCHR(G.statbuf.st_mode)) {
+ extent i;
+
+ /* pathcomp contains a name of a DOS character device (builtin or
+ * installed device driver).
+ * Prepend a '_' to allow creation of the item in the file system.
+ */
+ for (i = wcslen(pathcompw) + 1; i > 0; --i)
+ pathcompw[i] = pathcompw[i - 1];
+ pathcompw[0] = '_';
+ }
+} /* end function maskDOSdevicew() */
+
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
@@ -2080,19 +2807,511 @@
*pEndFAT = pEnd; /* filename is fine; point at terminating zero */
- if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ')
- last_dot[-1] = '_'; /* NO blank in front of '.'! */
+ if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ')
+ last_dot[-1] = '_'; /* NO blank in front of '.'! */
+ }
+} /* end function map2fat() */
+
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+
+static void map2fatw(pathcompw, pEndFATw)
+ wchar_t *pathcompw, **pEndFATw;
+{
+ wchar_t *ppcw = pathcompw; /* variable pointer to pathcomp */
+ wchar_t *pEndw = *pEndFATw; /* variable pointer to buildpathFAT */
+ wchar_t *pBeginw = *pEndFATw; /* constant pointer to start of this comp. */
+ wchar_t *last_dotw = NULL; /* last dot not converted to underscore */
+ register wchar_t workchw; /* hold the character being tested */
+
+
+ /* Only need check those characters which are legal in NTFS but not
+ * in FAT: to get here, must already have passed through mapname.
+ * Also must truncate path component to ensure 8.3 compliance.
+ */
+ while ((workchw = *ppcw++) != 0) {
+ switch (workchw) {
+ case '[':
+ case ']':
+ case '+':
+ case ',':
+ case ';':
+ case '=':
+ *pEndw++ = '_'; /* convert brackets to underscores */
+ break;
+
+ case '.':
+ if (pEndw == *pEndFATw) { /* nothing appended yet... */
+ if (*ppcw == '\0') /* don't bother appending a */
+ break; /* "./" component to the path */
+ else if (*ppcw == '.' && ppcw[1] == '\0') { /* "../" */
+ *pEndw++ = '.'; /* add first dot, */
+ *pEndw++ = '.'; /* add second dot, and */
+ ++ppcw; /* skip over to pathcomp's end */
+ } else { /* FAT doesn't allow null filename */
+ *pEndw++ = '_'; /* bodies, so map .exrc -> _exrc */
+ } /* (_.exr would keep max 3 chars) */
+ } else { /* found dot within path component */
+ last_dotw = pEndw; /* point at last dot so far... */
+ *pEndw++ = '_'; /* convert to underscore for now */
+ }
+ break;
+
+ default:
+ *pEndw++ = workchw;
+
+ } /* end switch */
+ } /* end while loop */
+
+ *pEndw = '\0'; /* terminate buildpathFAT */
+
+ /* NOTE: keep in mind that pEnd points to the end of the path
+ * component, and *pEndFAT still points to the *beginning* of it...
+ * Also note that the algorithm does not try to get too fancy:
+ * if there are no dots already, the name either gets truncated
+ * at 8 characters or the last underscore is converted to a dot
+ * (only if more characters are saved that way). In no case is
+ * a dot inserted between existing characters.
+ */
+ if (last_dotw == NULL) { /* no dots: check for underscores... */
+ wchar_t *pluw = wcschr(pBeginw, '_'); /* pointer to last underscore */
+
+ if ((pluw != NULL) && /* found underscore: convert to dot? */
+ (MIN(pluw - pBeginw, 8) + MIN(pEndw - pluw - 1, 3) > 8)) {
+ last_dotw = pluw; /* be lazy: drop through to next if-blk */
+ } else if ((pEndw - *pEndFATw) > 8) {
+ /* no underscore; or converting underscore to dot would save less
+ chars than leaving everything in the basename */
+ *pEndFATw += 8; /* truncate at 8 chars */
+ **pEndFATw = '\0';
+ } else
+ *pEndFATw = pEndw; /* whole thing fits into 8 chars or less */
+ }
+
+ if (last_dotw != NULL) { /* one dot is OK: */
+ *last_dotw = '.'; /* put it back in */
+
+ if ((last_dotw - pBeginw) > 8) {
+ wchar_t *pw, *qw;
+ int i;
+
+ pw = last_dotw;
+ qw = last_dotw = pBeginw + 8;
+ for (i = 0; (i < 4) && *pw; ++i) /* too many chars in basename: */
+ *qw++ = *pw++; /* shift .ext left and trun- */
+ *qw = '\0'; /* cate/terminate it */
+ *pEndFATw = qw;
+ } else if ((pEndw - last_dotw) > 4) { /* too many chars in extension */
+ *pEndFATw = last_dotw + 4;
+ **pEndFATw = '\0';
+ } else
+ *pEndFATw = pEndw; /* filename is fine; point at terminating zero */
+
+ if ((last_dotw - pBeginw) > 0 && last_dotw[-1] == ' ')
+ last_dotw[-1] = '_'; /* NO blank in front of '.'! */
+ }
+} /* end function map2fatw() */
+
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
+
+
+
+/***********************/ /* Borrowed from os2.c for UnZip 5.1. */
+/* Function checkdir() */ /* Difference: no EA stuff */
+/***********************/ /* HPFS stuff works on NTFS too */
+
+int checkdir(__G__ pathcomp, flag)
+ __GDEF
+ char *pathcomp;
+ int flag;
+/*
+ * returns:
+ * MPN_OK - no problem detected
+ * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
+ * MPN_INF_SKIP - path doesn't exist, not allowed to create
+ * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
+ * exists and is not a directory, but is supposed to be
+ * MPN_ERR_TOOLONG - path is too long
+ * MPN_NOMEM - can't allocate memory for filename buffers
+ */
+{
+ /* static int rootlen = 0; */ /* length of rootpath */
+ /* static char *rootpath; */ /* user's "extract-to" directory */
+ /* static char *buildpathHPFS; */ /* full path (so far) to extracted file, */
+ /* static char *buildpathFAT; */ /* both HPFS/EA (main) and FAT versions */
+ /* static char *endHPFS; */ /* corresponding pointers to end of */
+ /* static char *endFAT; */ /* buildpath ('\0') */
+
+# define FN_MASK 7
+# define FUNCTION (flag & FN_MASK)
+
+
+
+/*---------------------------------------------------------------------------
+ APPEND_DIR: append the path component to the path being built and check
+ for its existence. If doesn't exist and we are creating directories, do
+ so for this one; else signal success or error as appropriate.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == APPEND_DIR) {
+ char *p = pathcomp;
+ int too_long = FALSE;
+
+ Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
+ while ((*G.endHPFS = *p++) != '\0') /* copy to HPFS filename */
+ ++G.endHPFS;
+ if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
+ p = pathcomp;
+ while ((*G.endFAT = *p++) != '\0') /* copy to FAT filename, too */
+ ++G.endFAT;
+ } else
+ map2fat(pathcomp, &G.endFAT); /* map into FAT fn, update endFAT */
+
+ /* GRR: could do better check, see if overrunning buffer as we go:
+ * check endHPFS-buildpathHPFS after each append, set warning variable
+ * if within 20 of FILNAMSIZ; then if var set, do careful check when
+ * appending. Clear variable when begin new path. */
+
+ /* next check: need to append '/', at least one-char name, '\0' */
+ if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3)
+ too_long = TRUE; /* check if extracting dir? */
+#ifdef FIX_STAT_BUG
+ /* Borland C++ 5.0 does not handle a call to stat() well if the
+ * directory does not exist (it tends to crash in strange places.)
+ * This is apparently a problem only when compiling for GUI rather
+ * than console. The code below attempts to work around this problem.
+ */
+ if (access(G.buildpathFAT, 0) != 0) {
+ if (!G.create_dirs) { /* told not to create (freshening) */
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ /* path doesn't exist: nothing to do */
+ return MPN_INF_SKIP;
+ }
+ if (too_long) { /* GRR: should allow FAT extraction w/o EAs */
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: path too long: %s\n",
+ FnFilter1(G.buildpathHPFS)));
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ /* no room for filenames: fatal */
+ return MPN_ERR_TOOLONG;
+ }
+ if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: cannot create %s\n\
+ unable to process %s.\n",
+ FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ /* path didn't exist, tried to create, failed */
+ return MPN_ERR_SKIP;
+ }
+ G.created_dir = TRUE;
+ }
+#endif /* FIX_STAT_BUG */
+ if (SSTAT(G.buildpathFAT, &G.statbuf)) /* path doesn't exist */
+ {
+ if (!G.create_dirs) { /* told not to create (freshening) */
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ /* path doesn't exist: nothing to do */
+ return MPN_INF_SKIP;
+ }
+ if (too_long) { /* GRR: should allow FAT extraction w/o EAs */
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: path too long: %s\n",
+ FnFilter1(G.buildpathHPFS)));
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ /* no room for filenames: fatal */
+ return MPN_ERR_TOOLONG;
+ }
+ if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: cannot create %s\n\
+ unable to process %s.\n",
+ FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ /* path didn't exist, tried to create, failed */
+ return MPN_ERR_SKIP;
+ }
+ G.created_dir = TRUE;
+ } else if (!S_ISDIR(G.statbuf.st_mode)) {
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: %s exists but is not directory\n \
+ unable to process %s.\n",
+ FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ /* path existed but wasn't dir */
+ return MPN_ERR_SKIP;
+ }
+ if (too_long) {
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: path too long: %s\n",
+ FnFilter1(G.buildpathHPFS)));
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ /* no room for filenames: fatal */
+ return MPN_ERR_TOOLONG;
+ }
+ *G.endHPFS++ = '/';
+ *G.endFAT++ = '/';
+ *G.endHPFS = *G.endFAT = '\0';
+ Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now = [%s]\n",
+ FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
+ return MPN_OK;
+
+ } /* end if (FUNCTION == APPEND_DIR) */
+
+/*---------------------------------------------------------------------------
+ GETPATH: copy full FAT path to the string pointed at by pathcomp (want
+ filename to reflect name used on disk, not EAs; if full path is HPFS,
+ buildpathFAT and buildpathHPFS will be identical). Also free both paths.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == GETPATH) {
+ Trace((stderr, "getting and freeing FAT path [%s]\n",
+ FnFilter1(G.buildpathFAT)));
+ Trace((stderr, "freeing HPFS path [%s]\n",
+ FnFilter1(G.buildpathHPFS)));
+ strcpy(pathcomp, G.buildpathFAT);
+ free(G.buildpathFAT);
+ free(G.buildpathHPFS);
+ G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL;
+ return MPN_OK;
+ }
+
+/*---------------------------------------------------------------------------
+ APPEND_NAME: assume the path component is the filename; append it and
+ return without checking for existence.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == APPEND_NAME) {
+ char *p = pathcomp;
+ int error = MPN_OK;
+
+ Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
+ /* The buildpathHPFS buffer has been allocated large enough to
+ * hold the complete combined name, so there is no need to check
+ * for OS filename size limit overflow within the copy loop.
+ */
+ while ((*G.endHPFS = *p++) != '\0') { /* copy to HPFS filename */
+ ++G.endHPFS;
+ }
+ /* Now, check for OS filename size overflow. When detected, the
+ * mapped HPFS name is truncated and a warning message is shown.
+ */
+ if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) {
+ G.buildpathHPFS[FILNAMSIZ-1] = '\0';
+ Info(slide, 1, ((char *)slide,
+ "checkdir warning: path too long; truncating\n \
+ %s\n -> %s\n",
+ FnFilter1(G.filename), FnFilter2(G.buildpathHPFS)));
+ error = MPN_INF_TRUNC; /* filename truncated */
+ }
+
+ /* The buildpathFAT buffer has the same allocated size as the
+ * buildpathHPFS buffer, so there is no need for an overflow check
+ * within the following copy loop, either.
+ */
+ if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
+ /* copy to FAT filename, too */
+ p = pathcomp;
+ while ((*G.endFAT = *p++) != '\0')
+ ++G.endFAT;
+ } else
+ /* map into FAT fn, update endFAT */
+ map2fat(pathcomp, &G.endFAT);
+
+ /* Check that the FAT path does not exceed the FILNAMSIZ limit, and
+ * truncate when neccessary.
+ * Note that truncation can only happen when the HPFS path (which is
+ * never shorter than the FAT path) has been already truncated.
+ * So, emission of the warning message and setting the error code
+ * has already happened.
+ */
+ if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ)
+ G.buildpathFAT[FILNAMSIZ-1] = '\0';
+ Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT: %s\n",
+ FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
+
+ return error; /* could check for existence, prompt for new name... */
+
+ } /* end if (FUNCTION == APPEND_NAME) */
+
+/*---------------------------------------------------------------------------
+ INIT: allocate and initialize buffer space for the file currently being
+ extracted. If file was renamed with an absolute path, don't prepend the
+ extract-to path.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == INIT) {
+ Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
+#ifdef ACORN_FTYPE_NFS
+ if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+
+ (uO.acorn_nfs_ext ? 5 : 1)))
+#else
+ if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1))
+#endif
+ == NULL)
+ return MPN_NOMEM;
+#ifdef ACORN_FTYPE_NFS
+ if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+
+ (uO.acorn_nfs_ext ? 5 : 1)))
+#else
+ if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1))
+#endif
+ == NULL) {
+ free(G.buildpathHPFS);
+ return MPN_NOMEM;
+ }
+ if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */
+/* GRR: for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
+ if (G.renamed_fullpath && pathcomp[1] == ':')
+ *G.buildpathHPFS = (char)ToLower(*pathcomp);
+ else if (!G.renamed_fullpath && G.rootlen > 1 &&
+ G.rootpath[1] == ':')
+ *G.buildpathHPFS = (char)ToLower(*G.rootpath);
+ else {
+ char tmpN[MAX_PATH], *tmpP;
+ if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
+ { /* by definition of MAX_PATH we should never get here */
+ Info(slide, 1, ((char *)slide,
+ "checkdir warning: current dir path too long\n"));
+ return MPN_INF_TRUNC; /* can't get drive letter */
+ }
+ G.nLabelDrive = *tmpN - 'a' + 1;
+ *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a');
+ }
+ G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */
+ if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */
+ || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */
+ free(G.buildpathHPFS);
+ free(G.buildpathFAT);
+ return MPN_VOL_LABEL; /* skipping with message */
+ }
+ *G.buildpathHPFS = '\0';
+ } else if (G.renamed_fullpath) /* pathcomp = valid data */
+ strcpy(G.buildpathHPFS, pathcomp);
+ else if (G.rootlen > 0)
+ strcpy(G.buildpathHPFS, G.rootpath);
+ else
+ *G.buildpathHPFS = '\0';
+ G.endHPFS = G.buildpathHPFS;
+ G.endFAT = G.buildpathFAT;
+ while ((*G.endFAT = *G.endHPFS) != '\0') {
+ ++G.endFAT;
+ ++G.endHPFS;
+ }
+ Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS)));
+ return MPN_OK;
+ }
+
+/*---------------------------------------------------------------------------
+ ROOT: if appropriate, store the path in rootpath and create it if neces-
+ sary; else assume it's a zipfile member and return. This path segment
+ gets used in extracting all members from every zipfile specified on the
+ command line. Note that under OS/2 and MS-DOS, if a candidate extract-to
+ directory specification includes a drive letter (leading "x:"), it is
+ treated just as if it had a trailing '/'--that is, one directory level
+ will be created if the path doesn't exist, unless this is otherwise pro-
+ hibited (e.g., freshening).
+ ---------------------------------------------------------------------------*/
+
+#if (!defined(SFX) || defined(SFX_EXDIR))
+ if (FUNCTION == ROOT) {
+ Trace((stderr, "initializing root path to [%s]\n",
+ FnFilter1(pathcomp)));
+ if (pathcomp == NULL) {
+ G.rootlen = 0;
+ return MPN_OK;
+ }
+ if (G.rootlen > 0) /* rootpath was already set, nothing to do */
+ return MPN_OK;
+ if ((G.rootlen = strlen(pathcomp)) > 0) {
+ int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE;
+ char *tmproot;
+
+ if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) {
+ G.rootlen = 0;
+ return MPN_NOMEM;
+ }
+ strcpy(tmproot, pathcomp);
+ if (isalpha((uch)tmproot[0]) && tmproot[1] == ':')
+ has_drive = TRUE; /* drive designator */
+ if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') {
+ tmproot[--G.rootlen] = '\0';
+ had_trailing_pathsep = TRUE;
+ }
+ if (has_drive && (G.rootlen == 2)) {
+ if (!had_trailing_pathsep) /* i.e., original wasn't "x:/" */
+ add_dot = TRUE; /* relative path: add '.' before '/' */
+ } else if (G.rootlen > 0) { /* need not check "x:." and "x:/" */
+ if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
+ {
+ /* path does not exist */
+ if (!G.create_dirs /* || iswild(tmproot) */ ) {
+ free(tmproot);
+ G.rootlen = 0;
+ /* treat as stored file */
+ return MPN_INF_SKIP;
+ }
+ /* create directory (could add loop here scanning tmproot
+ * to create more than one level, but really necessary?) */
+ if (MKDIR(tmproot, 0777) == -1) {
+ Info(slide, 1, ((char *)slide,
+ "checkdir: cannot create extraction directory: %s\n",
+ FnFilter1(tmproot)));
+ free(tmproot);
+ G.rootlen = 0;
+ /* path didn't exist, tried to create, failed: */
+ /* file exists, or need 2+ subdir levels */
+ return MPN_ERR_SKIP;
+ }
+ }
+ }
+ if (add_dot) /* had just "x:", make "x:." */
+ tmproot[G.rootlen++] = '.';
+ tmproot[G.rootlen++] = '/';
+ tmproot[G.rootlen] = '\0';
+ if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
+ free(tmproot);
+ G.rootlen = 0;
+ return MPN_NOMEM;
+ }
+ Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
+ }
+ return MPN_OK;
+ }
+#endif /* !SFX || SFX_EXDIR */
+
+/*---------------------------------------------------------------------------
+ END: free rootpath, immediately prior to program exit.
+ ---------------------------------------------------------------------------*/
+
+ if (FUNCTION == END) {
+ Trace((stderr, "freeing rootpath\n"));
+ if (G.rootlen > 0) {
+ free(G.rootpath);
+ G.rootlen = 0;
+ }
+ return MPN_OK;
}
-} /* end function map2fat() */
+ return MPN_INVALID; /* should never reach */
+
+} /* end function checkdir() */
-/***********************/ /* Borrowed from os2.c for UnZip 5.1. */
-/* Function checkdir() */ /* Difference: no EA stuff */
-/***********************/ /* HPFS stuff works on NTFS too */
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
-int checkdir(__G__ pathcomp, flag)
+/* WIN32 wide version */
+
+int checkdirw(__G__ pathcompw, flag)
__GDEF
- char *pathcomp;
+ wchar_t *pathcompw;
int flag;
/*
@@ -2126,16 +3345,20 @@
if (FUNCTION == APPEND_DIR) {
- char *p = pathcomp;
+ wchar_t *pw = pathcompw;
int too_long = FALSE;
-
- Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
- while ((*G.endHPFS = *p++) != '\0') /* copy to HPFS filename */
- ++G.endHPFS;
- if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
- p = pathcomp;
- while ((*G.endFAT = *p++) != '\0') /* copy to FAT filename, too */
- ++G.endFAT;
+ char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all);
+ char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
+ /* Could use G.filename from the standard path, but may
+ not work well on this port */
+ char *fn = wchar_to_local_string(G.unipath_widefilename, G.unicode_escape_all);
+
+ while ((*G.endHPFSw = *pw++) != '\0') /* copy to HPFS filename */
+ ++G.endHPFSw;
+ if (!IsVolumeOldFATw(__G__ G.buildpathHPFSw)) {
+ pw = pathcompw;
+ while ((*G.endFATw = *pw++) != '\0') /* copy to FAT filename, too */
+ ++G.endFATw;
} else
- map2fat(pathcomp, &G.endFAT); /* map into FAT fn, update endFAT */
+ map2fatw(pathcompw, &G.endFATw); /* map into FAT fn, update endFAT */
/* GRR: could do better check, see if overrunning buffer as we go:
@@ -2145,5 +3368,5 @@
/* next check: need to append '/', at least one-char name, '\0' */
- if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3)
+ if ((G.endHPFSw-G.buildpathHPFSw) > FILNAMSIZ-3)
too_long = TRUE; /* check if extracting dir? */
#ifdef FIX_STAT_BUG
@@ -2153,8 +3376,11 @@
* than console. The code below attempts to work around this problem.
*/
- if (access(G.buildpathFAT, 0) != 0) {
+ if (_waccess(G.buildpathFATw, 0) != 0) {
if (!G.create_dirs) { /* told not to create (freshening) */
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
/* path doesn't exist: nothing to do */
return MPN_INF_SKIP;
@@ -2163,28 +3389,40 @@
Info(slide, 1, ((char *)slide,
"checkdir error: path too long: %s\n",
- FnFilter1(G.buildpathHPFS)));
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
+ FnFilter1(fn)));
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
/* no room for filenames: fatal */
return MPN_ERR_TOOLONG;
}
- if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
- Info(slide, 1, ((char *)slide,
- "checkdir error: cannot create %s\n\
- unable to process %s.\n",
- FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
- /* path didn't exist, tried to create, failed */
- return MPN_ERR_SKIP;
- }
- G.created_dir = TRUE;
+ {
+ int i = MKDIRW(G.buildpathFATw, 0777);
+ if (i == -1) { /* create the directory */
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: cannot create %s\n\
+ unable to process %s.\n",
+ FnFilter2(buildpathFAT), FnFilter1(fn)));
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
+ /* path didn't exist, tried to create, failed */
+ return MPN_ERR_SKIP;
+ }
+ G.created_dir = TRUE;
+ }
}
#endif /* FIX_STAT_BUG */
- if (SSTAT(G.buildpathFAT, &G.statbuf)) /* path doesn't exist */
+ if (SSTATW(G.buildpathFATw, &G.statbuf)) /* path doesn't exist */
{
if (!G.create_dirs) { /* told not to create (freshening) */
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
/* path doesn't exist: nothing to do */
return MPN_INF_SKIP;
@@ -2193,28 +3431,41 @@
Info(slide, 1, ((char *)slide,
"checkdir error: path too long: %s\n",
- FnFilter1(G.buildpathHPFS)));
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
+ FnFilter1(buildpathHPFS)));
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
/* no room for filenames: fatal */
return MPN_ERR_TOOLONG;
}
- if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
- Info(slide, 1, ((char *)slide,
- "checkdir error: cannot create %s\n\
- unable to process %s.\n",
- FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
- /* path didn't exist, tried to create, failed */
- return MPN_ERR_SKIP;
- }
- G.created_dir = TRUE;
+ {
+ char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all);
+ int i = MKDIRW(G.buildpathFATw, 0777);
+ if (i == -1) { /* create the directory */
+ Info(slide, 1, ((char *)slide,
+ "checkdir error: cannot create %s\n\
+ unable to process %s.\n",
+ FnFilter2(buildpathFAT), FnFilter1(fn)));
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
+ /* path didn't exist, tried to create, failed */
+ return MPN_ERR_SKIP;
+ }
+ G.created_dir = TRUE;
+ }
} else if (!S_ISDIR(G.statbuf.st_mode)) {
Info(slide, 1, ((char *)slide,
"checkdir error: %s exists but is not directory\n \
unable to process %s.\n",
- FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
+ FnFilter2(buildpathFAT), FnFilter1(fn)));
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
/* path existed but wasn't dir */
return MPN_ERR_SKIP;
@@ -2223,15 +3474,23 @@
Info(slide, 1, ((char *)slide,
"checkdir error: path too long: %s\n",
- FnFilter1(G.buildpathHPFS)));
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
+ FnFilter1(buildpathHPFS)));
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
/* no room for filenames: fatal */
return MPN_ERR_TOOLONG;
}
- *G.endHPFS++ = '/';
- *G.endFAT++ = '/';
- *G.endHPFS = *G.endFAT = '\0';
+ *G.endHPFSw++ = '/';
+ *G.endFATw++ = '/';
+ *G.endHPFSw = *G.endFATw = '\0';
Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now = [%s]\n",
- FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
+ FnFilter1(buildpathHPFS), FnFilter2(buildpathFAT)));
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ free(fn);
+ //free(G.buildpathHPFSw);
+ //free(G.buildpathFATw);
return MPN_OK;
@@ -2245,12 +3504,16 @@
if (FUNCTION == GETPATH) {
+ char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all);
+ char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
Trace((stderr, "getting and freeing FAT path [%s]\n",
- FnFilter1(G.buildpathFAT)));
+ FnFilter1(buildpathFAT)));
Trace((stderr, "freeing HPFS path [%s]\n",
- FnFilter1(G.buildpathHPFS)));
- strcpy(pathcomp, G.buildpathFAT);
- free(G.buildpathFAT);
- free(G.buildpathHPFS);
- G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL;
+ FnFilter1(buildpathHPFS)));
+ wcscpy(pathcompw, G.buildpathFATw);
+ free(buildpathFAT);
+ free(buildpathHPFS);
+ free(G.buildpathFATw);
+ free(G.buildpathHPFSw);
+ G.buildpathHPFSw = G.buildpathFATw = G.endHPFSw = G.endFATw = NULL;
return MPN_OK;
}
@@ -2262,6 +3525,8 @@
if (FUNCTION == APPEND_NAME) {
- char *p = pathcomp;
+ wchar_t *pw = pathcompw;
int error = MPN_OK;
+ char *pathcomp = wchar_to_local_string(pathcompw, G.unicode_escape_all);
+ char *fn = wchar_to_local_string(G.unipath_widefilename, G.unicode_escape_all);
Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
@@ -2270,16 +3535,19 @@
* for OS filename size limit overflow within the copy loop.
*/
- while ((*G.endHPFS = *p++) != '\0') { /* copy to HPFS filename */
- ++G.endHPFS;
+ while ((*G.endHPFSw = *pw++) != '\0') { /* copy to HPFS filename */
+ ++G.endHPFSw;
}
/* Now, check for OS filename size overflow. When detected, the
* mapped HPFS name is truncated and a warning message is shown.
*/
- if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) {
- G.buildpathHPFS[FILNAMSIZ-1] = '\0';
+ if ((G.endHPFSw-G.buildpathHPFSw) >= FILNAMSIZ) {
+ char *buildpathHPFS;
+ G.buildpathHPFSw[FILNAMSIZ-1] = '\0';
+ buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
Info(slide, 1, ((char *)slide,
"checkdir warning: path too long; truncating\n \
%s\n -> %s\n",
- FnFilter1(G.filename), FnFilter2(G.buildpathHPFS)));
+ FnFilter1(fn), FnFilter2(buildpathHPFS)));
+ free(buildpathHPFS);
error = MPN_INF_TRUNC; /* filename truncated */
}
@@ -2289,12 +3557,12 @@
* within the following copy loop, either.
*/
- if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
+ if (G.pInfo->vollabel || !IsVolumeOldFATw(__G__ G.buildpathHPFSw)) {
/* copy to FAT filename, too */
- p = pathcomp;
- while ((*G.endFAT = *p++) != '\0')
- ++G.endFAT;
+ pw = pathcompw;
+ while ((*G.endFATw = *pw++) != '\0')
+ ++G.endFATw;
} else
/* map into FAT fn, update endFAT */
- map2fat(pathcomp, &G.endFAT);
+ map2fatw(pathcompw, &G.endFATw);
/* Check that the FAT path does not exceed the FILNAMSIZ limit, and
@@ -2305,8 +3573,16 @@
* has already happened.
*/
- if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ)
- G.buildpathFAT[FILNAMSIZ-1] = '\0';
- Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT: %s\n",
- FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
+ if ((G.endFATw-G.buildpathFATw) >= FILNAMSIZ)
+ G.buildpathFATw[FILNAMSIZ-1] = '\0';
+ {
+ char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
+ char *buildpathFAT = wchar_to_local_string(G.buildpathFATw,G.unicode_escape_all);
+ Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT: %s\n",
+ FnFilter1(buildpathHPFS), FnFilter2(buildpathFAT)));
+ free(buildpathHPFS);
+ free(buildpathFAT);
+ }
+ free(fn);
+ free(pathcomp);
return error; /* could check for existence, prompt for new name... */
@@ -2321,33 +3597,23 @@
if (FUNCTION == INIT) {
- Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
-#ifdef ACORN_FTYPE_NFS
- if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+
- (uO.acorn_nfs_ext ? 5 : 1)))
-#else
- if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1))
-#endif
+ Trace((stderr, "initializing buildpathHPFSw and buildpathFATw to "));
+ if ((G.buildpathHPFSw = (wchar_t *)malloc((G.fnlen+G.rootlen+1) * sizeof(wchar_t)))
== NULL)
return MPN_NOMEM;
-#ifdef ACORN_FTYPE_NFS
- if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+
- (uO.acorn_nfs_ext ? 5 : 1)))
-#else
- if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1))
-#endif
+ if ((G.buildpathFATw = (wchar_t *)malloc((G.fnlen+G.rootlen+1) * sizeof(wchar_t)))
== NULL) {
- free(G.buildpathHPFS);
+ free(G.buildpathHPFSw);
return MPN_NOMEM;
}
if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */
/* GRR: for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
- if (G.renamed_fullpath && pathcomp[1] == ':')
- *G.buildpathHPFS = (char)ToLower(*pathcomp);
+ if (G.renamed_fullpath && pathcompw[1] == ':')
+ *G.buildpathHPFSw = (wchar_t)towlower(*pathcompw);
else if (!G.renamed_fullpath && G.rootlen > 1 &&
- G.rootpath[1] == ':')
- *G.buildpathHPFS = (char)ToLower(*G.rootpath);
+ G.rootpathw[1] == ':')
+ *G.buildpathHPFSw = (wchar_t)towlower(*G.rootpathw);
else {
- char tmpN[MAX_PATH], *tmpP;
- if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
+ wchar_t tmpNw[MAX_PATH], *tmpPw;
+ if (GetFullPathNameW(L".", MAX_PATH, tmpNw, &tmpPw) > MAX_PATH)
{ /* by definition of MAX_PATH we should never get here */
Info(slide, 1, ((char *)slide,
@@ -2355,28 +3621,33 @@
return MPN_INF_TRUNC; /* can't get drive letter */
}
- G.nLabelDrive = *tmpN - 'a' + 1;
- *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a');
+ G.nLabelDrive = (char)(*tmpNw - 'a' + 1);
+ *G.buildpathHPFSw = (wchar_t)(G.nLabelDrive - 1 + 'a');
}
- G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */
- if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */
+ G.nLabelDrive = (char)(*G.buildpathHPFSw - 'a' + 1); /* save for mapname() */
+ if (uO.volflag == 0 || *G.buildpathHPFSw < 'a' /* no labels/bogus? */
|| (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */
- free(G.buildpathHPFS);
- free(G.buildpathFAT);
+ free(G.buildpathHPFSw);
+ free(G.buildpathFATw);
return MPN_VOL_LABEL; /* skipping with message */
}
- *G.buildpathHPFS = '\0';
+ *G.buildpathHPFSw = '\0';
} else if (G.renamed_fullpath) /* pathcomp = valid data */
- strcpy(G.buildpathHPFS, pathcomp);
+ wcscpy(G.buildpathHPFSw, pathcompw);
else if (G.rootlen > 0)
- strcpy(G.buildpathHPFS, G.rootpath);
+ wcscpy(G.buildpathHPFSw, G.rootpathw);
else
- *G.buildpathHPFS = '\0';
- G.endHPFS = G.buildpathHPFS;
- G.endFAT = G.buildpathFAT;
- while ((*G.endFAT = *G.endHPFS) != '\0') {
- ++G.endFAT;
- ++G.endHPFS;
+ *G.buildpathHPFSw = '\0';
+ G.endHPFSw = G.buildpathHPFSw;
+ G.endFATw = G.buildpathFATw;
+ while ((*G.endFATw = *G.endHPFSw) != '\0') {
+ ++G.endFATw;
+ ++G.endHPFSw;
}
- Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS)));
+ {
+ char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
+ Trace((stderr, "[%s]\n", FnFilter1(buildpathHPFS)));
+ free(buildpathHPFS);
+ }
+
return MPN_OK;
}
@@ -2395,7 +3666,9 @@
#if (!defined(SFX) || defined(SFX_EXDIR))
if (FUNCTION == ROOT) {
+ char *pathcomp = wchar_to_local_string(pathcompw, G.unicode_escape_all);
Trace((stderr, "initializing root path to [%s]\n",
FnFilter1(pathcomp)));
- if (pathcomp == NULL) {
+ free(pathcomp);
+ if (pathcompw == NULL) {
G.rootlen = 0;
return MPN_OK;
@@ -2403,17 +3676,17 @@
if (G.rootlen > 0) /* rootpath was already set, nothing to do */
return MPN_OK;
- if ((G.rootlen = strlen(pathcomp)) > 0) {
+ if ((G.rootlen = wcslen(pathcompw)) > 0) {
int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE;
- char *tmproot;
+ wchar_t *tmprootw;
- if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) {
+ if ((tmprootw = (wchar_t *)malloc((G.rootlen+3) * sizeof(wchar_t))) == (wchar_t *)NULL) {
G.rootlen = 0;
return MPN_NOMEM;
}
- strcpy(tmproot, pathcomp);
- if (isalpha((uch)tmproot[0]) && tmproot[1] == ':')
+ wcscpy(tmprootw, pathcompw);
+ if (iswalpha(tmprootw[0]) && tmprootw[1] == ':')
has_drive = TRUE; /* drive designator */
- if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') {
- tmproot[--G.rootlen] = '\0';
+ if (tmprootw[G.rootlen-1] == '/' || tmprootw[G.rootlen-1] == '\\') {
+ tmprootw[--G.rootlen] = '\0';
had_trailing_pathsep = TRUE;
}
@@ -2422,9 +3695,9 @@
add_dot = TRUE; /* relative path: add '.' before '/' */
} else if (G.rootlen > 0) { /* need not check "x:." and "x:/" */
- if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
+ if (SSTATW(tmprootw, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
{
/* path does not exist */
if (!G.create_dirs /* || iswild(tmproot) */ ) {
- free(tmproot);
+ free(tmprootw);
G.rootlen = 0;
/* treat as stored file */
@@ -2433,12 +3706,15 @@
/* create directory (could add loop here scanning tmproot
* to create more than one level, but really necessary?) */
- if (MKDIR(tmproot, 0777) == -1) {
+ if (MKDIRW(tmprootw, 0777) == -1) {
+ char *tmproot = wchar_to_local_string(tmprootw, G.unicode_escape_all);
Info(slide, 1, ((char *)slide,
"checkdir: cannot create extraction directory: %s\n",
FnFilter1(tmproot)));
free(tmproot);
+ free(tmprootw);
G.rootlen = 0;
/* path didn't exist, tried to create, failed: */
/* file exists, or need 2+ subdir levels */
+ free(pathcomp);
return MPN_ERR_SKIP;
}
@@ -2446,13 +3722,17 @@
}
if (add_dot) /* had just "x:", make "x:." */
- tmproot[G.rootlen++] = '.';
- tmproot[G.rootlen++] = '/';
- tmproot[G.rootlen] = '\0';
- if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
- free(tmproot);
+ tmprootw[G.rootlen++] = '.';
+ tmprootw[G.rootlen++] = '/';
+ tmprootw[G.rootlen] = '\0';
+ if ((G.rootpathw = (wchar_t *)realloc(tmprootw, (G.rootlen+1) * sizeof(wchar_t))) == NULL) {
+ free(tmprootw);
G.rootlen = 0;
return MPN_NOMEM;
}
- Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
+ {
+ char *rootpath = wchar_to_local_string(G.rootpathw, G.unicode_escape_all);
+ Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
+ free(rootpath);
+ }
}
return MPN_OK;
@@ -2467,5 +3747,5 @@
Trace((stderr, "freeing rootpath\n"));
if (G.rootlen > 0) {
- free(G.rootpath);
+ free(G.rootpathw);
G.rootlen = 0;
}
@@ -2475,6 +3755,7 @@
return MPN_INVALID; /* should never reach */
-} /* end function checkdir() */
+} /* end function checkdirw() */
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
@@ -2809,4 +4090,99 @@
}
+
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
+
+int zstat_win32w(__W32STAT_GLOBALS__ const wchar_t *pathw, z_stat *buf)
+{
+ if (!zstatw(pathw, buf))
+ {
+ char *path = wchar_to_local_string((wchar_t *)pathw, G.unicode_escape_all);
+ /* stat was successful, now redo the time-stamp fetches */
+#ifndef NO_W32TIMES_IZFIX
+ int fs_uses_loctime = FStampIsLocTimeW(__G__ pathw);
+#endif
+ HANDLE h;
+ FILETIME Modft, Accft, Creft;
+
+ TTrace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
+ h = CreateFileW(pathw, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h != INVALID_HANDLE_VALUE) {
+ BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+ CloseHandle(h);
+
+ if (ftOK) {
+ FTTrace((stdout, "GetFileTime returned Modft", 0, &Modft));
+ FTTrace((stdout, "GetFileTime returned Creft", 0, &Creft));
+#ifndef NO_W32TIMES_IZFIX
+ if (!fs_uses_loctime) {
+ /* On a filesystem that stores UTC timestamps, we refill
+ * the time fields of the struct stat buffer by directly
+ * using the UTC values as returned by the Win32
+ * GetFileTime() API call.
+ */
+ NtfsFileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ NtfsFileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ NtfsFileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ TTrace((stdout,"NTFS, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ } else
+#endif /* NO_W32TIMES_IZFIX */
+ {
+ /* On VFAT and FAT-like filesystems, the FILETIME values
+ * are converted back to the stable local time before
+ * converting them to UTC unix time-stamps.
+ */
+ VFatFileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ TTrace((stdout, "VFAT, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ }
+ }
+ }
+ free(path);
+
+ return 0;
+ }
+#ifdef W32_STATROOT_FIX
+ else
+ {
+ DWORD flags;
+
+ flags = GetFileAttributesW(pathw);
+ if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
+ char *path = wchar_to_local_string((wchar_t *)pathw, G.unicode_escape_all);
+ Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
+ FnFilter1(path)));
+ free(path);
+ memset(buf, 0, sizeof(z_stat));
+ buf->st_atime = buf->st_ctime = buf->st_mtime =
+ dos_to_unix_time(DOSTIME_MINIMUM); /* 1-1-80 */
+ buf->st_mode = S_IFDIR | S_IREAD |
+ ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
+ return 0;
+ } /* assumes: stat() won't fail on non-dirs without good reason */
+ }
+#endif /* W32_STATROOT_FIX */
+ return -1;
+}
+
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
+
#endif /* W32_STAT_BANDAID */
@@ -2939,6 +4315,5 @@
-#if 0
-#ifdef UNICODE_SUPPORT
+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
wchar_t *utf8_to_wchar_string(utf8_string)
char *utf8_string; /* path to get utf-8 name for */
@@ -3030,22 +4405,40 @@
return qw;
}
-#endif /* UNICODE_SUPPORT */
-#endif /* 0 */
+int has_win32_wide()
+{
+ int is_win32_wide;
+ /* test if we have wide function support */
-/* --------------------------------------------------- */
-/* Large File Support
- *
- * Initial functions by E. Gordon and R. Nausedat
- * 9/10/2003
- * Lifted from Zip 3b, win32.c and place here by Myles Bennett
- * 7/6/2004
- *
- * These implement 64-bit file support for Windows. The
- * defines and headers are in win32/w32cfg.h.
- *
- * Moved to win32i64.c by Mike White to avoid conflicts in
- * same name functions in WiZ using UnZip and Zip libraries.
- * 9/25/2003
- */
+ /* first guess: On "real" WinNT, the WIN32 wide API >>is<< supported. */
+ is_win32_wide = IsWinNT();
+
+ if (!is_win32_wide)
+ {
+ /* On a non-WinNT environment (Win9x or Win32s), wide functions
+ * might although supported when program is linked against the
+ * Win9x Unicode support library.
+ * => run a check whether a needed API function is supported.
+ */
+ DWORD r;
+ /* get attributes for this directory */
+ r = GetFileAttributesA(".");
+
+ /* r should be 16 = FILE_ATTRIBUTE_DIRECTORY */
+ if (r == FILE_ATTRIBUTE_DIRECTORY) {
+ /* now see if it works for the wide version */
+ r = GetFileAttributesW(L".");
+ /* if this fails then we probably don't have wide functions */
+ if (r == 0xFFFFFFFF) {
+ /* error is probably "This function is only valid in Win32 mode." */
+ } else if (r == FILE_ATTRIBUTE_DIRECTORY) {
+ /* worked, so assume we have wide support */
+ is_win32_wide = TRUE;
+ }
+ }
+ }
+ return is_win32_wide;
+}
+
+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
diff -ru2 unz60d10/windll/vc6/dll/unz32dll.dsp unz60d10_w32w/windll/vc6/dll/unz32dll.dsp
--- unz60d10/windll/vc6/dll/unz32dll.dsp Wed Dec 27 23:25:00 2006
+++ unz60d10_w32w/windll/vc6/dll/unz32dll.dsp Mon Feb 11 02:38:32 2008
@@ -46,5 +46,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c
-# 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
+# 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
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
@@ -72,5 +72,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c
-# 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
+# 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
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
@@ -98,5 +98,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c
-# 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
+# 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
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
@@ -124,5 +124,5 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c
-# 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
+# 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
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32