netware.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. /*
  2. Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
  3. See the accompanying file LICENSE, version 2007-Mar-04 or later
  4. (the contents of which are also included in unzip.h) for terms of use.
  5. If, for some reason, all these files are missing, the Info-ZIP license
  6. also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
  7. */
  8. /*---------------------------------------------------------------------------
  9. netware.c
  10. This file implements these functions for a NetWare Loadable Module (NLM):
  11. Contains: InitUnZipConsole()
  12. do_wild()
  13. mapattr()
  14. mapname()
  15. checkdir()
  16. close_outfile()
  17. stamp_file()
  18. version()
  19. screensize()
  20. ---------------------------------------------------------------------------*/
  21. #define UNZIP_INTERNAL
  22. #include "unzip.h"
  23. #include <dirent.h>
  24. #include <nwdir.h>
  25. #include <nwnamspc.h>
  26. #include <nwconio.h>
  27. #include <nwthread.h>
  28. #include <nwadv.h>
  29. #ifdef ACORN_FTYPE_NFS
  30. /* Acorn bits for NFS filetyping */
  31. typedef struct {
  32. uch ID[2];
  33. uch size[2];
  34. uch ID_2[4];
  35. uch loadaddr[4];
  36. uch execaddr[4];
  37. uch attr[4];
  38. } RO_extra_block;
  39. #endif /* ACORN_FTYPE_NFS */
  40. static int created_dir; /* used in mapname(), checkdir() */
  41. static int renamed_fullpath; /* ditto */
  42. /*********************************/
  43. /* Function InitUnZipConsole() */
  44. /*********************************/
  45. void InitUnZipConsole()
  46. {
  47. unsigned int myHandle = GetNLMHandle();
  48. unsigned int *activeScreen =
  49. ImportSymbol(myHandle, "activeScreen");
  50. unsigned int *systemConsoleScreen =
  51. ImportSymbol(myHandle, "systemConsoleScreen");
  52. void (*pUseAccurateCaseForPaths)(int) =
  53. ImportSymbol(myHandle, "UseAccurateCaseForPaths");
  54. if (!activeScreen || !systemConsoleScreen ||
  55. *activeScreen == *systemConsoleScreen)
  56. CreateScreen("Info-ZIP UnZip Utility", 0);
  57. else
  58. CreateScreen("System Console", DONT_AUTO_ACTIVATE);
  59. SetCurrentNameSpace(NW_NS_LONG);
  60. if (pUseAccurateCaseForPaths)
  61. pUseAccurateCaseForPaths(TRUE);
  62. UnimportSymbol(myHandle, "activeScreen");
  63. UnimportSymbol(myHandle, "systemConsoleScreen");
  64. UnimportSymbol(myHandle, "UseAccurateCaseForPaths");
  65. }
  66. /**********************/
  67. /* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */
  68. /**********************/
  69. char *do_wild(__G__ wildspec)
  70. __GDEF
  71. ZCONST char *wildspec; /* only used first time on a given dir */
  72. {
  73. static DIR *wild_dir = (DIR *)NULL;
  74. static ZCONST char *wildname;
  75. static char *dirname, matchname[FILNAMSIZ];
  76. static int notfirstcall=FALSE, have_dirname, dirnamelen;
  77. struct dirent *file;
  78. /* Even when we're just returning wildspec, we *always* do so in
  79. * matchname[]--calling routine is allowed to append four characters
  80. * to the returned string, and wildspec may be a pointer to argv[].
  81. */
  82. if (!notfirstcall) { /* first call: must initialize everything */
  83. notfirstcall = TRUE;
  84. if (!iswild(wildspec)) {
  85. strncpy(matchname, wildspec, FILNAMSIZ);
  86. matchname[FILNAMSIZ-1] = '\0';
  87. have_dirname = FALSE;
  88. dir = NULL;
  89. return matchname;
  90. }
  91. /* break the wildspec into a directory part and a wildcard filename */
  92. if ((wildname = strrchr(wildspec, '/')) == (ZCONST char *)NULL) {
  93. dirname = ".";
  94. dirnamelen = 1;
  95. have_dirname = FALSE;
  96. wildname = wildspec;
  97. } else {
  98. ++wildname; /* point at character after '/' */
  99. dirnamelen = wildname - wildspec;
  100. if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  101. Info(slide, 0x201, ((char *)slide,
  102. "warning: cannot allocate wildcard buffers\n"));
  103. strncpy(matchname, wildspec, FILNAMSIZ);
  104. matchname[FILNAMSIZ-1] = '\0';
  105. return matchname; /* but maybe filespec was not a wildcard */
  106. }
  107. strncpy(dirname, wildspec, dirnamelen);
  108. dirname[dirnamelen] = '\0'; /* terminate for strcpy below */
  109. have_dirname = TRUE;
  110. }
  111. if ((wild_dir = opendir(dirname)) != (DIR *)NULL) {
  112. while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
  113. Trace((stderr, "do_wild: readdir returns %s\n",
  114. FnFilter1(file->d_name)));
  115. if (file->d_name[0] == '.' && wildname[0] != '.')
  116. continue; /* Unix: '*' and '?' do not match leading dot */
  117. if (match(file->d_name, wildname, 0 WISEP) && /* 0=case sens.*/
  118. /* skip "." and ".." directory entries */
  119. strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
  120. Trace((stderr, "do_wild: match() succeeds\n"));
  121. if (have_dirname) {
  122. strcpy(matchname, dirname);
  123. strcpy(matchname+dirnamelen, file->d_name);
  124. } else
  125. strcpy(matchname, file->d_name);
  126. return matchname;
  127. }
  128. }
  129. /* if we get to here directory is exhausted, so close it */
  130. closedir(wild_dir);
  131. wild_dir = (DIR *)NULL;
  132. }
  133. /* return the raw wildspec in case that works (e.g., directory not
  134. * searchable, but filespec was not wild and file is readable) */
  135. strncpy(matchname, wildspec, FILNAMSIZ);
  136. matchname[FILNAMSIZ-1] = '\0';
  137. return matchname;
  138. }
  139. /* last time through, might have failed opendir but returned raw wildspec */
  140. if (wild_dir == (DIR *)NULL) {
  141. notfirstcall = FALSE; /* nothing left to try--reset for new wildspec */
  142. if (have_dirname)
  143. free(dirname);
  144. return (char *)NULL;
  145. }
  146. /* If we've gotten this far, we've read and matched at least one entry
  147. * successfully (in a previous call), so dirname has been copied into
  148. * matchname already.
  149. */
  150. while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
  151. Trace((stderr, "do_wild: readdir returns %s\n",
  152. FnFilter1(file->d_name)));
  153. if (file->d_name[0] == '.' && wildname[0] != '.')
  154. continue; /* Unix: '*' and '?' do not match leading dot */
  155. if (match(file->d_name, wildname, 0 WISEP)) { /* 0 == case sens. */
  156. Trace((stderr, "do_wild: match() succeeds\n"));
  157. if (have_dirname) {
  158. /* strcpy(matchname, dirname); */
  159. strcpy(matchname+dirnamelen, file->d_name);
  160. } else
  161. strcpy(matchname, file->d_name);
  162. return matchname;
  163. }
  164. }
  165. closedir(wild_dir); /* have read at least one entry; nothing left */
  166. wild_dir = (DIR *)NULL;
  167. notfirstcall = FALSE; /* reset for new wildspec */
  168. if (have_dirname)
  169. free(dirname);
  170. return (char *)NULL;
  171. } /* end function do_wild() */
  172. /**********************/
  173. /* Function mapattr() */
  174. /**********************/
  175. int mapattr(__G)
  176. __GDEF
  177. {
  178. ulg tmp = G.crec.external_file_attributes;
  179. G.pInfo->file_attr = 0;
  180. /* initialized to 0 for check in "default" branch below... */
  181. switch (G.pInfo->hostnum) {
  182. case AMIGA_:
  183. tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */
  184. G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
  185. break;
  186. case UNIX_:
  187. case VMS_:
  188. case ACORN_:
  189. case ATARI_:
  190. case ATHEOS_:
  191. case BEOS_:
  192. case QDOS_:
  193. case TANDEM_:
  194. G.pInfo->file_attr = (unsigned)(tmp >> 16);
  195. if (G.pInfo->file_attr != 0 || !G.extra_field) {
  196. return 0;
  197. } else {
  198. /* Some (non-Info-ZIP) implementations of Zip for Unix and
  199. * VMS (and probably others ??) leave 0 in the upper 16-bit
  200. * part of the external_file_attributes field. Instead, they
  201. * store file permission attributes in some extra field.
  202. * As a work-around, we search for the presence of one of
  203. * these extra fields and fall back to the MSDOS compatible
  204. * part of external_file_attributes if one of the known
  205. * e.f. types has been detected.
  206. * Later, we might implement extraction of the permission
  207. * bits from the VMS extra field. But for now, the work-around
  208. * should be sufficient to provide "readable" extracted files.
  209. * (For ASI Unix e.f., an experimental remap from the e.f.
  210. * mode value IS already provided!)
  211. */
  212. ush ebID;
  213. unsigned ebLen;
  214. uch *ef = G.extra_field;
  215. unsigned ef_len = G.crec.extra_field_length;
  216. int r = FALSE;
  217. while (!r && ef_len >= EB_HEADSIZE) {
  218. ebID = makeword(ef);
  219. ebLen = (unsigned)makeword(ef+EB_LEN);
  220. if (ebLen > (ef_len - EB_HEADSIZE))
  221. /* discoverd some e.f. inconsistency! */
  222. break;
  223. switch (ebID) {
  224. case EF_ASIUNIX:
  225. if (ebLen >= (EB_ASI_MODE+2)) {
  226. G.pInfo->file_attr =
  227. (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
  228. /* force stop of loop: */
  229. ef_len = (ebLen + EB_HEADSIZE);
  230. break;
  231. }
  232. /* else: fall through! */
  233. case EF_PKVMS:
  234. /* "found nondecypherable e.f. with perm. attr" */
  235. r = TRUE;
  236. default:
  237. break;
  238. }
  239. ef_len -= (ebLen + EB_HEADSIZE);
  240. ef += (ebLen + EB_HEADSIZE);
  241. }
  242. if (!r)
  243. return 0;
  244. }
  245. /* fall through! */
  246. /* all remaining cases: expand MSDOS read-only bit into write perms */
  247. case FS_FAT_:
  248. /* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the
  249. * Unix attributes in the upper 16 bits of the external attributes
  250. * field, just like Info-ZIP's Zip for Unix. We try to use that
  251. * value, after a check for consistency with the MSDOS attribute
  252. * bits (see below).
  253. */
  254. G.pInfo->file_attr = (unsigned)(tmp >> 16);
  255. /* fall through! */
  256. case FS_HPFS_:
  257. case FS_NTFS_:
  258. case MAC_:
  259. case TOPS20_:
  260. default:
  261. /* Ensure that DOS subdir bit is set when the entry's name ends
  262. * in a '/'. Some third-party Zip programs fail to set the subdir
  263. * bit for directory entries.
  264. */
  265. if ((tmp & 0x10) == 0) {
  266. extent fnlen = strlen(G.filename);
  267. if (fnlen > 0 && G.filename[fnlen-1] == '/')
  268. tmp |= 0x10;
  269. }
  270. /* read-only bit --> write perms; subdir bit --> dir exec bit */
  271. tmp = !(tmp & 1) << 1 | (tmp & 0x10) >> 4;
  272. if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6))
  273. /* keep previous G.pInfo->file_attr setting, when its "owner"
  274. * part appears to be consistent with DOS attribute flags!
  275. */
  276. return 0;
  277. G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
  278. break;
  279. } /* end switch (host-OS-created-by) */
  280. /* for originating systems with no concept of "group," "other," "system": */
  281. umask( (int)(tmp=umask(0)) ); /* apply mask to expanded r/w(/x) perms */
  282. G.pInfo->file_attr &= ~tmp;
  283. return 0;
  284. } /* end function mapattr() */
  285. /**********************/
  286. /* Function mapname() */
  287. /**********************/
  288. int mapname(__G__ renamed)
  289. __GDEF
  290. int renamed;
  291. /*
  292. * returns:
  293. * MPN_OK - no problem detected
  294. * MPN_INF_TRUNC - caution (truncated filename)
  295. * MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
  296. * MPN_ERR_SKIP - error -> skip entry
  297. * MPN_ERR_TOOLONG - error -> path is too long
  298. * MPN_NOMEM - error (memory allocation failed) -> skip entry
  299. * [also MPN_VOL_LABEL, MPN_CREATED_DIR]
  300. */
  301. {
  302. char pathcomp[FILNAMSIZ]; /* path-component buffer */
  303. char *pp, *cp=(char *)NULL; /* character pointers */
  304. char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  305. #ifdef ACORN_FTYPE_NFS
  306. char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */
  307. RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */
  308. #endif
  309. int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
  310. int error = MPN_OK;
  311. register unsigned workch; /* hold the character being tested */
  312. /*---------------------------------------------------------------------------
  313. Initialize various pointers and counters and stuff.
  314. ---------------------------------------------------------------------------*/
  315. if (G.pInfo->vollabel)
  316. return MPN_VOL_LABEL; /* can't set disk volume labels in Netware */
  317. /* can create path as long as not just freshening, or if user told us */
  318. G.create_dirs = (!uO.fflag || renamed);
  319. created_dir = FALSE; /* not yet */
  320. /* user gave full pathname: don't prepend rootpath */
  321. renamed_fullpath = (renamed && (*G.filename == '/'));
  322. if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
  323. return MPN_NOMEM; /* initialize path buffer, unless no memory */
  324. *pathcomp = '\0'; /* initialize translation buffer */
  325. pp = pathcomp; /* point to translation buffer */
  326. if (uO.jflag) /* junking directories */
  327. cp = (char *)strrchr(G.filename, '/');
  328. if (cp == (char *)NULL) /* no '/' or not junking dirs */
  329. cp = G.filename; /* point to internal zipfile-member pathname */
  330. else
  331. ++cp; /* point to start of last component of path */
  332. /*---------------------------------------------------------------------------
  333. Begin main loop through characters in filename.
  334. ---------------------------------------------------------------------------*/
  335. while ((workch = (uch)*cp++) != 0) {
  336. switch (workch) {
  337. case '/': /* can assume -j flag not given */
  338. *pp = '\0';
  339. if (strcmp(pathcomp, ".") == 0) {
  340. /* don't bother appending "./" to the path */
  341. *pathcomp = '\0';
  342. } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
  343. /* "../" dir traversal detected, skip over it */
  344. *pathcomp = '\0';
  345. killed_ddot = TRUE; /* set "show message" flag */
  346. }
  347. /* when path component is not empty, append it now */
  348. if (*pathcomp != '\0' &&
  349. ((error = checkdir(__G__ pathcomp, APPEND_DIR))
  350. & MPN_MASK) > MPN_INF_TRUNC)
  351. return error;
  352. pp = pathcomp; /* reset conversion buffer for next piece */
  353. lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
  354. break;
  355. case ';': /* VMS version (or DEC-20 attrib?) */
  356. lastsemi = pp;
  357. *pp++ = ';'; /* keep for now; remove VMS ";##" */
  358. break; /* later, if requested */
  359. #ifdef ACORN_FTYPE_NFS
  360. case ',': /* NFS filetype extension */
  361. lastcomma = pp;
  362. *pp++ = ','; /* keep for now; may need to remove */
  363. break; /* later, if requested */
  364. #endif
  365. default:
  366. /* allow European characters in filenames: */
  367. if (isprint(workch) || (128 <= workch && workch <= 254))
  368. *pp++ = (char)workch;
  369. } /* end switch */
  370. } /* end while loop */
  371. /* Show warning when stripping insecure "parent dir" path components */
  372. if (killed_ddot && QCOND2) {
  373. Info(slide, 0, ((char *)slide,
  374. "warning: skipped \"../\" path component(s) in %s\n",
  375. FnFilter1(G.filename)));
  376. if (!(error & ~MPN_MASK))
  377. error = (error & MPN_MASK) | PK_WARN;
  378. }
  379. /*---------------------------------------------------------------------------
  380. Report if directory was created (and no file to create: filename ended
  381. in '/'), check name to be sure it exists, and combine path and name be-
  382. fore exiting.
  383. ---------------------------------------------------------------------------*/
  384. if (G.filename[strlen(G.filename) - 1] == '/') {
  385. checkdir(__G__ G.filename, GETPATH);
  386. if (created_dir) {
  387. if (QCOND2) {
  388. Info(slide, 0, ((char *)slide, " creating: %s\n",
  389. FnFilter1(G.filename)));
  390. }
  391. #if !defined(NO_CHMOD) && !defined(NLM)
  392. /* In NetWare, chmod does not work on directories */
  393. /* set approx. dir perms (make sure can still read/write in dir) */
  394. if (chmod(G.filename, (0xffff & G.pInfo->file_attr) | 0700))
  395. perror("chmod (directory attributes) error");
  396. #endif
  397. /* set dir time (note trailing '/') */
  398. return (error & ~MPN_MASK) | MPN_CREATED_DIR;
  399. }
  400. /* dir existed already; don't look for data to extract */
  401. return (error & ~MPN_MASK) | MPN_INF_SKIP;
  402. }
  403. *pp = '\0'; /* done with pathcomp: terminate it */
  404. /* if not saving them, remove VMS version numbers (appended ";###") */
  405. if (!uO.V_flag && lastsemi) {
  406. pp = lastsemi + 1;
  407. while (isdigit((uch)(*pp)))
  408. ++pp;
  409. if (*pp == '\0') /* only digits between ';' and end: nuke */
  410. *lastsemi = '\0';
  411. }
  412. #ifdef ACORN_FTYPE_NFS
  413. /* translate Acorn filetype information if asked to do so */
  414. if (uO.acorn_nfs_ext &&
  415. (ef_spark = (RO_extra_block *)
  416. getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
  417. != (RO_extra_block *)NULL)
  418. {
  419. /* file *must* have a RISC OS extra field */
  420. long ft = (long)makelong(ef_spark->loadaddr);
  421. /*32-bit*/
  422. if (lastcomma) {
  423. pp = lastcomma + 1;
  424. while (isxdigit((uch)(*pp))) ++pp;
  425. if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
  426. }
  427. if ((ft & 1<<31)==0) ft=0x000FFD00;
  428. sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
  429. }
  430. #endif /* ACORN_FTYPE_NFS */
  431. if (*pathcomp == '\0') {
  432. Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
  433. FnFilter1(G.filename)));
  434. return (error & ~MPN_MASK) | MPN_ERR_SKIP;
  435. }
  436. checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
  437. checkdir(__G__ G.filename, GETPATH);
  438. return error;
  439. } /* end function mapname() */
  440. /***********************/
  441. /* Function checkdir() */
  442. /***********************/
  443. int checkdir(__G__ pathcomp, flag)
  444. __GDEF
  445. char *pathcomp;
  446. int flag;
  447. /*
  448. * returns:
  449. * MPN_OK - no problem detected
  450. * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
  451. * MPN_INF_SKIP - path doesn't exist, not allowed to create
  452. * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
  453. * exists and is not a directory, but is supposed to be
  454. * MPN_ERR_TOOLONG - path is too long
  455. * MPN_NOMEM - can't allocate memory for filename buffers
  456. */
  457. {
  458. static int rootlen = 0; /* length of rootpath */
  459. static char *rootpath; /* user's "extract-to" directory */
  460. static char *buildpath; /* full path (so far) to extracted file */
  461. static char *end; /* pointer to end of buildpath ('\0') */
  462. # define FN_MASK 7
  463. # define FUNCTION (flag & FN_MASK)
  464. /*---------------------------------------------------------------------------
  465. APPEND_DIR: append the path component to the path being built and check
  466. for its existence. If doesn't exist and we are creating directories, do
  467. so for this one; else signal success or error as appropriate.
  468. ---------------------------------------------------------------------------*/
  469. if (FUNCTION == APPEND_DIR) {
  470. int too_long = FALSE;
  471. #ifdef SHORT_NAMES
  472. char *old_end = end;
  473. #endif
  474. Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
  475. while ((*end = *pathcomp++) != '\0')
  476. ++end;
  477. #ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */
  478. if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
  479. *(end = old_end + FILENAME_MAX) = '\0';
  480. #endif
  481. /* GRR: could do better check, see if overrunning buffer as we go:
  482. * check end-buildpath after each append, set warning variable if
  483. * within 20 of FILNAMSIZ; then if var set, do careful check when
  484. * appending. Clear variable when begin new path. */
  485. if ((end-buildpath) > FILNAMSIZ-3) /* need '/', one-char name, '\0' */
  486. too_long = TRUE; /* check if extracting directory? */
  487. if (stat(buildpath, &G.statbuf)) { /* path doesn't exist */
  488. if (!G.create_dirs) { /* told not to create (freshening) */
  489. free(buildpath);
  490. /* path doesn't exist: nothing to do */
  491. return MPN_INF_SKIP;
  492. }
  493. if (too_long) {
  494. Info(slide, 1, ((char *)slide,
  495. "checkdir error: path too long: %s\n",
  496. FnFilter1(buildpath)));
  497. free(buildpath);
  498. /* no room for filenames: fatal */
  499. return MPN_ERR_TOOLONG;
  500. }
  501. if (mkdir(buildpath) == -1) { /* create the directory */
  502. Info(slide, 1, ((char *)slide,
  503. "checkdir error: cannot create %s\n\
  504. unable to process %s.\n",
  505. FnFilter2(buildpath), FnFilter1(G.filename)));
  506. free(buildpath);
  507. /* path didn't exist, tried to create, failed */
  508. return MPN_ERR_SKIP;
  509. }
  510. created_dir = TRUE;
  511. } else if (!S_ISDIR(G.statbuf.st_mode)) {
  512. Info(slide, 1, ((char *)slide,
  513. "checkdir error: %s exists but is not directory\n\
  514. unable to process %s.\n",
  515. FnFilter2(buildpath), FnFilter1(G.filename)));
  516. free(buildpath);
  517. /* path existed but wasn't dir */
  518. return MPN_ERR_SKIP;
  519. }
  520. if (too_long) {
  521. Info(slide, 1, ((char *)slide,
  522. "checkdir error: path too long: %s\n", FnFilter1(buildpath)));
  523. free(buildpath);
  524. /* no room for filenames: fatal */
  525. return MPN_ERR_TOOLONG;
  526. }
  527. *end++ = '/';
  528. *end = '\0';
  529. Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
  530. return MPN_OK;
  531. } /* end if (FUNCTION == APPEND_DIR) */
  532. /*---------------------------------------------------------------------------
  533. GETPATH: copy full path to the string pointed at by pathcomp, and free
  534. buildpath.
  535. ---------------------------------------------------------------------------*/
  536. if (FUNCTION == GETPATH) {
  537. strcpy(pathcomp, buildpath);
  538. Trace((stderr, "getting and freeing path [%s]\n",
  539. FnFilter1(pathcomp)));
  540. free(buildpath);
  541. buildpath = end = (char *)NULL;
  542. return MPN_OK;
  543. }
  544. /*---------------------------------------------------------------------------
  545. APPEND_NAME: assume the path component is the filename; append it and
  546. return without checking for existence.
  547. ---------------------------------------------------------------------------*/
  548. if (FUNCTION == APPEND_NAME) {
  549. #ifdef SHORT_NAMES
  550. char *old_end = end;
  551. #endif
  552. Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
  553. while ((*end = *pathcomp++) != '\0') {
  554. ++end;
  555. #ifdef SHORT_NAMES /* truncate name at 14 characters, typically */
  556. if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
  557. *(end = old_end + FILENAME_MAX) = '\0';
  558. #endif
  559. if ((end-buildpath) >= FILNAMSIZ) {
  560. *--end = '\0';
  561. Info(slide, 0x201, ((char *)slide,
  562. "checkdir warning: path too long; truncating\n\
  563. %s\n -> %s\n",
  564. FnFilter1(G.filename), FnFilter2(buildpath)));
  565. return MPN_INF_TRUNC; /* filename truncated */
  566. }
  567. }
  568. Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
  569. /* could check for existence here, prompt for new name... */
  570. return MPN_OK;
  571. }
  572. /*---------------------------------------------------------------------------
  573. INIT: allocate and initialize buffer space for the file currently being
  574. extracted. If file was renamed with an absolute path, don't prepend the
  575. extract-to path.
  576. ---------------------------------------------------------------------------*/
  577. /* GRR: for VMS and TOPS-20, add up to 13 to strlen */
  578. if (FUNCTION == INIT) {
  579. Trace((stderr, "initializing buildpath to "));
  580. #ifdef ACORN_FTYPE_NFS
  581. if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+
  582. (uO.acorn_nfs_ext ? 5 : 1)))
  583. #else
  584. if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1))
  585. #endif
  586. == (char *)NULL)
  587. return MPN_NOMEM;
  588. if ((rootlen > 0) && !renamed_fullpath) {
  589. strcpy(buildpath, rootpath);
  590. end = buildpath + rootlen;
  591. } else {
  592. *buildpath = '\0';
  593. end = buildpath;
  594. }
  595. Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
  596. return MPN_OK;
  597. }
  598. /*---------------------------------------------------------------------------
  599. ROOT: if appropriate, store the path in rootpath and create it if neces-
  600. sary; else assume it's a zipfile member and return. This path segment
  601. gets used in extracting all members from every zipfile specified on the
  602. command line.
  603. ---------------------------------------------------------------------------*/
  604. #if (!defined(SFX) || defined(SFX_EXDIR))
  605. if (FUNCTION == ROOT) {
  606. Trace((stderr, "initializing root path to [%s]\n",
  607. FnFilter1(pathcomp)));
  608. if (pathcomp == (char *)NULL) {
  609. rootlen = 0;
  610. return MPN_OK;
  611. }
  612. if ((rootlen = strlen(pathcomp)) > 0) {
  613. if (pathcomp[rootlen-1] == '/') {
  614. pathcomp[--rootlen] = '\0';
  615. }
  616. if (rootlen > 0 && (stat(pathcomp, &G.statbuf) ||
  617. !S_ISDIR(G.statbuf.st_mode))) /* path does not exist */
  618. {
  619. if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  620. rootlen = 0;
  621. /* skip (or treat as stored file) */
  622. return MPN_INF_SKIP;
  623. }
  624. /* create the directory (could add loop here to scan pathcomp
  625. * and create more than one level, but why really necessary?) */
  626. if (mkdir(pathcomp) == -1) {
  627. Info(slide, 1, ((char *)slide,
  628. "checkdir: cannot create extraction directory: %s\n",
  629. FnFilter1(pathcomp)));
  630. rootlen = 0;
  631. /* path didn't exist, tried to create, and failed: */
  632. /* file exists, or 2+ subdirectory levels required */
  633. return MPN_ERR_SKIP;
  634. }
  635. }
  636. if ((rootpath = (char *)malloc(rootlen+2)) == (char *)NULL) {
  637. rootlen = 0;
  638. return MPN_NOMEM;
  639. }
  640. strcpy(rootpath, pathcomp);
  641. rootpath[rootlen++] = '/';
  642. rootpath[rootlen] = '\0';
  643. Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
  644. }
  645. return MPN_OK;
  646. }
  647. #endif /* !SFX || SFX_EXDIR */
  648. /*---------------------------------------------------------------------------
  649. END: free rootpath, immediately prior to program exit.
  650. ---------------------------------------------------------------------------*/
  651. if (FUNCTION == END) {
  652. Trace((stderr, "freeing rootpath\n"));
  653. if (rootlen > 0) {
  654. free(rootpath);
  655. rootlen = 0;
  656. }
  657. return MPN_OK;
  658. }
  659. return MPN_INVALID; /* should never reach */
  660. } /* end function checkdir() */
  661. /****************************/
  662. /* Function close_outfile() */
  663. /****************************/
  664. void close_outfile(__G) /* GRR: change to return PK-style warning level */
  665. __GDEF
  666. {
  667. fclose(G.outfile);
  668. /* skip restoring time stamps on user's request */
  669. if (uO.D_flag <= 1) {
  670. WORD date = G.lrec.last_mod_dos_datetime >> 16;
  671. WORD time = G.lrec.last_mod_dos_datetime & 0xffff;
  672. static struct ModifyStructure changeBuffer;
  673. /* set the file's access and modification times */
  674. changeBuffer.MLastAccessedDate = date;
  675. changeBuffer.MLastUpdatedDate = date;
  676. changeBuffer.MLastUpdatedTime = time;
  677. if (ChangeDirectoryEntry(G.filename, &changeBuffer,
  678. MLastAccessedDateBit | MLastUpdatedDateBit | MLastUpdatedTimeBit,
  679. 0))
  680. {
  681. if (uO.qflag)
  682. Info(slide, 0x201, ((char *)slide,
  683. "warning: cannot set times for %s\n",
  684. FnFilter1(G.filename)));
  685. else
  686. Info(slide, 0x201, ((char *)slide,
  687. " (warning) cannot set times"));
  688. }
  689. }
  690. /*---------------------------------------------------------------------------
  691. Change the file permissions from default ones to those stored in the
  692. zipfile.
  693. ---------------------------------------------------------------------------*/
  694. if (chmod(G.filename, 0xffff & G.pInfo->file_attr))
  695. perror("chmod (file attributes) error");
  696. } /* end function close_outfile() */
  697. #ifdef TIMESTAMP
  698. /***************************/
  699. /* Function stamp_file() */
  700. /***************************/
  701. int stamp_file(fname, modtime)
  702. ZCONST char *fname;
  703. time_t modtime;
  704. {
  705. ztimbuf tp;
  706. tp.modtime = tp.actime = modtime;
  707. return (utime(fname, &tp));
  708. } /* end function stamp_file() */
  709. #endif /* TIMESTAMP */
  710. /************************/
  711. /* Function version() */
  712. /************************/
  713. void version(__G)
  714. __GDEF
  715. {
  716. int len;
  717. #if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER)
  718. char buf[80];
  719. #endif
  720. len = sprintf((char *)slide, LoadFarString(CompiledWith),
  721. #if defined(__GNUC__)
  722. # ifdef __EMX__ /* __EMX__ is defined as "1" only (sigh) */
  723. "emx+gcc ", __VERSION__,
  724. # else
  725. "gcc/2 ", __VERSION__,
  726. # endif
  727. #elif defined(__WATCOMC__)
  728. "Watcom C", (sprintf(buf, " (__WATCOMC__ = %d)", __WATCOMC__), buf),
  729. #elif defined(__TURBOC__)
  730. # ifdef __BORLANDC__
  731. "Borland C++",
  732. # if (__BORLANDC__ < 0x0460)
  733. " 1.0",
  734. # elif (__BORLANDC__ == 0x0460)
  735. " 1.5", /* from Kai Uwe: three less than DOS */
  736. # else
  737. " 2.0", /* (__BORLANDC__ == 0x0500)? */
  738. # endif
  739. # else
  740. "Turbo C", /* these are probably irrelevant */
  741. # if (__TURBOC__ >= 661)
  742. "++ 1.0 or later",
  743. # elif (__TURBOC__ == 661)
  744. " 3.0?",
  745. # elif (__TURBOC__ == 397)
  746. " 2.0",
  747. # else
  748. " 1.0 or 1.5?",
  749. # endif
  750. # endif
  751. #elif defined(MSC)
  752. "Microsoft C ",
  753. # ifdef _MSC_VER
  754. (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
  755. # else
  756. "5.1 or earlier",
  757. # endif
  758. #else
  759. "unknown compiler", "",
  760. #endif /* ?compilers */
  761. "NetWare",
  762. " (32-bit)",
  763. #ifdef __DATE__
  764. " on ", __DATE__
  765. #else
  766. "", ""
  767. #endif
  768. );
  769. (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
  770. /* MSC can't handle huge macro expansions */
  771. } /* end function version() */
  772. #ifdef MORE
  773. /*************************/
  774. /* Function screensize() */
  775. /*************************/
  776. int screensize(int *tt_rows, int *tt_cols)
  777. {
  778. WORD height;
  779. WORD width;
  780. if (GetSizeOfScreen(&height, &width) == 0) {
  781. if (tt_rows != NULL) *tt_rows = height;
  782. if (tt_cols != NULL) *tt_cols = width;
  783. return 0; /* signal success */
  784. } else {
  785. if (tt_rows != NULL) *tt_rows = 25;
  786. if (tt_cols != NULL) *tt_cols = 80;
  787. return 1; /* signal failure */
  788. }
  789. }
  790. #endif /* MORE */