home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip540.zip / win32 / win32.c < prev   
C/C++ Source or Header  |  1998-11-28  |  86KB  |  2,391 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   win32.c
  4.  
  5.   32-bit Windows-specific (NT/95) routines for use with Info-ZIP's UnZip 5.3
  6.   and later.
  7.  
  8.   Contains:  GetLoadPath()
  9.              Opendir()
  10.              Readdir()
  11.              Closedir()
  12.              process_defer_NT()   process any deferred items
  13.              SetSD()              set security descriptor on file
  14.              EvalExtraFields()    evaluate and process and extra field NOW
  15.              IsWinNT()            indicate type of WIN32 platform
  16.              test_NTSD()          test integrity of NT security data
  17.              utime2FileTime()
  18.              FStampIsLocTime()
  19.              FileTime2utime()
  20.              VFatFileTime2utime()
  21.              UTCtime2Localtime()
  22.              NTtzbugWorkaround()
  23.              getNTfiletime()
  24.              close_outfile()
  25.              stamp_file()
  26.              isfloppy()
  27.              NTQueryVolInfo()
  28.              IsVolumeOldFAT()
  29.              do_wild()
  30.              mapattr()
  31.              mapname()
  32.              map2fat()
  33.              checkdir()
  34.              version()
  35.              zstat_win32()
  36.              getch_win32()
  37.  
  38.   ---------------------------------------------------------------------------*/
  39.  
  40.  
  41. #define UNZIP_INTERNAL
  42. #include "unzip.h"
  43. #include <windows.h>    /* must be AFTER unzip.h to avoid struct G problems */
  44. #ifdef __RSXNT__
  45. #  include "win32/rsxntwin.h"
  46. #endif
  47. #include "win32/nt.h"
  48.  
  49. #ifndef FUNZIP          /* most of this file is not used with fUnZip */
  50.  
  51. #if (defined(__GO32__) || defined(__EMX__) || defined(__CYGWIN32__))
  52. #  define MKDIR(path,mode)   mkdir(path,mode)
  53. #else
  54. #  define MKDIR(path,mode)   mkdir(path)
  55. #endif
  56.  
  57. #ifdef HAVE_WORKING_DIRENT_H
  58. #  undef HAVE_WORKING_DIRENT_H
  59. #endif
  60. /* The emxrtl dirent support of (__GO32__ || __EMX__) converts to lowercase! */
  61. #if defined(__CYGWIN32__)
  62. #  define HAVE_WORKING_DIRENT_H
  63. #endif
  64.  
  65. #ifndef SFX
  66. #  ifdef HAVE_WORKING_DIRENT_H
  67. #    include <dirent.h>         /* use readdir() */
  68. #    define zdirent  dirent
  69. #    define zDIR     DIR
  70. #    define Opendir  opendir
  71. #    define Readdir  readdir
  72. #    define Closedir closedir
  73. #  else /* !HAVE_WORKING_DIRENT_H */
  74.      typedef struct zdirent {
  75.          char    reserved [21];
  76.          char    ff_attrib;
  77.          short   ff_ftime;
  78.          short   ff_fdate;
  79.          long    size;
  80.          char    d_name[MAX_PATH];
  81.          int     d_first;
  82.          HANDLE  d_hFindFile;
  83.      } zDIR;
  84.  
  85.      static zDIR           *Opendir  (const char *n);
  86.      static struct zdirent *Readdir  (zDIR *d);
  87.      static void            Closedir (zDIR *d);
  88. #  endif /* ?HAVE_WORKING_DIRENT_H */
  89. #endif /* !SFX */
  90.  
  91.  
  92. /* Function prototypes */
  93. #ifdef NTSD_EAS
  94.    static int  SetSD(__GPRO__ char *path, PVOLUMECAPS VolumeCaps,
  95.                      uch *eb_ptr, unsigned eb_len);
  96.    static int  EvalExtraFields(__GPRO__ char *path, uch *ef_ptr,
  97.                                unsigned ef_len);
  98. #endif
  99.  
  100. #if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND) || \
  101.      defined(TIMESTAMP))
  102.    static void utime2FileTime(time_t ut, FILETIME *pft);
  103.    static int FStampIsLocTime(__GPRO__ const char *path);
  104. #endif /* USE_EF_UT_TIME || NT_TZBUG_WORKAROUND || TIMESTAMP */
  105. #ifdef NT_TZBUG_WORKAROUND
  106.    static int FileTime2utime(const FILETIME *pft, time_t *ut);
  107. #ifdef W32_STAT_BANDAID
  108.    static int VFatFileTime2utime(const FILETIME *pft, time_t *ut);
  109. #endif
  110.    static time_t UTCtime2Localtime(time_t utctime);
  111.    static void NTtzbugWorkaround(time_t ut, FILETIME *pft);
  112. #endif /* NT_TZBUG_WORKAROUND */
  113.  
  114. static int  getNTfiletime   (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT,
  115.                              FILETIME *pCreFT);
  116. static int  isfloppy        (int nDrive);
  117. static int  NTQueryVolInfo  (__GPRO__ const char *name);
  118. static int  IsVolumeOldFAT  (__GPRO__ const char *name);
  119. static void map2fat         (char *pathcomp, char **pEndFAT);
  120.  
  121.  
  122. #ifdef __MINGW32__
  123.    int _CRT_glob = 0;   /* suppress command line globbing by C RTL */
  124. #endif
  125.  
  126. /* static int created_dir;      */     /* used by mapname(), checkdir() */
  127. /* static int renamed_fullpath; */     /* ditto */
  128. /* static int fnlen;            */     /* ditto */
  129. /* static unsigned nLabelDrive; */     /* ditto */
  130.  
  131. extern char Far TruncNTSD[];    /* in extract.c */
  132.  
  133.  
  134.  
  135. #ifdef SFX
  136.  
  137. /**************************/
  138. /* Function GetLoadPath() */
  139. /**************************/
  140.  
  141. char *GetLoadPath(__GPRO)
  142. {
  143. #ifdef MSC
  144.     extern char *_pgmptr;
  145.     return _pgmptr;
  146.  
  147. #else    /* use generic API call */
  148.  
  149.     GetModuleFileName(NULL, G.filename, FILNAMSIZ-1);
  150.     _ISO_INTERN(G.filename);    /* translate to codepage of C rtl's stdio */
  151.     return G.filename;
  152. #endif
  153.  
  154. } /* end function GetLoadPath() */
  155.  
  156.  
  157.  
  158.  
  159.  
  160. #else /* !SFX */
  161.  
  162. #ifndef HAVE_WORKING_DIRENT_H
  163.  
  164. /**********************/        /* Borrowed from ZIP 2.0 sources            */
  165. /* Function Opendir() */        /* Difference: no special handling for      */
  166. /**********************/        /*             hidden or system files.      */
  167.  
  168. static zDIR *Opendir(n)
  169.     const char *n;          /* directory to open */
  170. {
  171.     zDIR *d;                /* malloc'd return value */
  172.     char *p;                /* malloc'd temporary string */
  173.     WIN32_FIND_DATA fd;
  174.     extent len = strlen(n);
  175.  
  176.     /* Start searching for files in directory n */
  177.  
  178.     if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL ||
  179.         (p = malloc(strlen(n) + 5)) == NULL)
  180.     {
  181.         if (d != (zDIR *)NULL)
  182.             free((void *)d);
  183.         return (zDIR *)NULL;
  184.     }
  185.     INTERN_TO_ISO(n, p);
  186.     if (len > 0) {
  187.         if (p[len-1] == ':')
  188.             p[len++] = '.';     /* x: => x:. */
  189.         else if (p[len-1] == '/' || p[len-1] == '\\')
  190.             --len;              /* foo/ => foo */
  191.     }
  192.     strcpy(p+len, "/*");
  193.  
  194.     if (INVALID_HANDLE_VALUE == (d->d_hFindFile = FindFirstFile(p, &fd))) {
  195.         free((zvoid *)d);
  196.         free((zvoid *)p);
  197.         return NULL;
  198.     }
  199.     strcpy(d->d_name, fd.cFileName);
  200.  
  201.     free((zvoid *)p);
  202.     d->d_first = 1;
  203.     return d;
  204.  
  205. } /* end of function Opendir() */
  206.  
  207.  
  208.  
  209.  
  210. /**********************/        /* Borrowed from ZIP 2.0 sources            */
  211. /* Function Readdir() */        /* Difference: no special handling for      */
  212. /**********************/        /*             hidden or system files.      */
  213.  
  214. static struct zdirent *Readdir(d)
  215.     zDIR *d;                    /* directory stream from which to read */
  216. {
  217.     /* Return pointer to first or next directory entry, or NULL if end. */
  218.  
  219.     if ( d->d_first )
  220.         d->d_first = 0;
  221.     else
  222.     {
  223.         WIN32_FIND_DATA fd;
  224.  
  225.         if ( !FindNextFile(d->d_hFindFile, &fd) )
  226.             return NULL;
  227.  
  228.         ISO_TO_INTERN(fd.cFileName, d->d_name);
  229.     }
  230.     return (struct zdirent *)d;
  231.  
  232. } /* end of function Readdir() */
  233.  
  234.  
  235.  
  236.  
  237. /***********************/
  238. /* Function Closedir() */       /* Borrowed from ZIP 2.0 sources */
  239. /***********************/
  240.  
  241. static void Closedir(d)
  242.     zDIR *d;                    /* directory stream to close */
  243. {
  244.     FindClose(d->d_hFindFile);
  245.     free(d);
  246. }
  247.  
  248. #endif /* !HAVE_WORKING_DIRENT_H */
  249. #endif /* ?SFX */
  250.  
  251.  
  252.  
  253.  
  254. #ifdef NTSD_EAS
  255.  
  256. /*********************************/
  257. /*  Function process_defer_NT()  */
  258. /*********************************/
  259.  
  260. void process_defer_NT(__G)
  261.     __GDEF
  262. {
  263.     /* process deferred items */
  264.  
  265.     DWORD dir, bytes;
  266.     DWORD dirfail, bytesfail;
  267.  
  268.     ProcessDefer(&dir, &bytes, &dirfail, &bytesfail);
  269.  
  270.     if (!uO.tflag && (uO.qflag < 2)) {
  271.         if (dir)
  272.             Info(slide, 0, ((char *)slide,
  273.               "    updated: %lu directory entries with %lu bytes security",
  274.               (ulg)dir, (ulg)bytes));
  275.         if (dirfail)
  276.             Info(slide, 0, ((char *)slide,
  277.               "     failed: %lu directory entries with %lu bytes security",
  278.               (ulg)dirfail, (ulg)bytesfail));
  279.     }
  280. }
  281.  
  282.  
  283.  
  284. /**********************/
  285. /*  Function SetSD()  */   /* return almost-PK errors */
  286. /**********************/
  287.  
  288. static int SetSD(__G__ path, VolumeCaps, eb_ptr, eb_len)
  289.     __GDEF
  290.     char *path;
  291.     PVOLUMECAPS VolumeCaps;
  292.     uch *eb_ptr;
  293.     unsigned eb_len;
  294. {
  295.     ulg ntsd_ucSize;
  296.     uch *security_data;
  297.     int error;
  298.  
  299.     if (eb_ptr == NULL || eb_len < EB_NTSD_L_LEN)
  300.         return PK_OK;  /* not a valid NTSD extra field:  assume OK */
  301.  
  302.     /* check if we know how to handle this version */
  303.     if (*(eb_ptr + (EB_HEADSIZE+EB_NTSD_VERSION)) > (uch)EB_NTSD_MAX_VER)
  304.         return PK_OK;
  305.  
  306.     ntsd_ucSize = makelong(eb_ptr + (EB_HEADSIZE+EB_UCSIZE_P));
  307.     if (ntsd_ucSize > 0L && eb_len <= (EB_NTSD_L_LEN + EB_CMPRHEADLEN))
  308.         return IZ_EF_TRUNC;               /* no compressed data! */
  309.  
  310.     /* allocate storage for uncompressed data */
  311.     security_data = (uch *)malloc((extent)ntsd_ucSize);
  312.     if (security_data == (uch *)NULL)
  313.         return PK_MEM4;
  314.  
  315.     error = memextract(__G__ security_data, ntsd_ucSize,
  316.       (eb_ptr + (EB_HEADSIZE+EB_NTSD_L_LEN)), (ulg)(eb_len - EB_NTSD_L_LEN));
  317.  
  318.     if (error == PK_OK) {
  319.         if (SecuritySet(path, VolumeCaps, security_data)) {
  320.             error = PK_COOL;
  321.             if (!uO.tflag && (uO.qflag < 2) &&
  322.                 (!(VolumeCaps->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))
  323.                 Info(slide, 0, ((char *)slide, " (%ld bytes security)",
  324.                   ntsd_ucSize));
  325.         }
  326.     }
  327.  
  328.     free(security_data);
  329.     return error;
  330. }
  331.  
  332.  
  333.  
  334.  
  335. /********************************/   /* scan extra fields for something */
  336. /*  Function EvalExtraFields()  */   /*  we happen to know */
  337. /********************************/
  338.  
  339. static int EvalExtraFields(__G__ path, ef_ptr, ef_len)
  340.     __GDEF
  341.     char *path;
  342.     uch *ef_ptr;
  343.     unsigned ef_len;
  344. {
  345.     int rc = PK_OK;
  346.  
  347.     if (!uO.X_flag)
  348.         return PK_OK;  /* user said don't process ACLs; for now, no other
  349.                           extra block types are handled here */
  350.  
  351.     while (ef_len >= EB_HEADSIZE)
  352.     {
  353.         unsigned eb_id = makeword(EB_ID + ef_ptr);
  354.         unsigned eb_len = makeword(EB_LEN + ef_ptr);
  355.  
  356.         if (eb_len > (ef_len - EB_HEADSIZE)) {
  357.             /* discovered some extra field inconsistency! */
  358.             Trace((stderr,
  359.               "EvalExtraFields: block length %u > rest ef_size %u\n", eb_len,
  360.               ef_len - EB_HEADSIZE));
  361.             break;
  362.         }
  363.  
  364.         switch (eb_id)
  365.         {
  366.             /* process security descriptor extra data if:
  367.                  Caller is WinNT AND
  368.                  Target local/remote drive supports acls AND
  369.                  Target file is not a directory (else we defer processing
  370.                    until later)
  371.              */
  372.             case EF_NTSD:
  373.                 if (IsWinNT()) {
  374.                     VOLUMECAPS VolumeCaps;
  375.  
  376.                     /* provide useful input */
  377.                     VolumeCaps.dwFileAttributes = G.pInfo->file_attr;
  378.                     VolumeCaps.bUsePrivileges = (uO.X_flag > 1);
  379.  
  380.                     /* check target volume capabilities - just fall through
  381.                      * and try if fail */
  382.                     if (GetVolumeCaps(G.rootpath, path, &VolumeCaps) &&
  383.                         !(VolumeCaps.dwFileSystemFlags & FS_PERSISTENT_ACLS))
  384.                     {
  385.                         rc = PK_OK;
  386.                         break;
  387.                     }
  388.                     rc = SetSD(__G__ path, &VolumeCaps, ef_ptr, eb_len);
  389.                 } else
  390.                     rc = PK_OK;
  391.                 break;
  392.  
  393. #if 0
  394.             /* perhaps later we can add support for unzipping OS/2 EAs to NT */
  395.             case EF_OS2:
  396.                 rc = SetEAs(__G__ path, ef_ptr);
  397.                 break;
  398.  
  399.             case EF_PKUNIX:
  400.             case EF_IZUNIX:
  401.             case EF_IZUNIX2:
  402.             case EF_TIME:
  403.                 break;          /* handled elsewhere */
  404. #else /* ! 0 */
  405. #ifdef DEBUG
  406.             case EF_AV:
  407.             case EF_OS2:
  408.             case EF_PKVMS:
  409.             case EF_PKW32:
  410.             case EF_PKUNIX:
  411.             case EF_IZVMS:
  412.             case EF_IZUNIX:
  413.             case EF_IZUNIX2:
  414.             case EF_TIME:
  415.             case EF_MAC3:
  416.             case EF_JLMAC:
  417.             case EF_ZIPIT:
  418.             case EF_VMCMS:
  419.             case EF_MVS:
  420.             case EF_ACL:
  421.             case EF_BEOS:
  422.             case EF_QDOS:
  423.             case EF_AOSVS:
  424.             case EF_SPARK:
  425.             case EF_MD5:
  426.             case EF_ASIUNIX:
  427.                 break;          /* shut up for other known e.f. blocks  */
  428. #endif /* DEBUG */
  429. #endif /* ? 0 */
  430.  
  431.             default:
  432.                 Trace((stderr,
  433.                   "EvalExtraFields: unknown extra field block, ID=%u\n",
  434.                   eb_id));
  435.                 break;
  436.         }
  437.  
  438.         ef_ptr += (eb_len + EB_HEADSIZE);
  439.         ef_len -= (eb_len + EB_HEADSIZE);
  440.  
  441.         if (rc != PK_OK)
  442.             break;
  443.     }
  444.  
  445.     return rc;
  446. }
  447.  
  448.  
  449.  
  450.  
  451. #ifndef SFX
  452.  
  453. /**************************/
  454. /*  Function test_NTSD()  */   /*  returns PK_WARN when NTSD data is invalid */
  455. /**************************/
  456.  
  457. #ifdef __BORLANDC__
  458. /* Turn off warning about not using all parameters for this function only */
  459. #pragma argsused
  460. #endif
  461. int test_NTSD(__G__ eb, eb_size, eb_ucptr, eb_ucsize)
  462.     __GDEF
  463.     uch *eb;
  464.     unsigned eb_size;
  465.     uch *eb_ucptr;
  466.     ulg eb_ucsize;
  467. {
  468.     int r = PK_OK;
  469.  
  470.     if (!ValidateSecurity(eb_ucptr))
  471.         r = PK_WARN;
  472.     return r;
  473.  
  474. } /* end function test_NTSD() */
  475.  
  476. #endif /* !SFX */
  477. #endif /* NTSD_EAS */
  478.  
  479.  
  480.  
  481.  
  482. /**********************/
  483. /* Function IsWinNT() */
  484. /**********************/
  485.  
  486. int IsWinNT(void)       /* returns TRUE if real NT, FALSE if Win95 or Win32s */
  487. {
  488.     static DWORD g_PlatformId = 0xFFFFFFFF; /* saved platform indicator */
  489.  
  490.     if (g_PlatformId == 0xFFFFFFFF) {
  491.         /* note: GetVersionEx() doesn't exist on WinNT 3.1 */
  492.         if (GetVersion() < 0x80000000)
  493.             g_PlatformId = TRUE;
  494.         else
  495.             g_PlatformId = FALSE;
  496.     }
  497.     return (int)g_PlatformId;
  498. }
  499.  
  500.  
  501. /* DEBUG_TIME insertion: */
  502. #ifdef DEBUG_TIME
  503. static int show_NTFileTime(FILE *hdo, char *TTmsg, int isloc, FILETIME *pft);
  504.  
  505. static int show_NTFileTime(FILE *hdo, char *TTmsg, int isloc, FILETIME *pft)
  506. {
  507.     SYSTEMTIME w32tm;
  508.     int rval;
  509.  
  510.     rval = FileTimeToSystemTime(pft, &w32tm);
  511.     if (!rval) {
  512.         fprintf(hdo, "%s\n %08lX,%08lX (%s) -> Conversion failed !!!\n",
  513.                 TTmsg, (ulg)(pft->dwHighDateTime), (ulg)(pft->dwLowDateTime),
  514.                 (isloc ? "local" : "UTC"));
  515.     } else {
  516.         fprintf(hdo, "%s\n %08lx,%08lx -> %04u-%02u-%02u, %02u:%02u:%02u %s\n",
  517.                 TTmsg, (ulg)(pft->dwHighDateTime), (ulg)(pft->dwLowDateTime),
  518.                 w32tm.wYear, w32tm.wMonth, w32tm.wDay, w32tm.wHour,
  519.                 w32tm.wMinute, w32tm.wSecond, (isloc ? "local" : "UTC"));
  520.     }
  521.     return rval;
  522. }
  523. #define FTTrace(x)   show_NTFileTime x
  524. #else
  525. #define FTTrace(x)
  526. #endif /* DEBUG_TIME */
  527. /* end of TIME_DEBUG insertion */
  528.  
  529. #if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND) || \
  530.      defined(TIMESTAMP))
  531.  
  532. #if ((defined(__GNUC__) || defined(ULONG_LONG_MAX)) && !defined(HAVE_INT64))
  533.    typedef long long            LLONG64;
  534.    typedef unsigned long long   ULLNG64;
  535. #  define HAVE_INT64
  536. #endif
  537. #if (defined(__WATCOMC__) && (__WATCOMC__ >= 1100) && !defined(HAVE_INT64))
  538.    typedef __int64              LLONG64;
  539.    typedef unsigned __int64     ULLNG64;
  540. #  define HAVE_INT64
  541. #endif
  542. #if (defined(_MSC_VER) && (_MSC_VER >= 1100) && !defined(HAVE_INT64))
  543.    typedef __int64              LLONG64;
  544.    typedef unsigned __int64     ULLNG64;
  545. #  define HAVE_INT64
  546. #endif
  547.  
  548. /*****************************/
  549. /* Function utime2FileTime() */     /* convert Unix time_t format into the */
  550. /*****************************/     /* form used by SetFileTime() in NT/95 */
  551.  
  552. #define UNIX_TIME_ZERO_HI  0x019DB1DEUL
  553. #define UNIX_TIME_ZERO_LO  0xD53E8000UL
  554. #define NT_QUANTA_PER_UNIX 10000000L
  555.  
  556. static void utime2FileTime(time_t ut, FILETIME *pft)
  557. {
  558. #ifdef HAVE_INT64
  559.     ULLNG64 NTtime;
  560.  
  561.     /* NT_QUANTA_PER_UNIX is small enough so that "ut * NT_QUANTA_PER_UNIX"
  562.      * cannot overflow in 64-bit signed calculation, regardless wether "ut"
  563.      * is signed or unsigned.  */
  564.     NTtime = ((LLONG64)ut * NT_QUANTA_PER_UNIX) +
  565.              ((ULLNG64)UNIX_TIME_ZERO_LO + ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
  566.     pft->dwLowDateTime = (DWORD)NTtime;
  567.     pft->dwHighDateTime = (DWORD)(NTtime >> 32);
  568.  
  569. #else /* !HAVE_INT64 (64-bit integer arithmetics may not be supported) */
  570.     unsigned int b1, b2, carry = 0;
  571.     unsigned long r0, r1, r2, r3;
  572.     long r4;            /* signed, to catch environments with signed time_t */
  573.  
  574.     b1 = ut & 0xFFFF;
  575.     b2 = (ut >> 16) & 0xFFFF;       /* if ut is over 32 bits, too bad */
  576.     r1 = b1 * (NT_QUANTA_PER_UNIX & 0xFFFF);
  577.     r2 = b1 * (NT_QUANTA_PER_UNIX >> 16);
  578.     r3 = b2 * (NT_QUANTA_PER_UNIX & 0xFFFF);
  579.     r4 = b2 * (NT_QUANTA_PER_UNIX >> 16);
  580.     r0 = (r1 + (r2 << 16)) & 0xFFFFFFFFL;
  581.     if (r0 < r1)
  582.         carry++;
  583.     r1 = r0;
  584.     r0 = (r0 + (r3 << 16)) & 0xFFFFFFFFL;
  585.     if (r0 < r1)
  586.         carry++;
  587.     pft->dwLowDateTime = r0 + UNIX_TIME_ZERO_LO;
  588.     if (pft->dwLowDateTime < r0)
  589.         carry++;
  590.     pft->dwHighDateTime = r4 + (r2 >> 16) + (r3 >> 16)
  591.                             + UNIX_TIME_ZERO_HI + carry;
  592. #endif /* ?HAVE_INT64 */
  593.  
  594. } /* end function utime2FileTime() */
  595.  
  596.  
  597.  
  598. /******************************/
  599. /* Function FStampIsLocTime() */
  600. /******************************/
  601.  
  602. static int FStampIsLocTime(__GPRO__ const char *path)
  603. {
  604.     return (NTQueryVolInfo(__G__ path) ? G.lastVolLocTim : FALSE);
  605. }
  606.  
  607. #endif /* USE_EF_UT_TIME || NT_TZBUG_WORKAROUND || TIMESTAMP */
  608.  
  609.  
  610.  
  611. #ifndef NT_TZBUG_WORKAROUND
  612. #  define UTIME_BOUNDCHECK_1(utimval) \
  613.      if (fs_uses_loctime) { \
  614.          utime_dosmin = dos_to_unix_time(DOSTIME_MINIMUM); \
  615.          if ((ulg)utimval < (ulg)utime_dosmin) \
  616.              utimval = utime_dosmin; \
  617.      }
  618. #  define UTIME_BOUNDCHECK_N(utimval) \
  619.      if (fs_uses_loctime && ((ulg)utimval < (ulg)utime_dosmin)) \
  620.          utimval = utime_dosmin;
  621. #  define NT_TZBUG_PRECOMPENSATE(ut, pft)
  622.  
  623. #else /* NT_TZBUG_WORKAROUND */
  624. #  define UNIX_TIME_UMAX_HI  0x0236485EUL
  625. #  define UNIX_TIME_UMAX_LO  0xD4A5E980UL
  626. #  define UNIX_TIME_SMIN_HI  0x0151669EUL
  627. #  define UNIX_TIME_SMIN_LO  0xD53E8000UL
  628. #  define UNIX_TIME_SMAX_HI  0x01E9FD1EUL
  629. #  define UNIX_TIME_SMAX_LO  0xD4A5E980UL
  630. #  define UTIME_1980_JAN_01_00_00   315532800L
  631. #  define UTIME_BOUNDCHECK_1(utimval)
  632. #  define UTIME_BOUNDCHECK_N(utimval)
  633. #  define NT_TZBUG_PRECOMPENSATE(ut, pft) \
  634.      if (fs_uses_loctime) NTtzbugWorkaround(ut, pft);
  635.  
  636.    /* nonzero if `y' is a leap year, else zero */
  637. #  define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0)
  638.    /* number of leap years from 1970 to `y' (not including `y' itself) */
  639. #  define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
  640.  
  641. extern ZCONST ush ydays[];              /* defined in fileio.c */
  642.  
  643. /*****************************/
  644. /* Function FileTime2utime() */
  645. /*****************************/
  646.  
  647. static int FileTime2utime(const FILETIME *pft, time_t *ut)
  648. {
  649. #ifdef HAVE_INT64
  650.     ULLNG64 NTtime;
  651.  
  652.     NTtime = ((ULLNG64)pft->dwLowDateTime +
  653.               ((ULLNG64)pft->dwHighDateTime << 32));
  654.  
  655.     /* underflow and overflow handling */
  656. #ifdef CHECK_UTIME_SIGNED_UNSIGNED
  657.     if ((time_t)0x80000000L < (time_t)0L)
  658.     {
  659.         if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO +
  660.                       ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) {
  661.             *ut = (time_t)LONG_MIN;
  662.             return FALSE;
  663.         }
  664.         if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO +
  665.                       ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) {
  666.             *ut = (time_t)LONG_MAX;
  667.             return FALSE;
  668.         }
  669.     }
  670.     else
  671. #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
  672.     {
  673.         if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO +
  674.                       ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) {
  675.             *ut = (time_t)0;
  676.             return FALSE;
  677.         }
  678.         if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO +
  679.                       ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) {
  680.             *ut = (time_t)ULONG_MAX;
  681.             return FALSE;
  682.         }
  683.     }
  684.  
  685.     NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO +
  686.                ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
  687.     *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
  688.     return TRUE;
  689. #else /* !HAVE_INT64 (64-bit integer arithmetics may not be supported) */
  690.     time_t days;
  691.     SYSTEMTIME w32tm;
  692.  
  693.     /* underflow and overflow handling */
  694. #ifdef CHECK_UTIME_SIGNED_UNSIGNED
  695.     if ((time_t)0x80000000L < (time_t)0L)
  696.     {
  697.         if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
  698.             ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
  699.              (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
  700.             *ut = (time_t)LONG_MIN;
  701.             return FALSE;
  702.         if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
  703.             ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
  704.              (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
  705.             *ut = (time_t)LONG_MAX;
  706.             return FALSE;
  707.         }
  708.     }
  709.     else
  710. #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
  711.     {
  712.         if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
  713.             ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
  714.              (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
  715.             *ut = (time_t)0;
  716.             return FALSE;
  717.         }
  718.         if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
  719.             ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
  720.              (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
  721.             *ut = (time_t)ULONG_MAX;
  722.             return FALSE;
  723.         }
  724.     }
  725.  
  726.     FileTimeToSystemTime(pft, &w32tm);
  727.  
  728.     /* set `days' to the number of days into the year */
  729.     days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] +
  730.            (w32tm.wMonth > 2 && leap (w32tm.wYear));
  731.  
  732.     /* now set `days' to the number of days since 1 Jan 1970 */
  733.     days += 365 * (time_t)(w32tm.wYear - 1970) +
  734.             (time_t)(nleap(w32tm.wYear));
  735.  
  736.     *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour +
  737.                    (time_t)(60 * w32tm.wMinute + w32tm.wSecond));
  738.     return TRUE;
  739. #endif /* ?HAVE_INT64 */
  740. } /* end function FileTime2utime() */
  741.  
  742.  
  743.  
  744. #ifdef W32_STAT_BANDAID
  745. /*********************************/
  746. /* Function VFatFileTime2utime() */
  747. /*********************************/
  748.  
  749. static int VFatFileTime2utime(const FILETIME *pft, time_t *ut)
  750. {
  751.     FILETIME lft;
  752. #ifndef HAVE_MKTIME
  753.     WORD wDOSDate, wDOSTime;
  754. #else
  755.     SYSTEMTIME w32tm;
  756.     struct tm ltm;
  757. #endif
  758.  
  759.     FileTimeToLocalFileTime(pft, &lft);
  760.     FTTrace((stdout, "VFatFT2utime, feed for mktime()", 1, &lft));
  761. #ifndef HAVE_MKTIME
  762.     /* This version of the FILETIME-to-UNIXTIME conversion function
  763.      * uses DOS-DATE-TIME format as intermediate stage. For modification
  764.      * and access times, this is no problem. But, the extra fine resolution
  765.      * of the VFAT-stored creation time gets lost.
  766.      */
  767.     FileTimeToDosDateTime(&lft, &wDOSDate, &wDOSTime);
  768.     TTrace((stdout,"DosDateTime is %04u-%02u-%02u %02u:%02u:%02u\n",
  769.       (unsigned)((wDOSDate>>9)&0x7f)+1980,(unsigned)((wDOSDate>>5)&0x0f),
  770.       (unsigned)(wDOSDate&0x1f),(unsigned)((wDOSTime>>11)&0x1f),
  771.       (unsigned)((wDOSTime>>5)&0x3f),(unsigned)((wDOSTime<<1)&0x3e)));
  772.     *ut = dos_to_unix_time(((ulg)wDOSDate << 16) | (ulg)wDOSTime);
  773.  
  774.     /* a cheap error check: dos_to_unix_time() only returns an odd time
  775.      * when clipping at maximum time_t value. DOS_DATE_TIME values have
  776.      * a resolution of 2 seconds and are therefore even numbers.
  777.      */
  778.     return (((*ut)&1) == (time_t)0);
  779. #else /* HAVE_MKTIME */
  780.     FileTimeToSystemTime(&lft, &w32tm);
  781.     /* underflow and overflow handling */
  782.     /* TODO: The range checks are not accurate, the actual limits may
  783.      *       be off by one daylight-saving-time shift (typically 1 hour),
  784.      *       depending on the current state of "is_dst".
  785.      */
  786. #ifdef CHECK_UTIME_SIGNED_UNSIGNED
  787.     if ((time_t)0x80000000L < (time_t)0L)
  788.     {
  789.         if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
  790.             ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
  791.              (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
  792.             *ut = (time_t)LONG_MIN;
  793.             return FALSE;
  794.         if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
  795.             ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
  796.              (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
  797.             *ut = (time_t)LONG_MAX;
  798.             return FALSE;
  799.         }
  800.     }
  801.     else
  802. #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
  803.     {
  804.         if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
  805.             ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
  806.              (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
  807.             *ut = (time_t)0;
  808.             return FALSE;
  809.         }
  810.         if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
  811.             ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
  812.              (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
  813.             *ut = (time_t)ULONG_MAX;
  814.             return FALSE;
  815.         }
  816.     }
  817.     ltm.tm_year = w32tm.wYear - 1900;
  818.     ltm.tm_mon = w32tm.wMonth - 1;
  819.     ltm.tm_mday = w32tm.wDay;
  820.     ltm.tm_hour = w32tm.wHour;
  821.     ltm.tm_min = w32tm.wMinute;
  822.     ltm.tm_sec = w32tm.wSecond;
  823.     ltm.tm_isdst = -1;  /* let mktime determine if DST is in effect */
  824.     *ut = mktime(<m);
  825.  
  826.     /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors.
  827.      * Normally, we would have to apply a consistency check because "-1"
  828.      * could also be a valid time. But, it is quite unlikely to read back odd
  829.      * time numbers from file systems that store time stamps in DOS format.
  830.      * (The only known exception is creation time on VFAT partitions.)
  831.      */
  832.     return (*ut != (time_t)-1L);
  833. #endif /* ?HAVE_MKTIME */
  834.  
  835. } /* end function VFatFileTime2utime() */
  836. #endif /* W32_STAT_BANDAID */
  837.  
  838.  
  839.  
  840. /********************************/
  841. /* Function UTCtime2Localtime() */      /* borrowed from Zip's mkgmtime() */
  842. /********************************/
  843.  
  844. static time_t UTCtime2Localtime(time_t utctime)
  845. {
  846.     time_t utc = utctime;
  847.     struct tm *tm;
  848.     unsigned years, months, days, hours, minutes, seconds;
  849.  
  850.  
  851. #ifdef __BORLANDC__   /* Borland C++ 5.x crashes when trying to reference tm */
  852.     if (utc < UTIME_1980_JAN_01_00_00)
  853.         utc = UTIME_1980_JAN_01_00_00;
  854. #endif
  855.     tm = localtime(&utc);
  856.     if (tm == (struct tm *)NULL)
  857.         /* localtime() did not accept given utc time value; as an emergency
  858.            exit, the unconverted utctime value is returned */
  859.         return utctime;
  860.  
  861.     years = tm->tm_year + 1900; /* year - 1900 -> year */
  862.     months = tm->tm_mon;        /* 0..11 */
  863.     days = tm->tm_mday - 1;     /* 1..31 -> 0..30 */
  864.     hours = tm->tm_hour;        /* 0..23 */
  865.     minutes = tm->tm_min;       /* 0..59 */
  866.     seconds = tm->tm_sec;       /* 0..61 in ANSI C */
  867.  
  868.     /* set `days' to the number of days into the year */
  869.     days += ydays[months] + (months > 1 && leap(years));
  870.  
  871.     /* now set `days' to the number of days since 1 Jan 1970 */
  872.     days += 365 * (years - 1970) + nleap(years);
  873.  
  874.     return (time_t)(86400L * (ulg)days + 3600L * (ulg)hours +
  875.                     (ulg)(60 * minutes + seconds));
  876.  
  877. } /* end function UTCtime2Localtime() */
  878.  
  879.  
  880.  
  881. /********************************/
  882. /* Function NTtzbugWorkaround() */
  883. /********************************/
  884.  
  885. static void NTtzbugWorkaround(time_t ut, FILETIME *pft)
  886. {
  887.     FILETIME C_RTL_locft, NTAPI_locft;
  888.     time_t ux_loctime = UTCtime2Localtime(ut);
  889.  
  890.     /* This routine is only used when the target file system stores time-
  891.      * stamps as local time in MSDOS format.  Thus we make sure that the
  892.      * resulting timestamp is within the range of MSDOS date-time values. */
  893.     if (ux_loctime < UTIME_1980_JAN_01_00_00)
  894.         ux_loctime = UTIME_1980_JAN_01_00_00;
  895.  
  896.     utime2FileTime(ux_loctime, &C_RTL_locft);
  897.     if (!FileTimeToLocalFileTime(pft, &NTAPI_locft))
  898.         return;
  899.     else {
  900.         long time_shift_l, time_shift_h;
  901.         int carry = 0;
  902.  
  903.         time_shift_l = C_RTL_locft.dwLowDateTime - NTAPI_locft.dwLowDateTime;
  904.         if (C_RTL_locft.dwLowDateTime < NTAPI_locft.dwLowDateTime)
  905.             carry--;
  906.         time_shift_h = C_RTL_locft.dwHighDateTime - NTAPI_locft.dwHighDateTime;
  907.         pft->dwLowDateTime += time_shift_l;
  908.         if (pft->dwLowDateTime < (ulg)time_shift_l)
  909.             carry++;
  910.         pft->dwHighDateTime += time_shift_h + carry;
  911.         TTrace((stdout, "FileTime shift: %08lx:%08lx\n",
  912.                 time_shift_h+carry,time_shift_l));
  913.     }
  914. } /* end function NTtzbugWorkaround() */
  915.  
  916. #endif /* ?NT_TZBUG_WORKAROUND */
  917.  
  918.  
  919.  
  920. /****************************/      /* Get the file time in a format that */
  921. /* Function getNTfiletime() */      /*  can be used by SetFileTime() in NT */
  922. /****************************/
  923.  
  924. static int getNTfiletime(__G__ pModFT, pAccFT, pCreFT)
  925.     __GDEF
  926.     FILETIME *pModFT;
  927.     FILETIME *pAccFT;
  928.     FILETIME *pCreFT;
  929. {
  930. #ifdef NT_TZBUG_WORKAROUND
  931.     time_t ux_modtime;
  932. #else /* !NT_TZBUG_WORKAROUND */
  933.     FILETIME locft;    /* 64-bit value made up of two 32-bit [low & high] */
  934.     WORD wDOSDate;     /* for converting from DOS date to Windows NT */
  935.     WORD wDOSTime;
  936. #endif /* ?NT_TZBUG_WORKAROUND */
  937. #ifdef USE_EF_UT_TIME
  938.     unsigned eb_izux_flg;
  939.     iztimes z_utime;   /* struct for Unix-style actime & modtime, + creatime */
  940. #endif
  941. #if (defined(USE_EF_UT_TIME) && !defined(NT_TZBUG_WORKAROUND))
  942.     time_t utime_dosmin;
  943. # endif
  944. #if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND))
  945.     int fs_uses_loctime = FStampIsLocTime(__G__ G.filename);
  946. #endif
  947.  
  948.     /* Copy and/or convert time and date variables, if necessary;
  949.      * return a flag indicating which time stamps are available. */
  950. #ifdef USE_EF_UT_TIME
  951.     if (G.extra_field &&
  952. #ifdef IZ_CHECK_TZ
  953.         G.tz_is_valid &&
  954. #endif
  955.         ((eb_izux_flg = ef_scan_for_izux(G.extra_field,
  956.           G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
  957.           &z_utime, NULL)) & EB_UT_FL_MTIME))
  958.     {
  959.         TTrace((stderr, "getNTfiletime:  Unix e.f. modif. time = %lu\n",
  960.           z_utime.mtime));
  961.         UTIME_BOUNDCHECK_1(z_utime.mtime)
  962.         utime2FileTime(z_utime.mtime, pModFT);
  963.         NT_TZBUG_PRECOMPENSATE(z_utime.mtime, pModFT)
  964.         if (eb_izux_flg & EB_UT_FL_ATIME) {
  965.             UTIME_BOUNDCHECK_N(z_utime.atime)
  966.             utime2FileTime(z_utime.atime, pAccFT);
  967.             NT_TZBUG_PRECOMPENSATE(z_utime.atime, pAccFT)
  968.         }
  969.         if (eb_izux_flg & EB_UT_FL_CTIME) {
  970.             UTIME_BOUNDCHECK_N(z_utime.ctime)
  971.             utime2FileTime(z_utime.ctime, pCreFT);
  972.             NT_TZBUG_PRECOMPENSATE(z_utime.ctime, pCreFT)
  973.         }
  974.         return (int)eb_izux_flg;
  975.     }
  976. #endif /* USE_EF_UT_TIME */
  977. #ifdef NT_TZBUG_WORKAROUND
  978.     ux_modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  979.     utime2FileTime(ux_modtime, pModFT);
  980.     NT_TZBUG_PRECOMPENSATE(ux_modtime, pModFT)
  981. #else /* !NT_TZBUG_WORKAROUND */
  982.  
  983.     wDOSTime = (WORD)(G.lrec.last_mod_dos_datetime);
  984.     wDOSDate = (WORD)(G.lrec.last_mod_dos_datetime >> 16);
  985.  
  986.     /* The DosDateTimeToFileTime() function converts a DOS date/time
  987.      * into a 64-bit Windows NT file time */
  988.     if (!DosDateTimeToFileTime(wDOSDate, wDOSTime, &locft))
  989.     {
  990.         Info(slide, 0, ((char *)slide, "DosDateTime failed: %d\n",
  991.           (int)GetLastError()));
  992.         return 0;
  993.     }
  994.     if (!LocalFileTimeToFileTime(&locft, pModFT))
  995.     {
  996.         Info(slide, 0, ((char *)slide, "LocalFileTime failed: %d\n",
  997.           (int)GetLastError()));
  998.         *pModFT = locft;
  999.     }
  1000. #endif /* ?NT_TZBUG_WORKAROUND */
  1001.     *pAccFT = *pModFT;
  1002.     return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
  1003.  
  1004. } /* end function getNTfiletime() */
  1005.  
  1006.  
  1007.  
  1008.  
  1009. /****************************/
  1010. /* Function close_outfile() */
  1011. /****************************/
  1012.  
  1013. void close_outfile(__G)
  1014.     __GDEF
  1015. {
  1016.     FILETIME Modft;    /* File time type defined in NT, `last modified' time */
  1017.     FILETIME Accft;    /* NT file time type, `last access' time */
  1018.     FILETIME Creft;    /* NT file time type, `file creation' time */
  1019.     HANDLE hFile;      /* File handle defined in NT    */
  1020.     int gotTime;
  1021. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1022.     char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
  1023.  
  1024.     INTERN_TO_ISO(G.filename, ansi_name);
  1025. #   define Ansi_Fname  ansi_name
  1026. #else
  1027. #   define Ansi_Fname  G.filename
  1028. #endif
  1029.  
  1030.     /* Close the file and then re-open it using the Win32
  1031.      * CreateFile call, so that the file can be created
  1032.      * with GENERIC_WRITE access, otherwise the SetFileTime
  1033.      * call will fail. */
  1034.     fclose(G.outfile);
  1035.  
  1036.     /* don't set the time stamp and attributes on standard output */
  1037.     if (uO.cflag)
  1038.         return;
  1039.  
  1040.     gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft);
  1041.  
  1042.     /* open a handle to the file before processing extra fields;
  1043.        we do this in case new security on file prevents us from updating
  1044.        time stamps */
  1045.     hFile = CreateFile(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
  1046.          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1047.  
  1048.     /* sfield@microsoft.com: set attributes before time in case we decide to
  1049.        support other filetime members later.  This also allows us to apply
  1050.        attributes before the security is changed, which may prevent this
  1051.        from succeeding otherwise.  Also, since most files don't have
  1052.        any interesting attributes, only change them if something other than
  1053.        FILE_ATTRIBUTE_ARCHIVE appears in the attributes.  This works well
  1054.        as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
  1055.        file anyway, when it's created new. */
  1056.     if((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
  1057.         if (!SetFileAttributes(Ansi_Fname, G.pInfo->file_attr & 0x7F))
  1058.             Info(slide, 1, ((char *)slide,
  1059.               "\nwarning (%d): could not set file attributes\n",
  1060.               (int)GetLastError()));
  1061.     }
  1062.  
  1063. #ifdef NTSD_EAS
  1064.     /* set extra fields, both stored-in-zipfile and .LONGNAME flavors */
  1065.     if (G.extra_field) {    /* zipfile extra field may have extended attribs */
  1066.         int err = EvalExtraFields(__G__ G.filename, G.extra_field,
  1067.                                   G.lrec.extra_field_length);
  1068.  
  1069.         if (err == IZ_EF_TRUNC) {
  1070.             if (uO.qflag)
  1071.                 Info(slide, 1, ((char *)slide, "%-22s ",
  1072.                   FnFilter1(G.filename)));
  1073.             Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
  1074.               makeword(G.extra_field+2)-10, uO.qflag? "\n":""));
  1075.         }
  1076.     }
  1077. #endif /* NTSD_EAS */
  1078.  
  1079.     if ( hFile == INVALID_HANDLE_VALUE )
  1080.         Info(slide, 1, ((char *)slide,
  1081.           "\nCreateFile error %d when trying set file time\n",
  1082.           (int)GetLastError()));
  1083.     else {
  1084.         if (gotTime) {
  1085.             FILETIME *pModft = (gotTime & EB_UT_FL_MTIME) ? &Modft : NULL;
  1086.             FILETIME *pAccft = (gotTime & EB_UT_FL_ATIME) ? &Accft : NULL;
  1087.             FILETIME *pCreft = (gotTime & EB_UT_FL_CTIME) ? &Creft : NULL;
  1088.  
  1089.             if (!SetFileTime(hFile, pCreft, pAccft, pModft))
  1090.                 Info(slide, 0, ((char *)slide, "\nSetFileTime failed: %d\n",
  1091.                   (int)GetLastError()));
  1092.         }
  1093.         CloseHandle(hFile);
  1094.     }
  1095.  
  1096.     return;
  1097.  
  1098. #undef Ansi_Fname
  1099.  
  1100. } /* end function close_outfile() */
  1101.  
  1102.  
  1103.  
  1104.  
  1105. #ifdef TIMESTAMP
  1106.  
  1107. /*************************/
  1108. /* Function stamp_file() */
  1109. /*************************/
  1110.  
  1111. int stamp_file(__GPRO__ ZCONST char *fname, time_t modtime)
  1112. {
  1113.     FILETIME Modft;    /* File time type defined in NT, `last modified' time */
  1114.     HANDLE hFile;      /* File handle defined in NT    */
  1115.     int errstat = 0;   /* return status: 0 == "OK", -1 == "Failure" */
  1116. #ifndef NT_TZBUG_WORKAROUND
  1117.     time_t utime_dosmin;        /* internal variable for UTIME_BOUNDCHECK_1 */
  1118. #endif
  1119.     int fs_uses_loctime = FStampIsLocTime(__G__ fname);
  1120. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1121.     char *ansi_name = (char *)alloca(strlen(fname) + 1);
  1122.  
  1123.     INTERN_TO_ISO(fname, ansi_name);
  1124. #   define Ansi_Fname  ansi_name
  1125. #else
  1126. #   define Ansi_Fname  fname
  1127. #endif
  1128.  
  1129.     /* open a handle to the file to prepare setting the mod-time stamp */
  1130.     hFile = CreateFile(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
  1131.          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1132.     if ( hFile == INVALID_HANDLE_VALUE ) {
  1133.         errstat = -1;
  1134.     } else {
  1135.         /* convert time_t modtime into WIN32 native 64bit format */
  1136.         UTIME_BOUNDCHECK_1(modtime)
  1137.         utime2FileTime(modtime, &Modft);
  1138.         NT_TZBUG_PRECOMPENSATE(modtime, &Modft)
  1139.         /* set Access and Modification times of the file to modtime */
  1140.         if (!SetFileTime(hFile, NULL, &Modft, &Modft)) {
  1141.             errstat = -1;
  1142.         }
  1143.         CloseHandle(hFile);
  1144.     }
  1145.  
  1146.     return errstat;
  1147.  
  1148. #undef Ansi_Fname
  1149. } /* end function stamp_file() */
  1150.  
  1151. #endif /* TIMESTAMP */
  1152.  
  1153.  
  1154.  
  1155.  
  1156. /***********************/
  1157. /* Function isfloppy() */   /* more precisely, is it removable? */
  1158. /***********************/
  1159.  
  1160. static int isfloppy(int nDrive)   /* 1 == A:, 2 == B:, etc. */
  1161. {
  1162.     char rootPathName[4];
  1163.  
  1164.     rootPathName[0] = (char)('A' + nDrive - 1);   /* build the root path */
  1165.     rootPathName[1] = ':';                        /*  name, e.g. "A:/" */
  1166.     rootPathName[2] = '/';
  1167.     rootPathName[3] = '\0';
  1168.  
  1169.     return (GetDriveType(rootPathName) == DRIVE_REMOVABLE);
  1170.  
  1171. } /* end function isfloppy() */
  1172.  
  1173.  
  1174.  
  1175.  
  1176. /*****************************/
  1177. /* Function NTQueryVolInfo() */
  1178. /*****************************/
  1179.  
  1180. /*
  1181.  * Note:  8.3 limits on filenames apply only to old-style FAT filesystems.
  1182.  *        More recent versions of Windows (Windows NT 3.5 / Windows 4.0)
  1183.  *        can support long filenames (LFN) on FAT filesystems.  Check the
  1184.  *        filesystem maximum component length field to detect LFN support.
  1185.  */
  1186.  
  1187. static int NTQueryVolInfo(__GPRO__ const char *name)
  1188. {
  1189.  /* static char lastRootPath[4] = ""; */
  1190.  /* static int lastVolOldFAT; */
  1191.  /* static int lastVolLocTim; */
  1192.     char     *tmp0;
  1193.     char      tmp1[MAX_PATH], tmp2[MAX_PATH];
  1194.     unsigned  volSerNo, maxCompLen, fileSysFlags;
  1195. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1196.     char *ansi_name = (char *)alloca(strlen(name) + 1);
  1197.  
  1198.     INTERN_TO_ISO(name, ansi_name);
  1199.     name = ansi_name;
  1200. #endif
  1201.  
  1202.     if ((!strncmp(name, "//", 2) || !strncmp(name,"\\\\", 2)) &&
  1203.         (name[2] != '\0' && name[2] != '/' && name[2] != '\\')) {
  1204.         /* GetFullPathname() and GetVolumeInformation() do not work
  1205.          * on UNC names. For now, we return "error".
  1206.          * **FIXME**: check if UNC name is mapped to a drive letter
  1207.          *            and use mapped drive for volume info query.
  1208.          */
  1209.         return FALSE;
  1210.     }
  1211.     if (isalpha((uch)name[0]) && (name[1] == ':'))
  1212.         tmp0 = (char *)name;
  1213.     else
  1214.     {
  1215.         if (!GetFullPathName(name, MAX_PATH, tmp1, &tmp0))
  1216.             return FALSE;
  1217.         tmp0 = &tmp1[0];
  1218.     }
  1219.     if (strncmp(G.lastRootPath, tmp0, 2) != 0) {
  1220.         /* For speed, we skip repeated queries for the same device */
  1221.         strncpy(G.lastRootPath, tmp0, 2);   /* Build the root path name, */
  1222.         G.lastRootPath[2] = '/';            /* e.g. "A:/"                */
  1223.         G.lastRootPath[3] = '\0';
  1224.  
  1225.         if (!GetVolumeInformation((LPCTSTR)G.lastRootPath,
  1226.               (LPTSTR)tmp1, (DWORD)MAX_PATH,
  1227.               (LPDWORD)&volSerNo, (LPDWORD)&maxCompLen,
  1228.               (LPDWORD)&fileSysFlags, (LPTSTR)tmp2, (DWORD)MAX_PATH)) {
  1229.             G.lastRootPath[0] = '\0';
  1230.             return FALSE;
  1231.         }
  1232.  
  1233.         /*  LFNs are available if the component length is > 12 */
  1234.         G.lastVolOldFAT = (maxCompLen <= 12);
  1235. /*      G.lastVolOldFAT = !strncmp(strupr(tmp2), "FAT", 3);   old version */
  1236.  
  1237.         /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
  1238.          * local time!
  1239.          */
  1240.         G.lastVolLocTim = !strncmp(strupr(tmp2), "VFAT", 4) ||
  1241.                           !strncmp(tmp2, "HPFS", 4) ||
  1242.                           !strncmp(tmp2, "FAT", 3);
  1243.     }
  1244.  
  1245.     return TRUE;
  1246.  
  1247. } /* end function NTQueryVolInfo() */
  1248.  
  1249.  
  1250.  
  1251.  
  1252. /*****************************/
  1253. /* Function IsVolumeOldFAT() */
  1254. /*****************************/
  1255.  
  1256. static int IsVolumeOldFAT(__GPRO__ const char *name)
  1257. {
  1258.     return (NTQueryVolInfo(__G__ name) ? G.lastVolOldFAT : FALSE);
  1259. }
  1260.  
  1261.  
  1262.  
  1263.  
  1264. #ifndef SFX
  1265.  
  1266. /************************/
  1267. /*  Function do_wild()  */   /* identical to OS/2 version */
  1268. /************************/
  1269.  
  1270. char *do_wild(__G__ wildspec)
  1271.     __GDEF
  1272.     char *wildspec;         /* only used first time on a given dir */
  1273. {
  1274.  /* static zDIR *wild_dir = NULL;                               */
  1275.  /* static char *dirname, *wildname, matchname[FILNAMSIZ]; */
  1276.  /* static int firstcall=TRUE, have_dirname, dirnamelen;   */
  1277.     char *fnamestart;
  1278.     struct zdirent *file;
  1279.  
  1280.     /* Even when we're just returning wildspec, we *always* do so in
  1281.      * matchname[]--calling routine is allowed to append four characters
  1282.      * to the returned string, and wildspec may be a pointer to argv[].
  1283.      */
  1284.     if (!G.notfirstcall) {  /* first call:  must initialize everything */
  1285.         G.notfirstcall = TRUE;
  1286.  
  1287.         if (!iswild(wildspec)) {
  1288.             strcpy(G.matchname, wildspec);
  1289.             G.have_dirname = FALSE;
  1290.             G.wild_dir = NULL;
  1291.             return G.matchname;
  1292.         }
  1293.  
  1294.         /* break the wildspec into a directory part and a wildcard filename */
  1295.         if ((G.wildname = strrchr(wildspec, '/')) == NULL &&
  1296.             (G.wildname = strrchr(wildspec, ':')) == NULL) {
  1297.             G.dirname = ".";
  1298.             G.dirnamelen = 1;
  1299.             G.have_dirname = FALSE;
  1300.             G.wildname = wildspec;
  1301.         } else {
  1302.             ++G.wildname;     /* point at character after '/' or ':' */
  1303.             G.dirnamelen = G.wildname - wildspec;
  1304.             if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) {
  1305.                 Info(slide, 1, ((char *)slide,
  1306.                   "warning:  cannot allocate wildcard buffers\n"));
  1307.                 strcpy(G.matchname, wildspec);
  1308.                 return G.matchname; /* but maybe filespec was not a wildcard */
  1309.             }
  1310.             strncpy(G.dirname, wildspec, G.dirnamelen);
  1311.             G.dirname[G.dirnamelen] = '\0';    /* terminate for strcpy below */
  1312.             G.have_dirname = TRUE;
  1313.         }
  1314.         Trace((stderr, "do_wild:  dirname = [%s]\n", G.dirname));
  1315.  
  1316.         if ((G.wild_dir = (zvoid *)Opendir(G.dirname)) != NULL) {
  1317.             if (G.have_dirname) {
  1318.                 strcpy(G.matchname, G.dirname);
  1319.                 fnamestart = G.matchname + G.dirnamelen;
  1320.             } else
  1321.                 fnamestart = G.matchname;
  1322.             while ((file = Readdir((zDIR *)G.wild_dir)) != NULL) {
  1323.                 Trace((stderr, "do_wild:  Readdir returns %s\n", file->d_name));
  1324.                 strcpy(fnamestart, file->d_name);
  1325.                 if (strrchr(fnamestart, '.') == (char *)NULL)
  1326.                     strcat(fnamestart, ".");
  1327.                 if (match(fnamestart, G.wildname, 1) &&  /* 1 == ignore case */
  1328.                     /* skip "." and ".." directory entries */
  1329.                     strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) {
  1330.                     Trace((stderr, "do_wild:  match() succeeds\n"));
  1331.                     /* remove trailing dot */
  1332.                     fnamestart += strlen(fnamestart) - 1;
  1333.                     if (*fnamestart == '.')
  1334.                         *fnamestart = '\0';
  1335.                     return G.matchname;
  1336.                 }
  1337.             }
  1338.             /* if we get to here directory is exhausted, so close it */
  1339.             Closedir((zDIR *)G.wild_dir);
  1340.             G.wild_dir = NULL;
  1341.         }
  1342.         Trace((stderr, "do_wild:  Opendir(%s) returns NULL\n", G.dirname));
  1343.  
  1344.         /* return the raw wildspec in case that works (e.g., directory not
  1345.          * searchable, but filespec was not wild and file is readable) */
  1346.         strcpy(G.matchname, wildspec);
  1347.         return G.matchname;
  1348.     }
  1349.  
  1350.     /* last time through, might have failed opendir but returned raw wildspec */
  1351.     if (G.wild_dir == NULL) {
  1352.         G.notfirstcall = FALSE;    /* reset for new wildspec */
  1353.         if (G.have_dirname)
  1354.             free(G.dirname);
  1355.         return (char *)NULL;
  1356.     }
  1357.  
  1358.     /* If we've gotten this far, we've read and matched at least one entry
  1359.      * successfully (in a previous call), so dirname has been copied into
  1360.      * matchname already.
  1361.      */
  1362.     if (G.have_dirname) {
  1363.         /* strcpy(G.matchname, G.dirname); */
  1364.         fnamestart = G.matchname + G.dirnamelen;
  1365.     } else
  1366.         fnamestart = G.matchname;
  1367.     while ((file = Readdir((zDIR *)G.wild_dir)) != NULL) {
  1368.         Trace((stderr, "do_wild:  readdir returns %s\n", file->d_name));
  1369.         strcpy(fnamestart, file->d_name);
  1370.         if (strrchr(fnamestart, '.') == (char *)NULL)
  1371.             strcat(fnamestart, ".");
  1372.         if (match(fnamestart, G.wildname, 1)) {     /* 1 == ignore case */
  1373.             Trace((stderr, "do_wild:  match() succeeds\n"));
  1374.             /* remove trailing dot */
  1375.             fnamestart += strlen(fnamestart) - 1;
  1376.             if (*fnamestart == '.')
  1377.                 *fnamestart = '\0';
  1378.             return G.matchname;
  1379.         }
  1380.     }
  1381.  
  1382.     Closedir((zDIR *)G.wild_dir);  /* at least one entry read; nothing left */
  1383.     G.wild_dir = NULL;
  1384.     G.notfirstcall = FALSE;        /* reset for new wildspec */
  1385.     if (G.have_dirname)
  1386.         free(G.dirname);
  1387.     return (char *)NULL;
  1388.  
  1389. } /* end function do_wild() */
  1390.  
  1391. #endif /* !SFX */
  1392.  
  1393.  
  1394.  
  1395. /**********************/
  1396. /* Function mapattr() */
  1397. /**********************/
  1398.  
  1399. /* Identical to MS-DOS, OS/2 versions.  However, NT has a lot of extra
  1400.  * permission stuff, so this function should probably be extended in the
  1401.  * future. */
  1402.  
  1403. int mapattr(__G)
  1404.     __GDEF
  1405. {
  1406.     /* set archive bit for file entries (file is not backed up): */
  1407.     G.pInfo->file_attr = ((unsigned)G.crec.external_file_attributes |
  1408.       (G.crec.external_file_attributes & FILE_ATTRIBUTE_DIRECTORY ?
  1409.        0 : FILE_ATTRIBUTE_ARCHIVE)) & 0xff;
  1410.     return 0;
  1411.  
  1412. } /* end function mapattr() */
  1413.  
  1414.  
  1415.  
  1416.  
  1417. /************************/
  1418. /*  Function mapname()  */
  1419. /************************/
  1420.                              /* return 0 if no error, 1 if caution (filename */
  1421. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  1422.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  1423.     int renamed;             /*  or 10 if out of memory (skip file) */
  1424. {                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  1425.     char pathcomp[FILNAMSIZ];   /* path-component buffer */
  1426.     char *pp, *cp=NULL;         /* character pointers */
  1427.     char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  1428.     int error;
  1429.     register unsigned workch;   /* hold the character being tested */
  1430.  
  1431.  
  1432. /*---------------------------------------------------------------------------
  1433.     Initialize various pointers and counters and stuff.
  1434.   ---------------------------------------------------------------------------*/
  1435.  
  1436.     /* can create path as long as not just freshening, or if user told us */
  1437.     G.create_dirs = (!uO.fflag || renamed);
  1438.  
  1439.     G.created_dir = FALSE;      /* not yet */
  1440.     G.renamed_fullpath = FALSE;
  1441.     G.fnlen = strlen(G.filename);
  1442.  
  1443.     if (renamed) {
  1444.         cp = G.filename - 1;    /* point to beginning of renamed name... */
  1445.         while (*++cp)
  1446.             if (*cp == '\\')    /* convert backslashes to forward */
  1447.                 *cp = '/';
  1448.         cp = G.filename;
  1449.         /* use temporary rootpath if user gave full pathname */
  1450.         if (G.filename[0] == '/') {
  1451.             G.renamed_fullpath = TRUE;
  1452.             pathcomp[0] = '/';  /* copy the '/' and terminate */
  1453.             pathcomp[1] = '\0';
  1454.             ++cp;
  1455.         } else if (isalpha((uch)G.filename[0]) && G.filename[1] == ':') {
  1456.             G.renamed_fullpath = TRUE;
  1457.             pp = pathcomp;
  1458.             *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
  1459.             *pp++ = *cp++;
  1460.             if (*cp == '/')
  1461.                 *pp++ = *cp++;  /* otherwise add "./"? */
  1462.             *pp = '\0';
  1463.         }
  1464.     }
  1465.  
  1466.     /* pathcomp is ignored unless renamed_fullpath is TRUE: */
  1467.     if ((error = checkdir(__G__ pathcomp, INIT)) != 0)    /* init path buffer */
  1468.         return error;           /* ...unless no mem or vol label on hard disk */
  1469.  
  1470.     *pathcomp = '\0';           /* initialize translation buffer */
  1471.     pp = pathcomp;              /* point to translation buffer */
  1472.     if (!renamed) {             /* cp already set if renamed */
  1473.         if (uO.jflag)           /* junking directories */
  1474.             cp = (char *)strrchr(G.filename, '/');
  1475.         if (cp == NULL)         /* no '/' or not junking dirs */
  1476.             cp = G.filename;    /* point to internal zipfile-member pathname */
  1477.         else
  1478.             ++cp;               /* point to start of last component of path */
  1479.     }
  1480.  
  1481. /*---------------------------------------------------------------------------
  1482.     Begin main loop through characters in filename.
  1483.   ---------------------------------------------------------------------------*/
  1484.  
  1485.     while ((workch = (uch)*cp++) != 0) {
  1486.  
  1487.         switch (workch) {
  1488.         case '/':             /* can assume -j flag not given */
  1489.             *pp = '\0';
  1490.             if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  1491.                 return error;
  1492.             pp = pathcomp;    /* reset conversion buffer for next piece */
  1493.             lastsemi = NULL;  /* leave directory semi-colons alone */
  1494.             break;
  1495.  
  1496.         case ':':             /* drive names not stored in zipfile, */
  1497.         case '<':             /*  so no colons allowed */
  1498.         case '>':             /* no redirection symbols allowed either */
  1499.         case '|':             /* no pipe signs allowed */
  1500.         case '"':             /* no double quotes allowed */
  1501.         case '?':             /* no wildcards allowed */
  1502.         case '*':
  1503.             *pp++ = '_';      /* these rules apply equally to FAT and NTFS */
  1504.             break;
  1505.         case ';':             /* start of VMS version? */
  1506.             lastsemi = pp;    /* remove VMS version later... */
  1507.             *pp++ = ';';      /*  but keep semicolon for now */
  1508.             break;
  1509.  
  1510.         case ' ':             /* keep spaces unless specifically */
  1511.             /* NT cannot create filenames with spaces on FAT volumes */
  1512.             if (uO.sflag || IsVolumeOldFAT(__G__ G.filename))
  1513.                 *pp++ = '_';
  1514.             else
  1515.                 *pp++ = ' ';
  1516.             break;
  1517.  
  1518.         default:
  1519.             /* allow European characters in filenames: */
  1520.             if (isprint(workch) || workch >= 127)
  1521.                 *pp++ = (char)workch;
  1522.         } /* end switch */
  1523.     } /* end while loop */
  1524.  
  1525.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  1526.  
  1527.     /* if not saving them, remove VMS version numbers (appended "###") */
  1528.     if (!uO.V_flag && lastsemi) {
  1529.         pp = lastsemi + 1;        /* semi-colon was kept:  expect #'s after */
  1530.         while (isdigit((uch)(*pp)))
  1531.             ++pp;
  1532.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  1533.             *lastsemi = '\0';
  1534.     }
  1535.  
  1536. /*---------------------------------------------------------------------------
  1537.     Report if directory was created (and no file to create:  filename ended
  1538.     in '/'), check name to be sure it exists, and combine path and name be-
  1539.     fore exiting.
  1540.   ---------------------------------------------------------------------------*/
  1541.  
  1542.     if (G.filename[G.fnlen-1] == '/') {
  1543.         checkdir(__G__ G.filename, GETPATH);
  1544.         if (G.created_dir) {
  1545. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1546.             char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
  1547.  
  1548.             INTERN_TO_ISO(G.filename, ansi_name);
  1549. #           define Ansi_Fname  ansi_name
  1550. #else
  1551. #           define Ansi_Fname  G.filename
  1552. #endif
  1553.             if (QCOND2) {
  1554.                 Info(slide, 0, ((char *)slide, "   creating: %-22s\n",
  1555.                   FnFilter1(G.filename)));
  1556.             }
  1557.  
  1558.             /* set file attributes:
  1559.                The default for newly created directories is "DIR attribute
  1560.                flags set", so there is no need to change attributes unless
  1561.                one of the DOS style attribute flags is set. The readonly
  1562.                attribute need not be masked, since it does not prevent
  1563.                modifications in the new directory. */
  1564.             if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
  1565.                 if (!SetFileAttributes(Ansi_Fname, G.pInfo->file_attr & 0x7F))
  1566.                     Info(slide, 1, ((char *)slide,
  1567.                       "\nwarning (%d): could not set file attributes for %s\n",
  1568.                       (int)GetLastError(), G.filename));
  1569.             }
  1570.  
  1571. #ifdef NTSD_EAS
  1572.             /* set extra fields, both stored-in-zipfile and .LONGNAME flavors */
  1573.             if (G.extra_field) { /* zipfile e.f. may have extended attribs */
  1574.                 int err = EvalExtraFields(__G__ G.filename, G.extra_field,
  1575.                                           G.lrec.extra_field_length);
  1576.  
  1577.                 if (err == IZ_EF_TRUNC) {
  1578.                     if (uO.qflag)
  1579.                         Info(slide, 1, ((char *)slide, "%-22s ",
  1580.                           FnFilter1(G.filename)));
  1581.                     Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
  1582.                       makeword(G.extra_field+2)-10, uO.qflag? "\n":""));
  1583.                 }
  1584.             }
  1585. #endif /* NTSD_EAS */
  1586.             return IZ_CREATED_DIR;      /* set dir time (note trailing '/') */
  1587.         }
  1588.         return 2;   /* dir existed already; don't look for data to extract */
  1589.     }
  1590.  
  1591.     if (*pathcomp == '\0') {
  1592.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  1593.           FnFilter1(G.filename)));
  1594.         return 3;
  1595.     }
  1596.  
  1597.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  1598.     checkdir(__G__ G.filename, GETPATH);
  1599.     Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n",
  1600.       FnFilter1(G.filename), error));
  1601.  
  1602.     if (G.pInfo->vollabel) {    /* set the volume label now */
  1603.         char drive[4];
  1604. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1605.         char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
  1606.         INTERN_TO_ISO(G.filename, ansi_name);
  1607. #       define Ansi_Fname  ansi_name
  1608. #else
  1609. #       define Ansi_Fname  G.filename
  1610. #endif
  1611.  
  1612.         /* Build a drive string, e.g. "b:" */
  1613.         drive[0] = (char)('a' + G.nLabelDrive - 1);
  1614.         strcpy(drive + 1, ":\\");
  1615.         if (QCOND2)
  1616.             Info(slide, 0, ((char *)slide, "labelling %s %-22s\n", drive,
  1617.               FnFilter1(G.filename)));
  1618.         if (!SetVolumeLabel(drive, Ansi_Fname)) {
  1619.             Info(slide, 1, ((char *)slide,
  1620.               "mapname:  error setting volume label\n"));
  1621.             return 3;
  1622.         }
  1623.         return 2;   /* success:  skip the "extraction" quietly */
  1624. #undef Ansi_Fname
  1625.     }
  1626.  
  1627.     return error;
  1628.  
  1629. } /* end function mapname() */
  1630.  
  1631.  
  1632.  
  1633.  
  1634. /**********************/
  1635. /* Function map2fat() */        /* Not quite identical to OS/2 version */
  1636. /**********************/
  1637.  
  1638. static void map2fat(pathcomp, pEndFAT)
  1639.     char *pathcomp, **pEndFAT;
  1640. {
  1641.     char *ppc = pathcomp;       /* variable pointer to pathcomp */
  1642.     char *pEnd = *pEndFAT;      /* variable pointer to buildpathFAT */
  1643.     char *pBegin = *pEndFAT;    /* constant pointer to start of this comp. */
  1644.     char *last_dot = NULL;      /* last dot not converted to underscore */
  1645.     int dotname = FALSE;        /* flag:  path component begins with dot */
  1646.                                 /*  ("." and ".." don't count) */
  1647.     register unsigned workch;   /* hold the character being tested */
  1648.  
  1649.  
  1650.     /* Only need check those characters which are legal in NTFS but not
  1651.      * in FAT:  to get here, must already have passed through mapname.
  1652.      * Also must truncate path component to ensure 8.3 compliance.
  1653.      */
  1654.     while ((workch = (uch)*ppc++) != 0) {
  1655.         switch (workch) {
  1656.             case '[':
  1657.             case ']':
  1658.             case '+':
  1659.             case ',':
  1660.             case ';':
  1661.             case '=':
  1662.                 *pEnd++ = '_';      /* convert brackets to underscores */
  1663.                 break;
  1664.  
  1665.             case '.':
  1666.                 if (pEnd == *pEndFAT) {   /* nothing appended yet... */
  1667.                     if (*ppc == '\0')     /* don't bother appending a */
  1668.                         break;            /*  "./" component to the path */
  1669.                     else if (*ppc == '.' && ppc[1] == '\0') {   /* "../" */
  1670.                         *pEnd++ = '.';    /* add first dot, unchanged... */
  1671.                         ++ppc;            /* skip second dot, since it will */
  1672.                     } else {              /*  be "added" at end of if-block */
  1673.                         *pEnd++ = '_';    /* FAT doesn't allow null filename */
  1674.                         dotname = TRUE;   /*  bodies, so map .exrc -> _.exrc */
  1675.                     }                     /*  (extra '_' now, "dot" below) */
  1676.                 } else if (dotname) {     /* found a second dot, but still */
  1677.                     dotname = FALSE;      /*  have extra leading underscore: */
  1678.                     *pEnd = '\0';         /*  remove it by shifting chars */
  1679.                     pEnd = *pEndFAT + 1;  /*  left one space (e.g., .p1.p2: */
  1680.                     while (pEnd[1]) {     /*  __p1 -> _p1_p2 -> _p1.p2 when */
  1681.                         *pEnd = pEnd[1];  /*  finished) [opt.:  since first */
  1682.                         ++pEnd;           /*  two chars are same, can start */
  1683.                     }                     /*  shifting at second position] */
  1684.                 }
  1685.                 last_dot = pEnd;    /* point at last dot so far... */
  1686.                 *pEnd++ = '_';      /* convert dot to underscore for now */
  1687.                 break;
  1688.  
  1689.             default:
  1690.                 *pEnd++ = (char)workch;
  1691.  
  1692.         } /* end switch */
  1693.     } /* end while loop */
  1694.  
  1695.     *pEnd = '\0';                 /* terminate buildpathFAT */
  1696.  
  1697.     /* NOTE:  keep in mind that pEnd points to the end of the path
  1698.      * component, and *pEndFAT still points to the *beginning* of it...
  1699.      * Also note that the algorithm does not try to get too fancy:
  1700.      * if there are no dots already, the name either gets truncated
  1701.      * at 8 characters or the last underscore is converted to a dot
  1702.      * (only if more characters are saved that way).  In no case is
  1703.      * a dot inserted between existing characters.
  1704.      */
  1705.     if (last_dot == NULL) {       /* no dots:  check for underscores... */
  1706.         char *plu = strrchr(pBegin, '_');   /* pointer to last underscore */
  1707.  
  1708.         if (plu == NULL) {   /* no dots, no underscores:  truncate at 8 chars */
  1709.             *pEndFAT += 8;        /* (or could insert '.' and keep 11...?) */
  1710.             if (*pEndFAT > pEnd)
  1711.                 *pEndFAT = pEnd;  /* oops...didn't have 8 chars to truncate */
  1712.             else
  1713.                 **pEndFAT = '\0';
  1714.         } else if (MIN(plu - pBegin, 8) + MIN(pEnd - plu - 1, 3) > 8) {
  1715.             last_dot = plu;       /* be lazy:  drop through to next if-blk */
  1716.         } else if ((pEnd - *pEndFAT) > 8) {
  1717.             *pEndFAT += 8;        /* more fits into just basename than if */
  1718.             **pEndFAT = '\0';     /*  convert last underscore to dot */
  1719.         } else
  1720.             *pEndFAT = pEnd;      /* whole thing fits into 8 chars or less */
  1721.     }
  1722.  
  1723.     if (last_dot != NULL) {       /* one dot (or two, in the case of */
  1724.         *last_dot = '.';          /*  "..") is OK:  put it back in */
  1725.  
  1726.         if ((last_dot - pBegin) > 8) {
  1727.             char *p, *q;
  1728.             int i;
  1729.  
  1730.             p = last_dot;
  1731.             q = last_dot = pBegin + 8;
  1732.             for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
  1733.                 *q++ = *p++;                   /*  shift .ext left and trun- */
  1734.             *q = '\0';                         /*  cate/terminate it */
  1735.             *pEndFAT = q;
  1736.         } else if ((pEnd - last_dot) > 4) {    /* too many chars in extension */
  1737.             *pEndFAT = last_dot + 4;
  1738.             **pEndFAT = '\0';
  1739.         } else
  1740.             *pEndFAT = pEnd;   /* filename is fine; point at terminating zero */
  1741.  
  1742.         if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ')
  1743.             last_dot[-1] = '_';                /* NO blank in front of '.'! */
  1744.     }
  1745. } /* end function map2fat() */
  1746.  
  1747.  
  1748.  
  1749.  
  1750. /***********************/       /* Borrowed from os2.c for UnZip 5.1.        */
  1751. /* Function checkdir() */       /* Difference: no EA stuff                   */
  1752. /***********************/       /*             HPFS stuff works on NTFS too  */
  1753.  
  1754. int checkdir(__G__ pathcomp, flag)
  1755.     __GDEF
  1756.     char *pathcomp;
  1757.     int flag;
  1758. /*
  1759.  * returns:  1 - (on APPEND_NAME) truncated filename
  1760.  *           2 - path doesn't exist, not allowed to create
  1761.  *           3 - path doesn't exist, tried to create and failed; or
  1762.  *               path exists and is not a directory, but is supposed to be
  1763.  *           4 - path is too long
  1764.  *          10 - can't allocate memory for filename buffers
  1765.  */
  1766. {
  1767.  /* static int rootlen = 0;     */   /* length of rootpath */
  1768.  /* static char *rootpath;      */   /* user's "extract-to" directory */
  1769.  /* static char *buildpathHPFS; */   /* full path (so far) to extracted file, */
  1770.  /* static char *buildpathFAT;  */   /*  both HPFS/EA (main) and FAT versions */
  1771.  /* static char *endHPFS;       */   /* corresponding pointers to end of */
  1772.  /* static char *endFAT;        */   /*  buildpath ('\0') */
  1773.  
  1774. #   define FN_MASK   7
  1775. #   define FUNCTION  (flag & FN_MASK)
  1776.  
  1777.  
  1778.  
  1779. /*---------------------------------------------------------------------------
  1780.     APPEND_DIR:  append the path component to the path being built and check
  1781.     for its existence.  If doesn't exist and we are creating directories, do
  1782.     so for this one; else signal success or error as appropriate.
  1783.   ---------------------------------------------------------------------------*/
  1784.  
  1785.     if (FUNCTION == APPEND_DIR) {
  1786.         char *p = pathcomp;
  1787.         int too_long=FALSE;
  1788.  
  1789.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  1790.         while ((*G.endHPFS = *p++) != '\0')     /* copy to HPFS filename */
  1791.             ++G.endHPFS;
  1792.         if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
  1793.             p = pathcomp;
  1794.             while ((*G.endFAT = *p++) != '\0')  /* copy to FAT filename, too */
  1795.                 ++G.endFAT;
  1796.         } else
  1797.             map2fat(pathcomp, &G.endFAT);   /* map into FAT fn, update endFAT */
  1798.  
  1799.         /* GRR:  could do better check, see if overrunning buffer as we go:
  1800.          * check endHPFS-buildpathHPFS after each append, set warning variable
  1801.          * if within 20 of FILNAMSIZ; then if var set, do careful check when
  1802.          * appending.  Clear variable when begin new path. */
  1803.  
  1804.         /* next check:  need to append '/', at least one-char name, '\0' */
  1805.         if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3)
  1806.             too_long = TRUE;                    /* check if extracting dir? */
  1807. #ifdef FIX_STAT_BUG
  1808.         /* Borland C++ 5.0 does not handle a call to stat() well if the
  1809.          * directory does not exist (it tends to crash in strange places.)
  1810.          * This is apparently a problem only when compiling for GUI rather
  1811.          * than console. The code below attempts to work around this problem.
  1812.          */
  1813.         if (access(G.buildpathFAT, 0) != 0) {
  1814.             if (!G.create_dirs) { /* told not to create (freshening) */
  1815.                 free(G.buildpathHPFS);
  1816.                 free(G.buildpathFAT);
  1817.                 return 2;         /* path doesn't exist:  nothing to do */
  1818.             }
  1819.             if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
  1820.                 Info(slide, 1, ((char *)slide,
  1821.                   "checkdir error:  path too long: %s\n",
  1822.                   FnFilter1(G.buildpathHPFS)));
  1823.                 free(G.buildpathHPFS);
  1824.                 free(G.buildpathFAT);
  1825.                 return 4;         /* no room for filenames:  fatal */
  1826.             }
  1827.             if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
  1828.                 Info(slide, 1, ((char *)slide,
  1829.                   "checkdir error:  cannot create %s\n\
  1830.                  unable to process %s.\n",
  1831.                   FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
  1832.                 free(G.buildpathHPFS);
  1833.                 free(G.buildpathFAT);
  1834.                 return 3;      /* path didn't exist, tried to create, failed */
  1835.             }
  1836.             G.created_dir = TRUE;
  1837.         }
  1838. #endif /* FIX_STAT_BUG */
  1839.         if (SSTAT(G.buildpathFAT, &G.statbuf))   /* path doesn't exist */
  1840.         {
  1841.             if (!G.create_dirs) { /* told not to create (freshening) */
  1842.                 free(G.buildpathHPFS);
  1843.                 free(G.buildpathFAT);
  1844.                 return 2;         /* path doesn't exist:  nothing to do */
  1845.             }
  1846.             if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
  1847.                 Info(slide, 1, ((char *)slide,
  1848.                   "checkdir error:  path too long: %s\n",
  1849.                   FnFilter1(G.buildpathHPFS)));
  1850.                 free(G.buildpathHPFS);
  1851.                 free(G.buildpathFAT);
  1852.                 return 4;         /* no room for filenames:  fatal */
  1853.             }
  1854.             if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
  1855.                 Info(slide, 1, ((char *)slide,
  1856.                   "checkdir error:  cannot create %s\n\
  1857.                  unable to process %s.\n",
  1858.                   FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
  1859.                 free(G.buildpathHPFS);
  1860.                 free(G.buildpathFAT);
  1861.                 return 3;      /* path didn't exist, tried to create, failed */
  1862.             }
  1863.             G.created_dir = TRUE;
  1864.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  1865.             Info(slide, 1, ((char *)slide,
  1866.               "checkdir error:  %s exists but is not directory\n   \
  1867.               unable to process %s.\n",
  1868.               FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
  1869.             free(G.buildpathHPFS);
  1870.             free(G.buildpathFAT);
  1871.             return 3;          /* path existed but wasn't dir */
  1872.         }
  1873.         if (too_long) {
  1874.             Info(slide, 1, ((char *)slide,
  1875.               "checkdir error:  path too long: %s\n",
  1876.                FnFilter1(G.buildpathHPFS)));
  1877.             free(G.buildpathHPFS);
  1878.             free(G.buildpathFAT);
  1879.             return 4;         /* no room for filenames:  fatal */
  1880.         }
  1881.         *G.endHPFS++ = '/';
  1882.         *G.endFAT++ = '/';
  1883.         *G.endHPFS = *G.endFAT = '\0';
  1884.         Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now =  [%s]\n",
  1885.           FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
  1886.         return 0;
  1887.  
  1888.     } /* end if (FUNCTION == APPEND_DIR) */
  1889.  
  1890. /*---------------------------------------------------------------------------
  1891.     GETPATH:  copy full FAT path to the string pointed at by pathcomp (want
  1892.     filename to reflect name used on disk, not EAs; if full path is HPFS,
  1893.     buildpathFAT and buildpathHPFS will be identical).  Also free both paths.
  1894.   ---------------------------------------------------------------------------*/
  1895.  
  1896.     if (FUNCTION == GETPATH) {
  1897.         Trace((stderr, "getting and freeing FAT path [%s]\n",
  1898.           FnFilter1(G.buildpathFAT)));
  1899.         Trace((stderr, "freeing HPFS path [%s]\n",
  1900.           FnFilter1(G.buildpathHPFS)));
  1901.         strcpy(pathcomp, G.buildpathFAT);
  1902.         free(G.buildpathFAT);
  1903.         free(G.buildpathHPFS);
  1904.         G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL;
  1905.         return 0;
  1906.     }
  1907.  
  1908. /*---------------------------------------------------------------------------
  1909.     APPEND_NAME:  assume the path component is the filename; append it and
  1910.     return without checking for existence.
  1911.   ---------------------------------------------------------------------------*/
  1912.  
  1913.     if (FUNCTION == APPEND_NAME) {
  1914.         char *p = pathcomp;
  1915.         int error = 0;
  1916.  
  1917.         Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
  1918.         while ((*G.endHPFS = *p++) != '\0') {   /* copy to HPFS filename */
  1919.             ++G.endHPFS;
  1920.             if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) {
  1921.                 *--G.endHPFS = '\0';
  1922.                 Info(slide, 1, ((char *)slide,
  1923.                   "checkdir warning:  path too long; truncating\n \
  1924.                   %s\n                -> %s\n",
  1925.                   FnFilter1(G.filename), FnFilter2(G.buildpathHPFS)));
  1926.                 error = 1;   /* filename truncated */
  1927.             }
  1928.         }
  1929.  
  1930.         if ( G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
  1931.             p = pathcomp;
  1932.             while ((*G.endFAT = *p++) != '\0')  /* copy to FAT filename, too */
  1933.                 ++G.endFAT;
  1934.         } else
  1935.             map2fat(pathcomp, &G.endFAT);   /* map into FAT fn, update endFAT */
  1936.         Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT:  %s\n",
  1937.           FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
  1938.  
  1939.         return error;  /* could check for existence, prompt for new name... */
  1940.  
  1941.     } /* end if (FUNCTION == APPEND_NAME) */
  1942.  
  1943. /*---------------------------------------------------------------------------
  1944.     INIT:  allocate and initialize buffer space for the file currently being
  1945.     extracted.  If file was renamed with an absolute path, don't prepend the
  1946.     extract-to path.
  1947.   ---------------------------------------------------------------------------*/
  1948.  
  1949.     if (FUNCTION == INIT) {
  1950.         Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
  1951.         if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1)) == NULL)
  1952.             return 10;
  1953.         if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1)) == NULL) {
  1954.             free(G.buildpathHPFS);
  1955.             return 10;
  1956.         }
  1957.         if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */
  1958. /* GRR:  for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
  1959.             if (G.renamed_fullpath && pathcomp[1] == ':')
  1960.                 *G.buildpathHPFS = (char)ToLower(*pathcomp);
  1961.             else if (!G.renamed_fullpath && G.rootlen > 1 &&
  1962.                      G.rootpath[1] == ':')
  1963.                 *G.buildpathHPFS = (char)ToLower(*G.rootpath);
  1964.             else {
  1965.                 char tmpN[MAX_PATH], *tmpP;
  1966.                 if (GetFullPathName(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
  1967.                 { /* by definition of MAX_PATH we should never get here */
  1968.                     Info(slide, 1, ((char *)slide,
  1969.                       "checkdir warning: current dir path too long\n"));
  1970.                     return 1;   /* can't get drive letter */
  1971.                 }
  1972.                 G.nLabelDrive = *tmpN - 'a' + 1;
  1973.                 *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a');
  1974.             }
  1975.             G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */
  1976.             if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */
  1977.                 || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */
  1978.                 free(G.buildpathHPFS);
  1979.                 free(G.buildpathFAT);
  1980.                 return IZ_VOL_LABEL;   /* skipping with message */
  1981.             }
  1982.             *G.buildpathHPFS = '\0';
  1983.         } else if (G.renamed_fullpath) /* pathcomp = valid data */
  1984.             strcpy(G.buildpathHPFS, pathcomp);
  1985.         else if (G.rootlen > 0)
  1986.             strcpy(G.buildpathHPFS, G.rootpath);
  1987.         else
  1988.             *G.buildpathHPFS = '\0';
  1989.         G.endHPFS = G.buildpathHPFS;
  1990.         G.endFAT = G.buildpathFAT;
  1991.         while ((*G.endFAT = *G.endHPFS) != '\0') {
  1992.             ++G.endFAT;
  1993.             ++G.endHPFS;
  1994.         }
  1995.         Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS)));
  1996.         return 0;
  1997.     }
  1998.  
  1999. /*---------------------------------------------------------------------------
  2000.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  2001.     sary; else assume it's a zipfile member and return.  This path segment
  2002.     gets used in extracting all members from every zipfile specified on the
  2003.     command line.  Note that under OS/2 and MS-DOS, if a candidate extract-to
  2004.     directory specification includes a drive letter (leading "x:"), it is
  2005.     treated just as if it had a trailing '/'--that is, one directory level
  2006.     will be created if the path doesn't exist, unless this is otherwise pro-
  2007.     hibited (e.g., freshening).
  2008.   ---------------------------------------------------------------------------*/
  2009.  
  2010. #if (!defined(SFX) || defined(SFX_EXDIR))
  2011.     if (FUNCTION == ROOT) {
  2012.         Trace((stderr, "initializing root path to [%s]\n",
  2013.           FnFilter1(pathcomp)));
  2014.         if (pathcomp == NULL) {
  2015.             G.rootlen = 0;
  2016.             return 0;
  2017.         }
  2018.         if ((G.rootlen = strlen(pathcomp)) > 0) {
  2019.             int had_trailing_pathsep=FALSE, has_drive=FALSE, xtra=2;
  2020.  
  2021.             if (isalpha((uch)pathcomp[0]) && pathcomp[1] == ':')
  2022.                 has_drive = TRUE;   /* drive designator */
  2023.             if (pathcomp[G.rootlen-1] == '/' || pathcomp[G.rootlen-1] == '\\') {
  2024.                 pathcomp[--G.rootlen] = '\0';
  2025.                 had_trailing_pathsep = TRUE;
  2026.             }
  2027.             if (has_drive && (G.rootlen == 2)) {
  2028.                 if (!had_trailing_pathsep)   /* i.e., original wasn't "x:/" */
  2029.                     xtra = 3;      /* room for '.' + '/' + 0 at end of "x:" */
  2030.             } else if (G.rootlen > 0) {   /* need not check "x:." and "x:/" */
  2031.                 if (SSTAT(pathcomp, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
  2032.                 {
  2033.                     /* path does not exist */
  2034.                     if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  2035.                         G.rootlen = 0;
  2036.                         return 2;   /* treat as stored file */
  2037.                     }
  2038.                     /* create directory (could add loop here to scan pathcomp
  2039.                      * and create more than one level, but really necessary?) */
  2040.                     if (MKDIR(pathcomp, 0777) == -1) {
  2041.                         Info(slide, 1, ((char *)slide,
  2042.                           "checkdir:  cannot create extraction directory: %s\n",
  2043.                           FnFilter1(pathcomp)));
  2044.                         G.rootlen = 0; /* path didn't exist, tried to create, */
  2045.                         return 3;  /* failed:  file exists, or need 2+ levels */
  2046.                     }
  2047.                 }
  2048.             }
  2049.             if ((G.rootpath = (char *)malloc(G.rootlen+xtra)) == NULL) {
  2050.                 G.rootlen = 0;
  2051.                 return 10;
  2052.             }
  2053.             strcpy(G.rootpath, pathcomp);
  2054.             if (xtra == 3)                  /* had just "x:", make "x:." */
  2055.                 G.rootpath[G.rootlen++] = '.';
  2056.             G.rootpath[G.rootlen++] = '/';
  2057.             G.rootpath[G.rootlen] = '\0';
  2058.             Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
  2059.         }
  2060.         return 0;
  2061.     }
  2062. #endif /* !SFX || SFX_EXDIR */
  2063.  
  2064. /*---------------------------------------------------------------------------
  2065.     END:  free rootpath, immediately prior to program exit.
  2066.   ---------------------------------------------------------------------------*/
  2067.  
  2068.     if (FUNCTION == END) {
  2069.         Trace((stderr, "freeing rootpath\n"));
  2070.         if (G.rootlen > 0) {
  2071.             free(G.rootpath);
  2072.             G.rootlen = 0;
  2073.         }
  2074.         return 0;
  2075.     }
  2076.  
  2077.     return 99;  /* should never reach */
  2078.  
  2079. } /* end function checkdir() */
  2080.  
  2081.  
  2082.  
  2083.  
  2084.  
  2085. #ifndef SFX
  2086. #ifndef WINDLL
  2087.  
  2088. /************************/
  2089. /*  Function version()  */
  2090. /************************/
  2091.  
  2092. void version(__G)
  2093.     __GDEF
  2094. {
  2095.     int len;
  2096. #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__))
  2097.     char buf[80];
  2098. #if (defined(_MSC_VER) && (_MSC_VER > 900))
  2099.     char buf2[80];
  2100. #endif
  2101. #endif
  2102.  
  2103.     len = sprintf((char *)slide, CompiledWith,
  2104.  
  2105. #if defined(_MSC_VER)  /* MSC == VC++, but what about SDK compiler? */
  2106.       (sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100), buf),
  2107. #  if (_MSC_VER == 800)
  2108.       "(Visual C++ v1.1)",
  2109. #  elif (_MSC_VER == 850)
  2110.       "(Windows NT v3.5 SDK)",
  2111. #  elif (_MSC_VER == 900)
  2112.       "(Visual C++ v2.x)",
  2113. #  elif (_MSC_VER > 900)
  2114.       (sprintf(buf2, "(Visual C++ %d.%d)", _MSC_VER/100 - 6, _MSC_VER%100/10),
  2115.         buf2),
  2116. #  else
  2117.       "(bad version)",
  2118. #  endif
  2119. #elif defined(__WATCOMC__)
  2120. #  if (__WATCOMC__ % 10 > 0)
  2121.       (sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
  2122.        __WATCOMC__ % 100), buf), "",
  2123. #  else
  2124.       (sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
  2125.        (__WATCOMC__ % 100) / 10), buf), "",
  2126. #  endif
  2127. #elif defined(__BORLANDC__)
  2128.       "Borland C++",
  2129. #  if (__BORLANDC__ < 0x0200)
  2130.       " 1.0",
  2131. #  elif (__BORLANDC__ == 0x0200)
  2132.       " 2.0",
  2133. #  elif (__BORLANDC__ == 0x0400)
  2134.       " 3.0",
  2135. #  elif (__BORLANDC__ == 0x0410)   /* __BCPLUSPLUS__ = 0x0310 */
  2136.       " 3.1",
  2137. #  elif (__BORLANDC__ == 0x0452)   /* __BCPLUSPLUS__ = 0x0320 */
  2138.       " 4.0 or 4.02",
  2139. #  elif (__BORLANDC__ == 0x0460)   /* __BCPLUSPLUS__ = 0x0340 */
  2140.       " 4.5",
  2141. #  elif (__BORLANDC__ == 0x0500)   /* __BCPLUSPLUS__ = 0x0340 */
  2142.       " 5.0",
  2143. #  elif (__BORLANDC__ == 0x0520)   /* __BCPLUSPLUS__ = 0x0520 */
  2144.       " 5.2 (C++ Builder)",        /* GRR:  assume this will stay sync'd? */
  2145. #  else
  2146.       " later than 5.2",
  2147. #  endif
  2148. #elif defined(__LCC__)
  2149.       "LCC-Win32", "",
  2150. #elif defined(__GNUC__)
  2151. #  if defined(__RSXNT__)
  2152. #    if (defined(__DJGPP__) && !defined(__EMX__))
  2153.       (sprintf(buf, "rsxnt(djgpp v%d.%02d) / gcc ",
  2154.         __DJGPP__, __DJGPP_MINOR__), buf),
  2155. #    elif defined(__DJGPP__)
  2156.       (sprintf(buf, "rsxnt(emx+djgpp v%d.%02d) / gcc ",
  2157.         __DJGPP__, __DJGPP_MINOR__), buf),
  2158. #    elif (defined(__GO32__) && !defined(__EMX__))
  2159.       "rsxnt(djgpp v1.x) / gcc ",
  2160. #    elif defined(__GO32__)
  2161.       "rsxnt(emx + djgpp v1.x) / gcc ",
  2162. #    elif defined(__EMX__)
  2163.       "rsxnt(emx)+gcc ",
  2164. #    else
  2165.       "rsxnt(unknown) / gcc ",
  2166. #    endif
  2167. #  elif defined(__CYGWIN32__)
  2168.       "cygnus win32 / gcc ",
  2169. #  elif defined(__MINGW32__)
  2170.       "mingw32 / gcc ",
  2171. #  else
  2172.       "gcc ",
  2173. #  endif
  2174.       __VERSION__,
  2175. #else /* !_MSC_VER, !__WATCOMC__, !__BORLANDC__, !__LCC__, !__GNUC__ */
  2176.       "unknown compiler (SDK?)", "",
  2177. #endif /* ?compilers */
  2178.  
  2179.       "Windows 95 / Windows NT", "\n(32-bit)",
  2180.  
  2181. #ifdef __DATE__
  2182.       " on ", __DATE__
  2183. #else
  2184.       "", ""
  2185. #endif
  2186.     );
  2187.  
  2188.     (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
  2189.  
  2190.     return;
  2191.  
  2192. } /* end function version() */
  2193.  
  2194. #endif /* !WINDLL */
  2195. #endif /* !SFX */
  2196.  
  2197.  
  2198.  
  2199. #ifdef W32_STAT_BANDAID
  2200.  
  2201. /* All currently known variants of WIN32 operating systems (Windows 95/98,
  2202.  * WinNT 3.x, 4.0, 5.0) have a nasty bug in the OS kernel concerning
  2203.  * conversions between UTC and local time: In the time conversion functions
  2204.  * of the Win32 API, the timezone offset (including seasonal daylight saving
  2205.  * shift) between UTC and local time evaluation is erratically based on the
  2206.  * current system time. The correct evaluation must determine the offset
  2207.  * value as it {was/is/will be} for the actual time to be converted.
  2208.  *
  2209.  * Some versions of MS C runtime lib's stat() returns utc time-stamps so
  2210.  * that localtime(timestamp) corresponds to the (potentially false) local
  2211.  * time shown by the OS' system programs (Explorer, command shell dir, etc.)
  2212.  * The RSXNT port follows the same strategy, but fails to recognize the
  2213.  * access-time attribute.
  2214.  *
  2215.  * For the NTFS file system (and other filesystems that store time-stamps
  2216.  * as UTC values), this results in st_mtime (, st_{c|a}time) fields which
  2217.  * are not stable but vary according to the seasonal change of "daylight
  2218.  * saving time in effect / not in effect".
  2219.  *
  2220.  * Other C runtime libs (CygWin, or the CRT DLLs supplied with Win95/NT
  2221.  * return the unix-time equivalent of the UTC FILETIME values as got back
  2222.  * from the Win32 API call. This time, return values from NTFS are correct
  2223.  * whereas utimes from files on (V)FAT volumes vary according to the DST
  2224.  * switches.
  2225.  *
  2226.  * To achieve timestamp consistency of UTC (UT extra field) values in
  2227.  * Zip archives, the Info-ZIP programs require work-around code for
  2228.  * proper time handling in stat() (and other time handling routines).
  2229.  */
  2230. /* stat() functions under Windows95 tend to fail for root directories.   *
  2231.  * Watcom and Borland, at least, are affected by this bug.  Watcom made  *
  2232.  * a partial fix for 11.0 but still missed some cases.  This substitute  *
  2233.  * detects the case and fills in reasonable values.  Otherwise we get    *
  2234.  * effects like failure to extract to a root dir because it's not found. */
  2235.  
  2236. int zstat_win32(__W32STAT_GLOBALS__ const char *path, struct stat *buf)
  2237. {
  2238.     if (!stat(path, buf))
  2239.     {
  2240. #ifdef NT_TZBUG_WORKAROUND
  2241.         /* stat was successful, now redo the time-stamp fetches */
  2242.         int fs_uses_loctime = FStampIsLocTime(__G__ path);
  2243.         HANDLE h;
  2244.         FILETIME Modft, Accft, Creft;
  2245. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  2246.         char *ansi_path = (char *)alloca(strlen(path) + 1);
  2247.  
  2248.         INTERN_TO_ISO(path, ansi_path);
  2249. #       define Ansi_Path  ansi_path
  2250. #else
  2251. #       define Ansi_Path  path
  2252. #endif
  2253.  
  2254.         TTrace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
  2255.         h = CreateFile(Ansi_Path, GENERIC_READ,
  2256.                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  2257.                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  2258.         if (h != INVALID_HANDLE_VALUE) {
  2259.             BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
  2260.             CloseHandle(h);
  2261.  
  2262.             if (ftOK) {
  2263.                 FTTrace((stdout, "GetFileTime returned Modft", 0, &Modft));
  2264.                 FTTrace((stdout, "GetFileTime returned Creft", 0, &Creft));
  2265.                 if (!fs_uses_loctime) {
  2266.                     /*  On a filesystem that stores UTC timestamps, we refill
  2267.                      *  the time fields of the struct stat buffer by directly
  2268.                      *  using the UTC values as returned by the Win32
  2269.                      *  GetFileTime() API call.
  2270.                      */
  2271.                     FileTime2utime(&Modft, &(buf->st_mtime));
  2272.                     if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
  2273.                         FileTime2utime(&Accft, &(buf->st_atime));
  2274.                     else
  2275.                         buf->st_atime = buf->st_mtime;
  2276.                     if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
  2277.                         FileTime2utime(&Creft, &(buf->st_ctime));
  2278.                     else
  2279.                         buf->st_ctime = buf->st_mtime;
  2280.                     TTrace((stdout,"NTFS, recalculated modtime %08lx\n",
  2281.                             buf->st_mtime));
  2282.                 } else {
  2283.                     /*  On VFAT and FAT-like filesystems, the FILETIME values
  2284.                      *  are converted back to the stable local time before
  2285.                      *  converting them to UTC unix time-stamps.
  2286.                      */
  2287.                     VFatFileTime2utime(&Modft, &(buf->st_mtime));
  2288.                     if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
  2289.                         VFatFileTime2utime(&Accft, &(buf->st_atime));
  2290.                     else
  2291.                         buf->st_atime = buf->st_mtime;
  2292.                     if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
  2293.                         VFatFileTime2utime(&Creft, &(buf->st_ctime));
  2294.                     else
  2295.                         buf->st_ctime = buf->st_mtime;
  2296.                     TTrace((stdout, "VFAT, recalculated modtime %08lx\n",
  2297.                             buf->st_mtime));
  2298.                 }
  2299.             }
  2300.         }
  2301. #       undef Ansi_Path
  2302. #endif /* NT_TZBUG_WORKAROUND */
  2303.         return 0;
  2304.     }
  2305. #ifdef W32_STATROOT_FIX
  2306.     else
  2307.     {
  2308.         DWORD flags;
  2309. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  2310.         char *ansi_path = (char *)alloca(strlen(path) + 1);
  2311.  
  2312.         INTERN_TO_ISO(path, ansi_path);
  2313. #       define Ansi_Path  ansi_path
  2314. #else
  2315. #       define Ansi_Path  path
  2316. #endif
  2317.  
  2318.         flags = GetFileAttributes(Ansi_Path);
  2319.         if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
  2320.             Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
  2321.                    path));
  2322.             memset(buf, 0, sizeof(struct stat));
  2323.             buf->st_atime = buf->st_ctime = buf->st_mtime =
  2324.               dos_to_unix_time(DOSTIME_MINIMUM);        /* 1-1-80 */
  2325.             buf->st_mode = S_IFDIR | S_IREAD |
  2326.                            ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
  2327.             return 0;
  2328.         } /* assumes: stat() won't fail on non-dirs without good reason */
  2329. #       undef Ansi_Path
  2330.     }
  2331. #endif /* W32_STATROOT_FIX */
  2332.     return -1;
  2333. }
  2334.  
  2335. #endif /* W32_STAT_BANDAID */
  2336.  
  2337. #endif /* !FUNZIP */
  2338.  
  2339.  
  2340.  
  2341. #ifndef WINDLL
  2342. /* This replacement getch() function was originally created for Watcom C
  2343.  * and then additionally used with CYGWIN. Since UnZip 5.4, all other Win32
  2344.  * ports apply this replacement rather that their supplied getch() (or
  2345.  * alike) function.  There are problems with unabsorbed LF characters left
  2346.  * over in the keyboard buffer under Win95 (and 98) when ENTER was pressed.
  2347.  * (Under Win95, ENTER returns two(!!) characters: CR-LF.)  This problem
  2348.  * does not appear when run on a WinNT console prompt!
  2349.  */
  2350.  
  2351. /* Watcom 10.6's getch() does not handle Alt+<digit><digit><digit>. */
  2352. /* Note that if PASSWD_FROM_STDIN is defined, the file containing   */
  2353. /* the password must have a carriage return after the word, not a   */
  2354. /* Unix-style newline (linefeed only).  This discards linefeeds.    */
  2355.  
  2356. int getch_win32(void)
  2357. {
  2358.   HANDLE stin;
  2359.   DWORD rc;
  2360.   unsigned char buf[2];
  2361.   int ret = -1;
  2362.   DWORD odemode = ~(DWORD)0;
  2363.  
  2364. #  ifdef PASSWD_FROM_STDIN
  2365.   stin = GetStdHandle(STD_INPUT_HANDLE);
  2366. #  else
  2367.   stin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
  2368.                     FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  2369.   if (stin == INVALID_HANDLE_VALUE)
  2370.     return -1;
  2371. #  endif
  2372.   if (GetConsoleMode(stin, &odemode))
  2373.     SetConsoleMode(stin, ENABLE_PROCESSED_INPUT);  /* raw except ^C noticed */
  2374.   if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
  2375.     ret = buf[0];
  2376.   /* when the user hits return we get CR LF.  We discard the LF, not the CR,
  2377.    * because when we call this for the first time after a previous input
  2378.    * such as the one for "replace foo? [y]es, ..." the LF may still be in
  2379.    * the input stream before whatever the user types at our prompt. */
  2380.   if (ret == '\n')
  2381.     if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
  2382.       ret = buf[0];
  2383.   if (odemode != ~(DWORD)0)
  2384.     SetConsoleMode(stin, odemode);
  2385. #  ifndef PASSWD_FROM_STDIN
  2386.   CloseHandle(stin);
  2387. #  endif
  2388.   return ret;
  2389. }
  2390. #endif /* !WINDLL */
  2391.