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_methodENHDEFLATED \ + && 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_methodENHDEFLATED \ - && 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 +#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