home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / unzip / part05 < prev    next >
Internet Message Format  |  1994-09-19  |  72KB

  1. From: zip-bugs@wkuvx1.wku.edu (Info-ZIP group)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i070:  unzip - Info-ZIP portable UnZip, version 5.12, Part05/20
  4. Date: 18 Sep 1994 23:14:49 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <35j37p$qmo@sparky.sterling.com>
  9. X-Md4-Signature: 67ab425609829ea013b7f64b4defee4f
  10.  
  11. Submitted-by: zip-bugs@wkuvx1.wku.edu (Info-ZIP group)
  12. Posting-number: Volume 44, Issue 70
  13. Archive-name: unzip/part05
  14. Environment: UNIX, VMS, OS/2, MS-DOS, MACINTOSH, WIN-NT, LINUX, MINIX, COHERENT, AMIGA?, ATARI TOS, SGI, DEC, Cray, Convex, Amdahl, Sun
  15. Supersedes: unzip50: Volume 31, Issue 104-117
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  unzip-5.12/Where unzip-5.12/os2/os2.c
  22. # Wrapped by kent@sparky on Sat Sep 17 23:33:37 1994
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 5 (of 20)."'
  26. if test -f 'unzip-5.12/Where' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'unzip-5.12/Where'\"
  28. else
  29.   echo shar: Extracting \"'unzip-5.12/Where'\" \(9912 characters\)
  30.   sed "s/^X//" >'unzip-5.12/Where' <<'END_OF_FILE'
  31. X__________________________________________________________________________
  32. X
  33. X  This is the Info-ZIP file ``Where,'' last updated on 7 September 1994.
  34. X__________________________________________________________________________
  35. X
  36. X   Note that some ftp sites may not yet have the latest versions of
  37. X   Zip and UnZip when you read this.  The latest versions, including
  38. X   the crypt sources, always appear in ftp.uu.net:/pub/archiving/zip
  39. X   (and subdirectories thereof) first.
  40. X
  41. X   IF YOU FIND AN ERROR:  please let us know!  We don't have time to
  42. X   check each and every site personally (or even collectively), so any
  43. X   number of the sites listed below may have moved or disappeared en-
  44. X   tirely.  E-mail to zip-bugs@wkuvx1.wku.edu and we'll update this file.
  45. X__________________________________________________________________________
  46. X
  47. X
  48. XSource-code archives for Info-ZIP's portable Zip, UnZip, and related
  49. Xutilities (on some ftp sites, the .zip files for UnZip may have a .zoo
  50. Xequivalent in Zoo 2.10 format):
  51. X
  52. X   zip201.zip      Zip 2.0.1 (deflation; includes zipnote, zipsplit)
  53. X   zip201.tar.Z    ditto, compress'd tar format
  54. X
  55. X   zip11.zip       Zip 1.1 (shrinking, implosion; compatible with PKUNZIP 1.1)
  56. X   zip11.tar.Z     ditto, compress'd tar format
  57. X
  58. X   unzip512.zip    UnZip 5.12 (all methods supported; zipinfo, funzip, unzipsfx)
  59. X   unzip512.tar.Z  ditto, compress'd tar format
  60. X
  61. X   wunz20sr.zip    WizUnZip 2.0 sources for Windows 3.x; based on UnZip 5.0p1
  62. X
  63. X   zcrypt23.zip    encryption/decryption support (includes zipcloak)
  64. X
  65. XExecutables archives (and related files) for Info-ZIP's software; see BBS
  66. Xsection below for special CompuServe (6.3) filenames:
  67. X
  68. X   zip201x.zip     MSDOS executables and docs for zip, zipnote, zipsplit
  69. X   zcryp20x.zip    MSDOS encryption executables and docs for zip, zipcloak
  70. X   zip201x1.zip    OS/2 1.x (16-bit) executables and docs (no encryption)
  71. X   zip201x2.zip    OS/2 2.x (32-bit) executables and docs (no encryption)
  72. X   zip201c2.zip    OS/2 2.x (32-bit) executables and docs (with encryption)
  73. X   zip201-vax.zip  VMS exes (VAX) and docs
  74. X   zip201-axp.zip  VMS exes (Alpha) and docs
  75. X   zip201x.lha     Amiga executables and docs
  76. X
  77. X   unz512x.exe     MSDOS self-extracting executable (16-bit unzip, ..., docs)
  78. X   unz512x3.exe    MSDOS self-extracting executable (16-, 32-bit unzip, docs)
  79. X   unz512x1.exe    OS/2 1.x (16-bit) self-extracting executables and docs
  80. X   unz512x2.exe    OS/2 2.x (32-bit) self-extracting executables and docs
  81. X   unz512xN.exe    Windows NT (and Chicago) self-extracting Intel exes and docs
  82. X  (unz512xN-mips.exe, unz512xN-axp.exe:  Windows NT exes/docs for MIPS & Alpha)
  83. X   unz512x-vax.exe VMS self-extracting executables and docs for VAX unzip
  84. X   unz512x-axp.exe VMS self-extracting executables and docs for Alpha unzip
  85. X   unz512x.lha     Amiga executables and docs for unzip
  86. X   unz512x.tos     Atari self-extracting executables and docs for unzip
  87. X   unz512x.hqx     Macintosh BinHex'd executables and docs for unzip
  88. X  (unz512x.tar.Z or .gz:  Unix exes/docs for Solaris 2.x, SCO Unix or Linux,
  89. X                   depending on directory/location)
  90. X
  91. X   UnzpHist.zip    complete changes history of UnZip and its precursors
  92. X
  93. X   wunz20x.zip     WizUnZip 2.0 executable/docs for Windows & NT 3.1, OS/2 2.1
  94. X   wunl20x.zip     same as wunz20x.zip, plus two DLLs for Win 3.0 and OS/2 2.0
  95. X
  96. XThe latest from PKWARE (the guys who started it all):
  97. X
  98. X   pkz204g.exe     MS-DOS PKZIP/PKUNZIP 2.04g (self-extracting archive)
  99. X   pkz110eu.exe    MS-DOS PKZIP/PKUNZIP 1.1 (self-extracting)
  100. X   pkz206-2.exe    OS/2 PKZIP/PKUNZIP 2.06 (IBM internal only; same as 2.04g)
  101. X   pkz102-2.exe    OS/2 PKZIP/PKUNZIP 1.02 (self-extracting)
  102. X
  103. XThird-party software which is based on or uses (or can use) Info-ZIP software:
  104. X
  105. X   zipme11.zip, zipctl.zip, wuz131.zip, zpfly91b.zip, pmzip01.zip (OS/2)
  106. X   winzip5b.zip, z101.zip (Windows)
  107. X
  108. Xftp sites for the US-exportable sources and executables:
  109. X
  110. X   NOTE:  Look for the file names given above in the following directories.
  111. X   Some sites like to use slightly different names, such as zip-2.0.1.tar.gz
  112. X   instead of zip201.tar.Z.  In the case of some comp.sources.misc archive
  113. X   sites, directories may be used (zip201/part01.Z, ..., zip201/part11.Z,
  114. X   zip201/patch01.Z, etc.).
  115. X
  116. X   ftp.uu.net:/pub/archiving/zip        [THIS MIRRORS THE INFO-ZIP HOME SITE]
  117. X
  118. X   oak.oakland.edu:/pub/msdos/{zip,windows3}       [AND OTHER SIMTEL MIRRORS]
  119. X   oak.oakland.edu:/pub/misc/{unix,vaxvms}
  120. X   garbo.uwasa.fi:/{unix,pc}/arcers                 [AND OTHER GARBO MIRRORS]
  121. X   ftp-os2.cdrom.com:/pub/os2/{2_x,all}/archiver
  122. X   ftp-os2.nmsu.edu:/os2/{2_x,all}/archiver
  123. X   ftp.informatik.tu-muenchen.de:/pub/comp/os/os2/archiver
  124. X   sumex-aim.stanford.edu:/info-mac/util
  125. X   ftp.wustl.edu:/pub/aminet/util/arc              [AND OTHER AMINET MIRRORS]
  126. X   atari.archive.umich.edu:/pub/Archivers (?)       [AND OTHER UMICH MIRRORS]
  127. X   lpuds.oea.ihep.su:/ ... ?
  128. X
  129. Xftp sites for the encryption and decryption sources and/or executables:
  130. X
  131. X   NOTE 1:  Non-US users, please do NOT ftp from the US sites (US
  132. X   regulations and all that).  Likewise, US users, please do not
  133. X   ftp from the European sites (it's not illegal, but it sure is
  134. X   a waste of expensive bandwidth).
  135. X
  136. X   NOTE 2:  Some sites may carry both encryption and non-encryption
  137. X   executables with slightly different names; for example, zip201c2.zip
  138. X   instead of zip201x2.zip ("c" == crypt version).  Other sites may
  139. X   include *only* the encryption-related executables (zip and zipcloak)
  140. X   in a second archive (e.g., zcryp20x.zip).
  141. X
  142. X   From the US:
  143. X      wuarchive.wustl.edu:/mirrors/garbo.uwasa.fi/arcutil
  144. X      ftp.uu.net:/pub/archiving/zip
  145. X
  146. X   Outside the US:
  147. X      garbo.uwasa.fi:/pc/arcutil
  148. X      ftp.inria.fr:/system/arch-compr
  149. X      ftp.informatik.tu-muenchen.de:/pub/comp/os/os2/archiver
  150. X         (mail server at ftp-mailer@informatik.tu-muenchen.de)
  151. X
  152. X      ftp.win.tue.nl:/pub/compression/zip/...
  153. X      ftp.uni-erlangen.de:/pub/pc/msdos/utilities/zip/...
  154. X
  155. Xftp sites for VMS-format Zip and UnZip packages (sources, object files and
  156. Xexecutables, no encryption/decryption--see also "Mail servers" section below):
  157. X
  158. X   ftp.spc.edu [192.107.46.27] and ftp.wku.edu:
  159. X
  160. X   [.MACRO32]AAAREADME.TXT
  161. X   [.MACRO32.SAVESETS]UNZIP.BCK  or  UNZIP.ZIP  (if already have older version)
  162. X   [.MACRO32.SAVESETS]ZIP20.ZIP  (to be renamed to ZIP.ZIP in next release)
  163. X
  164. XTo find other ftp sites:
  165. X
  166. X   The "archie" ftp database utility can be used to find an ftp site
  167. X   near you (although it always seems to find old versions...).  If
  168. X   you don't know how to use it, DON'T ASK US--check the Usenet groups
  169. X   news.announce.newusers or news.answers or some such, or ask your
  170. X   system administrator (or just RTFM :-) ).
  171. X
  172. XUUCP sites:
  173. X
  174. X   uunet!~/pub/archiving/zip/ ...
  175. X
  176. XBulletin boards (commercial and otherwise):
  177. X
  178. X   Sources, MS-DOS executables:
  179. X      CompuServe IBMPRO forum, Library 10, Data Compression (unz512.zip,
  180. X         sources; unz512.exe, self-extracting executables and docs)
  181. X      CompuServe (ZiffNet) PBSUTIL forum and Public Brand Software BBS
  182. X         [US, membership required; V.32 line, (317) 856-1490]
  183. X         (unz512.zip, sources; unz512.exe, self-extracting exes and docs)
  184. X      America Online OS/2 Forum, Free Uploading area; also Top Picks lib-
  185. X         rary, File/Disk Utilities library, and OS/2 1.x library (do key-
  186. X         word search via ctrl-K:  FILE SEARCH on "INFOZIP")
  187. X      FidoNet node 1:124/2113, Lunatic Fringe [Richardson, Texas; BBS
  188. X         (214) 235-5288; sysop john.stewart@lunatic.com; complete mirror
  189. X         of Info-ZIP home site]
  190. X      FidoNet node 1:246/74, Metal Shoppe BBS [Windsor, Ontario; CLink
  191. X         node 911:6510/0; BBS (519) 256-0278; sysop rakey@cyberspace.net
  192. X         (Ray Akey); micro-based files but no Unix/VMS/NT stuff]
  193. X      Drealm Conference System [London, UK; V.22bis, subscriber lines
  194. X         to V.32bis, etc.; (+44) 81 568 2204]
  195. X      Compulink Information eXchange (CIX) [London, UK; (+44) 181 390 1244
  196. X         and 181 390 1255; sources in free_software/sources, executables
  197. X         in "the filepool"]
  198. X
  199. X   Windows sources and executables:
  200. X      CompuServe ZENITH forum (wunzip.zip, WizUnZip exe + libs for
  201. X         Win 3.x, NT, OS/2 2.x)
  202. X      CompuServe CRAFTS forum (wunz20.exe, WizUnZip bare executable
  203. X         for Win 3.1, NT, OS/2 2.1)
  204. X
  205. X   OS/2 executables:
  206. X      CompuServe OS2USER forum (zip201.zip and unz512.exe, OS/2 16-
  207. X         and 32-bit exes and docs)
  208. X
  209. X   Amiga executables:
  210. X      BIX in AMIGA files section (perform keyword search on "info-zip")
  211. X         [requires account; telnet bix.com, or "C BIX" via local Sprint
  212. X         X.25 PAD, or dial direct in US at (617) 491-5410]
  213. X
  214. XMail servers:
  215. X
  216. X   If you don't have anonymous FTP capability, you can mail one
  217. X   of the following commands (in the body of an e-mail message) to
  218. X   listserv@vm.ecs.rpi.edu or listserv@vm1.nodak.edu in order to
  219. X   get a copy of the source code via e-mail:
  220. X
  221. X      /pdget mail /pub/misc/unix/unzip512.tar.Z uuencode
  222. X      /pdget mail /pub/msdos/zip/unzip512.zip uuencode
  223. X      /pdget mail /pub/msdos/zip/zip201.zip uuencode
  224. X
  225. X   The older, pseudo-TOPS-20 style also works:
  226. X
  227. X      /pdget mail pd:<misc.unix>unzip512.tar.Z uuencode
  228. X      /pdget mail pd:<misc.unix>zip201.zip uuencode
  229. X
  230. X   To get the encryption source by e-mail, send the following commands
  231. X   to ftp-mailer@informatik.tu-muenchen.de:
  232. X
  233. X      get /pub/comp/os/os2/archiver/zcrypt23.zip
  234. X      quit
  235. X
  236. X   To get the VMS Zip/UnZip package by e-mail, send the following
  237. X   commands in the body of a mail message to mxserver@wkuvx1.wku.edu
  238. X   (the "HELP" command is also accepted):
  239. X
  240. X      SEND UNZIP
  241. X      SEND ZIP20           <-- will change to plain "ZIP" in next release
  242. X      SEND FILESERV_TOOLS
  243. X
  244. X   To get Atari executables by e-mail, send a message to 
  245. X   atari@atari.archive.umich.edu for information about the mail server.
  246. X__________________________________________________________________________
  247. X
  248. END_OF_FILE
  249.   if test 9912 -ne `wc -c <'unzip-5.12/Where'`; then
  250.     echo shar: \"'unzip-5.12/Where'\" unpacked with wrong size!
  251.   fi
  252.   # end of 'unzip-5.12/Where'
  253. fi
  254. if test -f 'unzip-5.12/os2/os2.c' -a "${1}" != "-c" ; then 
  255.   echo shar: Will not clobber existing file \"'unzip-5.12/os2/os2.c'\"
  256. else
  257.   echo shar: Extracting \"'unzip-5.12/os2/os2.c'\" \(57190 characters\)
  258.   sed "s/^X//" >'unzip-5.12/os2/os2.c' <<'END_OF_FILE'
  259. X/*---------------------------------------------------------------------------
  260. X
  261. X  os2.c
  262. X
  263. X  OS/2-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  264. X
  265. X  This file contains the OS/2 versions of the file name/attribute/time/etc
  266. X  code.  Most or all of the routines which make direct use of OS/2 system
  267. X  calls (i.e., the non-lowercase routines) are Kai Uwe Rommel's.  The read-
  268. X  dir() suite was written by Michael Rendell and ported to OS/2 by Kai Uwe;
  269. X  it is in the public domain.
  270. X
  271. X  Contains:  GetCountryInfo()
  272. X             GetFileTime()
  273. X             SetPathInfo()
  274. X             IsEA()
  275. X             SetEAs()
  276. X             SizeOfEAs()
  277. X             GetLoadPath()
  278. X             opendir()
  279. X             closedir()
  280. X             readdir()
  281. X             [ seekdir() ]             not used
  282. X             [ telldir() ]             not used
  283. X             free_dircontents()
  284. X             getdirent()
  285. X             IsFileSystemFAT()
  286. X             do_wild()
  287. X             mapattr()
  288. X             mapname()
  289. X             checkdir()
  290. X             isfloppy()
  291. X             IsFileNameValid()
  292. X             map2fat()
  293. X             SetLongNameEA()
  294. X             close_outfile()
  295. X             check_for_newer()
  296. X             dateformat()
  297. X             version()
  298. X             InitNLS()
  299. X             IsUpperNLS()
  300. X             ToLowerNLS()
  301. X             StringLower()
  302. X             DebugMalloc()
  303. X
  304. X  ---------------------------------------------------------------------------*/
  305. X
  306. X
  307. X#include "unzip.h"
  308. Xchar *StringLower(char *szArg);
  309. X
  310. X/* local prototypes */
  311. Xstatic int   isfloppy        __((int nDrive));
  312. Xstatic int   IsFileNameValid __((char *name));
  313. Xstatic void  map2fat         __((char *pathcomp, char **pEndFAT));
  314. Xstatic int   SetLongNameEA   __((char *name, char *longname));
  315. Xstatic void  InitNLS         __((void));
  316. X
  317. X#ifndef __EMX__
  318. X#  if (_MSC_VER >= 600) || defined(__IBMC__)
  319. X#    include <direct.h>          /* have special MSC/IBM C mkdir prototype */
  320. X#  else                          /* own prototype because dir.h conflicts? */
  321. X     int mkdir(const char *path);
  322. X#  endif
  323. X#  define MKDIR(path,mode)   mkdir(path)
  324. X#else
  325. X#  define MKDIR(path,mode)   mkdir(path,mode)
  326. X#endif
  327. X
  328. X#define INCL_NOPM
  329. X#define INCL_DOSNLS
  330. X#define INCL_DOSPROCESS
  331. X#define INCL_DOSDEVICES
  332. X#define INCL_DOSDEVIOCTL
  333. X#define INCL_DOSERRORS
  334. X#include <os2.h>
  335. X
  336. X#ifdef __32BIT__
  337. X
  338. XUSHORT DosDevIOCtl32(PVOID pData, USHORT cbData, PVOID pParms, USHORT cbParms,
  339. X                     USHORT usFunction, USHORT usCategory, HFILE hDevice)
  340. X{
  341. X  ULONG ulParmLengthInOut = cbParms, ulDataLengthInOut = cbData;
  342. X  return (USHORT) DosDevIOCtl(hDevice, usCategory, usFunction,
  343. X                              pParms, cbParms, &ulParmLengthInOut,
  344. X                              pData, cbData, &ulDataLengthInOut);
  345. X}
  346. X
  347. X#  define DosDevIOCtl DosDevIOCtl32
  348. X#else
  349. X#  define DosDevIOCtl DosDevIOCtl2
  350. X#endif
  351. X
  352. X
  353. X#define EAID     0x0009
  354. X
  355. X
  356. Xtypedef struct
  357. X{
  358. X  ush nID;
  359. X  ush nSize;
  360. X  ulg lSize;
  361. X}
  362. XEAHEADER, *PEAHEADER;
  363. X
  364. X
  365. X#ifndef __32BIT__
  366. X
  367. Xtypedef struct
  368. X{
  369. X  ULONG oNextEntryOffset;
  370. X  BYTE fEA;
  371. X  BYTE cbName;
  372. X  USHORT cbValue;
  373. X  CHAR szName[1];
  374. X}
  375. XFEA2, *PFEA2;
  376. X
  377. Xtypedef struct
  378. X{
  379. X  ULONG cbList;
  380. X  FEA2 list[1];
  381. X}
  382. XFEA2LIST, *PFEA2LIST;
  383. X
  384. X
  385. X#define DosSetPathInfo(p1, p2, p3, p4, p5) \
  386. X        DosSetPathInfo(p1, p2, p3, p4, p5, 0)
  387. X#define DosQueryPathInfo(p1, p2, p3, p4) \
  388. X        DosQPathInfo(p1, p2, p3, p4, 0)
  389. X#define DosMapCase DosCaseMap
  390. X#define DosQueryCtryInfo DosGetCtryInfo
  391. X
  392. X#endif /* !__32BIT__ */
  393. X
  394. X
  395. X
  396. X
  397. X
  398. X/*
  399. X * @(#) dir.h 1.4 87/11/06   Public Domain.
  400. X */
  401. X
  402. X#define MAXNAMLEN  256
  403. X#define MAXPATHLEN 256
  404. X
  405. X#define A_RONLY    0x01
  406. X#define A_HIDDEN   0x02
  407. X#define A_SYSTEM   0x04
  408. X#define A_LABEL    0x08
  409. X#define A_DIR      0x10
  410. X#define A_ARCHIVE  0x20
  411. X
  412. X
  413. Xstruct direct
  414. X{
  415. X  ino_t    d_ino;                   /* a bit of a farce */
  416. X  int      d_reclen;                /* more farce */
  417. X  int      d_namlen;                /* length of d_name */
  418. X  char     d_name[MAXNAMLEN + 1];   /* null terminated */
  419. X  /* nonstandard fields */
  420. X  long     d_size;                  /* size in bytes */
  421. X  unsigned d_mode;                  /* MS-DOS or OS/2 file attributes */
  422. X  unsigned d_time;
  423. X  unsigned d_date;
  424. X};
  425. X
  426. X/* The fields d_size and d_mode are extensions by me (Kai Uwe Rommel).  The
  427. X * find_first and find_next calls deliver these data without any extra cost.
  428. X * If these data are needed, the fields save a lot of extra calls to stat()
  429. X * (each stat() again performs a find_first call !).
  430. X */
  431. X
  432. Xstruct _dircontents
  433. X{
  434. X  char *_d_entry;
  435. X  long _d_size;
  436. X  unsigned _d_mode, _d_time, _d_date;
  437. X  struct _dircontents *_d_next;
  438. X};
  439. X
  440. Xtypedef struct _dirdesc
  441. X{
  442. X  int  dd_id;                   /* uniquely identify each open directory */
  443. X  long dd_loc;                  /* where we are in directory entry is this */
  444. X  struct _dircontents *dd_contents;   /* pointer to contents of dir */
  445. X  struct _dircontents *dd_cp;         /* pointer to current position */
  446. X}
  447. XDIR;
  448. X
  449. X
  450. Xextern DIR *opendir(char *);
  451. Xextern struct direct *readdir(DIR *);
  452. Xextern void seekdir(DIR *, long);
  453. Xextern long telldir(DIR *);
  454. Xextern void closedir(DIR *);
  455. X#define rewinddir(dirp) seekdir(dirp, 0L)
  456. X
  457. Xint IsFileSystemFAT(char *dir);
  458. Xchar *StringLower(char *);
  459. X
  460. X
  461. X
  462. X
  463. X/*
  464. X * @(#)dir.c 1.4 87/11/06 Public Domain.
  465. X */
  466. X
  467. X#ifdef __32BIT__
  468. X#  define DosFindFirst(p1, p2, p3, p4, p5, p6) \
  469. X          DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
  470. X#else
  471. X#  define DosQueryCurrentDisk DosQCurDisk
  472. X#  define DosQueryFSAttach(p1, p2, p3, p4, p5) \
  473. X          DosQFSAttach(p1, p2, p3, p4, p5, 0)
  474. X#  define DosQueryPathInfo(p1, p2, p3, p4) \
  475. X          DosQPathInfo(p1, p2, p3, p4, 0)
  476. X#  define DosSetPathInfo(p1, p2, p3, p4, p5) \
  477. X          DosSetPathInfo(p1, p2, p3, p4, p5, 0)
  478. X#  define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \
  479. X          DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)
  480. X#  define DosFindFirst(p1, p2, p3, p4, p5, p6) \
  481. X          DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
  482. X#  define DosMapCase DosCaseMap
  483. X#endif
  484. X
  485. X#ifndef S_IFMT
  486. X#  define S_IFMT 0xF000
  487. X#endif
  488. X
  489. X
  490. X#ifdef __WATCOMC__
  491. X   unsigned char __near _osmode = OS2_MODE;
  492. X#endif
  493. X
  494. X#ifndef SFX
  495. X   static char *getdirent(char *);
  496. X   static void free_dircontents(struct _dircontents *);
  497. X   static int attributes = A_DIR | A_HIDDEN | A_SYSTEM;
  498. X#  ifdef __32BIT__
  499. X     static HDIR hdir;
  500. X     static ULONG count;
  501. X     static FILEFINDBUF3 find;
  502. X#  else
  503. X     static HDIR hdir;            /* GRR:  is there a difference?  HDIR2?? */
  504. X     static USHORT count;
  505. X     static FILEFINDBUF find;
  506. X#  endif
  507. X#endif /* !SFX */
  508. X
  509. X
  510. X
  511. X
  512. Xstatic int created_dir;        /* used by mapname(), checkdir() */
  513. Xstatic int renamed_fullpath;   /* ditto */
  514. Xstatic int fnlen;              /* ditto */
  515. X#ifdef __32BIT__
  516. X   static ULONG nLabelDrive;   /* ditto */
  517. X#else
  518. X   static USHORT nLabelDrive;
  519. X#endif
  520. Xstatic int longnameEA;         /* checkdir(), close_outfile() */
  521. Xstatic char *lastpathcomp;     /* ditto */
  522. X
  523. X
  524. Xint GetCountryInfo(void)
  525. X{
  526. X    COUNTRYINFO ctryi;
  527. X    COUNTRYCODE ctryc;
  528. X#ifdef __32BIT__
  529. X    ULONG cbInfo;
  530. X#else
  531. X    USHORT cbInfo;
  532. X#endif
  533. X
  534. X  ctryc.country = ctryc.codepage = 0;
  535. X
  536. X  if ( DosQueryCtryInfo(sizeof(ctryi), &ctryc, &ctryi, &cbInfo) != NO_ERROR )
  537. X    return 0;
  538. X
  539. X  return ctryi.fsDateFmt;
  540. X}
  541. X
  542. X
  543. Xlong GetFileTime(char *name)
  544. X{
  545. X#ifdef __32BIT__
  546. X  FILESTATUS3 fs;
  547. X#else
  548. X  FILESTATUS fs;
  549. X#endif
  550. X  USHORT nDate, nTime;
  551. X
  552. X  if ( DosQueryPathInfo(name, 1, (PBYTE) &fs, sizeof(fs)) )
  553. X    return -1;
  554. X
  555. X  nDate = * (USHORT *) &fs.fdateLastWrite;
  556. X  nTime = * (USHORT *) &fs.ftimeLastWrite;
  557. X
  558. X  return ((ULONG) nDate) << 16 | nTime;
  559. X}
  560. X
  561. X
  562. Xvoid SetPathInfo(char *path, ush moddate, ush modtime, int flags)
  563. X{
  564. X  union {
  565. X    FDATE fd;               /* system file date record */
  566. X    ush zdate;              /* date word */
  567. X  } ud;
  568. X  union {
  569. X    FTIME ft;               /* system file time record */
  570. X    ush ztime;              /* time word */
  571. X  } ut;
  572. X  FILESTATUS fs;
  573. X  USHORT nLength;
  574. X  char szName[CCHMAXPATH];
  575. X
  576. X  strcpy(szName, path);
  577. X  nLength = strlen(szName);
  578. X  if (szName[nLength - 1] == '/')
  579. X    szName[nLength - 1] = 0;
  580. X
  581. X  if ( DosQueryPathInfo(szName, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)) )
  582. X    return;
  583. X
  584. X  ud.zdate = moddate;
  585. X  ut.ztime = modtime;
  586. X  fs.fdateLastWrite = fs.fdateCreation = ud.fd;
  587. X  fs.ftimeLastWrite = fs.ftimeCreation = ut.ft;
  588. X
  589. X  if ( flags != -1 )
  590. X    fs.attrFile = flags; /* hidden, system, archive, read-only */
  591. X
  592. X  DosSetPathInfo(szName, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0);
  593. X}
  594. X
  595. X
  596. Xtypedef struct
  597. X{
  598. X  ULONG cbList;               /* length of value + 22 */
  599. X#ifdef __32BIT__
  600. X  ULONG oNext;
  601. X#endif
  602. X  BYTE fEA;                   /* 0 */
  603. X  BYTE cbName;                /* length of ".LONGNAME" = 9 */
  604. X  USHORT cbValue;             /* length of value + 4 */
  605. X  BYTE szName[10];            /* ".LONGNAME" */
  606. X  USHORT eaType;              /* 0xFFFD for length-preceded ASCII */
  607. X  USHORT eaSize;              /* length of value */
  608. X  BYTE szValue[CCHMAXPATH];
  609. X}
  610. XFEALST;
  611. X
  612. X
  613. Xint IsEA(void *extra_field)
  614. X{
  615. X  EAHEADER *pEAblock = (PEAHEADER) extra_field;
  616. X  return extra_field != NULL && pEAblock -> nID == EAID;
  617. X}
  618. X
  619. X
  620. Xvoid SetEAs(char *path, void *eablock)
  621. X{
  622. X  EAHEADER *pEAblock = (PEAHEADER) eablock;
  623. X#ifdef __32BIT__
  624. X  EAOP2 eaop;
  625. X  PFEA2LIST pFEA2list;
  626. X#else
  627. X  EAOP eaop;
  628. X  PFEALIST pFEAlist;
  629. X  PFEA pFEA;
  630. X  PFEA2LIST pFEA2list;
  631. X  PFEA2 pFEA2;
  632. X  ULONG nLength2;
  633. X#endif
  634. X  USHORT nLength;
  635. X  char szName[CCHMAXPATH];
  636. X
  637. X  if ( !IsEA(eablock) )
  638. X    return;
  639. X
  640. X  strcpy(szName, path);
  641. X  nLength = strlen(szName);
  642. X  if (szName[nLength - 1] == '/')
  643. X    szName[nLength - 1] = 0;
  644. X
  645. X  if ( (pFEA2list = (PFEA2LIST) malloc((size_t) pEAblock -> lSize)) == NULL )
  646. X    return;
  647. X
  648. X  if ( memextract((char *) pFEA2list, pEAblock -> lSize,
  649. X                  (char *) (pEAblock + 1), 
  650. X                  pEAblock -> nSize - sizeof(pEAblock -> lSize)) )
  651. X  {
  652. X    free(pFEA2list);
  653. X    return;
  654. X  }
  655. X
  656. X#ifdef __32BIT__
  657. X  eaop.fpGEA2List = NULL;
  658. X  eaop.fpFEA2List = pFEA2list;
  659. X#else
  660. X  pFEAlist  = (PVOID) pFEA2list;
  661. X  pFEA2 = pFEA2list -> list;
  662. X  pFEA  = pFEAlist  -> list;
  663. X
  664. X  do
  665. X  {
  666. X    nLength2 = pFEA2 -> oNextEntryOffset;
  667. X    nLength = sizeof(FEA) + pFEA2 -> cbName + 1 + pFEA2 -> cbValue;
  668. X
  669. X    memcpy(pFEA, (PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset), nLength);
  670. X
  671. X    pFEA2 = (PFEA2) ((PCH) pFEA2 + nLength2);
  672. X    pFEA = (PFEA) ((PCH) pFEA + nLength);
  673. X  }
  674. X  while ( nLength2 != 0 );
  675. X
  676. X  pFEAlist -> cbList = (PCH) pFEA - (PCH) pFEAlist;
  677. X
  678. X  eaop.fpGEAList = NULL;
  679. X  eaop.fpFEAList = pFEAlist;
  680. X#endif
  681. X
  682. X  eaop.oError = 0;
  683. X  DosSetPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &eaop, sizeof(eaop), 0);
  684. X
  685. X  if (!tflag && (qflag < 2))
  686. X    PRINTF(" (%ld bytes EA's)", pFEA2list -> cbList);
  687. X
  688. X  free(pFEA2list);
  689. X}
  690. X
  691. X
  692. Xulg SizeOfEAs(void *extra_field)
  693. X{
  694. X    EAHEADER *pEAblock = (PEAHEADER)extra_field;
  695. X
  696. X    if (extra_field != NULL  &&  makeword((uch *)&pEAblock->nID) == EAID)
  697. X        return makelong((uch *)&pEAblock->lSize);
  698. X
  699. X    return 0L;
  700. X}
  701. X
  702. X
  703. X
  704. X
  705. X
  706. X#ifdef SFX
  707. X
  708. Xchar *GetLoadPath(void) 
  709. X{
  710. X#ifdef __32BIT__ /* generic for 32-bit API */
  711. X
  712. X  PTIB pptib;
  713. X  PPIB pppib;
  714. X  char *szPath;
  715. X
  716. X  DosGetInfoBlocks(&pptib, &pppib);
  717. X  szPath = pppib -> pib_pchenv;
  718. X
  719. X  while (*szPath) /* find end of process environment */
  720. X    szPath = strchr(szPath, 0) + 1;
  721. X
  722. X  return szPath + 1; /* .exe file name follows environment */
  723. X
  724. X#else /* 16-bit, specific for MS C 6.00, note: requires large data model */
  725. X
  726. X  extern char _far *_pgmptr;
  727. X  return _pgmptr;
  728. X
  729. X#endif
  730. X} /* end function GetLoadPath() */
  731. X
  732. X
  733. X
  734. X
  735. X
  736. X#else /* !SFX */
  737. X
  738. XDIR *opendir(char *name)
  739. X{
  740. X  struct stat statb;
  741. X  DIR *dirp;
  742. X  char c;
  743. X  char *s;
  744. X  struct _dircontents *dp;
  745. X  char nbuf[MAXPATHLEN + 1];
  746. X  int len;
  747. X
  748. X  strcpy(nbuf, name);
  749. X  if ((len = strlen(nbuf)) == 0)
  750. X    return NULL;
  751. X
  752. X  if ( ((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1) )
  753. X  {
  754. X    nbuf[len - 1] = 0;
  755. X    --len;
  756. X
  757. X    if ( nbuf[len - 1] == ':' )
  758. X    {
  759. X      strcpy(nbuf+len, "\\.");
  760. X      len += 2;
  761. X    }
  762. X  }
  763. X  else
  764. X    if ( nbuf[len - 1] == ':' )
  765. X    {
  766. X      strcpy(nbuf+len, ".");
  767. X      ++len;
  768. X    }
  769. X
  770. X  /* GRR:  Borland and Watcom C return non-zero on wildcards... < 0 ? */
  771. X  if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
  772. X  {
  773. X    Trace((stderr, "opendir:  stat(%s) returns negative or not directory\n",
  774. X      nbuf));
  775. X    return NULL;
  776. X  }
  777. X
  778. X  if ( (dirp = malloc(sizeof(DIR))) == NULL )
  779. X    return NULL;
  780. X
  781. X  if ( nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.') )
  782. X    strcpy(nbuf+len-1, "*");
  783. X  else
  784. X    if ( ((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1) )
  785. X      strcpy(nbuf+len, "*");
  786. X    else
  787. X      strcpy(nbuf+len, "\\*");
  788. X
  789. X  /* len is no longer correct (but no longer needed) */
  790. X  Trace((stderr, "opendir:  nbuf = [%s]\n", nbuf));
  791. X
  792. X  dirp -> dd_loc = 0;
  793. X  dirp -> dd_contents = dirp -> dd_cp = NULL;
  794. X
  795. X  if ((s = getdirent(nbuf)) == NULL)
  796. X    return dirp;
  797. X
  798. X  do
  799. X  {
  800. X    if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
  801. X        ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL)      )
  802. X    {
  803. X      if (dp)
  804. X        free(dp);
  805. X      free_dircontents(dirp -> dd_contents);
  806. X
  807. X      return NULL;
  808. X    }
  809. X
  810. X    if (dirp -> dd_contents)
  811. X    {
  812. X      dirp -> dd_cp -> _d_next = dp;
  813. X      dirp -> dd_cp = dirp -> dd_cp -> _d_next;
  814. X    }
  815. X    else
  816. X      dirp -> dd_contents = dirp -> dd_cp = dp;
  817. X
  818. X    strcpy(dp -> _d_entry, s);
  819. X    dp -> _d_next = NULL;
  820. X
  821. X    dp -> _d_size = find.cbFile;
  822. X    dp -> _d_mode = find.attrFile;
  823. X    dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
  824. X    dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
  825. X  }
  826. X  while ((s = getdirent(NULL)) != NULL);
  827. X
  828. X  dirp -> dd_cp = dirp -> dd_contents;
  829. X
  830. X  return dirp;
  831. X}
  832. X
  833. X
  834. Xvoid closedir(DIR * dirp)
  835. X{
  836. X  free_dircontents(dirp -> dd_contents);
  837. X  free(dirp);
  838. X}
  839. X
  840. X
  841. Xstruct direct *readdir(DIR * dirp)
  842. X{
  843. X  static struct direct dp;
  844. X
  845. X  if (dirp -> dd_cp == NULL)
  846. X    return NULL;
  847. X
  848. X  dp.d_namlen = dp.d_reclen =
  849. X    strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
  850. X
  851. X  dp.d_ino = 0;
  852. X
  853. X  dp.d_size = dirp -> dd_cp -> _d_size;
  854. X  dp.d_mode = dirp -> dd_cp -> _d_mode;
  855. X  dp.d_time = dirp -> dd_cp -> _d_time;
  856. X  dp.d_date = dirp -> dd_cp -> _d_date;
  857. X
  858. X  dirp -> dd_cp = dirp -> dd_cp -> _d_next;
  859. X  dirp -> dd_loc++;
  860. X
  861. X  return &dp;
  862. X}
  863. X
  864. X
  865. X
  866. X#if 0  /* not used in unzip; retained for possibly future use */
  867. X
  868. Xvoid seekdir(DIR * dirp, long off)
  869. X{
  870. X  long i = off;
  871. X  struct _dircontents *dp;
  872. X
  873. X  if (off >= 0)
  874. X  {
  875. X    for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
  876. X
  877. X    dirp -> dd_loc = off - (i + 1);
  878. X    dirp -> dd_cp = dp;
  879. X  }
  880. X}
  881. X
  882. X
  883. Xlong telldir(DIR * dirp)
  884. X{
  885. X  return dirp -> dd_loc;
  886. X}
  887. X
  888. X#endif /* 0 */
  889. X
  890. X
  891. X
  892. Xstatic void free_dircontents(struct _dircontents * dp)
  893. X{
  894. X  struct _dircontents *odp;
  895. X
  896. X  while (dp)
  897. X  {
  898. X    if (dp -> _d_entry)
  899. X      free(dp -> _d_entry);
  900. X
  901. X    dp = (odp = dp) -> _d_next;
  902. X    free(odp);
  903. X  }
  904. X}
  905. X
  906. X
  907. Xstatic char *getdirent(char *dir)
  908. X{
  909. X  int done;
  910. X  static int lower;
  911. X
  912. X  if (dir != NULL)
  913. X  {                                    /* get first entry */
  914. X    hdir = HDIR_SYSTEM;
  915. X    count = 1;
  916. X    done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count);
  917. X    lower = IsFileSystemFAT(dir);
  918. X  }
  919. X  else                                 /* get next entry */
  920. X    done = DosFindNext(hdir, &find, sizeof(find), &count);
  921. X
  922. X  if (done == 0)
  923. X  {
  924. X    if ( lower )
  925. X      StringLower(find.achName);
  926. X    return find.achName;
  927. X  }
  928. X  else
  929. X  {
  930. X    DosFindClose(hdir);
  931. X    return NULL;
  932. X  }
  933. X}
  934. X
  935. X
  936. X
  937. Xint IsFileSystemFAT(char *dir)     /* FAT / HPFS detection */
  938. X{
  939. X  static USHORT nLastDrive=(USHORT)(-1), nResult;
  940. X  ULONG lMap;
  941. X  BYTE bData[64], bName[3];
  942. X#ifdef __32BIT__
  943. X  ULONG nDrive, cbData;
  944. X  PFSQBUFFER2 pData = (PFSQBUFFER2) bData;
  945. X#else
  946. X  USHORT nDrive, cbData;
  947. X  PFSQBUFFER pData = (PFSQBUFFER) bData;
  948. X#endif
  949. X
  950. X  if ( _osmode == DOS_MODE )
  951. X    return TRUE;
  952. X  else
  953. X  {
  954. X    /* We separate FAT and HPFS+other file systems here.
  955. X       at the moment I consider other systems to be similar to HPFS,
  956. X       i.e. support long file names and case sensitive */
  957. X
  958. X    if ( isalpha(dir[0]) && (dir[1] == ':') )
  959. X      nDrive = toupper(dir[0]) - '@';
  960. X    else
  961. X      DosQueryCurrentDisk(&nDrive, &lMap);
  962. X
  963. X    if ( nDrive == nLastDrive )
  964. X      return nResult;
  965. X
  966. X    bName[0] = (char) (nDrive + '@');
  967. X    bName[1] = ':';
  968. X    bName[2] = 0;
  969. X
  970. X    nLastDrive = nDrive;
  971. X    cbData = sizeof(bData);
  972. X
  973. X    if ( !DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData) )
  974. X      nResult = !strcmp(pData -> szFSDName + pData -> cbName, "FAT");
  975. X    else
  976. X      nResult = FALSE;
  977. X
  978. X    /* End of this ugly code */
  979. X    return nResult;
  980. X  }
  981. X} /* end function IsFileSystemFAT() */
  982. X
  983. X
  984. X
  985. X
  986. X
  987. X/************************/
  988. X/*  Function do_wild()  */
  989. X/************************/
  990. X
  991. Xchar *do_wild(wildspec)
  992. X    char *wildspec;         /* only used first time on a given dir */
  993. X{
  994. X    static DIR *dir = NULL;
  995. X    static char *dirname, *wildname, matchname[FILNAMSIZ];
  996. X    static int firstcall=TRUE, have_dirname, dirnamelen;
  997. X    struct direct *file;
  998. X
  999. X
  1000. X    /* Even when we're just returning wildspec, we *always* do so in
  1001. X     * matchname[]--calling routine is allowed to append four characters
  1002. X     * to the returned string, and wildspec may be a pointer to argv[].
  1003. X     */
  1004. X    if (firstcall) {        /* first call:  must initialize everything */
  1005. X        firstcall = FALSE;
  1006. X
  1007. X        /* break the wildspec into a directory part and a wildcard filename */
  1008. X        if ((wildname = strrchr(wildspec, '/')) == NULL &&
  1009. X            (wildname = strrchr(wildspec, ':')) == NULL) {
  1010. X            dirname = ".";
  1011. X            dirnamelen = 1;
  1012. X            have_dirname = FALSE;
  1013. X            wildname = wildspec;
  1014. X        } else {
  1015. X            ++wildname;     /* point at character after '/' or ':' */
  1016. X            dirnamelen = wildname - wildspec;
  1017. X            if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
  1018. X                FPRINTF(stderr, "warning:  can't allocate wildcard buffers\n");
  1019. X                strcpy(matchname, wildspec);
  1020. X                return matchname;   /* but maybe filespec was not a wildcard */
  1021. X            }
  1022. X            strncpy(dirname, wildspec, dirnamelen);
  1023. X            dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
  1024. X            have_dirname = TRUE;
  1025. X        }
  1026. X        Trace((stderr, "do_wild:  dirname = [%s]\n", dirname));
  1027. X
  1028. X        if ((dir = opendir(dirname)) != NULL) {
  1029. X            while ((file = readdir(dir)) != NULL) {
  1030. X                Trace((stderr, "do_wild:  readdir returns %s\n", file->d_name));
  1031. X                if (match(file->d_name, wildname, 1)) {  /* 1 == ignore case */
  1032. X                    Trace((stderr, "do_wild:  match() succeeds\n"));
  1033. X                    if (have_dirname) {
  1034. X                        strcpy(matchname, dirname);
  1035. X                        strcpy(matchname+dirnamelen, file->d_name);
  1036. X                    } else
  1037. X                        strcpy(matchname, file->d_name);
  1038. X                    return matchname;
  1039. X                }
  1040. X            }
  1041. X            /* if we get to here directory is exhausted, so close it */
  1042. X            closedir(dir);
  1043. X            dir = NULL;
  1044. X        }
  1045. X        Trace((stderr, "do_wild:  opendir(%s) returns NULL\n", dirname));
  1046. X
  1047. X        /* return the raw wildspec in case that works (e.g., directory not
  1048. X         * searchable, but filespec was not wild and file is readable) */
  1049. X        strcpy(matchname, wildspec);
  1050. X        return matchname;
  1051. X    }
  1052. X
  1053. X    /* last time through, might have failed opendir but returned raw wildspec */
  1054. X    if (dir == NULL) {
  1055. X        firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  1056. X        if (have_dirname)
  1057. X            free(dirname);
  1058. X        return (char *)NULL;
  1059. X    }
  1060. X
  1061. X    /* If we've gotten this far, we've read and matched at least one entry
  1062. X     * successfully (in a previous call), so dirname has been copied into
  1063. X     * matchname already.
  1064. X     */
  1065. X    while ((file = readdir(dir)) != NULL)
  1066. X        if (match(file->d_name, wildname, 1)) {   /* 1 == ignore case */
  1067. X            if (have_dirname) {
  1068. X                /* strcpy(matchname, dirname); */
  1069. X                strcpy(matchname+dirnamelen, file->d_name);
  1070. X            } else
  1071. X                strcpy(matchname, file->d_name);
  1072. X            return matchname;
  1073. X        }
  1074. X
  1075. X    closedir(dir);     /* have read at least one dir entry; nothing left */
  1076. X    dir = NULL;
  1077. X    firstcall = TRUE;  /* reset for new wildspec */
  1078. X    if (have_dirname)
  1079. X        free(dirname);
  1080. X    return (char *)NULL;
  1081. X
  1082. X} /* end function do_wild() */
  1083. X
  1084. X#endif /* !SFX */
  1085. X
  1086. X
  1087. X
  1088. X
  1089. X
  1090. X/************************/
  1091. X/*  Function mapattr()  */
  1092. X/************************/
  1093. X
  1094. Xint mapattr()
  1095. X{
  1096. X    /* set archive bit (file is not backed up): */
  1097. X    pInfo->file_attr = (unsigned)(crec.external_file_attributes | 32) & 0xff;
  1098. X    return 0;
  1099. X}
  1100. X
  1101. X
  1102. X
  1103. X
  1104. X
  1105. X/************************/
  1106. X/*  Function mapname()  */
  1107. X/************************/
  1108. X
  1109. X/*
  1110. X * There are presently two possibilities in OS/2:  the output filesystem is
  1111. X * FAT, or it is HPFS.  If the former, we need to map to FAT, obviously, but
  1112. X * we *also* must map to HPFS and store that version of the name in extended
  1113. X * attributes.  Either way, we need to map to HPFS, so the main mapname
  1114. X * routine does that.  In the case that the output file system is FAT, an
  1115. X * extra filename-mapping routine is called in checkdir().  While it should
  1116. X * be possible to determine the filesystem immediately upon entry to mapname(),
  1117. X * it is conceivable that the DOS APPEND utility could be added to OS/2 some-
  1118. X * day, allowing a FAT directory to be APPENDed to an HPFS drive/path.  There-
  1119. X * fore we simply check the filesystem at each path component.
  1120. X *
  1121. X * Note that when alternative IFS's become available/popular, everything will
  1122. X * become immensely more complicated.  For example, a Minix filesystem would
  1123. X * have limited filename lengths like FAT but no extended attributes in which
  1124. X * to store the longer versions of the names.  A BSD Unix filesystem would
  1125. X * support paths of length 1024 bytes or more, but it is not clear that FAT
  1126. X * EAs would allow such long .LONGNAME fields or that OS/2 would properly
  1127. X * restore such fields when moving files from FAT to the new filesystem.
  1128. X *
  1129. X * GRR:  some or all of the following chars should be checked in either
  1130. X *       mapname (HPFS) or map2fat (FAT), depending:  ,=^+'"[]<>|\t&
  1131. X */
  1132. X
  1133. Xint mapname(renamed)  /* return 0 if no error, 1 if caution (filename trunc), */
  1134. X    int renamed;      /* 2 if warning (skip file because dir doesn't exist), */
  1135. X{                     /* 3 if error (skip file), 10 if no memory (skip file), */
  1136. X                      /* IZ_VOL_LABEL if can't do vol label, IZ_CREATED_DIR */
  1137. X    char pathcomp[FILNAMSIZ];    /* path-component buffer */
  1138. X    char *pp, *cp=(char *)NULL;  /* character pointers */
  1139. X    char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  1140. X    int quote = FALSE;           /* flag:  next char is literal */
  1141. X    int error = 0;
  1142. X    register unsigned workch;    /* hold the character being tested */
  1143. X
  1144. X
  1145. X/*---------------------------------------------------------------------------
  1146. X    Initialize various pointers and counters and stuff.
  1147. X  ---------------------------------------------------------------------------*/
  1148. X
  1149. X    /* can create path as long as not just freshening, or if user told us */
  1150. X    create_dirs = (!fflag || renamed);
  1151. X
  1152. X    created_dir = FALSE;        /* not yet */
  1153. X    renamed_fullpath = FALSE;
  1154. X    fnlen = strlen(filename);
  1155. X
  1156. X/* GRR:  for VMS, convert to internal format now or later? or never? */
  1157. X    if (renamed) {
  1158. X        cp = filename - 1;      /* point to beginning of renamed name... */
  1159. X        while (*++cp)
  1160. X            if (*cp == '\\')    /* convert backslashes to forward */
  1161. X                *cp = '/';
  1162. X        cp = filename;
  1163. X        /* use temporary rootpath if user gave full pathname */
  1164. X        if (filename[0] == '/') {
  1165. X            renamed_fullpath = TRUE;
  1166. X            pathcomp[0] = '/';  /* copy the '/' and terminate */
  1167. X            pathcomp[1] = '\0';
  1168. X            ++cp;
  1169. X        } else if (isalpha(filename[0]) && filename[1] == ':') {
  1170. X            renamed_fullpath = TRUE;
  1171. X            pp = pathcomp;
  1172. X            *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
  1173. X            *pp++ = *cp++;
  1174. X            if (*cp == '/')
  1175. X                *pp++ = *cp++;  /* otherwise add "./"? */
  1176. X            *pp = '\0';
  1177. X        }
  1178. X    }
  1179. X
  1180. X    /* pathcomp is ignored unless renamed_fullpath is TRUE: */
  1181. X    if ((error = checkdir(pathcomp, INIT)) != 0)    /* initialize path buffer */
  1182. X        return error;           /* ...unless no mem or vol label on hard disk */
  1183. X
  1184. X    *pathcomp = '\0';           /* initialize translation buffer */
  1185. X    pp = pathcomp;              /* point to translation buffer */
  1186. X    if (!renamed) {             /* cp already set if renamed */
  1187. X        if (jflag)              /* junking directories */
  1188. X/* GRR:  watch out for VMS version... */
  1189. X            cp = (char *)strrchr(filename, '/');
  1190. X        if (cp == (char *)NULL)     /* no '/' or not junking dirs */
  1191. X            cp = filename;          /* point to internal zipfile-member pathname */
  1192. X        else
  1193. X            ++cp;                   /* point to start of last component of path */
  1194. X    }
  1195. X
  1196. X/*---------------------------------------------------------------------------
  1197. X    Begin main loop through characters in filename.
  1198. X  ---------------------------------------------------------------------------*/
  1199. X
  1200. X    while ((workch = (uch)*cp++) != 0) {
  1201. X
  1202. X        if (quote) {              /* if character quoted, */
  1203. X            *pp++ = (char)workch; /*  include it literally */
  1204. X            quote = FALSE;
  1205. X        } else
  1206. X            switch (workch) {
  1207. X            case '/':             /* can assume -j flag not given */
  1208. X                *pp = '\0';
  1209. X                if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
  1210. X                    return error;
  1211. X                pp = pathcomp;    /* reset conversion buffer for next piece */
  1212. X                lastsemi = (char *)NULL; /* leave directory semi-colons alone */
  1213. X                break;
  1214. X
  1215. X            case ':':
  1216. X                *pp++ = '_';      /* drive names not stored in zipfile, */
  1217. X                break;            /*  so no colons allowed */
  1218. X
  1219. X            case ';':             /* start of VMS version? */
  1220. X                lastsemi = pp;    /* remove VMS version later... */
  1221. X                *pp++ = ';';      /*  but keep semicolon for now */
  1222. X                break;
  1223. X
  1224. X            case '\026':          /* control-V quote for special chars */
  1225. X                quote = TRUE;     /* set flag for next character */
  1226. X                break;
  1227. X
  1228. X            case ' ':             /* keep spaces unless specifically */
  1229. X                if (sflag)        /*  requested to change to underscore */
  1230. X                    *pp++ = '_';
  1231. X                else
  1232. X                    *pp++ = ' ';
  1233. X                break;
  1234. X
  1235. X            default:
  1236. X                /* allow European characters in filenames: */
  1237. X                if (isprint(workch) || (128 <= workch && workch <= 254))
  1238. X                    *pp++ = (char)workch;
  1239. X            } /* end switch */
  1240. X
  1241. X    } /* end while loop */
  1242. X
  1243. X    *pp = '\0';                   /* done with pathcomp:  terminate it */
  1244. X
  1245. X    /* if not saving them, remove VMS version numbers (appended "###") */
  1246. X    if (!V_flag && lastsemi) {
  1247. X        pp = lastsemi + 1;        /* semi-colon was kept:  expect #'s after */
  1248. X        while (isdigit((uch)(*pp)))
  1249. X            ++pp;
  1250. X        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  1251. X            *lastsemi = '\0';
  1252. X    }
  1253. X
  1254. X/*---------------------------------------------------------------------------
  1255. X    Report if directory was created (and no file to create:  filename ended
  1256. X    in '/'), check name to be sure it exists, and combine path and name be-
  1257. X    fore exiting.
  1258. X  ---------------------------------------------------------------------------*/
  1259. X
  1260. X    if (filename[fnlen-1] == '/') {
  1261. X        checkdir(filename, GETPATH);
  1262. X        if (created_dir && QCOND2) {
  1263. X/* GRR:  trailing '/'?  need to strip or not? */
  1264. X            FPRINTF(stdout, "   creating: %-22s\n", filename);
  1265. X            if (extra_field)  /* zipfile extra field has extended attributes */
  1266. X                SetEAs(filename, extra_field);
  1267. X            SetPathInfo(filename, lrec.last_mod_file_date,
  1268. X                                  lrec.last_mod_file_time, -1);
  1269. X            return IZ_CREATED_DIR;   /* dir time already set */
  1270. X        }
  1271. X        return 2;   /* dir existed already; don't look for data to extract */
  1272. X    }
  1273. X
  1274. X    if (*pathcomp == '\0') {
  1275. X        FPRINTF(stderr, "mapname:  conversion of %s failed\n", filename);
  1276. X        return 3;
  1277. X    }
  1278. X
  1279. X    checkdir(pathcomp, APPEND_NAME);   /* returns 1 if truncated:  care? */
  1280. X    checkdir(filename, GETPATH);
  1281. X    Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n",
  1282. X      filename, error));
  1283. X
  1284. X    if (pInfo->vollabel) {   /* set the volume label now */
  1285. X        VOLUMELABEL FSInfoBuf;
  1286. X/* GRR:  "VOLUMELABEL" defined for IBM C and emx, but haven't checked MSC... */
  1287. X        strcpy(FSInfoBuf.szVolLabel, filename);
  1288. X        FSInfoBuf.cch = (BYTE)strlen(FSInfoBuf.szVolLabel);
  1289. X        if (QCOND2)
  1290. X            FPRINTF(stdout, "labelling %c: %-22s\n",
  1291. X              (char)(nLabelDrive + 'a' - 1), filename);
  1292. X        if (DosSetFSInfo(nLabelDrive, FSIL_VOLSER, (PBYTE)&FSInfoBuf,
  1293. X                         sizeof(VOLUMELABEL)))
  1294. X        {
  1295. X            FPRINTF(stderr, "mapname:  error setting volume label\n");
  1296. X            return 3;
  1297. X        }
  1298. X        return 2;   /* success:  skip the "extraction" quietly */
  1299. X    }
  1300. X
  1301. X    return error;
  1302. X
  1303. X} /* end function mapname() */
  1304. X
  1305. X
  1306. X
  1307. X
  1308. X
  1309. X/***********************/
  1310. X/* Function checkdir() */
  1311. X/***********************/
  1312. X
  1313. Xint checkdir(pathcomp, flag)
  1314. X    char *pathcomp;
  1315. X    int flag;
  1316. X/*
  1317. X * returns:  1 - (on APPEND_NAME) truncated filename
  1318. X *           2 - path doesn't exist, not allowed to create
  1319. X *           3 - path doesn't exist, tried to create and failed; or
  1320. X *               path exists and is not a directory, but is supposed to be
  1321. X *           4 - path is too long
  1322. X *          10 - can't allocate memory for filename buffers
  1323. X */
  1324. X{
  1325. X    static int rootlen = 0;      /* length of rootpath */
  1326. X    static char *rootpath;       /* user's "extract-to" directory */
  1327. X    static char *buildpathHPFS;  /* full path (so far) to extracted file, */
  1328. X    static char *buildpathFAT;   /*  both HPFS/EA (main) and FAT versions */
  1329. X    static char *endHPFS;        /* corresponding pointers to end of */
  1330. X    static char *endFAT;         /*  buildpath ('\0') */
  1331. X
  1332. X#   define FN_MASK   7
  1333. X#   define FUNCTION  (flag & FN_MASK)
  1334. X
  1335. X
  1336. X
  1337. X/*---------------------------------------------------------------------------
  1338. X    APPEND_DIR:  append the path component to the path being built and check
  1339. X    for its existence.  If doesn't exist and we are creating directories, do
  1340. X    so for this one; else signal success or error as appropriate.
  1341. X  ---------------------------------------------------------------------------*/
  1342. X
  1343. X    if (FUNCTION == APPEND_DIR) {
  1344. X        char *p = pathcomp;
  1345. X        int longdirEA, too_long=FALSE;
  1346. X
  1347. X        Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  1348. X        while ((*endHPFS = *p++) != '\0')     /* copy to HPFS filename */
  1349. X            ++endHPFS;
  1350. X        if (IsFileNameValid(buildpathHPFS)) {
  1351. X            longdirEA = FALSE;
  1352. X            p = pathcomp;
  1353. X            while ((*endFAT = *p++) != '\0')  /* copy to FAT filename, too */
  1354. X                ++endFAT;
  1355. X        } else {
  1356. X            longdirEA = TRUE;
  1357. X/* GRR:  check error return? */
  1358. X            map2fat(pathcomp, &endFAT);  /* map, put in FAT fn, update endFAT */
  1359. X        }
  1360. X
  1361. X        /* GRR:  could do better check, see if overrunning buffer as we go:
  1362. X         * check endHPFS-buildpathHPFS after each append, set warning variable
  1363. X         * if within 20 of FILNAMSIZ; then if var set, do careful check when
  1364. X         * appending.  Clear variable when begin new path. */
  1365. X
  1366. X        /* next check:  need to append '/', at least one-char name, '\0' */
  1367. X        if ((endHPFS-buildpathHPFS) > FILNAMSIZ-3)
  1368. X            too_long = TRUE;                 /* check if extracting dir? */
  1369. X#ifdef MSC /* MSC 6.00 bug:  stat(non-existent-dir) == 0 [exists!] */
  1370. X        if (GetFileTime(buildpathFAT) == -1 || stat(buildpathFAT, &statbuf))
  1371. X#else
  1372. X        if (stat(buildpathFAT, &statbuf))    /* path doesn't exist */
  1373. X#endif
  1374. X        {
  1375. X            if (!create_dirs) {   /* told not to create (freshening) */
  1376. X                free(buildpathHPFS);
  1377. X                free(buildpathFAT);
  1378. X                return 2;         /* path doesn't exist:  nothing to do */
  1379. X            }
  1380. X            if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
  1381. X                FPRINTF(stderr, "checkdir error:  path too long: %s\n",
  1382. X                  buildpathHPFS);
  1383. X                fflush(stderr);
  1384. X                free(buildpathHPFS);
  1385. X                free(buildpathFAT);
  1386. X                return 4;         /* no room for filenames:  fatal */
  1387. X            }
  1388. X            if (MKDIR(buildpathFAT, 0777) == -1) {   /* create the directory */
  1389. X                FPRINTF(stderr, "checkdir error:  can't create %s\n\
  1390. X                 unable to process %s.\n", buildpathFAT, filename);
  1391. X                fflush(stderr);
  1392. X                free(buildpathHPFS);
  1393. X                free(buildpathFAT);
  1394. X                return 3;      /* path didn't exist, tried to create, failed */
  1395. X            }
  1396. X            created_dir = TRUE;
  1397. X            /* only set EA if creating directory */
  1398. X/* GRR:  need trailing '/' before function call? */
  1399. X            if (longdirEA) {
  1400. X#ifdef DEBUG
  1401. X                int e =
  1402. X#endif
  1403. X                  SetLongNameEA(buildpathFAT, pathcomp);
  1404. X                Trace((stderr, "APPEND_DIR:  SetLongNameEA() returns %d\n", e));
  1405. X            }
  1406. X        } else if (!S_ISDIR(statbuf.st_mode)) {
  1407. X            FPRINTF(stderr, "checkdir error:  %s exists but is not directory\n\
  1408. X                 unable to process %s.\n", buildpathFAT, filename);
  1409. X            fflush(stderr);
  1410. X            free(buildpathHPFS);
  1411. X            free(buildpathFAT);
  1412. X            return 3;          /* path existed but wasn't dir */
  1413. X        }
  1414. X        if (too_long) {
  1415. X            FPRINTF(stderr, "checkdir error:  path too long: %s\n",
  1416. X              buildpathHPFS);
  1417. X            fflush(stderr);
  1418. X            free(buildpathHPFS);
  1419. X            free(buildpathFAT);
  1420. X            return 4;         /* no room for filenames:  fatal */
  1421. X        }
  1422. X        *endHPFS++ = '/';
  1423. X        *endFAT++ = '/';
  1424. X        *endHPFS = *endFAT = '\0';
  1425. X        Trace((stderr, "buildpathHPFS now = [%s]\n", buildpathHPFS));
  1426. X        Trace((stderr, "buildpathFAT now =  [%s]\n", buildpathFAT));
  1427. X        return 0;
  1428. X
  1429. X    } /* end if (FUNCTION == APPEND_DIR) */
  1430. X
  1431. X/*---------------------------------------------------------------------------
  1432. X    GETPATH:  copy full FAT path to the string pointed at by pathcomp (want
  1433. X    filename to reflect name used on disk, not EAs; if full path is HPFS,
  1434. X    buildpathFAT and buildpathHPFS will be identical).  Also free both paths.
  1435. X  ---------------------------------------------------------------------------*/
  1436. X
  1437. X    if (FUNCTION == GETPATH) {
  1438. X        Trace((stderr, "getting and freeing FAT path [%s]\n", buildpathFAT));
  1439. X        Trace((stderr, "freeing HPFS path [%s]\n", buildpathHPFS));
  1440. X        strcpy(pathcomp, buildpathFAT);
  1441. X        free(buildpathFAT);
  1442. X        free(buildpathHPFS);
  1443. X        buildpathHPFS = buildpathFAT = endHPFS = endFAT = (char *)NULL;
  1444. X        return 0;
  1445. X    }
  1446. X
  1447. X/*---------------------------------------------------------------------------
  1448. X    APPEND_NAME:  assume the path component is the filename; append it and
  1449. X    return without checking for existence.
  1450. X  ---------------------------------------------------------------------------*/
  1451. X
  1452. X    if (FUNCTION == APPEND_NAME) {
  1453. X        char *p = pathcomp;
  1454. X        int error = 0;
  1455. X
  1456. X        Trace((stderr, "appending filename [%s]\n", pathcomp));
  1457. X        while ((*endHPFS = *p++) != '\0') {    /* copy to HPFS filename */
  1458. X            ++endHPFS;
  1459. X            if ((endHPFS-buildpathHPFS) >= FILNAMSIZ) {
  1460. X                *--endHPFS = '\0';
  1461. X                FPRINTF(stderr, "checkdir warning:  path too long; truncating\n\
  1462. X                   %s\n                -> %s\n", filename, buildpathHPFS);
  1463. X                fflush(stderr);
  1464. X                error = 1;   /* filename truncated */
  1465. X            }
  1466. X        }
  1467. X
  1468. X/* GRR:  how can longnameEA ever be set before this point???  we don't want
  1469. X * to save the original name to EAs if user renamed it, do we?
  1470. X *
  1471. X * if (!longnameEA && ((longnameEA = !IsFileNameValid(name)) != 0))
  1472. X */
  1473. X        if (pInfo->vollabel || IsFileNameValid(buildpathHPFS)) {
  1474. X            longnameEA = FALSE;
  1475. X            p = pathcomp;
  1476. X            while ((*endFAT = *p++) != '\0')   /* copy to FAT filename, too */
  1477. X                ++endFAT;
  1478. X        } else {
  1479. X            longnameEA = TRUE;
  1480. X            if ((lastpathcomp = (char *)malloc(strlen(pathcomp)+1)) ==
  1481. X                (char *)NULL)
  1482. X            {
  1483. X                FPRINTF(stderr,
  1484. X                  "checkdir warning:  can't save longname EA: out of memory\n");
  1485. X                longnameEA = FALSE;
  1486. X                error = 1;   /* can't set .LONGNAME extended attribute */
  1487. X            } else           /* used and freed in close_outfile() */
  1488. X                strcpy(lastpathcomp, pathcomp);
  1489. X            map2fat(pathcomp, &endFAT);  /* map, put in FAT fn, update endFAT */
  1490. X        }
  1491. X        Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT:  %s\n",
  1492. X          buildpathHPFS, buildpathFAT));
  1493. X
  1494. X        return error;  /* could check for existence, prompt for new name... */
  1495. X
  1496. X    } /* end if (FUNCTION == APPEND_NAME) */
  1497. X
  1498. X/*---------------------------------------------------------------------------
  1499. X    INIT:  allocate and initialize buffer space for the file currently being
  1500. X    extracted.  If file was renamed with an absolute path, don't prepend the
  1501. X    extract-to path.
  1502. X  ---------------------------------------------------------------------------*/
  1503. X
  1504. X    if (FUNCTION == INIT) {
  1505. X        Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
  1506. X        if ((buildpathHPFS = (char *)malloc(fnlen+rootlen+1)) == (char *)NULL)
  1507. X            return 10;
  1508. X        if ((buildpathFAT = (char *)malloc(fnlen+rootlen+1)) == (char *)NULL) {
  1509. X            free(buildpathHPFS);
  1510. X            return 10;
  1511. X        }
  1512. X        if (pInfo->vollabel) {  /* use root or renamed path, but don't store */
  1513. X/* GRR:  for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
  1514. X            if (renamed_fullpath && pathcomp[1] == ':')
  1515. X                *buildpathHPFS = ToLower(*pathcomp);
  1516. X            else if (!renamed_fullpath && rootpath && rootpath[1] == ':')
  1517. X                *buildpathHPFS = ToLower(*rootpath);
  1518. X            else {
  1519. X                ULONG lMap;
  1520. X                DosQueryCurrentDisk(&nLabelDrive, &lMap);
  1521. X                *buildpathHPFS = (char)(nLabelDrive - 1 + 'a');
  1522. X            }
  1523. X            nLabelDrive = *buildpathHPFS - 'a' + 1;     /* save for mapname() */
  1524. X            if (volflag == 0 || *buildpathHPFS < 'a' ||   /* no labels/bogus? */
  1525. X                (volflag == 1 && !isfloppy(nLabelDrive))) {  /* -$:  no fixed */
  1526. X                free(buildpathHPFS);
  1527. X                free(buildpathFAT);
  1528. X                return IZ_VOL_LABEL;   /* skipping with message */
  1529. X            }
  1530. X            *buildpathHPFS = '\0';
  1531. X        } else if (renamed_fullpath)   /* pathcomp = valid data */
  1532. X            strcpy(buildpathHPFS, pathcomp);
  1533. X        else if (rootlen > 0)
  1534. X            strcpy(buildpathHPFS, rootpath);
  1535. X        else
  1536. X            *buildpathHPFS = '\0';
  1537. X        endHPFS = buildpathHPFS;
  1538. X        endFAT = buildpathFAT;
  1539. X        while ((*endFAT = *endHPFS) != '\0') {
  1540. X            ++endFAT;
  1541. X            ++endHPFS;
  1542. X        }
  1543. X        Trace((stderr, "[%s]\n", buildpathHPFS));
  1544. X        return 0;
  1545. X    }
  1546. X
  1547. X/*---------------------------------------------------------------------------
  1548. X    ROOT:  if appropriate, store the path in rootpath and create it if neces-
  1549. X    sary; else assume it's a zipfile member and return.  This path segment
  1550. X    gets used in extracting all members from every zipfile specified on the
  1551. X    command line.  Note that under OS/2 and MS-DOS, if a candidate extract-to
  1552. X    directory specification includes a drive letter (leading "x:"), it is
  1553. X    treated just as if it had a trailing '/'--that is, one directory level
  1554. X    will be created if the path doesn't exist, unless this is otherwise pro-
  1555. X    hibited (e.g., freshening).
  1556. X  ---------------------------------------------------------------------------*/
  1557. X
  1558. X#if (!defined(SFX) || defined(SFX_EXDIR))
  1559. X    if (FUNCTION == ROOT) {
  1560. X        Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  1561. X        if (pathcomp == (char *)NULL) {
  1562. X            rootlen = 0;
  1563. X            return 0;
  1564. X        }
  1565. X        if ((rootlen = strlen(pathcomp)) > 0) {
  1566. X            int had_trailing_pathsep=FALSE, has_drive=FALSE, xtra=2;
  1567. X
  1568. X            if (isalpha(pathcomp[0]) && pathcomp[1] == ':')
  1569. X                has_drive = TRUE;   /* drive designator */
  1570. X            if (pathcomp[rootlen-1] == '/') {
  1571. X                pathcomp[--rootlen] = '\0';
  1572. X                had_trailing_pathsep = TRUE;
  1573. X            }
  1574. X            if (has_drive && (rootlen == 2)) {
  1575. X                if (!had_trailing_pathsep)   /* i.e., original wasn't "x:/" */
  1576. X                    xtra = 3;      /* room for '.' + '/' + 0 at end of "x:" */
  1577. X            } else if (rootlen > 0) {     /* need not check "x:." and "x:/" */
  1578. X#ifdef MSC      /* MSC 6.00 bug:  stat(non-existent-dir) == 0 [exists!] */
  1579. X                if (GetFileTime(pathcomp) == -1 || 
  1580. X                    SSTAT(pathcomp, &statbuf) || !S_ISDIR(statbuf.st_mode))
  1581. X#else
  1582. X                if (SSTAT(pathcomp, &statbuf) || !S_ISDIR(statbuf.st_mode))
  1583. X#endif
  1584. X                {   /* path does not exist */
  1585. X                    if (!create_dirs                 /* || iswild(pathcomp) */
  1586. X#ifdef OLD_EXDIR
  1587. X                                     || (!has_drive && !had_trailing_pathsep)
  1588. X#endif
  1589. X                                                                             ) {
  1590. X                        rootlen = 0;
  1591. X                        return 2;   /* treat as stored file */
  1592. X                    }
  1593. X                    /* create directory (could add loop here to scan pathcomp
  1594. X                     * and create more than one level, but really necessary?) */
  1595. X                    if (MKDIR(pathcomp, 0777) == -1) {
  1596. X                        FPRINTF(stderr,
  1597. X                          "checkdir:  can't create extraction directory: %s\n",
  1598. X                          pathcomp);
  1599. X                        fflush(stderr);
  1600. X                        rootlen = 0;   /* path didn't exist, tried to create, */
  1601. X                        return 3;  /* failed:  file exists, or need 2+ levels */
  1602. X                    }
  1603. X                }
  1604. X            }
  1605. X            if ((rootpath = (char *)malloc(rootlen+xtra)) == (char *)NULL) {
  1606. X                rootlen = 0;
  1607. X                return 10;
  1608. X            }
  1609. X            strcpy(rootpath, pathcomp);
  1610. X            if (xtra == 3)                  /* had just "x:", make "x:." */
  1611. X                rootpath[rootlen++] = '.';
  1612. X            rootpath[rootlen++] = '/';
  1613. X            rootpath[rootlen] = '\0';
  1614. X        }
  1615. X        Trace((stderr, "rootpath now = [%s]\n", rootpath));
  1616. X        return 0;
  1617. X    }
  1618. X#endif /* !SFX || SFX_EXDIR */
  1619. X
  1620. X/*---------------------------------------------------------------------------
  1621. X    END:  free rootpath, immediately prior to program exit.
  1622. X  ---------------------------------------------------------------------------*/
  1623. X
  1624. X    if (FUNCTION == END) {
  1625. X        Trace((stderr, "freeing rootpath\n"));
  1626. X        if (rootlen > 0)
  1627. X            free(rootpath);
  1628. X        return 0;
  1629. X    }
  1630. X
  1631. X    return 99;  /* should never reach */
  1632. X
  1633. X} /* end function checkdir() */
  1634. X
  1635. X
  1636. X
  1637. X
  1638. X
  1639. X/***********************/
  1640. X/* Function isfloppy() */   /* more precisely, is it removable? */
  1641. X/***********************/
  1642. X
  1643. Xstatic int isfloppy(nDrive)
  1644. X    int nDrive;   /* 1 == A:, 2 == B:, etc. */
  1645. X{
  1646. X    uch ParmList[1] = {0};
  1647. X    uch DataArea[1] = {0};
  1648. X    char Name[3];
  1649. X    HFILE handle;
  1650. X#ifdef __32BIT__
  1651. X    ULONG rc;
  1652. X    ULONG action;
  1653. X#else
  1654. X    USHORT rc;
  1655. X    UINT action;
  1656. X#endif
  1657. X
  1658. X
  1659. X    Name[0] = (char) (nDrive + 'A' - 1);
  1660. X    Name[1] = ':';
  1661. X    Name[2] = 0;
  1662. X
  1663. X    rc = DosOpen(Name, &handle, &action, 0L, FILE_NORMAL, FILE_OPEN,
  1664. X                 OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
  1665. X                 OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0L);
  1666. X
  1667. X    if (rc == ERROR_NOT_READY)   /* must be removable */
  1668. X      return TRUE;
  1669. X    else if (rc) {   /* other error:  do default a/b heuristic instead */
  1670. X      Trace((stderr, "error in DosOpen(DASD):  guessing...\n", rc));
  1671. X      return (nDrive == 1 || nDrive == 2)? TRUE : FALSE;
  1672. X    }
  1673. X
  1674. X    rc = DosDevIOCtl(DataArea, sizeof(DataArea), ParmList, sizeof(ParmList),
  1675. X                     DSK_BLOCKREMOVABLE, IOCTL_DISK, handle);
  1676. X    DosClose(handle);
  1677. X
  1678. X    if (rc) {   /* again, just check for a/b */
  1679. X        Trace((stderr, "error in DosDevIOCtl category IOCTL_DISK, function "
  1680. X          "DSK_BLOCKREMOVABLE\n  (rc = 0x%04x):  guessing...\n", rc));
  1681. X        return (nDrive == 1 || nDrive == 2)? TRUE : FALSE;
  1682. X    } else {
  1683. X        return DataArea[0] ? FALSE : TRUE;
  1684. X    }
  1685. X} /* end function isfloppy() */
  1686. X
  1687. X
  1688. X
  1689. X
  1690. X
  1691. Xint IsFileNameValid(char *name)
  1692. X{
  1693. X  HFILE hf;
  1694. X#ifdef __32BIT__
  1695. X  ULONG uAction;
  1696. X#else
  1697. X  USHORT uAction;
  1698. X#endif
  1699. X
  1700. X  switch( DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
  1701. X                  OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0) )
  1702. X  {
  1703. X  case ERROR_INVALID_NAME:
  1704. X  case ERROR_FILENAME_EXCED_RANGE:
  1705. X    return FALSE;
  1706. X  case NO_ERROR:
  1707. X    DosClose(hf);
  1708. X  default:
  1709. X    return TRUE;
  1710. X  }
  1711. X}
  1712. X
  1713. X
  1714. X
  1715. X
  1716. X
  1717. X/**********************/
  1718. X/* Function map2fat() */
  1719. X/**********************/
  1720. X
  1721. Xvoid map2fat(pathcomp, pEndFAT)
  1722. X    char *pathcomp, **pEndFAT;
  1723. X{
  1724. X    char *ppc = pathcomp;          /* variable pointer to pathcomp */
  1725. X    char *pEnd = *pEndFAT;         /* variable pointer to buildpathFAT */
  1726. X    char *pBegin = *pEndFAT;       /* constant pointer to start of this comp. */
  1727. X    char *last_dot = (char *)NULL; /* last dot not converted to underscore */
  1728. X    int dotname = FALSE;           /* flag:  path component begins with dot */
  1729. X                                   /*  ("." and ".." don't count) */
  1730. X    register unsigned workch;      /* hold the character being tested */
  1731. X
  1732. X
  1733. X    /* Only need check those characters which are legal in HPFS but not
  1734. X     * in FAT:  to get here, must already have passed through mapname.
  1735. X     * (GRR:  oops, small bug--if char was quoted, no longer have any
  1736. X     * knowledge of that.)  Also must truncate path component to ensure
  1737. X     * 8.3 compliance...
  1738. X     */
  1739. X    while ((workch = (uch)*ppc++) != 0) {
  1740. X        switch (workch) {
  1741. X            case '[':
  1742. X            case ']':
  1743. X                *pEnd++ = '_';      /* convert brackets to underscores */
  1744. X                break;
  1745. X
  1746. X            case '.':
  1747. X                if (pEnd == *pEndFAT) {   /* nothing appended yet... */
  1748. X                    if (*ppc == '\0')     /* don't bother appending a */
  1749. X                        break;            /*  "./" component to the path */
  1750. X                    else if (*ppc == '.' && ppc[1] == '\0') {   /* "../" */
  1751. X                        *pEnd++ = '.';    /* add first dot, unchanged... */
  1752. X                        ++ppc;            /* skip second dot, since it will */
  1753. X                    } else {              /*  be "added" at end of if-block */
  1754. X                        *pEnd++ = '_';    /* FAT doesn't allow null filename */
  1755. X                        dotname = TRUE;   /*  bodies, so map .exrc -> _.exrc */
  1756. X                    }                     /*  (extra '_' now, "dot" below) */
  1757. X                } else if (dotname) {     /* found a second dot, but still */
  1758. X                    dotname = FALSE;      /*  have extra leading underscore: */
  1759. X                    *pEnd = '\0';         /*  remove it by shifting chars */
  1760. X                    pEnd = *pEndFAT + 1;  /*  left one space (e.g., .p1.p2: */
  1761. X                    while (pEnd[1]) {     /*  __p1 -> _p1_p2 -> _p1.p2 when */
  1762. X                        *pEnd = pEnd[1];  /*  finished) [opt.:  since first */
  1763. X                        ++pEnd;           /*  two chars are same, can start */
  1764. X                    }                     /*  shifting at second position] */
  1765. X                }
  1766. X                last_dot = pEnd;    /* point at last dot so far... */
  1767. X                *pEnd++ = '_';      /* convert dot to underscore for now */
  1768. X                break;
  1769. X
  1770. X            default:
  1771. X                *pEnd++ = (char)workch;
  1772. X
  1773. X        } /* end switch */
  1774. X    } /* end while loop */
  1775. X
  1776. X    *pEnd = '\0';                 /* terminate buildpathFAT */
  1777. X
  1778. X    /* NOTE:  keep in mind that pEnd points to the end of the path
  1779. X     * component, and *pEndFAT still points to the *beginning* of it...
  1780. X     * Also note that the algorithm does not try to get too fancy:
  1781. X     * if there are no dots already, the name either gets truncated
  1782. X     * at 8 characters or the last underscore is converted to a dot
  1783. X     * (only if more characters are saved that way).  In no case is
  1784. X     * a dot inserted between existing characters.
  1785. X     */
  1786. X    if (last_dot == (char *)NULL) {  /* no dots:  check for underscores... */
  1787. X        char *plu = strrchr(pBegin, '_');    /* pointer to last underscore */
  1788. X
  1789. X        if (plu == (char *)NULL) { /* no dots, no underscores:  truncate at 8 */
  1790. X            *pEndFAT += 8;        /* chars (or could insert '.' and keep 11?) */
  1791. X            if (*pEndFAT > pEnd)
  1792. X                *pEndFAT = pEnd;  /* oops...didn't have 8 chars to truncate */
  1793. X            else
  1794. X                **pEndFAT = '\0';
  1795. X        } else if (MIN(plu - pBegin, 8) + MIN(pEnd - plu - 1, 3) > 8) {
  1796. X            last_dot = plu;       /* be lazy:  drop through to next if-blk */
  1797. X        } else if ((pEnd - *pEndFAT) > 8) {
  1798. X            *pEndFAT += 8;        /* more fits into just basename than if */
  1799. X            **pEndFAT = '\0';     /*  convert last underscore to dot */
  1800. X        } else
  1801. X            *pEndFAT = pEnd;      /* whole thing fits into 8 chars or less */
  1802. X    }
  1803. X
  1804. X    if (last_dot != (char *)NULL) {   /* one dot (or two, in the case of */
  1805. X        *last_dot = '.';              /*  "..") is OK:  put it back in */
  1806. X
  1807. X        if ((last_dot - pBegin) > 8) {
  1808. X            char *p=last_dot, *q=pBegin+8;
  1809. X            int i;
  1810. X
  1811. X            for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
  1812. X                *q++ = *p++;                   /*  shift .ext left and trun- */
  1813. X            *q = '\0';                         /*  cate/terminate it */
  1814. X            *pEndFAT = q;
  1815. X        } else if ((pEnd - last_dot) > 4) {    /* too many chars in extension */
  1816. X            *pEndFAT = last_dot + 4;
  1817. X            **pEndFAT = '\0';
  1818. X        } else
  1819. X            *pEndFAT = pEnd;   /* filename is fine; point at terminating zero */
  1820. X    }
  1821. X} /* end function map2fat() */
  1822. X
  1823. X
  1824. X
  1825. X
  1826. X
  1827. Xint SetLongNameEA(char *name, char *longname)
  1828. X{
  1829. X  EAOP eaop;
  1830. X  FEALST fealst;
  1831. X
  1832. X  eaop.fpFEAList = (PFEALIST) &fealst;
  1833. X  eaop.fpGEAList = NULL;
  1834. X  eaop.oError = 0;
  1835. X
  1836. X  strcpy(fealst.szName, ".LONGNAME");
  1837. X  strcpy(fealst.szValue, longname);
  1838. X
  1839. X  fealst.cbList  = sizeof(fealst) - CCHMAXPATH + strlen(fealst.szValue);
  1840. X  fealst.cbName  = (BYTE) strlen(fealst.szName);
  1841. X  fealst.cbValue = sizeof(USHORT) * 2 + strlen(fealst.szValue);
  1842. X
  1843. X#ifdef __32BIT__
  1844. X  fealst.oNext   = 0;
  1845. X#endif
  1846. X  fealst.fEA     = 0;
  1847. X  fealst.eaType  = 0xFFFD;
  1848. X  fealst.eaSize  = strlen(fealst.szValue);
  1849. X
  1850. X  return DosSetPathInfo(name, FIL_QUERYEASIZE,
  1851. X                        (PBYTE) &eaop, sizeof(eaop), 0);
  1852. X}
  1853. X
  1854. X
  1855. X
  1856. X
  1857. X
  1858. X/****************************/
  1859. X/* Function close_outfile() */
  1860. X/****************************/
  1861. X
  1862. Xvoid close_outfile()   /* only for extracted files, not directories */
  1863. X{
  1864. X    fclose(outfile);
  1865. X
  1866. X    /* set extra fields, both stored-in-zipfile and .LONGNAME flavors */
  1867. X    if (extra_field)
  1868. X        SetEAs(filename, extra_field);
  1869. X
  1870. X    if (longnameEA) {
  1871. X#ifdef DEBUG
  1872. X        int e =
  1873. X#endif
  1874. X          SetLongNameEA(filename, lastpathcomp);
  1875. X        Trace((stderr, "close_outfile:  SetLongNameEA() returns %d\n", e));
  1876. X        free(lastpathcomp);
  1877. X    }
  1878. X
  1879. X    /* set date/time and permissions */
  1880. X    SetPathInfo(filename, lrec.last_mod_file_date,
  1881. X                          lrec.last_mod_file_time, pInfo->file_attr);
  1882. X
  1883. X} /* end function close_outfile() */
  1884. X
  1885. X
  1886. X
  1887. X
  1888. X
  1889. X/******************************/
  1890. X/* Function check_for_newer() */
  1891. X/******************************/
  1892. X
  1893. Xint check_for_newer(filename)   /* return 1 if existing file newer or equal; */
  1894. X    char *filename;             /*  0 if older; -1 if doesn't exist yet */
  1895. X{
  1896. X    long existing, archive;
  1897. X
  1898. X    if ((existing = GetFileTime(filename)) == -1)
  1899. X        return DOES_NOT_EXIST;
  1900. X    archive = ((long) lrec.last_mod_file_date) << 16 | lrec.last_mod_file_time;
  1901. X
  1902. X    return (existing >= archive);
  1903. X}
  1904. X
  1905. X
  1906. X
  1907. X
  1908. X
  1909. X#ifndef SFX
  1910. X
  1911. X/*************************/
  1912. X/* Function dateformat() */
  1913. X/*************************/
  1914. X
  1915. Xint dateformat()
  1916. X{
  1917. X/*-----------------------------------------------------------------------------
  1918. X  For those operating systems which support it, this function returns a value
  1919. X  which tells how national convention says that numeric dates are displayed.
  1920. X  Return values are DF_YMD, DF_DMY and DF_MDY.
  1921. X -----------------------------------------------------------------------------*/
  1922. X
  1923. X    switch (GetCountryInfo()) {
  1924. X        case 0:
  1925. X            return DF_MDY;
  1926. X        case 1:
  1927. X            return DF_DMY;
  1928. X        case 2:
  1929. X            return DF_YMD;
  1930. X    }
  1931. X    return DF_MDY;   /* default if error */
  1932. X
  1933. X} /* end function dateformat() */
  1934. X
  1935. X
  1936. X
  1937. X
  1938. X
  1939. X/************************/
  1940. X/*  Function version()  */
  1941. X/************************/
  1942. X
  1943. Xvoid version()
  1944. X{
  1945. X    extern char Far  CompiledWith[];
  1946. X#if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER)
  1947. X    char buf[80];
  1948. X#endif
  1949. X
  1950. X    PRINTF(LoadFarString(CompiledWith),
  1951. X
  1952. X#ifdef __GNUC__
  1953. X#  ifdef __EMX__  /* __EMX__ is defined as "1" only (sigh) */
  1954. X      "emx+gcc ", __VERSION__,
  1955. X#  else
  1956. X      "gcc/2 ", __VERSION__,
  1957. X#  endif
  1958. X#else
  1959. X#ifdef __IBMC__
  1960. X      "IBM C Set/2", (sprintf(buf, " %d.%02d", __IBMC__/100,__IBMC__%100), buf),
  1961. X#else
  1962. X#ifdef __WATCOMC__
  1963. X      "Watcom C", (sprintf(buf, " (__WATCOMC__ = %d)", __WATCOMC__), buf),
  1964. X#else
  1965. X#ifdef __TURBOC__
  1966. X#  ifdef __BORLANDC__
  1967. X      "Borland C++",
  1968. X#    if (__BORLANDC__ < 0x0200)
  1969. X        " 1.0",
  1970. X#    else
  1971. X#    if (__BORLANDC__ == 0x0200)
  1972. X        " 2.0",
  1973. X#    else
  1974. X#    if (__BORLANDC__ == 0x0400)
  1975. X        " 3.0",
  1976. X#    else
  1977. X#    if (__BORLANDC__ == 0x0410)
  1978. X        " 3.1",
  1979. X#    else
  1980. X        " later than 3.1",
  1981. X#    endif
  1982. X#    endif
  1983. X#    endif
  1984. X#    endif
  1985. X#  else
  1986. X      "Turbo C",
  1987. X#    if (__TURBOC__ >= 661)
  1988. X       "++ 1.0 or later",
  1989. X#    else
  1990. X#    if (__TURBOC__ == 661)
  1991. X       " 3.0?",
  1992. X#    else
  1993. X#    if (__TURBOC__ == 397)
  1994. X       " 2.0",
  1995. X#    else
  1996. X       " 1.0 or 1.5?",
  1997. X#    endif
  1998. X#    endif
  1999. X#    endif
  2000. X#  endif
  2001. X#else
  2002. X#ifdef MSC
  2003. X      "Microsoft C ",
  2004. X#  ifdef _MSC_VER
  2005. X      (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
  2006. X#  else
  2007. X      "5.1 or earlier",
  2008. X#  endif
  2009. X#else
  2010. X      "unknown compiler", "",
  2011. X#endif /* MSC */
  2012. X#endif /* __TURBOC__ */
  2013. X#endif /* __WATCOMC__ */
  2014. X#endif /* __IBMC__ */
  2015. X#endif /* __GNUC__ */
  2016. X
  2017. X      "OS/2",
  2018. X
  2019. X/* GRR:  does IBM C/2 identify itself as IBM rather than Microsoft? */
  2020. X#if (defined(MSC) || (defined(__WATCOMC__) && !defined(__386__)))
  2021. X#  if defined(M_I86HM) || defined(__HUGE__)
  2022. X      " (16-bit, huge)",
  2023. X#  else
  2024. X#  if defined(M_I86LM) || defined(__LARGE__)
  2025. X      " (16-bit, large)",
  2026. X#  else
  2027. X#  if defined(M_I86MM) || defined(__MEDIUM__)
  2028. X      " (16-bit, medium)",
  2029. X#  else
  2030. X#  if defined(M_I86CM) || defined(__COMPACT__)
  2031. X      " (16-bit, compact)",
  2032. X#  else
  2033. X#  if defined(M_I86SM) || defined(__SMALL__)
  2034. X      " (16-bit, small)",
  2035. X#  else
  2036. X#  if defined(M_I86TM) || defined(__TINY__)
  2037. X      " (16-bit, tiny)",
  2038. X#  else
  2039. X      " (16-bit)",
  2040. X#  endif
  2041. X#  endif
  2042. X#  endif
  2043. X#  endif
  2044. X#  endif
  2045. X#  endif
  2046. X#else
  2047. X      " 2.x (32-bit)",
  2048. X#endif
  2049. X
  2050. X#ifdef __DATE__
  2051. X      " on ", __DATE__
  2052. X#else
  2053. X      "", ""
  2054. X#endif
  2055. X      );
  2056. X
  2057. X    /* temporary debugging code for Borland compilers only */
  2058. X#ifdef __TURBOC__
  2059. X    PRINTF("\t(__TURBOC__ = 0x%04x = %d)\n", __TURBOC__, __TURBOC__);
  2060. X#ifdef __BORLANDC__
  2061. X    PRINTF("\t(__BORLANDC__ = 0x%04x)\n", __BORLANDC__);
  2062. X#else
  2063. X    PRINTF("\tdebug(__BORLANDC__ not defined)\n");
  2064. X#endif
  2065. X#ifdef __TCPLUSPLUS__
  2066. X    PRINTF("\t(__TCPLUSPLUS__ = 0x%04x)\n", __TCPLUSPLUS__);
  2067. X#else
  2068. X    PRINTF("\tdebug(__TCPLUSPLUS__ not defined)\n");
  2069. X#endif
  2070. X#ifdef __BCPLUSPLUS__
  2071. X    PRINTF("\t(__BCPLUSPLUS__ = 0x%04x)\n\n", __BCPLUSPLUS__);
  2072. X#else
  2073. X    PRINTF("\tdebug(__BCPLUSPLUS__ not defined)\n\n");
  2074. X#endif
  2075. X#endif /* __TURBOC__ */
  2076. X
  2077. X} /* end function version() */
  2078. X
  2079. X#endif /* !SFX */
  2080. X
  2081. X
  2082. X
  2083. X
  2084. X
  2085. Xstatic unsigned char cUpperCase[256], cLowerCase[256];
  2086. Xstatic BOOL bInitialized;
  2087. X
  2088. X/* Initialize the tables of upper- and lowercase characters, including
  2089. X   handling of country-dependent characters. */
  2090. X
  2091. Xstatic void InitNLS(void)
  2092. X{
  2093. X  unsigned nCnt, nU;
  2094. X  COUNTRYCODE cc;
  2095. X
  2096. X  bInitialized = TRUE;
  2097. X
  2098. X  for ( nCnt = 0; nCnt < 256; nCnt++ )
  2099. X    cUpperCase[nCnt] = cLowerCase[nCnt] = (unsigned char) nCnt;
  2100. X
  2101. X  cc.country = cc.codepage = 0;
  2102. X  DosMapCase(sizeof(cUpperCase), &cc, (PCHAR) cUpperCase);
  2103. X
  2104. X  for ( nCnt = 0; nCnt < 256; nCnt++ )
  2105. X  {
  2106. X    nU = cUpperCase[nCnt];
  2107. X    if (nU != nCnt && cLowerCase[nU] == (unsigned char) nU)
  2108. X      cLowerCase[nU] = (unsigned char) nCnt;
  2109. X  }
  2110. X
  2111. X  for ( nCnt = 'A'; nCnt <= 'Z'; nCnt++ )
  2112. X    cLowerCase[nCnt] = (unsigned char) (nCnt - 'A' + 'a');
  2113. X}
  2114. X
  2115. X
  2116. Xint IsUpperNLS(int nChr)
  2117. X{
  2118. X  if (!bInitialized)
  2119. X    InitNLS();
  2120. X  return (cUpperCase[nChr] == (unsigned char) nChr);
  2121. X}
  2122. X
  2123. X
  2124. Xint ToLowerNLS(int nChr)
  2125. X{
  2126. X  if (!bInitialized)
  2127. X    InitNLS();
  2128. X  return cLowerCase[nChr];
  2129. X}
  2130. X
  2131. X
  2132. Xchar *StringLower(char *szArg)
  2133. X{
  2134. X  unsigned char *szPtr;
  2135. X
  2136. X  if (!bInitialized)
  2137. X    InitNLS();
  2138. X  for ( szPtr = szArg; *szPtr; szPtr++ )
  2139. X    *szPtr = cLowerCase[*szPtr];
  2140. X  return szArg;
  2141. X}
  2142. X
  2143. X
  2144. X#if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
  2145. Xvoid DebugMalloc(void)
  2146. X{
  2147. X  _dump_allocated(0); /* print out debug malloc memory statistics */
  2148. X}
  2149. X#endif
  2150. END_OF_FILE
  2151.   if test 57190 -ne `wc -c <'unzip-5.12/os2/os2.c'`; then
  2152.     echo shar: \"'unzip-5.12/os2/os2.c'\" unpacked with wrong size!
  2153.   fi
  2154.   # end of 'unzip-5.12/os2/os2.c'
  2155. fi
  2156. echo shar: End of archive 5 \(of 20\).
  2157. cp /dev/null ark5isdone
  2158. MISSING=""
  2159. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
  2160.     if test ! -f ark${I}isdone ; then
  2161.     MISSING="${MISSING} ${I}"
  2162.     fi
  2163. done
  2164. if test "${MISSING}" = "" ; then
  2165.     echo You have unpacked all 20 archives.
  2166.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2167. else
  2168.     echo You still must unpack the following archives:
  2169.     echo "        " ${MISSING}
  2170. fi
  2171. exit 0
  2172. exit 0 # Just in case...
  2173.