Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.   Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
  3.  
  4.   See the accompanying file LICENSE, version 2007-Mar-04 or later
  5.   (the contents of which are also included in unzip.h) for terms of use.
  6.   If, for some reason, all these files are missing, the Info-ZIP license
  7.   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
  8. */
  9. /*---------------------------------------------------------------------------
  10.  
  11.   win32.c
  12.  
  13.   32-bit Windows-specific (NT/9x) routines for use with Info-ZIP's UnZip 5.3
  14.   and later.
  15.  
  16.   Contains:  GetLoadPath()
  17.              Opendir()
  18.              Readdir()
  19.              Closedir()
  20.              SetSD()              set security descriptor on file
  21.              FindSDExtraField()   extract SD e.f. block from extra field
  22.              IsWinNT()            indicate type of WIN32 platform
  23.              test_NTSD()          test integrity of NT security data
  24.              utime2NtfsFileTime()
  25.              utime2VFatFileTime()
  26.              FStampIsLocTime()
  27.              NtfsFileTime2utime()
  28.              VFatFileTime2utime()
  29.              getNTfiletime()
  30.              SetFileSize()
  31.              close_outfile()
  32.              defer_dir_attribs()
  33.              set_direc_attribs()
  34.              stamp_file()
  35.              isfloppy()
  36.              NTQueryVolInfo()
  37.              IsVolumeOldFAT()
  38.              do_wild()
  39.              mapattr()
  40.              mapname()
  41.              maskDOSdevice()
  42.              map2fat()
  43.              checkdir()
  44.              dateformat()
  45.              dateseparator()
  46.              version()
  47.              screensize()
  48.              zstat_win32()
  49.              conv_to_rule()
  50.              GetPlatformLocalTimezone()
  51.              getch_win32()
  52.  
  53.   ---------------------------------------------------------------------------*/
  54.  
  55.  
  56. #define UNZIP_INTERNAL
  57. #include "../unzip.h"
  58. #include <windows.h>    /* must be AFTER unzip.h to avoid struct G problems */
  59. #ifdef __RSXNT__
  60. #  include "../win32/rsxntwin.h"
  61. #endif
  62. #include "../win32/nt.h"
  63.  
  64. #ifndef FUNZIP          /* most of this file is not used with fUnZip */
  65.  
  66. /* some non-MS runtime headers (e.g. lcc) may miss this definition */
  67. #ifndef FILE_WRITE_ATTRIBUTES
  68. #  define FILE_WRITE_ATTRIBUTES 0x0100
  69. #endif
  70.  
  71. #if (defined(__EMX__) || defined(__CYGWIN__))
  72. #  define MKDIR(path,mode)   mkdir(path,mode)
  73. #else
  74. #  define MKDIR(path,mode)   mkdir(path)
  75. #endif
  76.  
  77. #ifdef HAVE_WORKING_DIRENT_H
  78. #  undef HAVE_WORKING_DIRENT_H
  79. #endif
  80. /* The emxrtl dirent support of (__GO32__ || __EMX__) converts to lowercase! */
  81. #if defined(__CYGWIN__)
  82. #  define HAVE_WORKING_DIRENT_H
  83. #endif
  84.  
  85. #ifndef SFX
  86. #  ifdef HAVE_WORKING_DIRENT_H
  87. #    include <dirent.h>         /* use readdir() */
  88. #    define zdirent  dirent
  89. #    define zDIR     DIR
  90. #    define Opendir  opendir
  91. #    define Readdir  readdir
  92. #    define Closedir closedir
  93. #  else /* !HAVE_WORKING_DIRENT_H */
  94.      typedef struct zdirent {
  95.          char    reserved [21];
  96.          char    ff_attrib;
  97.          short   ff_ftime;
  98.          short   ff_fdate;
  99.          long    size;
  100.          char    d_name[MAX_PATH];
  101.          int     d_first;
  102.          HANDLE  d_hFindFile;
  103.      } zDIR;
  104.  
  105.      static zDIR           *Opendir  (const char *n);
  106.      static struct zdirent *Readdir  (zDIR *d);
  107.      static void            Closedir (zDIR *d);
  108. #  endif /* ?HAVE_WORKING_DIRENT_H */
  109. #endif /* !SFX */
  110.  
  111. #ifdef SET_DIR_ATTRIB
  112. typedef struct NTdirattr {      /* struct for holding unix style directory */
  113.     struct NTdirattr *next;     /*  info until can be sorted and set at end */
  114.     char *fn;                   /* filename of directory */
  115.     FILETIME Modft;    /* File time type defined in NT, `last modified' time */
  116.     FILETIME Accft;    /* NT file time type, `last access' time */
  117.     FILETIME Creft;    /* NT file time type, `file creation' time */
  118.     int gotTime;
  119.     unsigned perms;             /* same as min_info.file_attr */
  120. #ifdef NTSD_EAS
  121.     unsigned SDlen;             /* length of SD data in buf */
  122. #endif
  123.     char buf[1];                /* buffer stub for directory SD and name */
  124. } NTdirattr;
  125. #define NtAtt(d)  ((NTdirattr *)d)    /* typecast shortcut */
  126. #endif /* SET_DIR_ATTRIB */
  127.  
  128.  
  129. /* Function prototypes */
  130. #ifdef NTSD_EAS
  131.    static int  SetSD(__GPRO__ char *path, unsigned fperms,
  132.                      uch *eb_ptr, unsigned eb_len);
  133.    static int  FindSDExtraField(__GPRO__
  134.                                 uch *ef_ptr, unsigned ef_len,
  135.                                 uch **p_ebSD_ptr, unsigned *p_ebSD_len);
  136. #endif
  137.  
  138. #ifndef NO_W32TIMES_IZFIX
  139.    static void utime2NtfsFileTime(time_t ut, FILETIME *pft);
  140. #endif
  141. static void utime2VFatFileTime(time_t ut, FILETIME *pft, int clipDosMin);
  142. #if (defined(W32_STAT_BANDAID) && !defined(NO_W32TIMES_IZFIX))
  143.    static int NtfsFileTime2utime(const FILETIME *pft, time_t *ut);
  144. #endif
  145. #ifdef W32_STAT_BANDAID
  146.    static int VFatFileTime2utime(const FILETIME *pft, time_t *ut);
  147. #endif
  148. static int FStampIsLocTime(__GPRO__ const char *path);
  149.  
  150.  
  151. static int  getNTfiletime   (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT,
  152.                              FILETIME *pCreFT);
  153. static int  isfloppy        (int nDrive);
  154. static int  NTQueryVolInfo  (__GPRO__ const char *name);
  155. static int  IsVolumeOldFAT  (__GPRO__ const char *name);
  156. static void maskDOSdevice   (__GPRO__ char *pathcomp);
  157. static void map2fat         (char *pathcomp, char **pEndFAT);
  158.  
  159.  
  160. #if (defined(__MINGW32__) && !defined(USE_MINGW_GLOBBING))
  161.    int _CRT_glob = 0;   /* suppress command line globbing by C RTL */
  162. #endif
  163.  
  164. #ifdef ACORN_FTYPE_NFS
  165. /* Acorn bits for NFS filetyping */
  166. typedef struct {
  167.   uch ID[2];
  168.   uch size[2];
  169.   uch ID_2[4];
  170.   uch loadaddr[4];
  171.   uch execaddr[4];
  172.   uch attr[4];
  173. } RO_extra_block;
  174.  
  175. #endif /* ACORN_FTYPE_NFS */
  176.  
  177. /* static int created_dir;      */     /* used by mapname(), checkdir() */
  178. /* static int renamed_fullpath; */     /* ditto */
  179. /* static int fnlen;            */     /* ditto */
  180. /* static unsigned nLabelDrive; */     /* ditto */
  181.  
  182. extern char Far TruncNTSD[];    /* in extract.c */
  183.  
  184.  
  185.  
  186. #ifdef SFX
  187.  
  188. /**************************/
  189. /* Function GetLoadPath() */
  190. /**************************/
  191.  
  192. char *GetLoadPath(__GPRO)
  193. {
  194. #ifdef MSC
  195.     extern char *_pgmptr;
  196.     return _pgmptr;
  197.  
  198. #else    /* use generic API call */
  199.  
  200.     GetModuleFileName(NULL, G.filename, FILNAMSIZ);
  201.     _ISO_INTERN(G.filename);    /* translate to codepage of C rtl's stdio */
  202.     return G.filename;
  203. #endif
  204.  
  205. } /* end function GetLoadPath() */
  206.  
  207.  
  208.  
  209.  
  210.  
  211. #else /* !SFX */
  212.  
  213. #ifndef HAVE_WORKING_DIRENT_H
  214.  
  215. /**********************/        /* Borrowed from ZIP 2.0 sources            */
  216. /* Function Opendir() */        /* Difference: no special handling for      */
  217. /**********************/        /*             hidden or system files.      */
  218.  
  219. static zDIR *Opendir(n)
  220.     const char *n;          /* directory to open */
  221. {
  222.     zDIR *d;                /* malloc'd return value */
  223.     char *p;                /* malloc'd temporary string */
  224.     WIN32_FIND_DATAA fd;
  225.     extent len = strlen(n);
  226.  
  227.     /* Start searching for files in directory n */
  228.  
  229.     if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL ||
  230.         (p = malloc(strlen(n) + 5)) == NULL)
  231.     {
  232.         if (d != (zDIR *)NULL)
  233.             free((void *)d);
  234.         return (zDIR *)NULL;
  235.     }
  236.     INTERN_TO_ISO(n, p);
  237.     if (len > 0) {
  238.         if (p[len-1] == ':')
  239.             p[len++] = '.';     /* x: => x:. */
  240.         else if (p[len-1] == '/' || p[len-1] == '\\')
  241.             --len;              /* foo/ => foo */
  242.     }
  243.     strcpy(p+len, "/*");
  244.  
  245.     if (INVALID_HANDLE_VALUE == (d->d_hFindFile = FindFirstFileA(p, &fd))) {
  246.         free((zvoid *)d);
  247.         free((zvoid *)p);
  248.         return NULL;
  249.     }
  250.     strcpy(d->d_name, fd.cFileName);
  251.  
  252.     free((zvoid *)p);
  253.     d->d_first = 1;
  254.     return d;
  255.  
  256. } /* end of function Opendir() */
  257.  
  258.  
  259.  
  260.  
  261. /**********************/        /* Borrowed from ZIP 2.0 sources            */
  262. /* Function Readdir() */        /* Difference: no special handling for      */
  263. /**********************/        /*             hidden or system files.      */
  264.  
  265. static struct zdirent *Readdir(d)
  266.     zDIR *d;                    /* directory stream from which to read */
  267. {
  268.     /* Return pointer to first or next directory entry, or NULL if end. */
  269.  
  270.     if ( d->d_first )
  271.         d->d_first = 0;
  272.     else
  273.     {
  274.         WIN32_FIND_DATAA fd;
  275.  
  276.         if ( !FindNextFileA(d->d_hFindFile, &fd) )
  277.             return NULL;
  278.  
  279.         ISO_TO_INTERN(fd.cFileName, d->d_name);
  280.     }
  281.     return (struct zdirent *)d;
  282.  
  283. } /* end of function Readdir() */
  284.  
  285.  
  286.  
  287.  
  288. /***********************/
  289. /* Function Closedir() */       /* Borrowed from ZIP 2.0 sources */
  290. /***********************/
  291.  
  292. static void Closedir(d)
  293.     zDIR *d;                    /* directory stream to close */
  294. {
  295.     FindClose(d->d_hFindFile);
  296.     free(d);
  297. }
  298.  
  299. #endif /* !HAVE_WORKING_DIRENT_H */
  300. #endif /* ?SFX */
  301.  
  302.  
  303.  
  304.  
  305. #ifdef NTSD_EAS
  306.  
  307. /**********************/
  308. /*  Function SetSD()  */   /* return almost-PK errors */
  309. /**********************/
  310.  
  311. static int SetSD(__G__ path, fperms, eb_ptr, eb_len)
  312.     __GDEF
  313.     char *path;
  314.     unsigned fperms;
  315.     uch *eb_ptr;
  316.     unsigned eb_len;
  317. {
  318.     ulg ntsd_ucSize;
  319.     VOLUMECAPS VolumeCaps;
  320.     uch *security_data;
  321.     int error;
  322.  
  323.     ntsd_ucSize = makelong(eb_ptr + (EB_HEADSIZE+EB_UCSIZE_P));
  324.     if (ntsd_ucSize > 0L && eb_len <= (EB_NTSD_L_LEN + EB_CMPRHEADLEN))
  325.         return IZ_EF_TRUNC;               /* no compressed data! */
  326.  
  327.     /* provide useful input */
  328.     VolumeCaps.dwFileAttributes = fperms;
  329.     VolumeCaps.bUsePrivileges = (uO.X_flag > 1);
  330.  
  331.     /* check target volume capabilities - just fall through
  332.      * and try if fail */
  333.     if (GetVolumeCaps(G.rootpath, path, &VolumeCaps) &&
  334.         !(VolumeCaps.dwFileSystemFlags & FS_PERSISTENT_ACLS))
  335.         return PK_OK;
  336.  
  337.     /* allocate storage for uncompressed data */
  338.     security_data = (uch *)malloc((extent)ntsd_ucSize);
  339.     if (security_data == (uch *)NULL)
  340.         return PK_MEM4;
  341.  
  342.     error = memextract(__G__ security_data, ntsd_ucSize,
  343.       (eb_ptr + (EB_HEADSIZE+EB_NTSD_L_LEN)), (ulg)(eb_len - EB_NTSD_L_LEN));
  344.  
  345.     if (error == PK_OK) {
  346.         if (SecuritySet(path, &VolumeCaps, security_data)) {
  347.             error = PK_COOL;
  348.             if (!uO.tflag && QCOND2)
  349.                 Info(slide, 0, ((char *)slide, " (%ld bytes security)",
  350.                   ntsd_ucSize));
  351.         }
  352.     }
  353.  
  354.     free(security_data);
  355.     return error;
  356. }
  357.  
  358.  
  359.  
  360.  
  361. /********************************/   /* scan extra fields for something */
  362. /*  Function FindSDExtraField() */   /*  we happen to know */
  363. /********************************/
  364. /* Returns TRUE when a valid NTFS SD block is found.
  365.  * Address and size of the NTSD e.f. block are passed up to the caller.
  366.  * In case of more than one valid NTSD block in the e.f., the last block
  367.  * found is passed up.
  368.  * Returns FALSE and leaves the content of the ebSD_ptr and ebSD_len
  369.  * parameters untouched when no valid NTFS SD block is found. */
  370. static int FindSDExtraField(__GPRO__
  371.                             uch *ef_ptr, unsigned ef_len,
  372.                             uch **p_ebSD_ptr, unsigned *p_ebSD_len)
  373. {
  374.     int rc = FALSE;
  375.  
  376.     if (!uO.X_flag)
  377.         return FALSE;  /* user said don't process ACLs; for now, no other
  378.                           extra block types are handled here */
  379.  
  380.     while (ef_len >= EB_HEADSIZE)
  381.     {
  382.         unsigned eb_id = makeword(EB_ID + ef_ptr);
  383.         unsigned eb_len = makeword(EB_LEN + ef_ptr);
  384.  
  385.         if (eb_len > (ef_len - EB_HEADSIZE)) {
  386.             /* discovered some extra field inconsistency! */
  387.             Trace((stderr,
  388.               "FindSDExtraField: block length %u > rest ef_size %u\n", eb_len,
  389.               ef_len - EB_HEADSIZE));
  390.             break;
  391.         }
  392.  
  393.         switch (eb_id)
  394.         {
  395.             /* process security descriptor extra data if:
  396.                  Caller is WinNT AND
  397.                  Target local/remote drive supports acls AND
  398.                  Target file is not a directory (else we defer processing
  399.                    until later)
  400.              */
  401.             case EF_NTSD:
  402.                 if (!IsWinNT())
  403.                     break; /* OS not capable of handling NTFS attributes */
  404.  
  405.                 if (eb_len < EB_NTSD_L_LEN)
  406.                     break; /* not a valid NTSD extra field */
  407.  
  408.                 /* check if we know how to handle this version */
  409.                 if (*(ef_ptr + (EB_HEADSIZE+EB_NTSD_VERSION))
  410.                     > (uch)EB_NTSD_MAX_VER)
  411.                     break;
  412.  
  413.                 *p_ebSD_ptr = ef_ptr;
  414.                 *p_ebSD_len = eb_len;
  415.                 rc = TRUE;
  416.                 break;
  417.  
  418. #ifdef DEBUG
  419.             case EF_OS2:
  420.             case EF_AV:
  421.             case EF_PKVMS:
  422.             case EF_PKW32:
  423.             case EF_PKUNIX:
  424.             case EF_IZVMS:
  425.             case EF_IZUNIX:
  426.             case EF_IZUNIX2:
  427.             case EF_TIME:
  428.             case EF_MAC3:
  429.             case EF_JLMAC:
  430.             case EF_ZIPIT:
  431.             case EF_VMCMS:
  432.             case EF_MVS:
  433.             case EF_ACL:
  434.             case EF_ATHEOS:
  435.             case EF_BEOS:
  436.             case EF_QDOS:
  437.             case EF_AOSVS:
  438.             case EF_SPARK:
  439.             case EF_MD5:
  440.             case EF_ASIUNIX:
  441.                 break;          /* shut up for other known e.f. blocks  */
  442. #endif /* DEBUG */
  443.  
  444.             default:
  445.                 Trace((stderr,
  446.                   "FindSDExtraField: unknown extra field block, ID=%u\n",
  447.                   eb_id));
  448.                 break;
  449.         }
  450.  
  451.         ef_ptr += (eb_len + EB_HEADSIZE);
  452.         ef_len -= (eb_len + EB_HEADSIZE);
  453.     }
  454.  
  455.     return rc;
  456. }
  457.  
  458.  
  459.  
  460.  
  461. #ifndef SFX
  462.  
  463. /**************************/
  464. /*  Function test_NTSD()  */   /*  returns PK_WARN when NTSD data is invalid */
  465. /**************************/
  466.  
  467. #ifdef __BORLANDC__
  468. /* Turn off warning about not using all parameters for this function only */
  469. #pragma argsused
  470. #endif
  471. int test_NTSD(__G__ eb, eb_size, eb_ucptr, eb_ucsize)
  472.     __GDEF
  473.     uch *eb;
  474.     unsigned eb_size;
  475.     uch *eb_ucptr;
  476.     ulg eb_ucsize;
  477. {
  478.     return (ValidateSecurity(eb_ucptr) ? PK_OK : PK_WARN);
  479. } /* end function test_NTSD() */
  480.  
  481. #endif /* !SFX */
  482. #endif /* NTSD_EAS */
  483.  
  484.  
  485.  
  486.  
  487. /**********************/
  488. /* Function IsWinNT() */
  489. /**********************/
  490.  
  491. int IsWinNT(void)       /* returns TRUE if real NT, FALSE if Win9x or Win32s */
  492. {
  493.     static DWORD g_PlatformId = 0xFFFFFFFF; /* saved platform indicator */
  494.  
  495.     if (g_PlatformId == 0xFFFFFFFF) {
  496.         /* note: GetVersionEx() doesn't exist on WinNT 3.1 */
  497.         if (GetVersion() < 0x80000000)
  498.             g_PlatformId = TRUE;
  499.         else
  500.             g_PlatformId = FALSE;
  501.     }
  502.     return (int)g_PlatformId;
  503. }
  504.  
  505.  
  506. /* DEBUG_TIME insertion: */
  507. #ifdef DEBUG_TIME
  508. static int show_NTFileTime(FILE *hdo, char *TTmsg, int isloc, FILETIME *pft);
  509.  
  510. static int show_NTFileTime(FILE *hdo, char *TTmsg, int isloc, FILETIME *pft)
  511. {
  512.     SYSTEMTIME w32tm;
  513.     int rval;
  514.  
  515.     rval = FileTimeToSystemTime(pft, &w32tm);
  516.     if (!rval) {
  517.         fprintf(hdo, "%s\n %08lX,%08lX (%s) -> Conversion failed !!!\n",
  518.                 TTmsg, (ulg)(pft->dwHighDateTime), (ulg)(pft->dwLowDateTime),
  519.                 (isloc ? "local" : "UTC"));
  520.     } else {
  521.         fprintf(hdo, "%s\n %08lx,%08lx -> %04u-%02u-%02u, %02u:%02u:%02u %s\n",
  522.                 TTmsg, (ulg)(pft->dwHighDateTime), (ulg)(pft->dwLowDateTime),
  523.                 w32tm.wYear, w32tm.wMonth, w32tm.wDay, w32tm.wHour,
  524.                 w32tm.wMinute, w32tm.wSecond, (isloc ? "local" : "UTC"));
  525.     }
  526.     return rval;
  527. }
  528. #define FTTrace(x)   show_NTFileTime x
  529. #else
  530. #define FTTrace(x)
  531. #endif /* DEBUG_TIME */
  532. /* end of DEBUG_TIME insertion */
  533.  
  534. #ifndef IZ_USE_INT64
  535. #  if (defined(__GNUC__) || defined(ULONG_LONG_MAX))
  536.      typedef long long            LLONG64;
  537.      typedef unsigned long long   ULLNG64;
  538. #    define IZ_USE_INT64
  539. #  elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100))
  540.      typedef __int64              LLONG64;
  541.      typedef unsigned __int64     ULLNG64;
  542. #    define IZ_USE_INT64
  543. #  elif (defined(_MSC_VER) && (_MSC_VER >= 1100))
  544.      typedef __int64              LLONG64;
  545.      typedef unsigned __int64     ULLNG64;
  546. #    define IZ_USE_INT64
  547. #  elif (defined(__IBMC__) && (__IBMC__ >= 350))
  548.      typedef __int64              LLONG64;
  549.      typedef unsigned __int64     ULLNG64;
  550. #    define IZ_USE_INT64
  551. #  elif defined(HAVE_INT64)
  552.      typedef __int64              LLONG64;
  553.      typedef unsigned __int64     ULLNG64;
  554. #    define IZ_USE_INT64
  555. #  endif
  556. #endif
  557.  
  558. /* scale factor and offset for conversion time_t -> FILETIME */
  559. #define NT_QUANTA_PER_UNIX 10000000L
  560. #define UNIX_TIME_ZERO_HI  0x019DB1DEUL
  561. #define UNIX_TIME_ZERO_LO  0xD53E8000UL
  562. /* special FILETIME values for bound-checks */
  563. #define UNIX_TIME_UMAX_HI  0x0236485EUL
  564. #define UNIX_TIME_UMAX_LO  0xD4A5E980UL
  565. #define UNIX_TIME_SMIN_HI  0x0151669EUL
  566. #define UNIX_TIME_SMIN_LO  0xD53E8000UL
  567. #define UNIX_TIME_SMAX_HI  0x01E9FD1EUL
  568. #define UNIX_TIME_SMAX_LO  0xD4A5E980UL
  569. #define DOSTIME_MIN_FT_HI  0x01A8E79FUL
  570. #define DOSTIME_MIN_FT_LO  0xE1D58000UL
  571. /* time_t equivalent of DOSTIME_MINIMUM */
  572. #define UTIME_1980_JAN_01_00_00   315532800L
  573.  
  574.  
  575. #ifndef NO_W32TIMES_IZFIX
  576. /*********************************/
  577. /* Function utime2NtfsFileTime() */ /* convert Unix time_t format into the */
  578. /*********************************/ /* form used by SetFileTime() in NT/9x */
  579.  
  580. static void utime2NtfsFileTime(time_t ut, FILETIME *pft)
  581. {
  582. #ifdef IZ_USE_INT64
  583.     ULLNG64 NTtime;
  584.  
  585.     /* NT_QUANTA_PER_UNIX is small enough so that "ut * NT_QUANTA_PER_UNIX"
  586.      * cannot overflow in 64-bit signed calculation, regardless whether "ut"
  587.      * is signed or unsigned.  */
  588.     NTtime = ((LLONG64)ut * NT_QUANTA_PER_UNIX) +
  589.              ((ULLNG64)UNIX_TIME_ZERO_LO + ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
  590.     pft->dwLowDateTime = (DWORD)NTtime;
  591.     pft->dwHighDateTime = (DWORD)(NTtime >> 32);
  592.  
  593. #else /* !IZ_USE_INT64 (64-bit integer arithmetics may not be supported) */
  594.     unsigned int b1, b2, carry = 0;
  595.     unsigned long r0, r1, r2, r3;
  596.     long r4;            /* signed, to catch environments with signed time_t */
  597.  
  598.     b1 = ut & 0xFFFF;
  599.     b2 = (ut >> 16) & 0xFFFF;       /* if ut is over 32 bits, too bad */
  600.     r1 = b1 * (NT_QUANTA_PER_UNIX & 0xFFFF);
  601.     r2 = b1 * (NT_QUANTA_PER_UNIX >> 16);
  602.     r3 = b2 * (NT_QUANTA_PER_UNIX & 0xFFFF);
  603.     r4 = b2 * (NT_QUANTA_PER_UNIX >> 16);
  604.     r0 = (r1 + (r2 << 16)) & 0xFFFFFFFFL;
  605.     if (r0 < r1)
  606.         carry++;
  607.     r1 = r0;
  608.     r0 = (r0 + (r3 << 16)) & 0xFFFFFFFFL;
  609.     if (r0 < r1)
  610.         carry++;
  611.     pft->dwLowDateTime = r0 + UNIX_TIME_ZERO_LO;
  612.     if (pft->dwLowDateTime < r0)
  613.         carry++;
  614.     pft->dwHighDateTime = r4 + (r2 >> 16) + (r3 >> 16)
  615.                             + UNIX_TIME_ZERO_HI + carry;
  616. #endif /* ?IZ_USE_INT64 */
  617.  
  618. } /* end function utime2NtfsFileTime() */
  619. #endif /* !NO_W32TIMES_IZFIX */
  620.  
  621.  
  622.  
  623. /*********************************/
  624. /* Function utime2VFatFileTime() */ /* convert Unix time_t format into the */
  625. /*********************************/ /* form used by SetFileTime() in NT/9x */
  626.  
  627. static void utime2VFatFileTime(time_t ut, FILETIME *pft, int clipDosMin)
  628. {
  629.     time_t utc = ut;
  630.     struct tm *ltm;
  631.     SYSTEMTIME w32tm;
  632.     FILETIME lft;
  633.  
  634.     /* The milliseconds field gets always initialized to 0. */
  635.     w32tm.wMilliseconds = 0;
  636.  
  637. #ifdef __BORLANDC__   /* Borland C++ 5.x crashes when trying to reference tm */
  638.     if (utc < UTIME_1980_JAN_01_00_00)
  639.         utc = UTIME_1980_JAN_01_00_00;
  640. #endif
  641.     ltm = localtime(&utc);
  642.     if (ltm == (struct tm *)NULL)
  643.         /* localtime() did not accept given utc time value; try to use
  644.            the UTC value */
  645.         ltm = gmtime(&utc);
  646.     if (ltm == (struct tm *)NULL) {
  647.         if (ut <= (UTIME_1980_JAN_01_00_00 + 86400)) {
  648.             /* use DOSTIME_MINIMUM date instead of "early" failure dates */
  649.             w32tm.wYear = 1980;
  650.             w32tm.wMonth = 1;
  651.             w32tm.wDay = 1;
  652.             w32tm.wHour = 0;
  653.             w32tm.wMinute = 0;
  654.             w32tm.wSecond = 0;
  655.         } else {
  656.             /* as a last resort, use the current system time */
  657.             GetLocalTime(&w32tm);
  658.         }
  659.     } else if (clipDosMin && (ltm->tm_year < 80)) {
  660.         w32tm.wYear = 1980;
  661.         w32tm.wMonth = 1;
  662.         w32tm.wDay = 1;
  663.         w32tm.wHour = 0;
  664.         w32tm.wMinute = 0;
  665.         w32tm.wSecond = 0;
  666.     } else {
  667.         w32tm.wYear = ltm->tm_year + 1900; /* year + 1900 -> year */
  668.         w32tm.wMonth = ltm->tm_mon + 1;    /* 0..11 -> 1..12 */
  669.         w32tm.wDay = ltm->tm_mday;         /* 1..31 */
  670.         w32tm.wHour = ltm->tm_hour;        /* 0..23 */
  671.         w32tm.wMinute = ltm->tm_min;       /* 0..59 */
  672.         w32tm.wSecond = ltm->tm_sec;       /* 0..61 in ANSI C */
  673.     }
  674.  
  675.     SystemTimeToFileTime(&w32tm, &lft);
  676.     LocalFileTimeToFileTime(&lft, pft);
  677.  
  678. } /* end function utime2VFatFileTime() */
  679.  
  680.  
  681.  
  682.  /* nonzero if `y' is a leap year, else zero */
  683. #define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0)
  684.  /* number of leap years from 1970 to `y' (not including `y' itself) */
  685. #define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
  686.  
  687. extern ZCONST ush ydays[];              /* defined in fileio.c */
  688.  
  689. #if (defined(W32_STAT_BANDAID) && !defined(NO_W32TIMES_IZFIX))
  690. /*********************************/
  691. /* Function NtfsFileTime2utime() */
  692. /*********************************/
  693.  
  694. static int NtfsFileTime2utime(const FILETIME *pft, time_t *ut)
  695. {
  696. #ifdef IZ_USE_INT64
  697.     ULLNG64 NTtime;
  698.  
  699.     NTtime = ((ULLNG64)pft->dwLowDateTime +
  700.               ((ULLNG64)pft->dwHighDateTime << 32));
  701.  
  702. #ifndef TIME_T_TYPE_DOUBLE
  703.     /* underflow and overflow handling */
  704. #ifdef CHECK_UTIME_SIGNED_UNSIGNED
  705.     if ((time_t)0x80000000L < (time_t)0L)
  706.     {
  707.         if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO +
  708.                       ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) {
  709.             *ut = (time_t)LONG_MIN;
  710.             return FALSE;
  711.         }
  712.         if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO +
  713.                       ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) {
  714.             *ut = (time_t)LONG_MAX;
  715.             return FALSE;
  716.         }
  717.     }
  718.     else
  719. #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
  720.     {
  721.         if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO +
  722.                       ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) {
  723.             *ut = (time_t)0;
  724.             return FALSE;
  725.         }
  726.         if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO +
  727.                       ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) {
  728.             *ut = (time_t)ULONG_MAX;
  729.             return FALSE;
  730.         }
  731.     }
  732. #endif /* !TIME_T_TYPE_DOUBLE */
  733.  
  734.     NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO +
  735.                ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
  736.     *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
  737.     return TRUE;
  738. #else /* !IZ_USE_INT64 (64-bit integer arithmetics may not be supported) */
  739.     time_t days;
  740.     SYSTEMTIME w32tm;
  741.  
  742. #ifndef TIME_T_TYPE_DOUBLE
  743.     /* underflow and overflow handling */
  744. #ifdef CHECK_UTIME_SIGNED_UNSIGNED
  745.     if ((time_t)0x80000000L < (time_t)0L)
  746.     {
  747.         if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
  748.             ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
  749.              (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
  750.             *ut = (time_t)LONG_MIN;
  751.             return FALSE;
  752.         if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
  753.             ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
  754.              (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
  755.             *ut = (time_t)LONG_MAX;
  756.             return FALSE;
  757.         }
  758.     }
  759.     else
  760. #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
  761.     {
  762.         if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
  763.             ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
  764.              (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
  765.             *ut = (time_t)0;
  766.             return FALSE;
  767.         }
  768.         if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
  769.             ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
  770.              (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
  771.             *ut = (time_t)ULONG_MAX;
  772.             return FALSE;
  773.         }
  774.     }
  775. #endif /* !TIME_T_TYPE_DOUBLE */
  776.  
  777.     FileTimeToSystemTime(pft, &w32tm);
  778.  
  779.     /* set `days' to the number of days into the year */
  780.     days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] +
  781.            (w32tm.wMonth > 2 && leap (w32tm.wYear));
  782.  
  783.     /* now set `days' to the number of days since 1 Jan 1970 */
  784.     days += 365 * (time_t)(w32tm.wYear - 1970) +
  785.             (time_t)(nleap(w32tm.wYear));
  786.  
  787.     *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour +
  788.                    (time_t)(60 * w32tm.wMinute + w32tm.wSecond));
  789.     return TRUE;
  790. #endif /* ?IZ_USE_INT64 */
  791. } /* end function NtfsFileTime2utime() */
  792. #endif /* W32_STAT_BANDAID && !NO_W32TIMES_IZFIX */
  793.  
  794.  
  795.  
  796. #ifdef W32_STAT_BANDAID
  797. /*********************************/
  798. /* Function VFatFileTime2utime() */
  799. /*********************************/
  800.  
  801. static int VFatFileTime2utime(const FILETIME *pft, time_t *ut)
  802. {
  803.     FILETIME lft;
  804. #ifndef HAVE_MKTIME
  805.     WORD wDOSDate, wDOSTime;
  806. #else
  807.     SYSTEMTIME w32tm;
  808.     struct tm ltm;
  809. #endif
  810.  
  811.     if (!FileTimeToLocalFileTime(pft, &lft)) {
  812.         /* if pft cannot be converted to local time, set ut to current time */
  813.         time(ut);
  814.         return FALSE;
  815.     }
  816.     FTTrace((stdout, "VFatFT2utime, feed for mktime()", 1, &lft));
  817. #ifndef HAVE_MKTIME
  818.     /* This version of the FILETIME-to-UNIXTIME conversion function
  819.      * uses DOS-DATE-TIME format as intermediate stage. For modification
  820.      * and access times, this is no problem. But, the extra fine resolution
  821.      * of the VFAT-stored creation time gets lost.
  822.      */
  823.     if (!FileTimeToDosDateTime(&lft, &wDOSDate, &wDOSTime)) {
  824.         static const FILETIME dosmin_ft =
  825.                 {DOSTIME_MIN_FT_LO, DOSTIME_MIN_FT_HI};
  826.         if (CompareFileTime(&lft, &dosmin_ft) <= 0) {
  827.             /* underflow -> set to minimum DOS time */
  828.             wDOSDate = (WORD)((DWORD)DOSTIME_MINIMUM >> 16);
  829.             wDOSTime = (WORD)DOSTIME_MINIMUM;
  830.         } else {
  831.             /* overflow -> set to maximum DOS time */
  832.             wDOSDate = (WORD)0xFF9F;    /* 2107-12-31 */
  833.             wDOSTime = (WORD)0xBF7D;    /* 23:59:58 */
  834.         }
  835.     }
  836.     TTrace((stdout,"DosDateTime is %04u-%02u-%02u %02u:%02u:%02u\n",
  837.       (unsigned)((wDOSDate>>9)&0x7f)+1980,(unsigned)((wDOSDate>>5)&0x0f),
  838.       (unsigned)(wDOSDate&0x1f),(unsigned)((wDOSTime>>11)&0x1f),
  839.       (unsigned)((wDOSTime>>5)&0x3f),(unsigned)((wDOSTime<<1)&0x3e)));
  840.     *ut = dos_to_unix_time(((ulg)wDOSDate << 16) | (ulg)wDOSTime);
  841.  
  842.     /* a cheap error check: dos_to_unix_time() only returns an odd time
  843.      * when clipping at maximum time_t value. DOS_DATE_TIME values have
  844.      * a resolution of 2 seconds and are therefore even numbers.
  845.      */
  846.     return (((*ut)&1) == (time_t)0);
  847. #else /* HAVE_MKTIME */
  848.     FileTimeToSystemTime(&lft, &w32tm);
  849. #ifndef TIME_T_TYPE_DOUBLE
  850.     /* underflow and overflow handling */
  851.     /* TODO: The range checks are not accurate, the actual limits may
  852.      *       be off by one daylight-saving-time shift (typically 1 hour),
  853.      *       depending on the current state of "is_dst".
  854.      */
  855. #ifdef CHECK_UTIME_SIGNED_UNSIGNED
  856.     if ((time_t)0x80000000L < (time_t)0L)
  857.     {
  858.         if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
  859.             ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
  860.              (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
  861.             *ut = (time_t)LONG_MIN;
  862.             return FALSE;
  863.         if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
  864.             ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
  865.              (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
  866.             *ut = (time_t)LONG_MAX;
  867.             return FALSE;
  868.         }
  869.     }
  870.     else
  871. #endif /* CHECK_UTIME_SIGNED_UNSIGNED */
  872.     {
  873.         if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
  874.             ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
  875.              (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
  876.             *ut = (time_t)0;
  877.             return FALSE;
  878.         }
  879.         if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
  880.             ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
  881.              (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
  882.             *ut = (time_t)ULONG_MAX;
  883.             return FALSE;
  884.         }
  885.     }
  886. #endif /* !TIME_T_TYPE_DOUBLE */
  887.     ltm.tm_year = w32tm.wYear - 1900;
  888.     ltm.tm_mon = w32tm.wMonth - 1;
  889.     ltm.tm_mday = w32tm.wDay;
  890.     ltm.tm_hour = w32tm.wHour;
  891.     ltm.tm_min = w32tm.wMinute;
  892.     ltm.tm_sec = w32tm.wSecond;
  893.     ltm.tm_isdst = -1;  /* let mktime determine if DST is in effect */
  894.     *ut = mktime(&ltm);
  895.  
  896.     /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors.
  897.      * Normally, we would have to apply a consistency check because "-1"
  898.      * could also be a valid time. But, it is quite unlikely to read back odd
  899.      * time numbers from file systems that store time stamps in DOS format.
  900.      * (The only known exception is creation time on VFAT partitions.)
  901.      */
  902.     return (*ut != (time_t)-1L);
  903. #endif /* ?HAVE_MKTIME */
  904.  
  905. } /* end function VFatFileTime2utime() */
  906. #endif /* W32_STAT_BANDAID */
  907.  
  908.  
  909.  
  910. /******************************/
  911. /* Function FStampIsLocTime() */
  912. /******************************/
  913.  
  914. static int FStampIsLocTime(__GPRO__ const char *path)
  915. {
  916.     return (NTQueryVolInfo(__G__ path) ? G.lastVolLocTim : FALSE);
  917. }
  918.  
  919.  
  920.  
  921. #ifndef NO_W32TIMES_IZFIX
  922. # define UTIME_2_IZFILETIME(ut, pft) \
  923.    if (fs_uses_loctime) {utime2VFatFileTime(ut, pft, TRUE);} \
  924.    else {utime2NtfsFileTime(ut, pft);}
  925. #else
  926. # define UTIME_2_IZFILETIME(ut, pft) \
  927.    utime2VFatFileTime(ut, pft, fs_uses_loctime);
  928. #endif
  929.  
  930.  
  931.  
  932. /****************************/      /* Get the file time in a format that */
  933. /* Function getNTfiletime() */      /*  can be used by SetFileTime() in NT */
  934. /****************************/
  935.  
  936. static int getNTfiletime(__G__ pModFT, pAccFT, pCreFT)
  937.     __GDEF
  938.     FILETIME *pModFT;
  939.     FILETIME *pAccFT;
  940.     FILETIME *pCreFT;
  941. {
  942. #ifdef USE_EF_UT_TIME
  943.     unsigned eb_izux_flg;
  944.     iztimes z_utime;   /* struct for Unix-style actime & modtime, + creatime */
  945. #endif
  946.     int fs_uses_loctime = FStampIsLocTime(__G__ G.filename);
  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_2_IZFILETIME(z_utime.mtime, pModFT)
  962.         if (eb_izux_flg & EB_UT_FL_ATIME) {
  963.             UTIME_2_IZFILETIME(z_utime.atime, pAccFT)
  964.         }
  965.         if (eb_izux_flg & EB_UT_FL_CTIME) {
  966.             UTIME_2_IZFILETIME(z_utime.ctime, pCreFT)
  967.         }
  968.         return (int)eb_izux_flg;
  969.     }
  970. #endif /* USE_EF_UT_TIME */
  971. #ifndef NO_W32TIMES_IZFIX
  972.     if (!fs_uses_loctime) {
  973.         time_t ux_modtime;
  974.  
  975.         ux_modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  976.         utime2NtfsFileTime(ux_modtime, pModFT);
  977.     } else
  978. #endif /* NO_W32TIMES_IZFIX */
  979.     {
  980.         FILETIME lft;
  981.  
  982.         DosDateTimeToFileTime((WORD)(G.lrec.last_mod_dos_datetime >> 16),
  983.                               (WORD)(G.lrec.last_mod_dos_datetime & 0xFFFFL),
  984.                               &lft);
  985.         LocalFileTimeToFileTime(&lft, pModFT);
  986.     }
  987.     *pAccFT = *pModFT;
  988.     return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
  989.  
  990. } /* end function getNTfiletime() */
  991.  
  992.  
  993.  
  994.  
  995. /**************************/
  996. /* Function SetFileSize() */
  997. /**************************/
  998.  
  999. int SetFileSize(FILE *file, zusz_t filesize)
  1000. {
  1001. #ifdef __RSXNT__
  1002.     /* RSXNT environment lacks a translation function from C file pointer
  1003.        to Win32-API file handle. So, simply do nothing. */
  1004.     return 0;
  1005. #else /* !__RSXNT__ */
  1006.     /* not yet verified, if that really creates an unfragmented file
  1007.       rommel@ars.de
  1008.      */
  1009.     HANDLE os_fh;
  1010. #ifdef Z_UINT8_DEFINED
  1011.     LARGE_INTEGER fsbuf;
  1012. #endif
  1013.  
  1014.     /* Win9x supports FAT file system, only; presetting file size does
  1015.        not help to prevent fragmentation. */
  1016.     if (!IsWinNT()) return 0;
  1017.  
  1018.     /* Win32-API calls require access to the Win32 file handle.
  1019.        The interface function used to retrieve the Win32 handle for
  1020.        a file opened by the C rtl is non-standard and may not be
  1021.        available for every Win32 compiler environment.
  1022.        (see also win32/win32.c of the Zip distribution)
  1023.      */
  1024.     os_fh = (HANDLE)_get_osfhandle(fileno(file));
  1025.     /* move file pointer behind the last byte of the expected file size */
  1026. #ifdef Z_UINT8_DEFINED
  1027.     fsbuf.QuadPart = filesize;
  1028.     if ((SetFilePointer(os_fh, fsbuf.LowPart, &fsbuf.HighPart, FILE_BEGIN)
  1029.          == 0xFFFFFFFF) && GetLastError() != NO_ERROR)
  1030. #else
  1031.     if (SetFilePointer(os_fh, (ulg)filesize, 0, FILE_BEGIN) == 0xFFFFFFFF)
  1032. #endif
  1033.         return -1;
  1034.     /* extend/truncate file to the current position */
  1035.     if (SetEndOfFile(os_fh) == 0)
  1036.         return -1;
  1037.     /* move file position pointer back to the start of the file! */
  1038.     return (SetFilePointer(os_fh, 0, 0, FILE_BEGIN) == 0xFFFFFFFF) ? -1 : 0;
  1039. #endif /* ?__RSXNT__ */
  1040. } /* end function SetFileSize() */
  1041.  
  1042.  
  1043.  
  1044.  
  1045. /****************************/
  1046. /* Function close_outfile() */
  1047. /****************************/
  1048.  
  1049. void close_outfile(__G)
  1050.     __GDEF
  1051. {
  1052.     FILETIME Modft;    /* File time type defined in NT, `last modified' time */
  1053.     FILETIME Accft;    /* NT file time type, `last access' time */
  1054.     FILETIME Creft;    /* NT file time type, `file creation' time */
  1055.     HANDLE hFile = INVALID_HANDLE_VALUE;        /* File handle defined in NT */
  1056.     int gotTime;
  1057. #ifdef NTSD_EAS
  1058.     uch *ebSDptr;
  1059.     unsigned ebSDlen;
  1060. #endif
  1061. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1062.     char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
  1063.  
  1064.     INTERN_TO_ISO(G.filename, ansi_name);
  1065. #   define Ansi_Fname  ansi_name
  1066. #else
  1067. #   define Ansi_Fname  G.filename
  1068. #endif
  1069.  
  1070. #ifndef __RSXNT__
  1071.     if (IsWinNT()) {
  1072.         /* Truncate the file to the current position.
  1073.          * This is needed to remove excess allocation in case the
  1074.          * extraction has failed or stopped prematurely. */
  1075.         SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile)));
  1076.     }
  1077. #endif
  1078.  
  1079.     /* Close the file and then re-open it using the Win32
  1080.      * CreateFile call, so that the file can be created
  1081.      * with GENERIC_WRITE access, otherwise the SetFileTime
  1082.      * call will fail. */
  1083.     fclose(G.outfile);
  1084.  
  1085.     /* don't set the time stamp and attributes on standard output */
  1086.     if (uO.cflag)
  1087.         return;
  1088.  
  1089.     /* skip restoring time stamps on user's request */
  1090.     if (uO.D_flag <= 1) {
  1091.         gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft);
  1092.  
  1093.         /* open a handle to the file before processing extra fields;
  1094.            we do this in case new security on file prevents us from updating
  1095.            time stamps */
  1096.         hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
  1097.              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1098.     } else {
  1099.         gotTime = 0;
  1100.     }
  1101.  
  1102.     /* sfield@microsoft.com: set attributes before time in case we decide to
  1103.        support other filetime members later.  This also allows us to apply
  1104.        attributes before the security is changed, which may prevent this
  1105.        from succeeding otherwise.  Also, since most files don't have
  1106.        any interesting attributes, only change them if something other than
  1107.        FILE_ATTRIBUTE_ARCHIVE appears in the attributes.  This works well
  1108.        as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
  1109.        file anyway, when it's created new. */
  1110.     if ((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
  1111.         if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
  1112.             Info(slide, 1, ((char *)slide,
  1113.               "\nwarning (%d): could not set file attributes\n",
  1114.               (int)GetLastError()));
  1115.     }
  1116.  
  1117. #ifdef NTSD_EAS
  1118.     /* set NTFS SD extra fields */
  1119.     if (G.extra_field &&    /* zipfile extra field may have extended attribs */
  1120.         FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
  1121.                          &ebSDptr, &ebSDlen))
  1122.     {
  1123.         int err = SetSD(__G__ Ansi_Fname, G.pInfo->file_attr,
  1124.                         ebSDptr, ebSDlen);
  1125.  
  1126.         if (err == IZ_EF_TRUNC) {
  1127.             if (uO.qflag)
  1128.                 Info(slide, 1, ((char *)slide, "%-22s ",
  1129.                   FnFilter1(G.filename)));
  1130.             Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
  1131.               ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":""));
  1132.         }
  1133.     }
  1134. #endif /* NTSD_EAS */
  1135.  
  1136.     /* skip restoring time stamps on user's request */
  1137.     if (uO.D_flag <= 1) {
  1138.         if ( hFile == INVALID_HANDLE_VALUE )
  1139.             Info(slide, 1, ((char *)slide,
  1140.               "\nCreateFile() error %d when trying set file time\n",
  1141.               (int)GetLastError()));
  1142.         else {
  1143.             if (gotTime) {
  1144.                 FILETIME *pModft = (gotTime & EB_UT_FL_MTIME) ? &Modft : NULL;
  1145.                 FILETIME *pAccft = (gotTime & EB_UT_FL_ATIME) ? &Accft : NULL;
  1146.                 FILETIME *pCreft = (gotTime & EB_UT_FL_CTIME) ? &Creft : NULL;
  1147.  
  1148.                 if (!SetFileTime(hFile, pCreft, pAccft, pModft))
  1149.                     Info(slide, 0, ((char *)slide,
  1150.                       "\nSetFileTime failed: %d\n", (int)GetLastError()));
  1151.             }
  1152.             CloseHandle(hFile);
  1153.         }
  1154.     }
  1155.  
  1156.     return;
  1157.  
  1158. #undef Ansi_Fname
  1159.  
  1160. } /* end function close_outfile() */
  1161.  
  1162.  
  1163.  
  1164.  
  1165. #ifdef SET_DIR_ATTRIB
  1166.  
  1167. int defer_dir_attribs(__G__ pd)
  1168.     __GDEF
  1169.     direntry **pd;
  1170. {
  1171.     NTdirattr *d_entry;
  1172. #ifdef NTSD_EAS
  1173.     uch *ebSDptr;
  1174.     unsigned ebSDlen;
  1175. #endif
  1176.  
  1177.     /* Win9x does not support setting directory time stamps. */
  1178.     if (!IsWinNT()) {
  1179.         *pd = (direntry *)NULL;
  1180.         return PK_OK;
  1181.     }
  1182.  
  1183. #ifdef NTSD_EAS
  1184.     /* set extended attributes from extra fields */
  1185.     if (G.extra_field &&  /* zipfile e.f. may have extended attribs */
  1186.         FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
  1187.                          &ebSDptr, &ebSDlen)) {
  1188.         /* ebSDlen contains the payload size of the e.f. block, but
  1189.            we store it including the e.b. header. */
  1190.         ebSDlen += EB_HEADSIZE;
  1191.     } else {
  1192.         /* no NTSD e.f. block -> no space needed to allocate */
  1193.         ebSDlen = 0;
  1194.     }
  1195. #endif /* NTSD_EAS */
  1196.  
  1197.     d_entry = (NTdirattr *)malloc(sizeof(NTdirattr)
  1198. #ifdef NTSD_EAS
  1199.                                   + ebSDlen
  1200. #endif
  1201.                                   + strlen(G.filename));
  1202.     *pd = (direntry *)d_entry;
  1203.     if (d_entry == (NTdirattr *)NULL) {
  1204.         return PK_MEM;
  1205.     }
  1206. #ifdef NTSD_EAS
  1207.     if (ebSDlen > 0)
  1208.         memcpy(d_entry->buf, ebSDptr, ebSDlen);
  1209.     d_entry->SDlen = ebSDlen;
  1210.     d_entry->fn = d_entry->buf + ebSDlen;
  1211. #else
  1212.     d_entry->fn = d_entry->buf;
  1213. #endif
  1214.  
  1215.     strcpy(d_entry->fn, G.filename);
  1216.  
  1217.     d_entry->perms = G.pInfo->file_attr;
  1218.  
  1219.     d_entry->gotTime = (uO.D_flag <= 0
  1220.                         ? getNTfiletime(__G__ &(d_entry->Modft),
  1221.                                         &(d_entry->Accft), &(d_entry->Creft))
  1222.                         : 0);
  1223.     return PK_OK;
  1224. } /* end function defer_dir_attribs() */
  1225.  
  1226.  
  1227. int set_direc_attribs(__G__ d)
  1228.     __GDEF
  1229.     direntry *d;
  1230. {
  1231.     int errval;
  1232.     HANDLE hFile = INVALID_HANDLE_VALUE;        /* File handle defined in NT */
  1233. #ifdef __RSXNT__
  1234.     char *ansi_name;
  1235. #endif
  1236.  
  1237.     /* Win9x does not support setting directory time stamps. */
  1238.     if (!IsWinNT())
  1239.         return PK_OK;
  1240.  
  1241.     errval = PK_OK;
  1242. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1243.     ansi_name = (char *)alloca(strlen(d->fn) + 1);
  1244.     INTERN_TO_ISO(d->fn, ansi_name);
  1245. #   define Ansi_Dirname  ansi_name
  1246. #else
  1247. #   define Ansi_Dirname  d->fn
  1248. #endif
  1249.  
  1250.     /* Skip restoring directory time stamps on user' request. */
  1251.     if (uO.D_flag <= 0) {
  1252.         /* Open a handle to the directory before processing extra fields;
  1253.            we do this in case new security on file prevents us from updating
  1254.            time stamps.
  1255.            Although the WIN32 documentation recommends to use GENERIC_WRITE
  1256.            access flag to create the handle for SetFileTime(), this is too
  1257.            demanding for directories with the "read-only" attribute bit set.
  1258.            So we use the more specific flag FILE_WRITE_ATTRIBUTES here to
  1259.            request the minimum required access rights. (This problem is a
  1260.            Windows bug that has been silently fixed in Windows XP SP2.) */
  1261.         hFile = CreateFileA(Ansi_Dirname, FILE_WRITE_ATTRIBUTES,
  1262.                             FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
  1263.                             OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  1264.     }
  1265.  
  1266. #ifdef NTSD_EAS
  1267.     if (NtAtt(d)->SDlen > 0) {
  1268.         int err;
  1269.  
  1270.         if (QCOND2) {
  1271.             Info(slide, 1, ((char *)slide, " set attrib: %-22s  ",
  1272.               FnFilter1(d->fn)));
  1273.         }
  1274.  
  1275.         /* set NTFS SD extra fields */
  1276.         err = SetSD(__G__ Ansi_Dirname, NtAtt(d)->perms,
  1277.                         NtAtt(d)->buf, NtAtt(d)->SDlen - EB_HEADSIZE);
  1278.         if (err == IZ_EF_TRUNC) {
  1279.             if (!QCOND2)
  1280.                 Info(slide, 1, ((char *)slide, "%-22s  ",
  1281.                   FnFilter1(d->fn)));
  1282.             Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
  1283.               NtAtt(d)->SDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
  1284.         } else if (QCOND2) {
  1285.             Info(slide, 0, ((char *)slide, "\n"));
  1286.         }
  1287.         if (errval < err)
  1288.             errval = err;
  1289.     }
  1290. #endif /* NTSD_EAS */
  1291.  
  1292.     /* Skip restoring directory time stamps on user' request. */
  1293.     if (uO.D_flag <= 0) {
  1294.         if (hFile == INVALID_HANDLE_VALUE) {
  1295.             Info(slide, 1, ((char *)slide,
  1296.               "warning: CreateFile() error %d (set file times for %s)\n",
  1297.               (int)GetLastError(), FnFilter1(d->fn)));
  1298.             if (!errval)
  1299.                 errval = PK_WARN;
  1300.         } else {
  1301.             if (NtAtt(d)->gotTime) {
  1302.                 FILETIME *pModft = (NtAtt(d)->gotTime & EB_UT_FL_MTIME)
  1303.                                   ? &(NtAtt(d)->Modft) : NULL;
  1304.                 FILETIME *pAccft = (NtAtt(d)->gotTime & EB_UT_FL_ATIME)
  1305.                                   ? &(NtAtt(d)->Accft) : NULL;
  1306.                 FILETIME *pCreft = (NtAtt(d)->gotTime & EB_UT_FL_CTIME)
  1307.                                   ? &(NtAtt(d)->Creft) : NULL;
  1308.  
  1309.                 if (!SetFileTime(hFile, pCreft, pAccft, pModft)) {
  1310.                     Info(slide, 0, ((char *)slide,
  1311.                       "warning:  SetFileTime() for %s error %d\n",
  1312.                       FnFilter1(d->fn), (int)GetLastError()));
  1313.                     if (!errval)
  1314.                         errval = PK_WARN;
  1315.                 }
  1316.             }
  1317.             CloseHandle(hFile);
  1318.         }
  1319.     }
  1320.  
  1321.     return errval;
  1322. } /* end function set_direc_attribs() */
  1323.  
  1324. #endif /* SET_DIR_ATTRIB */
  1325.  
  1326.  
  1327.  
  1328.  
  1329. #ifdef TIMESTAMP
  1330.  
  1331. /*************************/
  1332. /* Function stamp_file() */
  1333. /*************************/
  1334.  
  1335. int stamp_file(__GPRO__ ZCONST char *fname, time_t modtime)
  1336. {
  1337.     FILETIME Modft;    /* File time type defined in NT, `last modified' time */
  1338.     HANDLE hFile;      /* File handle defined in NT    */
  1339.     int errstat = 0;   /* return status: 0 == "OK", -1 == "Failure" */
  1340.     int fs_uses_loctime = FStampIsLocTime(__G__ fname);
  1341. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1342.     char *ansi_name = (char *)alloca(strlen(fname) + 1);
  1343.  
  1344.     INTERN_TO_ISO(fname, ansi_name);
  1345. #   define Ansi_Fname  ansi_name
  1346. #else
  1347. #   define Ansi_Fname  fname
  1348. #endif
  1349.  
  1350.     /* open a handle to the file to prepare setting the mod-time stamp */
  1351.     hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
  1352.          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1353.     if ( hFile == INVALID_HANDLE_VALUE ) {
  1354.         errstat = -1;
  1355.     } else {
  1356.         /* convert time_t modtime into WIN32 native 64bit format */
  1357.         UTIME_2_IZFILETIME(modtime, &Modft)
  1358.         /* set Access and Modification times of the file to modtime */
  1359.         if (!SetFileTime(hFile, NULL, &Modft, &Modft)) {
  1360.             errstat = -1;
  1361.         }
  1362.         CloseHandle(hFile);
  1363.     }
  1364.  
  1365.     return errstat;
  1366.  
  1367. #undef Ansi_Fname
  1368. } /* end function stamp_file() */
  1369.  
  1370. #endif /* TIMESTAMP */
  1371.  
  1372.  
  1373.  
  1374.  
  1375. /***********************/
  1376. /* Function isfloppy() */   /* more precisely, is it removable? */
  1377. /***********************/
  1378.  
  1379. static int isfloppy(int nDrive)   /* 1 == A:, 2 == B:, etc. */
  1380. {
  1381.     char rootPathName[4];
  1382.  
  1383.     rootPathName[0] = (char)('A' + nDrive - 1);   /* build the root path */
  1384.     rootPathName[1] = ':';                        /*  name, e.g. "A:/" */
  1385.     rootPathName[2] = '/';
  1386.     rootPathName[3] = '\0';
  1387.  
  1388.     return (GetDriveTypeA(rootPathName) == DRIVE_REMOVABLE);
  1389.  
  1390. } /* end function isfloppy() */
  1391.  
  1392.  
  1393.  
  1394.  
  1395. /*****************************/
  1396. /* Function NTQueryVolInfo() */
  1397. /*****************************/
  1398.  
  1399. /*
  1400.  * Note:  8.3 limits on filenames apply only to old-style FAT filesystems.
  1401.  *        More recent versions of Windows (Windows NT 3.5 / Windows 4.0)
  1402.  *        can support long filenames (LFN) on FAT filesystems.  Check the
  1403.  *        filesystem maximum component length field to detect LFN support.
  1404.  */
  1405.  
  1406. static int NTQueryVolInfo(__GPRO__ const char *name)
  1407. {
  1408.  /* static char lastRootPath[4] = ""; */
  1409.  /* static int lastVolOldFAT; */
  1410.  /* static int lastVolLocTim; */
  1411.     char *tmp0;
  1412.     char tmp1[MAX_PATH], tmp2[MAX_PATH];
  1413.     DWORD volSerNo, maxCompLen, fileSysFlags;
  1414. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1415.     char *ansi_name = (char *)alloca(strlen(name) + 1);
  1416.  
  1417.     INTERN_TO_ISO(name, ansi_name);
  1418.     name = ansi_name;
  1419. #endif
  1420.  
  1421.     if ((!strncmp(name, "//", 2) || !strncmp(name, "\\\\", 2)) &&
  1422.         (name[2] != '\0' && name[2] != '/' && name[2] != '\\')) {
  1423.         /* GetFullPathname() and GetVolumeInformation() do not work
  1424.          * on UNC names. For now, we return "error".
  1425.          * **FIXME**: check if UNC name is mapped to a drive letter
  1426.          *            and use mapped drive for volume info query.
  1427.          */
  1428.         return FALSE;
  1429.     }
  1430.     if (isalpha((uch)name[0]) && (name[1] == ':'))
  1431.         tmp0 = (char *)name;
  1432.     else
  1433.     {
  1434.         if (!GetFullPathNameA(name, MAX_PATH, tmp1, &tmp0))
  1435.             return FALSE;
  1436.         tmp0 = &tmp1[0];
  1437.     }
  1438.     if (strncmp(G.lastRootPath, tmp0, 2) != 0) {
  1439.         /* For speed, we skip repeated queries for the same device */
  1440.         strncpy(G.lastRootPath, tmp0, 2);   /* Build the root path name, */
  1441.         G.lastRootPath[2] = '/';            /* e.g. "A:/"                */
  1442.         G.lastRootPath[3] = '\0';
  1443.  
  1444.         if (!GetVolumeInformationA((LPCSTR)G.lastRootPath,
  1445.               (LPSTR)tmp1, (DWORD)MAX_PATH,
  1446.               &volSerNo, &maxCompLen, &fileSysFlags,
  1447.               (LPSTR)tmp2, (DWORD)MAX_PATH)) {
  1448.             G.lastRootPath[0] = '\0';
  1449.             return FALSE;
  1450.         }
  1451.  
  1452.         /*  LFNs are available if the component length is > 12 */
  1453.         G.lastVolOldFAT = (maxCompLen <= 12);
  1454. /*      G.lastVolOldFAT = !strncmp(strupr(tmp2), "FAT", 3);   old version */
  1455.  
  1456.         /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
  1457.          * local time!
  1458.          */
  1459.         G.lastVolLocTim = !strncmp(strupr(tmp2), "VFAT", 4) ||
  1460.                           !strncmp(tmp2, "HPFS", 4) ||
  1461.                           !strncmp(tmp2, "FAT", 3);
  1462.     }
  1463.  
  1464.     return TRUE;
  1465.  
  1466. } /* end function NTQueryVolInfo() */
  1467.  
  1468.  
  1469.  
  1470.  
  1471. /*****************************/
  1472. /* Function IsVolumeOldFAT() */
  1473. /*****************************/
  1474.  
  1475. static int IsVolumeOldFAT(__GPRO__ const char *name)
  1476. {
  1477.     return (NTQueryVolInfo(__G__ name) ? G.lastVolOldFAT : FALSE);
  1478. }
  1479.  
  1480.  
  1481.  
  1482.  
  1483. #ifndef SFX
  1484.  
  1485. /************************/
  1486. /*  Function do_wild()  */   /* identical to OS/2 version */
  1487. /************************/
  1488.  
  1489. char *do_wild(__G__ wildspec)
  1490.     __GDEF
  1491.     ZCONST char *wildspec;  /* only used first time on a given dir */
  1492. {
  1493. /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in w32cfg.h:
  1494.     static zDIR *wild_dir = NULL;
  1495.     static ZCONST char *wildname;
  1496.     static char *dirname, matchname[FILNAMSIZ];
  1497.     static int notfirstcall=FALSE, have_dirname, dirnamelen;
  1498. */
  1499.     char *fnamestart;
  1500.     struct zdirent *file;
  1501.  
  1502.     /* Even when we're just returning wildspec, we *always* do so in
  1503.      * matchname[]--calling routine is allowed to append four characters
  1504.      * to the returned string, and wildspec may be a pointer to argv[].
  1505.      */
  1506.     if (!G.notfirstcall) {  /* first call:  must initialize everything */
  1507.         G.notfirstcall = TRUE;
  1508.  
  1509.         if (!iswild(wildspec)) {
  1510.             strncpy(G.matchname, wildspec, FILNAMSIZ);
  1511.             G.matchname[FILNAMSIZ-1] = '\0';
  1512.             G.have_dirname = FALSE;
  1513.             G.wild_dir = NULL;
  1514.             return G.matchname;
  1515.         }
  1516.  
  1517.         /* break the wildspec into a directory part and a wildcard filename */
  1518.         if ((G.wildname = MBSRCHR(wildspec, '/')) == (ZCONST char *)NULL &&
  1519.             (G.wildname = MBSRCHR(wildspec, ':')) == (ZCONST char *)NULL) {
  1520.             G.dirname = ".";
  1521.             G.dirnamelen = 1;
  1522.             G.have_dirname = FALSE;
  1523.             G.wildname = wildspec;
  1524.         } else {
  1525.             ++G.wildname;     /* point at character after '/' or ':' */
  1526.             G.dirnamelen = G.wildname - wildspec;
  1527.             if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) {
  1528.                 Info(slide, 1, ((char *)slide,
  1529.                   "warning:  cannot allocate wildcard buffers\n"));
  1530.                 strncpy(G.matchname, wildspec, FILNAMSIZ);
  1531.                 G.matchname[FILNAMSIZ-1] = '\0';
  1532.                 return G.matchname; /* but maybe filespec was not a wildcard */
  1533.             }
  1534.             strncpy(G.dirname, wildspec, G.dirnamelen);
  1535.             G.dirname[G.dirnamelen] = '\0';   /* terminate for strcpy below */
  1536.             G.have_dirname = TRUE;
  1537.         }
  1538.         Trace((stderr, "do_wild:  dirname = [%s]\n", FnFilter1(G.dirname)));
  1539.  
  1540.         if ((G.wild_dir = (zvoid *)Opendir(G.dirname)) != NULL) {
  1541.             if (G.have_dirname) {
  1542.                 strcpy(G.matchname, G.dirname);
  1543.                 fnamestart = G.matchname + G.dirnamelen;
  1544.             } else
  1545.                 fnamestart = G.matchname;
  1546.             while ((file = Readdir((zDIR *)G.wild_dir)) != NULL) {
  1547.                 Trace((stderr, "do_wild:  Readdir returns %s\n",
  1548.                   FnFilter1(file->d_name)));
  1549.                 strcpy(fnamestart, file->d_name);
  1550.                 if (MBSRCHR(fnamestart, '.') == (char *)NULL)
  1551.                     strcat(fnamestart, ".");
  1552.                 if (match(fnamestart, G.wildname, TRUE WISEP) &&
  1553.                     /* skip "." and ".." directory entries */
  1554.                     strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) {
  1555.                     Trace((stderr, "do_wild:  match() succeeds\n"));
  1556.                     /* remove trailing dot */
  1557.                     fnamestart = plastchar(fnamestart, strlen(fnamestart));
  1558.                     if (*fnamestart == '.')
  1559.                         *fnamestart = '\0';
  1560.                     return G.matchname;
  1561.                 }
  1562.             }
  1563.             /* if we get to here directory is exhausted, so close it */
  1564.             Closedir((zDIR *)G.wild_dir);
  1565.             G.wild_dir = NULL;
  1566.         }
  1567.         Trace((stderr, "do_wild:  Opendir(%s) returns NULL\n",
  1568.           FnFilter1(G.dirname)));
  1569.  
  1570.         /* return the raw wildspec in case that works (e.g., directory not
  1571.          * searchable, but filespec was not wild and file is readable) */
  1572.         strncpy(G.matchname, wildspec, FILNAMSIZ);
  1573.         G.matchname[FILNAMSIZ-1] = '\0';
  1574.         return G.matchname;
  1575.     }
  1576.  
  1577.     /* last time through, might have failed opendir but returned raw wildspec */
  1578.     if (G.wild_dir == NULL) {
  1579.         G.notfirstcall = FALSE;    /* reset for new wildspec */
  1580.         if (G.have_dirname)
  1581.             free(G.dirname);
  1582.         return (char *)NULL;
  1583.     }
  1584.  
  1585.     /* If we've gotten this far, we've read and matched at least one entry
  1586.      * successfully (in a previous call), so dirname has been copied into
  1587.      * matchname already.
  1588.      */
  1589.     if (G.have_dirname) {
  1590.         /* strcpy(G.matchname, G.dirname); */
  1591.         fnamestart = G.matchname + G.dirnamelen;
  1592.     } else
  1593.         fnamestart = G.matchname;
  1594.     while ((file = Readdir((zDIR *)G.wild_dir)) != NULL) {
  1595.         Trace((stderr, "do_wild:  readdir returns %s\n",
  1596.           FnFilter1(file->d_name)));
  1597.         strcpy(fnamestart, file->d_name);
  1598.         if (MBSRCHR(fnamestart, '.') == (char *)NULL)
  1599.             strcat(fnamestart, ".");
  1600.         if (match(fnamestart, G.wildname, TRUE WISEP)) {
  1601.             Trace((stderr, "do_wild:  match() succeeds\n"));
  1602.             /* remove trailing dot */
  1603.             fnamestart = plastchar(fnamestart, strlen(fnamestart));
  1604.             if (*fnamestart == '.')
  1605.                 *fnamestart = '\0';
  1606.             return G.matchname;
  1607.         }
  1608.     }
  1609.  
  1610.     Closedir((zDIR *)G.wild_dir);  /* at least one entry read; nothing left */
  1611.     G.wild_dir = NULL;
  1612.     G.notfirstcall = FALSE;        /* reset for new wildspec */
  1613.     if (G.have_dirname)
  1614.         free(G.dirname);
  1615.     return (char *)NULL;
  1616.  
  1617. } /* end function do_wild() */
  1618.  
  1619. #endif /* !SFX */
  1620.  
  1621.  
  1622.  
  1623. /**********************/
  1624. /* Function mapattr() */
  1625. /**********************/
  1626.  
  1627. /* Identical to MS-DOS, OS/2 versions.  However, NT has a lot of extra
  1628.  * permission stuff, so this function should probably be extended in the
  1629.  * future. */
  1630.  
  1631. int mapattr(__G)
  1632.     __GDEF
  1633. {
  1634.     /* set archive bit for file entries (file is not backed up): */
  1635.     G.pInfo->file_attr = ((unsigned)G.crec.external_file_attributes |
  1636.       (G.crec.external_file_attributes & FILE_ATTRIBUTE_DIRECTORY ?
  1637.        0 : FILE_ATTRIBUTE_ARCHIVE)) & 0xff;
  1638.     return 0;
  1639.  
  1640. } /* end function mapattr() */
  1641.  
  1642.  
  1643.  
  1644.  
  1645. /************************/
  1646. /*  Function mapname()  */
  1647. /************************/
  1648.  
  1649. int mapname(__G__ renamed)
  1650.     __GDEF
  1651.     int renamed;
  1652. /*
  1653.  * returns:
  1654.  *  MPN_OK          - no problem detected
  1655.  *  MPN_INF_TRUNC   - caution (truncated filename)
  1656.  *  MPN_INF_SKIP    - info "skip entry" (dir doesn't exist)
  1657.  *  MPN_ERR_SKIP    - error -> skip entry
  1658.  *  MPN_ERR_TOOLONG - error -> path is too long
  1659.  *  MPN_NOMEM       - error (memory allocation failed) -> skip entry
  1660.  *  [also MPN_VOL_LABEL, MPN_CREATED_DIR]
  1661.  */
  1662. {
  1663.     char pathcomp[FILNAMSIZ];   /* path-component buffer */
  1664.     char *pp, *cp=NULL;         /* character pointers */
  1665.     char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  1666. #ifdef ACORN_FTYPE_NFS
  1667.     char *lastcomma=(char *)NULL;  /* pointer to last comma in pathcomp */
  1668.     RO_extra_block *ef_spark;      /* pointer Acorn FTYPE ef block */
  1669. #endif
  1670.     int killed_ddot = FALSE;    /* is set when skipping "../" pathcomp */
  1671.     int error;
  1672.     register unsigned workch;   /* hold the character being tested */
  1673.  
  1674.  
  1675. /*---------------------------------------------------------------------------
  1676.     Initialize various pointers and counters and stuff.
  1677.   ---------------------------------------------------------------------------*/
  1678.  
  1679.     /* can create path as long as not just freshening, or if user told us */
  1680.     G.create_dirs = (!uO.fflag || renamed);
  1681.  
  1682.     G.created_dir = FALSE;      /* not yet */
  1683.     G.renamed_fullpath = FALSE;
  1684.     G.fnlen = strlen(G.filename);
  1685.  
  1686.     if (renamed) {
  1687.         cp = G.filename;    /* point to beginning of renamed name... */
  1688.         if (*cp) do {
  1689.             if (*cp == '\\')    /* convert backslashes to forward */
  1690.                 *cp = '/';
  1691.         } while (*PREINCSTR(cp));
  1692.         cp = G.filename;
  1693.         /* use temporary rootpath if user gave full pathname */
  1694.         if (G.filename[0] == '/') {
  1695.             G.renamed_fullpath = TRUE;
  1696.             pathcomp[0] = '/';  /* copy the '/' and terminate */
  1697.             pathcomp[1] = '\0';
  1698.             ++cp;
  1699.         } else if (isalpha((uch)G.filename[0]) && G.filename[1] == ':') {
  1700.             G.renamed_fullpath = TRUE;
  1701.             pp = pathcomp;
  1702.             *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
  1703.             *pp++ = *cp++;
  1704.             if (*cp == '/')
  1705.                 *pp++ = *cp++;  /* otherwise add "./"? */
  1706.             *pp = '\0';
  1707.         }
  1708.     }
  1709.  
  1710.     /* pathcomp is ignored unless renamed_fullpath is TRUE: */
  1711.     if ((error = checkdir(__G__ pathcomp, INIT)) != 0)    /* init path buffer */
  1712.         return error;           /* ...unless no mem or vol label on hard disk */
  1713.  
  1714.     *pathcomp = '\0';           /* initialize translation buffer */
  1715.     pp = pathcomp;              /* point to translation buffer */
  1716.     if (!renamed) {             /* cp already set if renamed */
  1717.         if (uO.jflag)           /* junking directories */
  1718.             cp = (char *)MBSRCHR(G.filename, '/');
  1719.         if (cp == NULL)         /* no '/' or not junking dirs */
  1720.             cp = G.filename;    /* point to internal zipfile-member pathname */
  1721.         else
  1722.             ++cp;               /* point to start of last component of path */
  1723.     }
  1724.  
  1725. /*---------------------------------------------------------------------------
  1726.     Begin main loop through characters in filename.
  1727.   ---------------------------------------------------------------------------*/
  1728.  
  1729.     for (; (workch = (uch)*cp) != 0; INCSTR(cp)) {
  1730.  
  1731.         switch (workch) {
  1732.             case '/':             /* can assume -j flag not given */
  1733.                 *pp = '\0';
  1734.                 maskDOSdevice(__G__ pathcomp);
  1735.                 if (strcmp(pathcomp, ".") == 0) {
  1736.                     /* don't bother appending "./" to the path */
  1737.                     *pathcomp = '\0';
  1738.                 } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
  1739.                     /* "../" dir traversal detected, skip over it */
  1740.                     *pathcomp = '\0';
  1741.                     killed_ddot = TRUE;     /* set "show message" flag */
  1742.                 }
  1743.                 /* when path component is not empty, append it now */
  1744.                 if (*pathcomp != '\0' &&
  1745.                     ((error = checkdir(__G__ pathcomp, APPEND_DIR))
  1746.                      & MPN_MASK) > MPN_INF_TRUNC)
  1747.                     return error;
  1748.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  1749.                 lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
  1750.                 break;
  1751.  
  1752.             case ':':             /* drive spec not stored, so no colon allowed */
  1753.             case '\\':            /* '\\' may come as normal filename char (not */
  1754.             case '<':             /*  dir sep char!) from unix-like file system */
  1755.             case '>':             /* no redirection symbols allowed either */
  1756.             case '|':             /* no pipe signs allowed */
  1757.             case '"':             /* no double quotes allowed */
  1758.             case '?':             /* no wildcards allowed */
  1759.             case '*':
  1760.                 *pp++ = '_';      /* these rules apply equally to FAT and NTFS */
  1761.                 break;
  1762.             case ';':             /* start of VMS version? */
  1763.                 lastsemi = pp;    /* remove VMS version later... */
  1764.                 *pp++ = ';';      /*  but keep semicolon for now */
  1765.                 break;
  1766.  
  1767. #ifdef ACORN_FTYPE_NFS
  1768.             case ',':             /* NFS filetype extension */
  1769.                 lastcomma = pp;
  1770.                 *pp++ = ',';      /* keep for now; may need to remove */
  1771.                 break;            /*  later, if requested */
  1772. #endif
  1773.  
  1774.             case ' ':             /* keep spaces unless specifically */
  1775.                 /* NT cannot create filenames with spaces on FAT volumes */
  1776.                 if (uO.sflag || IsVolumeOldFAT(__G__ G.filename))
  1777.                     *pp++ = '_';
  1778.                 else
  1779.                     *pp++ = ' ';
  1780.                 break;
  1781.  
  1782.             default:
  1783.                 /* allow European characters in filenames: */
  1784.                 if (isprint(workch) || workch >= 127)
  1785. #ifdef _MBCS
  1786.                 {
  1787.                     memcpy(pp, cp, CLEN(cp));
  1788.                     INCSTR(pp);
  1789.                 }
  1790. #else
  1791.                     *pp++ = (char)workch;
  1792. #endif
  1793.         } /* end switch */
  1794.  
  1795.     } /* end while loop */
  1796.  
  1797.     /* Show warning when stripping insecure "parent dir" path components */
  1798.     if (killed_ddot && QCOND2) {
  1799.         Info(slide, 0, ((char *)slide,
  1800.           "warning:  skipped \"../\" path component(s) in %s\n",
  1801.           FnFilter1(G.filename)));
  1802.         if (!(error & ~MPN_MASK))
  1803.             error = (error & MPN_MASK) | PK_WARN;
  1804.     }
  1805.  
  1806. /*---------------------------------------------------------------------------
  1807.     Report if directory was created (and no file to create:  filename ended
  1808.     in '/'), check name to be sure it exists, and combine path and name be-
  1809.     fore exiting.
  1810.   ---------------------------------------------------------------------------*/
  1811.  
  1812.     if (lastchar(G.filename, G.fnlen) == '/') {
  1813. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1814.         char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
  1815.  
  1816.         INTERN_TO_ISO(G.filename, ansi_name);
  1817. #       define Ansi_Fname  ansi_name
  1818. #else
  1819. #       define Ansi_Fname  G.filename
  1820. #endif
  1821.         checkdir(__G__ G.filename, GETPATH);
  1822.         if (G.created_dir) {
  1823.             if (QCOND2) {
  1824.                 Info(slide, 0, ((char *)slide, "   creating: %-22s\n",
  1825.                   FnFilter1(G.filename)));
  1826.             }
  1827.  
  1828.             /* set file attributes:
  1829.                The default for newly created directories is "DIR attribute
  1830.                flags set", so there is no need to change attributes unless
  1831.                one of the DOS style attribute flags is set. The readonly
  1832.                attribute need not be masked, since it does not prevent
  1833.                modifications in the new directory. */
  1834.             if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
  1835.                 if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
  1836.                     Info(slide, 1, ((char *)slide,
  1837.                       "\nwarning (%d): could not set file attributes for %s\n",
  1838.                       (int)GetLastError(), FnFilter1(G.filename)));
  1839.             }
  1840.  
  1841.             /* set dir time (note trailing '/') */
  1842.             return (error & ~MPN_MASK) | MPN_CREATED_DIR;
  1843.         } else if (IS_OVERWRT_ALL) {
  1844.             /* overwrite attributes of existing directory on user's request */
  1845.  
  1846.             /* set file attributes: */
  1847.             if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
  1848.                 if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
  1849.                     Info(slide, 1, ((char *)slide,
  1850.                       "\nwarning (%d): could not set file attributes for %s\n",
  1851.                       (int)GetLastError(), FnFilter1(G.filename)));
  1852.             }
  1853.         }
  1854.         /* dir existed already; don't look for data to extract */
  1855.         return (error & ~MPN_MASK) | MPN_INF_SKIP;
  1856.     }
  1857.  
  1858.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  1859.  
  1860.     /* if not saving them, remove VMS version numbers (appended "###") */
  1861.     if (!uO.V_flag && lastsemi) {
  1862.         pp = lastsemi + 1;        /* semi-colon was kept:  expect #'s after */
  1863.         while (isdigit((uch)(*pp)))
  1864.             ++pp;
  1865.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  1866.             *lastsemi = '\0';
  1867.     }
  1868.  
  1869. #ifdef ACORN_FTYPE_NFS
  1870.     /* translate Acorn filetype information if asked to do so */
  1871.     if (uO.acorn_nfs_ext &&
  1872.         (ef_spark = (RO_extra_block *)
  1873.                     getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
  1874.         != (RO_extra_block *)NULL)
  1875.     {
  1876.         /* file *must* have a RISC OS extra field */
  1877.         long ft = (long)makelong(ef_spark->loadaddr);
  1878.         /*32-bit*/
  1879.         if (lastcomma) {
  1880.             pp = lastcomma + 1;
  1881.             while (isxdigit((uch)(*pp))) ++pp;
  1882.             if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
  1883.         }
  1884.         if ((ft & 1<<31)==0) ft=0x000FFD00;
  1885.         sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
  1886.     }
  1887. #endif /* ACORN_FTYPE_NFS */
  1888.  
  1889.     maskDOSdevice(__G__ pathcomp);
  1890.  
  1891.     if (*pathcomp == '\0') {
  1892.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  1893.           FnFilter1(G.filename)));
  1894.         return (error & ~MPN_MASK) | MPN_ERR_SKIP;
  1895.     }
  1896.  
  1897.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  1898.     checkdir(__G__ G.filename, GETPATH);
  1899.  
  1900.     if (G.pInfo->vollabel) {    /* set the volume label now */
  1901.         char drive[4];
  1902. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  1903.         char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
  1904.         INTERN_TO_ISO(G.filename, ansi_name);
  1905. #       define Ansi_Fname  ansi_name
  1906. #else
  1907. #       define Ansi_Fname  G.filename
  1908. #endif
  1909.  
  1910.         /* Build a drive string, e.g. "b:" */
  1911.         drive[0] = (char)('a' + G.nLabelDrive - 1);
  1912.         strcpy(drive + 1, ":\\");
  1913.         if (QCOND2)
  1914.             Info(slide, 0, ((char *)slide, "labelling %s %-22s\n", drive,
  1915.               FnFilter1(G.filename)));
  1916.         if (!SetVolumeLabelA(drive, Ansi_Fname)) {
  1917.             Info(slide, 1, ((char *)slide,
  1918.               "mapname:  error setting volume label\n"));
  1919.             return (error & ~MPN_MASK) | MPN_ERR_SKIP;
  1920.         }
  1921.         /* success:  skip the "extraction" quietly */
  1922.         return (error & ~MPN_MASK) | MPN_INF_SKIP;
  1923. #undef Ansi_Fname
  1924.     }
  1925.  
  1926.     Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n",
  1927.       FnFilter1(G.filename), error));
  1928.     return error;
  1929.  
  1930. } /* end function mapname() */
  1931.  
  1932.  
  1933.  
  1934.  
  1935. /****************************/
  1936. /* Function maskDOSdevice() */
  1937. /****************************/
  1938.  
  1939. static void maskDOSdevice(__G__ pathcomp)
  1940.     __GDEF
  1941.     char *pathcomp;
  1942. {
  1943. /*---------------------------------------------------------------------------
  1944.     Put an underscore in front of the file name if the file name is a
  1945.     DOS/WINDOWS device name like CON.*, AUX.*, PRN.*, etc. Trying to
  1946.     extract such a file would fail at best and wedge us at worst.
  1947.   ---------------------------------------------------------------------------*/
  1948. #if !defined(S_IFCHR) && defined(_S_IFCHR)
  1949. #  define S_IFCHR _S_IFCHR
  1950. #endif
  1951. #if !defined(S_ISCHR)
  1952. # if defined(_S_ISCHR)
  1953. #  define S_ISCHR(m) _S_ISCHR(m)
  1954. # elif defined(S_IFCHR)
  1955. #  define S_ISCHR(m) ((m) & S_IFCHR)
  1956. # endif
  1957. #endif
  1958.  
  1959. #ifdef DEBUG
  1960.     if (zstat(pathcomp, &G.statbuf) == 0) {
  1961.         Trace((stderr,
  1962.                "maskDOSdevice() stat(\"%s\", buf) st_mode result: %X, %o\n",
  1963.                FnFilter1(pathcomp), G.statbuf.st_mode, G.statbuf.st_mode));
  1964.     } else {
  1965.         Trace((stderr, "maskDOSdevice() stat(\"%s\", buf) failed\n",
  1966.                FnFilter1(pathcomp)));
  1967.     }
  1968. #endif
  1969.     if (zstat(pathcomp, &G.statbuf) == 0 && S_ISCHR(G.statbuf.st_mode)) {
  1970.         extent i;
  1971.  
  1972.         /* pathcomp contains a name of a DOS character device (builtin or
  1973.          * installed device driver).
  1974.          * Prepend a '_' to allow creation of the item in the file system.
  1975.          */
  1976.         for (i = strlen(pathcomp) + 1; i > 0; --i)
  1977.             pathcomp[i] = pathcomp[i - 1];
  1978.         pathcomp[0] = '_';
  1979.     }
  1980. } /* end function maskDOSdevice() */
  1981.  
  1982.  
  1983.  
  1984.  
  1985.  
  1986. /**********************/
  1987. /* Function map2fat() */        /* Not quite identical to OS/2 version */
  1988. /**********************/
  1989.  
  1990. static void map2fat(pathcomp, pEndFAT)
  1991.     char *pathcomp, **pEndFAT;
  1992. {
  1993.     char *ppc = pathcomp;       /* variable pointer to pathcomp */
  1994.     char *pEnd = *pEndFAT;      /* variable pointer to buildpathFAT */
  1995.     char *pBegin = *pEndFAT;    /* constant pointer to start of this comp. */
  1996.     char *last_dot = NULL;      /* last dot not converted to underscore */
  1997.     register unsigned workch;   /* hold the character being tested */
  1998.  
  1999.  
  2000.     /* Only need check those characters which are legal in NTFS but not
  2001.      * in FAT:  to get here, must already have passed through mapname.
  2002.      * Also must truncate path component to ensure 8.3 compliance.
  2003.      */
  2004.     while ((workch = (uch)*ppc++) != 0) {
  2005.         switch (workch) {
  2006.             case '[':
  2007.             case ']':
  2008.             case '+':
  2009.             case ',':
  2010.             case ';':
  2011.             case '=':
  2012.                 *pEnd++ = '_';      /* convert brackets to underscores */
  2013.                 break;
  2014.  
  2015.             case '.':
  2016.                 if (pEnd == *pEndFAT) {   /* nothing appended yet... */
  2017.                     if (*ppc == '\0')     /* don't bother appending a */
  2018.                         break;            /*  "./" component to the path */
  2019.                     else if (*ppc == '.' && ppc[1] == '\0') {   /* "../" */
  2020.                         *pEnd++ = '.';    /*  add first dot, */
  2021.                         *pEnd++ = '.';    /*  add second dot, and */
  2022.                         ++ppc;            /*  skip over to pathcomp's end */
  2023.                     } else {              /* FAT doesn't allow null filename */
  2024.                         *pEnd++ = '_';    /*  bodies, so map .exrc -> _exrc */
  2025.                     }                     /*  (_.exr would keep max 3 chars) */
  2026.                 } else {                  /* found dot within path component */
  2027.                     last_dot = pEnd;      /*  point at last dot so far... */
  2028.                     *pEnd++ = '_';        /*  convert to underscore for now */
  2029.                 }
  2030.                 break;
  2031.  
  2032.             default:
  2033.                 *pEnd++ = (char)workch;
  2034.  
  2035.         } /* end switch */
  2036.     } /* end while loop */
  2037.  
  2038.     *pEnd = '\0';                 /* terminate buildpathFAT */
  2039.  
  2040.     /* NOTE:  keep in mind that pEnd points to the end of the path
  2041.      * component, and *pEndFAT still points to the *beginning* of it...
  2042.      * Also note that the algorithm does not try to get too fancy:
  2043.      * if there are no dots already, the name either gets truncated
  2044.      * at 8 characters or the last underscore is converted to a dot
  2045.      * (only if more characters are saved that way).  In no case is
  2046.      * a dot inserted between existing characters.
  2047.      */
  2048.     if (last_dot == NULL) {       /* no dots:  check for underscores... */
  2049.         char *plu = MBSRCHR(pBegin, '_');   /* pointer to last underscore */
  2050.  
  2051.         if ((plu != NULL) &&      /* found underscore: convert to dot? */
  2052.             (MIN(plu - pBegin, 8) + MIN(pEnd - plu - 1, 3) > 8)) {
  2053.             last_dot = plu;       /* be lazy:  drop through to next if-blk */
  2054.         } else if ((pEnd - *pEndFAT) > 8) {
  2055.             /* no underscore; or converting underscore to dot would save less
  2056.                chars than leaving everything in the basename */
  2057.             *pEndFAT += 8;        /* truncate at 8 chars */
  2058.             **pEndFAT = '\0';
  2059.         } else
  2060.             *pEndFAT = pEnd;      /* whole thing fits into 8 chars or less */
  2061.     }
  2062.  
  2063.     if (last_dot != NULL) {       /* one dot is OK: */
  2064.         *last_dot = '.';          /* put it back in */
  2065.  
  2066.         if ((last_dot - pBegin) > 8) {
  2067.             char *p, *q;
  2068.             int i;
  2069.  
  2070.             p = last_dot;
  2071.             q = last_dot = pBegin + 8;
  2072.             for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
  2073.                 *q++ = *p++;                   /*  shift .ext left and trun- */
  2074.             *q = '\0';                         /*  cate/terminate it */
  2075.             *pEndFAT = q;
  2076.         } else if ((pEnd - last_dot) > 4) {    /* too many chars in extension */
  2077.             *pEndFAT = last_dot + 4;
  2078.             **pEndFAT = '\0';
  2079.         } else
  2080.             *pEndFAT = pEnd;   /* filename is fine; point at terminating zero */
  2081.  
  2082.         if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ')
  2083.             last_dot[-1] = '_';                /* NO blank in front of '.'! */
  2084.     }
  2085. } /* end function map2fat() */
  2086.  
  2087.  
  2088.  
  2089.  
  2090. /***********************/       /* Borrowed from os2.c for UnZip 5.1.        */
  2091. /* Function checkdir() */       /* Difference: no EA stuff                   */
  2092. /***********************/       /*             HPFS stuff works on NTFS too  */
  2093.  
  2094. int checkdir(__G__ pathcomp, flag)
  2095.     __GDEF
  2096.     char *pathcomp;
  2097.     int flag;
  2098. /*
  2099.  * returns:
  2100.  *  MPN_OK          - no problem detected
  2101.  *  MPN_INF_TRUNC   - (on APPEND_NAME) truncated filename
  2102.  *  MPN_INF_SKIP    - path doesn't exist, not allowed to create
  2103.  *  MPN_ERR_SKIP    - path doesn't exist, tried to create and failed; or path
  2104.  *                    exists and is not a directory, but is supposed to be
  2105.  *  MPN_ERR_TOOLONG - path is too long
  2106.  *  MPN_NOMEM       - can't allocate memory for filename buffers
  2107.  */
  2108. {
  2109.  /* static int rootlen = 0;     */   /* length of rootpath */
  2110.  /* static char *rootpath;      */   /* user's "extract-to" directory */
  2111.  /* static char *buildpathHPFS; */   /* full path (so far) to extracted file, */
  2112.  /* static char *buildpathFAT;  */   /*  both HPFS/EA (main) and FAT versions */
  2113.  /* static char *endHPFS;       */   /* corresponding pointers to end of */
  2114.  /* static char *endFAT;        */   /*  buildpath ('\0') */
  2115.  
  2116. #   define FN_MASK   7
  2117. #   define FUNCTION  (flag & FN_MASK)
  2118.  
  2119.  
  2120.  
  2121. /*---------------------------------------------------------------------------
  2122.     APPEND_DIR:  append the path component to the path being built and check
  2123.     for its existence.  If doesn't exist and we are creating directories, do
  2124.     so for this one; else signal success or error as appropriate.
  2125.   ---------------------------------------------------------------------------*/
  2126.  
  2127.     if (FUNCTION == APPEND_DIR) {
  2128.         char *p = pathcomp;
  2129.         int too_long = FALSE;
  2130.  
  2131.         Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
  2132.         while ((*G.endHPFS = *p++) != '\0')     /* copy to HPFS filename */
  2133.             ++G.endHPFS;
  2134.         if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
  2135.             p = pathcomp;
  2136.             while ((*G.endFAT = *p++) != '\0')  /* copy to FAT filename, too */
  2137.                 ++G.endFAT;
  2138.         } else
  2139.             map2fat(pathcomp, &G.endFAT);   /* map into FAT fn, update endFAT */
  2140.  
  2141.         /* GRR:  could do better check, see if overrunning buffer as we go:
  2142.          * check endHPFS-buildpathHPFS after each append, set warning variable
  2143.          * if within 20 of FILNAMSIZ; then if var set, do careful check when
  2144.          * appending.  Clear variable when begin new path. */
  2145.  
  2146.         /* next check:  need to append '/', at least one-char name, '\0' */
  2147.         if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3)
  2148.             too_long = TRUE;                    /* check if extracting dir? */
  2149. #ifdef FIX_STAT_BUG
  2150.         /* Borland C++ 5.0 does not handle a call to stat() well if the
  2151.          * directory does not exist (it tends to crash in strange places.)
  2152.          * This is apparently a problem only when compiling for GUI rather
  2153.          * than console. The code below attempts to work around this problem.
  2154.          */
  2155.         if (access(G.buildpathFAT, 0) != 0) {
  2156.             if (!G.create_dirs) { /* told not to create (freshening) */
  2157.                 free(G.buildpathHPFS);
  2158.                 free(G.buildpathFAT);
  2159.                 /* path doesn't exist:  nothing to do */
  2160.                 return MPN_INF_SKIP;
  2161.             }
  2162.             if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
  2163.                 Info(slide, 1, ((char *)slide,
  2164.                   "checkdir error:  path too long: %s\n",
  2165.                   FnFilter1(G.buildpathHPFS)));
  2166.                 free(G.buildpathHPFS);
  2167.                 free(G.buildpathFAT);
  2168.                 /* no room for filenames:  fatal */
  2169.                 return MPN_ERR_TOOLONG;
  2170.             }
  2171.             if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
  2172.                 Info(slide, 1, ((char *)slide,
  2173.                   "checkdir error:  cannot create %s\n\
  2174.                 %s\n\
  2175.                 unable to process %s.\n",
  2176.                   FnFilter2(G.buildpathFAT),
  2177.                   strerror(errno),
  2178.                   FnFilter1(G.filename)));
  2179.                 free(G.buildpathHPFS);
  2180.                 free(G.buildpathFAT);
  2181.                 /* path didn't exist, tried to create, failed */
  2182.                 return MPN_ERR_SKIP;
  2183.             }
  2184.             G.created_dir = TRUE;
  2185.         }
  2186. #endif /* FIX_STAT_BUG */
  2187.         if (SSTAT(G.buildpathFAT, &G.statbuf))   /* path doesn't exist */
  2188.         {
  2189.             if (!G.create_dirs) { /* told not to create (freshening) */
  2190.                 free(G.buildpathHPFS);
  2191.                 free(G.buildpathFAT);
  2192.                 /* path doesn't exist:  nothing to do */
  2193.                 return MPN_INF_SKIP;
  2194.             }
  2195.             if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
  2196.                 Info(slide, 1, ((char *)slide,
  2197.                   "checkdir error:  path too long: %s\n",
  2198.                   FnFilter1(G.buildpathHPFS)));
  2199.                 free(G.buildpathHPFS);
  2200.                 free(G.buildpathFAT);
  2201.                 /* no room for filenames:  fatal */
  2202.                 return MPN_ERR_TOOLONG;
  2203.             }
  2204.             if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
  2205.                 Info(slide, 1, ((char *)slide,
  2206.                   "checkdir error:  cannot create %s\n\
  2207.                 %s\n\
  2208.                 unable to process %s.\n",
  2209.                   FnFilter2(G.buildpathFAT),
  2210.                   strerror(errno),
  2211.                   FnFilter1(G.filename)));
  2212.                 free(G.buildpathHPFS);
  2213.                 free(G.buildpathFAT);
  2214.                 /* path didn't exist, tried to create, failed */
  2215.                 return MPN_ERR_SKIP;
  2216.             }
  2217.             G.created_dir = TRUE;
  2218.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  2219.             Info(slide, 1, ((char *)slide,
  2220.               "checkdir error:  %s exists but is not directory\n\
  2221.                 unable to process %s.\n",
  2222.               FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
  2223.             free(G.buildpathHPFS);
  2224.             free(G.buildpathFAT);
  2225.             /* path existed but wasn't dir */
  2226.             return MPN_ERR_SKIP;
  2227.         }
  2228.         if (too_long) {
  2229.             Info(slide, 1, ((char *)slide,
  2230.               "checkdir error:  path too long: %s\n",
  2231.               FnFilter1(G.buildpathHPFS)));
  2232.             free(G.buildpathHPFS);
  2233.             free(G.buildpathFAT);
  2234.             /* no room for filenames:  fatal */
  2235.             return MPN_ERR_TOOLONG;
  2236.         }
  2237.         *G.endHPFS++ = '/';
  2238.         *G.endFAT++ = '/';
  2239.         *G.endHPFS = *G.endFAT = '\0';
  2240.         Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now =  [%s]\n",
  2241.           FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
  2242.         return MPN_OK;
  2243.  
  2244.     } /* end if (FUNCTION == APPEND_DIR) */
  2245.  
  2246. /*---------------------------------------------------------------------------
  2247.     GETPATH:  copy full FAT path to the string pointed at by pathcomp (want
  2248.     filename to reflect name used on disk, not EAs; if full path is HPFS,
  2249.     buildpathFAT and buildpathHPFS will be identical).  Also free both paths.
  2250.   ---------------------------------------------------------------------------*/
  2251.  
  2252.     if (FUNCTION == GETPATH) {
  2253.         Trace((stderr, "getting and freeing FAT path [%s]\n",
  2254.           FnFilter1(G.buildpathFAT)));
  2255.         Trace((stderr, "freeing HPFS path [%s]\n",
  2256.           FnFilter1(G.buildpathHPFS)));
  2257.         strcpy(pathcomp, G.buildpathFAT);
  2258.         free(G.buildpathFAT);
  2259.         free(G.buildpathHPFS);
  2260.         G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL;
  2261.         return MPN_OK;
  2262.     }
  2263.  
  2264. /*---------------------------------------------------------------------------
  2265.     APPEND_NAME:  assume the path component is the filename; append it and
  2266.     return without checking for existence.
  2267.   ---------------------------------------------------------------------------*/
  2268.  
  2269.     if (FUNCTION == APPEND_NAME) {
  2270.         char *p = pathcomp;
  2271.         int error = MPN_OK;
  2272.  
  2273.         Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
  2274.         /* The buildpathHPFS buffer has been allocated large enough to
  2275.          * hold the complete combined name, so there is no need to check
  2276.          * for OS filename size limit overflow within the copy loop.
  2277.          */
  2278.         while ((*G.endHPFS = *p++) != '\0') {   /* copy to HPFS filename */
  2279.             ++G.endHPFS;
  2280.         }
  2281.         /* Now, check for OS filename size overflow.  When detected, the
  2282.          * mapped HPFS name is truncated and a warning message is shown.
  2283.          */
  2284.         if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) {
  2285.             G.buildpathHPFS[FILNAMSIZ-1] = '\0';
  2286.             Info(slide, 1, ((char *)slide,
  2287.               "checkdir warning:  path too long; truncating\n \
  2288.              %s\n                -> %s\n",
  2289.               FnFilter1(G.filename), FnFilter2(G.buildpathHPFS)));
  2290.             error = MPN_INF_TRUNC;  /* filename truncated */
  2291.         }
  2292.  
  2293.         /* The buildpathFAT buffer has the same allocated size as the
  2294.          * buildpathHPFS buffer, so there is no need for an overflow check
  2295.          * within the following copy loop, either.
  2296.          */
  2297.         if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
  2298.             /* copy to FAT filename, too */
  2299.             p = pathcomp;
  2300.             while ((*G.endFAT = *p++) != '\0')
  2301.                 ++G.endFAT;
  2302.         } else
  2303.             /* map into FAT fn, update endFAT */
  2304.             map2fat(pathcomp, &G.endFAT);
  2305.  
  2306.         /* Check that the FAT path does not exceed the FILNAMSIZ limit, and
  2307.          * truncate when neccessary.
  2308.          * Note that truncation can only happen when the HPFS path (which is
  2309.          * never shorter than the FAT path) has been already truncated.
  2310.          * So, emission of the warning message and setting the error code
  2311.          * has already happened.
  2312.          */
  2313.         if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ)
  2314.             G.buildpathFAT[FILNAMSIZ-1] = '\0';
  2315.         Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT:  %s\n",
  2316.           FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
  2317.  
  2318.         return error;  /* could check for existence, prompt for new name... */
  2319.  
  2320.     } /* end if (FUNCTION == APPEND_NAME) */
  2321.  
  2322. /*---------------------------------------------------------------------------
  2323.     INIT:  allocate and initialize buffer space for the file currently being
  2324.     extracted.  If file was renamed with an absolute path, don't prepend the
  2325.     extract-to path.
  2326.   ---------------------------------------------------------------------------*/
  2327.  
  2328.     if (FUNCTION == INIT) {
  2329.         Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
  2330. #ifdef ACORN_FTYPE_NFS
  2331.         if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+
  2332.                                               (uO.acorn_nfs_ext ? 5 : 1)))
  2333. #else
  2334.         if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1))
  2335. #endif
  2336.             == NULL)
  2337.             return MPN_NOMEM;
  2338. #ifdef ACORN_FTYPE_NFS
  2339.         if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+
  2340.                                              (uO.acorn_nfs_ext ? 5 : 1)))
  2341. #else
  2342.         if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1))
  2343. #endif
  2344.             == NULL) {
  2345.             free(G.buildpathHPFS);
  2346.             return MPN_NOMEM;
  2347.         }
  2348.         if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */
  2349. /* GRR:  for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
  2350.             if (G.renamed_fullpath && pathcomp[1] == ':')
  2351.                 *G.buildpathHPFS = (char)ToLower(*pathcomp);
  2352.             else if (!G.renamed_fullpath && G.rootlen > 1 &&
  2353.                      G.rootpath[1] == ':')
  2354.                 *G.buildpathHPFS = (char)ToLower(*G.rootpath);
  2355.             else {
  2356.                 char tmpN[MAX_PATH], *tmpP;
  2357.                 if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
  2358.                 { /* by definition of MAX_PATH we should never get here */
  2359.                     Info(slide, 1, ((char *)slide,
  2360.                       "checkdir warning: current dir path too long\n"));
  2361.                     return MPN_INF_TRUNC;   /* can't get drive letter */
  2362.                 }
  2363.                 G.nLabelDrive = *tmpN - 'a' + 1;
  2364.                 *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a');
  2365.             }
  2366.             G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */
  2367.             if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */
  2368.                 || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */
  2369.                 free(G.buildpathHPFS);
  2370.                 free(G.buildpathFAT);
  2371.                 return MPN_VOL_LABEL;  /* skipping with message */
  2372.             }
  2373.             *G.buildpathHPFS = '\0';
  2374.         } else if (G.renamed_fullpath) /* pathcomp = valid data */
  2375.             strcpy(G.buildpathHPFS, pathcomp);
  2376.         else if (G.rootlen > 0)
  2377.             strcpy(G.buildpathHPFS, G.rootpath);
  2378.         else
  2379.             *G.buildpathHPFS = '\0';
  2380.         G.endHPFS = G.buildpathHPFS;
  2381.         G.endFAT = G.buildpathFAT;
  2382.         while ((*G.endFAT = *G.endHPFS) != '\0') {
  2383.             ++G.endFAT;
  2384.             ++G.endHPFS;
  2385.         }
  2386.         Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS)));
  2387.         return MPN_OK;
  2388.     }
  2389.  
  2390. /*---------------------------------------------------------------------------
  2391.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  2392.     sary; else assume it's a zipfile member and return.  This path segment
  2393.     gets used in extracting all members from every zipfile specified on the
  2394.     command line.  Note that under OS/2 and MS-DOS, if a candidate extract-to
  2395.     directory specification includes a drive letter (leading "x:"), it is
  2396.     treated just as if it had a trailing '/'--that is, one directory level
  2397.     will be created if the path doesn't exist, unless this is otherwise pro-
  2398.     hibited (e.g., freshening).
  2399.   ---------------------------------------------------------------------------*/
  2400.  
  2401. #if (!defined(SFX) || defined(SFX_EXDIR))
  2402.     if (FUNCTION == ROOT) {
  2403.         Trace((stderr, "initializing root path to [%s]\n",
  2404.           FnFilter1(pathcomp)));
  2405.         if (pathcomp == NULL) {
  2406.             G.rootlen = 0;
  2407.             return MPN_OK;
  2408.         }
  2409.         if (G.rootlen > 0)      /* rootpath was already set, nothing to do */
  2410.             return MPN_OK;
  2411.         if ((G.rootlen = strlen(pathcomp)) > 0) {
  2412.             int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE;
  2413.             char *tmproot;
  2414.  
  2415.             if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) {
  2416.                 G.rootlen = 0;
  2417.                 return MPN_NOMEM;
  2418.             }
  2419.             strcpy(tmproot, pathcomp);
  2420.             if (isalpha((uch)tmproot[0]) && tmproot[1] == ':')
  2421.                 has_drive = TRUE;   /* drive designator */
  2422.             if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') {
  2423.                 tmproot[--G.rootlen] = '\0';
  2424.                 had_trailing_pathsep = TRUE;
  2425.             }
  2426.             if (has_drive && (G.rootlen == 2)) {
  2427.                 if (!had_trailing_pathsep)   /* i.e., original wasn't "x:/" */
  2428.                     add_dot = TRUE;    /* relative path: add '.' before '/' */
  2429.             } else if (G.rootlen > 0) {   /* need not check "x:." and "x:/" */
  2430.                 if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
  2431.                 {
  2432.                     /* path does not exist */
  2433.                     if (!G.create_dirs /* || iswild(tmproot) */ ) {
  2434.                         free(tmproot);
  2435.                         G.rootlen = 0;
  2436.                         /* treat as stored file */
  2437.                         return MPN_INF_SKIP;
  2438.                     }
  2439.                     /* create directory (could add loop here scanning tmproot
  2440.                      * to create more than one level, but really necessary?) */
  2441.                     if (MKDIR(tmproot, 0777) == -1) {
  2442.                         Info(slide, 1, ((char *)slide,
  2443.                           "checkdir:  cannot create extraction directory: %s\n",
  2444.                           FnFilter1(tmproot)));
  2445.                         free(tmproot);
  2446.                         G.rootlen = 0;
  2447.                         /* path didn't exist, tried to create, failed: */
  2448.                         /* file exists, or need 2+ subdir levels */
  2449.                         return MPN_ERR_SKIP;
  2450.                     }
  2451.                 }
  2452.             }
  2453.             if (add_dot)                    /* had just "x:", make "x:." */
  2454.                 tmproot[G.rootlen++] = '.';
  2455.             tmproot[G.rootlen++] = '/';
  2456.             tmproot[G.rootlen] = '\0';
  2457.             if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
  2458.                 free(tmproot);
  2459.                 G.rootlen = 0;
  2460.                 return MPN_NOMEM;
  2461.             }
  2462.             Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
  2463.         }
  2464.         return MPN_OK;
  2465.     }
  2466. #endif /* !SFX || SFX_EXDIR */
  2467.  
  2468. /*---------------------------------------------------------------------------
  2469.     END:  free rootpath, immediately prior to program exit.
  2470.   ---------------------------------------------------------------------------*/
  2471.  
  2472.     if (FUNCTION == END) {
  2473.         Trace((stderr, "freeing rootpath\n"));
  2474.         if (G.rootlen > 0) {
  2475.             free(G.rootpath);
  2476.             G.rootlen = 0;
  2477.         }
  2478.         return MPN_OK;
  2479.     }
  2480.  
  2481.     return MPN_INVALID; /* should never reach */
  2482.  
  2483. } /* end function checkdir() */
  2484.  
  2485.  
  2486.  
  2487.  
  2488.  
  2489. #ifndef SFX
  2490.  
  2491. /*************************/
  2492. /* Function dateformat() */
  2493. /*************************/
  2494.  
  2495. int dateformat()
  2496. {
  2497.   char df[2];   /* LOCALE_IDATE has a maximum value of 2 */
  2498.  
  2499.   if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDATE, df, 2) != 0) {
  2500.     switch (df[0])
  2501.     {
  2502.       case '0':
  2503.         return DF_MDY;
  2504.       case '1':
  2505.         return DF_DMY;
  2506.       case '2':
  2507.         return DF_YMD;
  2508.     }
  2509.   }
  2510.   return DF_MDY;
  2511. }
  2512.  
  2513.  
  2514. /****************************/
  2515. /* Function dateseparator() */
  2516. /****************************/
  2517.  
  2518. char dateseparator()
  2519. {
  2520.   char df[2];   /* use only if it is one character */
  2521.  
  2522.   if ((GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDATE, df, 2) != 0) &&
  2523.       (df[0] != '\0'))
  2524.     return df[0];
  2525.   else
  2526.     return '-';
  2527. }
  2528.  
  2529.  
  2530. #ifndef WINDLL
  2531.  
  2532. /************************/
  2533. /*  Function version()  */
  2534. /************************/
  2535.  
  2536. void version(__G)
  2537.     __GDEF
  2538. {
  2539.     int len;
  2540. #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__))
  2541.     char buf[80];
  2542. #if (defined(_MSC_VER) && (_MSC_VER > 900))
  2543.     char buf2[80];
  2544. #endif
  2545. #endif
  2546.  
  2547.     len = sprintf((char *)slide, CompiledWith,
  2548.  
  2549. #if defined(_MSC_VER)  /* MSC == VC++, but what about SDK compiler? */
  2550.       (sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100), buf),
  2551. #  if (_MSC_VER == 800)
  2552.       "(Visual C++ v1.1)",
  2553. #  elif (_MSC_VER == 850)
  2554.       "(Windows NT v3.5 SDK)",
  2555. #  elif (_MSC_VER == 900)
  2556.       "(Visual C++ v2.x)",
  2557. #  elif (_MSC_VER > 900)
  2558.       (sprintf(buf2, "(Visual C++ %d.%d)", _MSC_VER/100 - 6, _MSC_VER%100/10),
  2559.         buf2),
  2560. #  else
  2561.       "(bad version)",
  2562. #  endif
  2563. #elif defined(__WATCOMC__)
  2564. #  if (__WATCOMC__ % 10 > 0)
  2565.       (sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
  2566.        __WATCOMC__ % 100), buf), "",
  2567. #  else
  2568.       (sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
  2569.        (__WATCOMC__ % 100) / 10), buf), "",
  2570. #  endif
  2571. #elif defined(__BORLANDC__)
  2572.       "Borland C++",
  2573. #  if (__BORLANDC__ < 0x0200)
  2574.       " 1.0",
  2575. #  elif (__BORLANDC__ == 0x0200)
  2576.       " 2.0",
  2577. #  elif (__BORLANDC__ == 0x0400)
  2578.       " 3.0",
  2579. #  elif (__BORLANDC__ == 0x0410)   /* __TURBOC__ = 0x0310 */
  2580.       " 3.1",
  2581. #  elif (__BORLANDC__ == 0x0452)   /* __TURBOC__ = 0x0320 */
  2582.       " 4.0 or 4.02",
  2583. #  elif (__BORLANDC__ == 0x0460)   /* __TURBOC__ = 0x0340 */
  2584.       " 4.5",
  2585. #  elif (__BORLANDC__ == 0x0500)   /* __TURBOC__ = 0x0340 */
  2586.       " 5.0",
  2587. #  elif (__BORLANDC__ == 0x0520)   /* __TURBOC__ = 0x0520 */
  2588.       " 5.2 (C++ Builder 1.0)",
  2589. #  elif (__BORLANDC__ == 0x0530)   /* __TURBOC__ = 0x0530 */
  2590.       " 5.3 (C++ Builder 3.0)",
  2591. #  elif (__BORLANDC__ == 0x0540)   /* __TURBOC__ = 0x0540 */
  2592.       " 5.4 (C++ Builder 4.0)",
  2593. #  elif (__BORLANDC__ == 0x0550)   /* __TURBOC__ = 0x0550 */
  2594.       " 5.5 (C++ Builder 5.0)",
  2595. #  elif (__BORLANDC__ == 0x0551)   /* __TURBOC__ = 0x0551 */
  2596.       " 5.5.1 (C++ Builder 5.0.1)",
  2597. #  elif (__BORLANDC__ == 0x0560)   /* __TURBOC__ = 0x0560 */
  2598.       " 6.0 (C++ Builder 6.0)",
  2599. #  else
  2600.       " later than 6.0",
  2601. #  endif
  2602. #elif defined(__LCC__)
  2603.       "LCC-Win32", "",
  2604. #elif defined(__GNUC__)
  2605. #  if defined(__RSXNT__)
  2606. #    if (defined(__DJGPP__) && !defined(__EMX__))
  2607.       (sprintf(buf, "rsxnt(djgpp v%d.%02d) / gcc ",
  2608.         __DJGPP__, __DJGPP_MINOR__), buf),
  2609. #    elif defined(__DJGPP__)
  2610.       (sprintf(buf, "rsxnt(emx+djgpp v%d.%02d) / gcc ",
  2611.         __DJGPP__, __DJGPP_MINOR__), buf),
  2612. #    elif (defined(__GO32__) && !defined(__EMX__))
  2613.       "rsxnt(djgpp v1.x) / gcc ",
  2614. #    elif defined(__GO32__)
  2615.       "rsxnt(emx + djgpp v1.x) / gcc ",
  2616. #    elif defined(__EMX__)
  2617.       "rsxnt(emx)+gcc ",
  2618. #    else
  2619.       "rsxnt(unknown) / gcc ",
  2620. #    endif
  2621. #  elif defined(__CYGWIN__)
  2622.       "cygnus win32 / gcc ",
  2623. #  elif defined(__MINGW32__)
  2624.       "mingw32 / gcc ",
  2625. #  else
  2626.       "gcc ",
  2627. #  endif
  2628.       __VERSION__,
  2629. #else /* !_MSC_VER, !__WATCOMC__, !__BORLANDC__, !__LCC__, !__GNUC__ */
  2630.       "unknown compiler (SDK?)", "",
  2631. #endif /* ?compilers */
  2632.  
  2633.       "\nWindows 9x / Windows NT/2K/XP/2K3", " (32-bit)",
  2634.  
  2635. #ifdef __DATE__
  2636.       " on ", __DATE__
  2637. #else
  2638.       "", ""
  2639. #endif
  2640.     );
  2641.  
  2642.     (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
  2643.  
  2644.     return;
  2645.  
  2646. } /* end function version() */
  2647.  
  2648. #endif /* !WINDLL */
  2649. #endif /* !SFX */
  2650.  
  2651.  
  2652.  
  2653. #ifdef MORE
  2654.  
  2655. int screensize(int *tt_rows, int *tt_cols)
  2656. {
  2657.     HANDLE hstdout;
  2658.     CONSOLE_SCREEN_BUFFER_INFO scr;
  2659.  
  2660.     hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
  2661.     GetConsoleScreenBufferInfo(hstdout, &scr);
  2662.     if (tt_rows != NULL) *tt_rows = scr.srWindow.Bottom - scr.srWindow.Top + 1;
  2663.     if (tt_cols != NULL) *tt_cols = scr.srWindow.Right - scr.srWindow.Left + 1;
  2664.     return 0;           /* signal success */
  2665. }
  2666.  
  2667. #endif /* MORE */
  2668.  
  2669.  
  2670.  
  2671. #ifdef W32_STAT_BANDAID
  2672.  
  2673. /* All currently known variants of WIN32 operating systems (Windows 95/98,
  2674.  * WinNT 3.x, 4.0, 5.x) have a nasty bug in the OS kernel concerning
  2675.  * conversions between UTC and local time: In the time conversion functions
  2676.  * of the Win32 API, the timezone offset (including seasonal daylight saving
  2677.  * shift) between UTC and local time evaluation is erratically based on the
  2678.  * current system time. The correct evaluation must determine the offset
  2679.  * value as it {was/is/will be} for the actual time to be converted.
  2680.  *
  2681.  * Newer versions of MS C runtime lib's stat() returns utc time-stamps so
  2682.  * that localtime(timestamp) corresponds to the (potentially false) local
  2683.  * time shown by the OS' system programs (Explorer, command shell dir, etc.)
  2684.  * The RSXNT port follows the same strategy, but fails to recognize the
  2685.  * access-time attribute.
  2686.  *
  2687.  * For the NTFS file system (and other filesystems that store time-stamps
  2688.  * as UTC values), this results in st_mtime (, st_{c|a}time) fields which
  2689.  * are not stable but vary according to the seasonal change of "daylight
  2690.  * saving time in effect / not in effect".
  2691.  *
  2692.  * Other C runtime libs (CygWin), or the crtdll.dll supplied with Win9x/NT
  2693.  * return the unix-time equivalent of the UTC FILETIME values as got back
  2694.  * from the Win32 API call. This time, return values from NTFS are correct
  2695.  * whereas utimes from files on (V)FAT volumes vary according to the DST
  2696.  * switches.
  2697.  *
  2698.  * To achieve timestamp consistency of UTC (UT extra field) values in
  2699.  * Zip archives, the Info-ZIP programs require work-around code for
  2700.  * proper time handling in stat() (and other time handling routines).
  2701.  *
  2702.  * However, nowadays most other programs on Windows systems use the
  2703.  * time conversion strategy of Microsofts C runtime lib "msvcrt.dll".
  2704.  * To improve interoperability in environments where a "consistent" (but
  2705.  * false) "UTC<-->LocalTime" conversion is preferred over "stable" time
  2706.  * stamps, the Info-ZIP specific time conversion handling can be
  2707.  * deactivated by defining the preprocessor flag NO_W32TIMES_IZFIX.
  2708.  */
  2709. /* stat() functions under Windows95 tend to fail for root directories.   *
  2710.  * Watcom and Borland, at least, are affected by this bug.  Watcom made  *
  2711.  * a partial fix for 11.0 but still missed some cases.  This substitute  *
  2712.  * detects the case and fills in reasonable values.  Otherwise we get    *
  2713.  * effects like failure to extract to a root dir because it's not found. */
  2714.  
  2715. int zstat_win32(__W32STAT_GLOBALS__ const char *path, z_stat *buf)
  2716. {
  2717.     if (!zstat(path, buf))
  2718.     {
  2719.         /* stat was successful, now redo the time-stamp fetches */
  2720. #ifndef NO_W32TIMES_IZFIX
  2721.         int fs_uses_loctime = FStampIsLocTime(__G__ path);
  2722. #endif
  2723.         HANDLE h;
  2724.         FILETIME Modft, Accft, Creft;
  2725. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  2726.         char *ansi_path = (char *)alloca(strlen(path) + 1);
  2727.  
  2728.         INTERN_TO_ISO(path, ansi_path);
  2729. #       define Ansi_Path  ansi_path
  2730. #else
  2731. #       define Ansi_Path  path
  2732. #endif
  2733.  
  2734.         TTrace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
  2735.         h = CreateFileA(Ansi_Path, GENERIC_READ,
  2736.                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  2737.                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  2738.         if (h != INVALID_HANDLE_VALUE) {
  2739.             BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
  2740.             CloseHandle(h);
  2741.  
  2742.             if (ftOK) {
  2743.                 FTTrace((stdout, "GetFileTime returned Modft", 0, &Modft));
  2744.                 FTTrace((stdout, "GetFileTime returned Creft", 0, &Creft));
  2745. #ifndef NO_W32TIMES_IZFIX
  2746.                 if (!fs_uses_loctime) {
  2747.                     /*  On a filesystem that stores UTC timestamps, we refill
  2748.                      *  the time fields of the struct stat buffer by directly
  2749.                      *  using the UTC values as returned by the Win32
  2750.                      *  GetFileTime() API call.
  2751.                      */
  2752.                     NtfsFileTime2utime(&Modft, &(buf->st_mtime));
  2753.                     if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
  2754.                         NtfsFileTime2utime(&Accft, &(buf->st_atime));
  2755.                     else
  2756.                         buf->st_atime = buf->st_mtime;
  2757.                     if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
  2758.                         NtfsFileTime2utime(&Creft, &(buf->st_ctime));
  2759.                     else
  2760.                         buf->st_ctime = buf->st_mtime;
  2761.                     TTrace((stdout,"NTFS, recalculated modtime %08lx\n",
  2762.                             buf->st_mtime));
  2763.                 } else
  2764. #endif /* NO_W32TIMES_IZFIX */
  2765.                 {
  2766.                     /*  On VFAT and FAT-like filesystems, the FILETIME values
  2767.                      *  are converted back to the stable local time before
  2768.                      *  converting them to UTC unix time-stamps.
  2769.                      */
  2770.                     VFatFileTime2utime(&Modft, &(buf->st_mtime));
  2771.                     if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
  2772.                         VFatFileTime2utime(&Accft, &(buf->st_atime));
  2773.                     else
  2774.                         buf->st_atime = buf->st_mtime;
  2775.                     if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
  2776.                         VFatFileTime2utime(&Creft, &(buf->st_ctime));
  2777.                     else
  2778.                         buf->st_ctime = buf->st_mtime;
  2779.                     TTrace((stdout, "VFAT, recalculated modtime %08lx\n",
  2780.                             buf->st_mtime));
  2781.                 }
  2782.             }
  2783.         }
  2784. #       undef Ansi_Path
  2785.         return 0;
  2786.     }
  2787. #ifdef W32_STATROOT_FIX
  2788.     else
  2789.     {
  2790.         DWORD flags;
  2791. #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
  2792.         char *ansi_path = (char *)alloca(strlen(path) + 1);
  2793.  
  2794.         INTERN_TO_ISO(path, ansi_path);
  2795. #       define Ansi_Path  ansi_path
  2796. #else
  2797. #       define Ansi_Path  path
  2798. #endif
  2799.  
  2800.         flags = GetFileAttributesA(Ansi_Path);
  2801.         if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
  2802.             Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
  2803.                    FnFilter1(path)));
  2804.             memset(buf, 0, sizeof(z_stat));
  2805.             buf->st_atime = buf->st_ctime = buf->st_mtime =
  2806.               dos_to_unix_time(DOSTIME_MINIMUM);        /* 1-1-80 */
  2807.             buf->st_mode = S_IFDIR | S_IREAD |
  2808.                            ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
  2809.             return 0;
  2810.         } /* assumes: stat() won't fail on non-dirs without good reason */
  2811. #       undef Ansi_Path
  2812.     }
  2813. #endif /* W32_STATROOT_FIX */
  2814.     return -1;
  2815. }
  2816.  
  2817. #endif /* W32_STAT_BANDAID */
  2818.  
  2819.  
  2820.  
  2821. #ifdef W32_USE_IZ_TIMEZONE
  2822. #include "timezone.h"
  2823. #define SECSPERMIN      60
  2824. #define MINSPERHOUR     60
  2825. #define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
  2826. static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule);
  2827.  
  2828. static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule)
  2829. {
  2830.     if (lpw32tm->wYear != 0) {
  2831.         ptrule->r_type = JULIAN_DAY;
  2832.         ptrule->r_day = ydays[lpw32tm->wMonth - 1] + lpw32tm->wDay;
  2833.     } else {
  2834.         ptrule->r_type = MONTH_NTH_DAY_OF_WEEK;
  2835.         ptrule->r_mon = lpw32tm->wMonth;
  2836.         ptrule->r_day = lpw32tm->wDayOfWeek;
  2837.         ptrule->r_week = lpw32tm->wDay;
  2838.     }
  2839.     ptrule->r_time = (long)lpw32tm->wHour * SECSPERHOUR +
  2840.                      (long)(lpw32tm->wMinute * SECSPERMIN) +
  2841.                      (long)lpw32tm->wSecond;
  2842. }
  2843.  
  2844. int GetPlatformLocalTimezone(register struct state * ZCONST sp,
  2845.         void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
  2846.                                         ZCONST struct rule * ZCONST start,
  2847.                                         ZCONST struct rule * ZCONST end))
  2848. {
  2849.     TIME_ZONE_INFORMATION tzinfo;
  2850.     DWORD res;
  2851.  
  2852.     /* read current timezone settings from registry if TZ envvar missing */
  2853.     res = GetTimeZoneInformation(&tzinfo);
  2854.     if (res != TIME_ZONE_ID_INVALID)
  2855.     {
  2856.         struct rule startrule, stoprule;
  2857.  
  2858.         conv_to_rule(&(tzinfo.StandardDate), &stoprule);
  2859.         conv_to_rule(&(tzinfo.DaylightDate), &startrule);
  2860.         sp->timecnt = 0;
  2861.         sp->ttis[0].tt_abbrind = 0;
  2862.         if ((sp->charcnt =
  2863.              WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1,
  2864.                                  sp->chars, sizeof(sp->chars), NULL, NULL))
  2865.             == 0)
  2866.             sp->chars[sp->charcnt++] = '\0';
  2867.         sp->ttis[1].tt_abbrind = sp->charcnt;
  2868.         sp->charcnt +=
  2869.             WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1,
  2870.                                 sp->chars + sp->charcnt,
  2871.                                 sizeof(sp->chars) - sp->charcnt, NULL, NULL);
  2872.         if ((sp->charcnt - sp->ttis[1].tt_abbrind) == 0)
  2873.             sp->chars[sp->charcnt++] = '\0';
  2874.         sp->ttis[0].tt_gmtoff = - (tzinfo.Bias + tzinfo.StandardBias)
  2875.                                 * MINSPERHOUR;
  2876.         sp->ttis[1].tt_gmtoff = - (tzinfo.Bias + tzinfo.DaylightBias)
  2877.                                 * MINSPERHOUR;
  2878.         sp->ttis[0].tt_isdst = 0;
  2879.         sp->ttis[1].tt_isdst = 1;
  2880.         sp->typecnt = (startrule.r_mon == 0 && stoprule.r_mon == 0) ? 1 : 2;
  2881.  
  2882.         if (sp->typecnt > 1)
  2883.             (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
  2884.         return TRUE;
  2885.     }
  2886.     return FALSE;
  2887. }
  2888. #endif /* W32_USE_IZ_TIMEZONE */
  2889.  
  2890. #endif /* !FUNZIP */
  2891.  
  2892.  
  2893.  
  2894. #ifndef WINDLL
  2895. /* This replacement getch() function was originally created for Watcom C
  2896.  * and then additionally used with CYGWIN. Since UnZip 5.4, all other Win32
  2897.  * ports apply this replacement rather that their supplied getch() (or
  2898.  * alike) function.  There are problems with unabsorbed LF characters left
  2899.  * over in the keyboard buffer under Win95 (and 98) when ENTER was pressed.
  2900.  * (Under Win95, ENTER returns two(!!) characters: CR-LF.)  This problem
  2901.  * does not appear when run on a WinNT console prompt!
  2902.  */
  2903.  
  2904. /* Watcom 10.6's getch() does not handle Alt+<digit><digit><digit>. */
  2905. /* Note that if PASSWD_FROM_STDIN is defined, the file containing   */
  2906. /* the password must have a carriage return after the word, not a   */
  2907. /* Unix-style newline (linefeed only).  This discards linefeeds.    */
  2908.  
  2909. int getch_win32(void)
  2910. {
  2911.   HANDLE stin;
  2912.   DWORD rc;
  2913.   unsigned char buf[2];
  2914.   int ret = -1;
  2915.   DWORD odemode = ~(DWORD)0;
  2916.  
  2917. #  ifdef PASSWD_FROM_STDIN
  2918.   stin = GetStdHandle(STD_INPUT_HANDLE);
  2919. #  else
  2920.   stin = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
  2921.                      FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  2922.   if (stin == INVALID_HANDLE_VALUE)
  2923.     return -1;
  2924. #  endif
  2925.   if (GetConsoleMode(stin, &odemode))
  2926.     SetConsoleMode(stin, ENABLE_PROCESSED_INPUT);  /* raw except ^C noticed */
  2927.   if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
  2928.     ret = buf[0];
  2929.   /* when the user hits return we get CR LF.  We discard the LF, not the CR,
  2930.    * because when we call this for the first time after a previous input
  2931.    * such as the one for "replace foo? [y]es, ..." the LF may still be in
  2932.    * the input stream before whatever the user types at our prompt. */
  2933.   if (ret == '\n')
  2934.     if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
  2935.       ret = buf[0];
  2936.   if (odemode != ~(DWORD)0)
  2937.     SetConsoleMode(stin, odemode);
  2938. #  ifndef PASSWD_FROM_STDIN
  2939.   CloseHandle(stin);
  2940. #  endif
  2941.   return ret;
  2942. }
  2943. #endif /* !WINDLL */
  2944.  
  2945.  
  2946.  
  2947. #if (defined(UNICODE_SUPPORT) && !defined(FUNZIP))
  2948. /* convert wide character string to multi-byte character string */
  2949. char *wide_to_local_string(wide_string, escape_all)
  2950.   ZCONST zwchar *wide_string;
  2951.   int escape_all;
  2952. {
  2953.   int i;
  2954.   wchar_t wc;
  2955.   int bytes_char;
  2956.   int default_used;
  2957.   int wsize = 0;
  2958.   int max_bytes = 9;
  2959.   char buf[9];
  2960.   char *buffer = NULL;
  2961.   char *local_string = NULL;
  2962.  
  2963.   for (wsize = 0; wide_string[wsize]; wsize++) ;
  2964.  
  2965.   if (max_bytes < MB_CUR_MAX)
  2966.     max_bytes = MB_CUR_MAX;
  2967.  
  2968.   if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
  2969.     return NULL;
  2970.   }
  2971.  
  2972.   /* convert it */
  2973.   buffer[0] = '\0';
  2974.   for (i = 0; i < wsize; i++) {
  2975.     if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
  2976.       /* wchar_t probably 2 bytes */
  2977.       /* could do surrogates if state_dependent and wctomb can do */
  2978.       wc = zwchar_to_wchar_t_default_char;
  2979.     } else {
  2980.       wc = (wchar_t)wide_string[i];
  2981.     }
  2982.     /* Unter some vendor's C-RTL, the Wide-to-MultiByte conversion functions
  2983.      * (like wctomb() et. al.) do not use the same codepage as the other
  2984.      * string arguments I/O functions (fopen, mkdir, rmdir etc.).
  2985.      * Therefore, we have to fall back to the underlying Win32-API call to
  2986.      * achieve a consistent behaviour for all supported compiler environments.
  2987.      * Failing RTLs are for example:
  2988.      *   Borland (locale uses OEM-CP as default, but I/O functions expect ANSI
  2989.      *            names)
  2990.      *   Watcom  (only "C" locale, wctomb() always uses OEM CP)
  2991.      * (in other words: all supported environments except the Microsoft RTLs)
  2992.      */
  2993.     bytes_char = WideCharToMultiByte(
  2994.                           CP_ACP, WC_COMPOSITECHECK,
  2995.                           &wc, 1,
  2996.                           (LPSTR)buf, sizeof(buf),
  2997.                           NULL, &default_used);
  2998.     if (default_used)
  2999.       bytes_char = -1;
  3000.     if (escape_all) {
  3001.       if (bytes_char == 1 && (uch)buf[0] <= 0x7f) {
  3002.         /* ASCII */
  3003.         strncat(buffer, buf, 1);
  3004.       } else {
  3005.         /* use escape for wide character */
  3006.         char *escape_string = wide_to_escape_string(wide_string[i]);
  3007.         strcat(buffer, escape_string);
  3008.         free(escape_string);
  3009.       }
  3010.     } else if (bytes_char > 0) {
  3011.       /* multi-byte char */
  3012.       strncat(buffer, buf, bytes_char);
  3013.     } else {
  3014.       /* no MB for this wide */
  3015.       /* use escape for wide character */
  3016.       char *escape_string = wide_to_escape_string(wide_string[i]);
  3017.       strcat(buffer, escape_string);
  3018.       free(escape_string);
  3019.     }
  3020.   }
  3021.   if ((local_string = (char *)realloc(buffer, strlen(buffer) + 1)) == NULL) {
  3022.     free(buffer);
  3023.     return NULL;
  3024.   }
  3025.  
  3026.   return local_string;
  3027. }
  3028.  
  3029.  
  3030. #if 0
  3031. wchar_t *utf8_to_wchar_string(utf8_string)
  3032.   char *utf8_string;       /* path to get utf-8 name for */
  3033. {
  3034.   wchar_t  *qw;
  3035.   int       ulen;
  3036.   int       ulenw;
  3037.  
  3038.   if (utf8_string == NULL)
  3039.     return NULL;
  3040.  
  3041.     /* get length */
  3042.     ulenw = MultiByteToWideChar(
  3043.                 CP_UTF8,           /* UTF-8 code page */
  3044.                 0,                 /* flags for character-type options */
  3045.                 utf8_string,       /* string to convert */
  3046.                 -1,                /* string length (-1 = NULL terminated) */
  3047.                 NULL,              /* buffer */
  3048.                 0 );               /* buffer length (0 = return length) */
  3049.     if (ulenw == 0) {
  3050.       /* failed */
  3051.       return NULL;
  3052.     }
  3053.     ulenw++;
  3054.     /* get length in bytes */
  3055.     ulen = sizeof(wchar_t) * (ulenw + 1);
  3056.     if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
  3057.       return NULL;
  3058.     }
  3059.     /* convert multibyte to wide */
  3060.     ulen = MultiByteToWideChar(
  3061.                CP_UTF8,           /* UTF-8 code page */
  3062.                0,                 /* flags for character-type options */
  3063.                utf8_string,       /* string to convert */
  3064.                -1,                /* string length (-1 = NULL terminated) */
  3065.                qw,                /* buffer */
  3066.                ulenw);            /* buffer length (0 = return length) */
  3067.     if (ulen == 0) {
  3068.       /* failed */
  3069.       free(qw);
  3070.       return NULL;
  3071.     }
  3072.  
  3073.   return qw;
  3074. }
  3075.  
  3076. wchar_t *local_to_wchar_string(local_string)
  3077.   char *local_string;       /* path of local name */
  3078. {
  3079.   wchar_t  *qw;
  3080.   int       ulen;
  3081.   int       ulenw;
  3082.  
  3083.   if (local_string == NULL)
  3084.     return NULL;
  3085.  
  3086.     /* get length */
  3087.     ulenw = MultiByteToWideChar(
  3088.                 CP_ACP,            /* ANSI code page */
  3089.                 0,                 /* flags for character-type options */
  3090.                 local_string,      /* string to convert */
  3091.                 -1,                /* string length (-1 = NULL terminated) */
  3092.                 NULL,              /* buffer */
  3093.                 0 );               /* buffer length (0 = return length) */
  3094.     if (ulenw == 0) {
  3095.       /* failed */
  3096.       return NULL;
  3097.     }
  3098.     ulenw++;
  3099.     /* get length in bytes */
  3100.     ulen = sizeof(wchar_t) * (ulenw + 1);
  3101.     if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
  3102.       return NULL;
  3103.     }
  3104.     /* convert multibyte to wide */
  3105.     ulen = MultiByteToWideChar(
  3106.                CP_ACP,            /* ANSI code page */
  3107.                0,                 /* flags for character-type options */
  3108.                local_string,      /* string to convert */
  3109.                -1,                /* string length (-1 = NULL terminated) */
  3110.                qw,                /* buffer */
  3111.                ulenw);            /* buffer length (0 = return length) */
  3112.     if (ulen == 0) {
  3113.       /* failed */
  3114.       free(qw);
  3115.       return NULL;
  3116.     }
  3117.  
  3118.   return qw;
  3119. }
  3120. #endif /* 0 */
  3121. #endif /* UNICODE_SUPPORT && !FUNZIP */
  3122.  
  3123.  
  3124.  
  3125. /* --------------------------------------------------- */
  3126. /* Large File Support
  3127.  *
  3128.  * Initial functions by E. Gordon and R. Nausedat
  3129.  * 9/10/2003
  3130.  * Lifted from Zip 3b, win32.c and place here by Myles Bennett
  3131.  * 7/6/2004
  3132.  *
  3133.  * These implement 64-bit file support for Windows.  The
  3134.  * defines and headers are in win32/w32cfg.h.
  3135.  *
  3136.  * Moved to win32i64.c by Mike White to avoid conflicts in
  3137.  * same name functions in WiZ using UnZip and Zip libraries.
  3138.  * 9/25/2003
  3139.  */
  3140.