Archive-Unzip-Burst

 view release on metacpan or  search on metacpan

unzip-6.0/win32-experimental/unz60d10_w32wide-Unicode_patch.txt  view on Meta::CPAN

+                                          &(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';

unzip-6.0/win32-experimental/unz60d10_w32wide-Unicode_patch.txt  view on Meta::CPAN

+            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



( run in 1.778 second using v1.01-cache-2.11-cpan-d7f47b0818f )