flexos.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. /*
  2. Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
  3. See the accompanying file LICENSE, version 2000-Apr-09 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. flexos.c
  10. FlexOS-specific routines for use with Info-ZIP's UnZip 5.2 and later.
  11. Based upon the MSDOS version of this file (msdos/msdos.c)
  12. Contains: do_wild()
  13. mapattr()
  14. mapname()
  15. map2fat()
  16. checkdir()
  17. close_outfile()
  18. dateformat()
  19. version()
  20. _wildarg()
  21. ---------------------------------------------------------------------------*/
  22. #define UNZIP_INTERNAL
  23. #include "unzip.h"
  24. #include <flexif.h>
  25. /* The following should really be a static declaration, but the compiler
  26. complains (crappy compiler can't cope with a static forward declaration).
  27. */
  28. extern void map2fat OF((char *pathcomp, char *last_dot));
  29. static int created_dir; /* used by mapname(), checkdir() */
  30. static int renamed_fullpath; /* ditto */
  31. /*****************************/
  32. /* Strings used in flexos.c */
  33. /*****************************/
  34. #ifndef SFX
  35. static ZCONST char Far CantAllocateWildcard[] =
  36. "warning: cannot allocate wildcard buffers\n";
  37. #endif
  38. static ZCONST char Far WarnDirTraversSkip[] =
  39. "warning: skipped \"../\" path component(s) in %s\n";
  40. static ZCONST char Far Creating[] = " creating: %s\n";
  41. static ZCONST char Far ConversionFailed[] =
  42. "mapname: conversion of %s failed\n";
  43. static ZCONST char Far PathTooLong[] = "checkdir error: path too long: %s\n";
  44. static ZCONST char Far CantCreateDir[] = "checkdir error: cannot create %s\n\
  45. unable to process %s.\n";
  46. static ZCONST char Far DirIsntDirectory[] =
  47. "checkdir error: %s exists but is not directory\n\
  48. unable to process %s.\n";
  49. static ZCONST char Far PathTooLongTrunc[] =
  50. "checkdir warning: path too long; truncating\n %s\n\
  51. -> %s\n";
  52. #if (!defined(SFX) || defined(SFX_EXDIR))
  53. static ZCONST char Far CantCreateExtractDir[] =
  54. "checkdir: cannot create extraction directory: %s\n";
  55. #endif
  56. #include <dirent.h>
  57. #ifndef SFX
  58. /************************/
  59. /* Function do_wild() */ /* identical to OS/2 version */
  60. /************************/
  61. char *do_wild(__G__ wildspec)
  62. __GDEF
  63. ZCONST char *wildspec; /* only used first time on a given dir */
  64. {
  65. static DIR *wild_dir = (DIR *)NULL;
  66. static ZCONST char *wildname;
  67. static char *dirname, matchname[FILNAMSIZ];
  68. static int notfirstcall=FALSE, have_dirname, dirnamelen;
  69. char *fnamestart;
  70. struct dirent *file;
  71. /* Even when we're just returning wildspec, we *always* do so in
  72. * matchname[]--calling routine is allowed to append four characters
  73. * to the returned string, and wildspec may be a pointer to argv[].
  74. */
  75. if (!notfirstcall) { /* first call: must initialize everything */
  76. notfirstcall = TRUE;
  77. if (!iswild(wildspec)) {
  78. strncpy(matchname, wildspec, FILNAMSIZ);
  79. matchname[FILNAMSIZ-1] = '\0';
  80. have_dirname = FALSE;
  81. dir = NULL;
  82. return matchname;
  83. }
  84. /* break the wildspec into a directory part and a wildcard filename */
  85. if ((wildname = strrchr(wildspec, '/')) == (ZCONST char *)NULL &&
  86. (wildname = strrchr(wildspec, ':')) == (ZCONST char *)NULL) {
  87. dirname = ".";
  88. dirnamelen = 1;
  89. have_dirname = FALSE;
  90. wildname = wildspec;
  91. } else {
  92. ++wildname; /* point at character after '/' or ':' */
  93. dirnamelen = (int)(wildname - wildspec);
  94. if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  95. Info(slide, 1, ((char *)slide,
  96. LoadFarString(CantAllocateWildcard)));
  97. strncpy(matchname, wildspec, FILNAMSIZ);
  98. matchname[FILNAMSIZ-1] = '\0';
  99. return matchname; /* but maybe filespec was not a wildcard */
  100. }
  101. /* GRR: cannot strip trailing char for opendir since might be "d:/" or "d:"
  102. * (would have to check for "./" at end--let opendir handle it instead) */
  103. strncpy(dirname, wildspec, dirnamelen);
  104. dirname[dirnamelen] = '\0'; /* terminate for strcpy below */
  105. have_dirname = TRUE;
  106. }
  107. Trace((stderr, "do_wild: dirname = [%s]\n", FnFilter1(dirname)));
  108. if ((wild_dir = opendir(dirname)) != (DIR *)NULL) {
  109. if (have_dirname) {
  110. strcpy(matchname, dirname);
  111. fnamestart = matchname + dirnamelen;
  112. } else
  113. fnamestart = matchname;
  114. while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
  115. Trace((stderr, "do_wild: readdir returns %s\n",
  116. FnFilter1(file->d_name)));
  117. strcpy(fnamestart, file->d_name);
  118. if (strrchr(fnamestart, '.') == (char *)NULL)
  119. strcat(fnamestart, ".");
  120. if (match(fnamestart, wildname, 1 WISEP) && /* 1=ignore case */
  121. /* skip "." and ".." directory entries */
  122. strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) {
  123. Trace((stderr, "do_wild: match() succeeds\n"));
  124. /* remove trailing dot */
  125. fnamestart += strlen(fnamestart) - 1;
  126. if (*fnamestart == '.')
  127. *fnamestart = '\0';
  128. return matchname;
  129. }
  130. }
  131. /* if we get to here directory is exhausted, so close it */
  132. closedir(wild_dir);
  133. wild_dir = (DIR *)NULL;
  134. }
  135. #ifdef DEBUG
  136. else {
  137. Trace((stderr, "do_wild: opendir(%s) returns NULL\n",
  138. FnFilter1(dirname)));
  139. }
  140. #endif /* DEBUG */
  141. /* return the raw wildspec in case that works (e.g., directory not
  142. * searchable, but filespec was not wild and file is readable) */
  143. strncpy(matchname, wildspec, FILNAMSIZ);
  144. matchname[FILNAMSIZ-1] = '\0';
  145. return matchname;
  146. }
  147. /* last time through, might have failed opendir but returned raw wildspec */
  148. if (wild_dir == (DIR *)NULL) {
  149. notfirstcall = FALSE; /* nothing left to try--reset for new wildspec */
  150. if (have_dirname)
  151. free(dirname);
  152. return (char *)NULL;
  153. }
  154. /* If we've gotten this far, we've read and matched at least one entry
  155. * successfully (in a previous call), so dirname has been copied into
  156. * matchname already.
  157. */
  158. if (have_dirname) {
  159. /* strcpy(matchname, dirname); */
  160. fnamestart = matchname + dirnamelen;
  161. } else
  162. fnamestart = matchname;
  163. while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
  164. Trace((stderr, "do_wild: readdir returns %s\n",
  165. FnFilter1(file->d_name)));
  166. strcpy(fnamestart, file->d_name);
  167. if (strrchr(fnamestart, '.') == (char *)NULL)
  168. strcat(fnamestart, ".");
  169. if (match(fnamestart, wildname, 1 WISEP)) { /* 1 == ignore case */
  170. Trace((stderr, "do_wild: match() succeeds\n"));
  171. /* remove trailing dot */
  172. fnamestart += strlen(fnamestart) - 1;
  173. if (*fnamestart == '.')
  174. *fnamestart = '\0';
  175. return matchname;
  176. }
  177. }
  178. closedir(wild_dir); /* have read at least one entry; nothing left */
  179. wild_dir = (DIR *)NULL;
  180. notfirstcall = FALSE; /* reset for new wildspec */
  181. if (have_dirname)
  182. free(dirname);
  183. return (char *)NULL;
  184. } /* end function do_wild() */
  185. #endif /* !SFX */
  186. /**********************/
  187. /* Function mapattr() */
  188. /**********************/
  189. int mapattr(__G)
  190. __GDEF
  191. {
  192. /* set archive bit (file is not backed up): */
  193. G.pInfo->file_attr = (unsigned)(G.crec.external_file_attributes & 7) | 32;
  194. return 0;
  195. }
  196. /**********************/
  197. /* Function mapname() */
  198. /**********************/
  199. int mapname(__G__ renamed)
  200. __GDEF
  201. int renamed;
  202. /*
  203. * returns:
  204. * MPN_OK - no problem detected
  205. * MPN_INF_TRUNC - caution (truncated filename)
  206. * MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
  207. * MPN_ERR_SKIP - error -> skip entry
  208. * MPN_ERR_TOOLONG - error -> path is too long
  209. * MPN_NOMEM - error (memory allocation failed) -> skip entry
  210. * [also MPN_VOL_LABEL, MPN_CREATED_DIR]
  211. */
  212. {
  213. char pathcomp[FILNAMSIZ]; /* path-component buffer */
  214. char *pp, *cp=(char *)NULL; /* character pointers */
  215. char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  216. char *last_dot=(char *)NULL; /* last dot not converted to underscore */
  217. int dotname = FALSE; /* path component begins with dot? */
  218. int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
  219. int error = MPN_OK;
  220. register unsigned workch; /* hold the character being tested */
  221. if (G.pInfo->vollabel)
  222. return MPN_VOL_LABEL; /* Cannot set disk volume labels in FlexOS */
  223. /*---------------------------------------------------------------------------
  224. Initialize various pointers and counters and stuff.
  225. ---------------------------------------------------------------------------*/
  226. /* can create path as long as not just freshening, or if user told us */
  227. G.create_dirs = (!uO.fflag || renamed);
  228. created_dir = FALSE; /* not yet */
  229. renamed_fullpath = FALSE;
  230. if (renamed) {
  231. cp = G.filename - 1; /* point to beginning of renamed name... */
  232. while (*++cp)
  233. if (*cp == '\\') /* convert backslashes to forward */
  234. *cp = '/';
  235. cp = G.filename;
  236. /* use temporary rootpath if user gave full pathname */
  237. if (G.filename[0] == '/') {
  238. renamed_fullpath = TRUE;
  239. pathcomp[0] = '/'; /* copy the '/' and terminate */
  240. pathcomp[1] = '\0';
  241. ++cp;
  242. } else if (isalpha((uch)G.filename[0]) && G.filename[1] == ':') {
  243. renamed_fullpath = TRUE;
  244. pp = pathcomp;
  245. *pp++ = *cp++; /* copy the "d:" (+ '/', possibly) */
  246. *pp++ = *cp++;
  247. if (*cp == '/')
  248. *pp++ = *cp++; /* otherwise add "./"? */
  249. *pp = '\0';
  250. }
  251. }
  252. /* pathcomp is ignored unless renamed_fullpath is TRUE: */
  253. if ((error = checkdir(__G__ pathcomp, INIT)) != 0) /* initialize path buf */
  254. return error; /* ...unless no mem or vol label on hard disk */
  255. *pathcomp = '\0'; /* initialize translation buffer */
  256. pp = pathcomp; /* point to translation buffer */
  257. if (!renamed) { /* cp already set if renamed */
  258. if (uO.jflag) /* junking directories */
  259. cp = (char *)strrchr(G.filename, '/');
  260. if (cp == (char *)NULL) /* no '/' or not junking dirs */
  261. cp = G.filename; /* point to internal zipfile-member pathname */
  262. else
  263. ++cp; /* point to start of last component of path */
  264. }
  265. /*---------------------------------------------------------------------------
  266. Begin main loop through characters in filename.
  267. ---------------------------------------------------------------------------*/
  268. while ((workch = (uch)*cp++) != 0) {
  269. switch (workch) {
  270. case '/': /* can assume -j flag not given */
  271. *pp = '\0';
  272. map2fat(pathcomp, last_dot); /* 8.3 truncation (in place) */
  273. last_dot = (char *)NULL;
  274. if (strcmp(pathcomp, ".") == 0) {
  275. /* don't bother appending "./" to the path */
  276. *pathcomp = '\0';
  277. } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
  278. /* "../" dir traversal detected, skip over it */
  279. *pathcomp = '\0';
  280. killed_ddot = TRUE; /* set "show message" flag */
  281. }
  282. /* when path component is not empty, append it now */
  283. if (*pathcomp != '\0' &&
  284. ((error = checkdir(__G__ pathcomp, APPEND_DIR))
  285. & MPN_MASK) > MPN_INF_TRUNC)
  286. return error;
  287. pp = pathcomp; /* reset conversion buffer for next piece */
  288. lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
  289. break;
  290. case '.':
  291. if (pp == pathcomp) { /* nothing appended yet... */
  292. if (*cp == '.' && cp[1] == '/') { /* "../" */
  293. *pp++ = '.'; /* add first dot, unchanged... */
  294. ++cp; /* skip second dot, since it will */
  295. } else { /* be "added" at end of if-block */
  296. *pp++ = '_'; /* FAT doesn't allow null filename */
  297. dotname = TRUE; /* bodies, so map .exrc -> _.exrc */
  298. } /* (extra '_' now, "dot" below) */
  299. } else if (dotname) { /* found a second dot, but still */
  300. dotname = FALSE; /* have extra leading underscore: */
  301. *pp = '\0'; /* remove it by shifting chars */
  302. pp = pathcomp + 1; /* left one space (e.g., .p1.p2: */
  303. while (pp[1]) { /* __p1 -> _p1_p2 -> _p1.p2 when */
  304. *pp = pp[1]; /* finished) [opt.: since first */
  305. ++pp; /* two chars are same, can start */
  306. } /* shifting at second position] */
  307. }
  308. last_dot = pp; /* point at last dot so far... */
  309. *pp++ = '_'; /* convert dot to underscore for now */
  310. break;
  311. /* drive names are not stored in zipfile, so no colons allowed;
  312. * no brackets or most other punctuation either (all of which
  313. * can appear in Unix-created archives; backslash is particularly
  314. * bad unless all necessary directories exist) */
  315. case '[': /* these punctuation characters forbidden */
  316. case ']': /* only on plain FAT file systems */
  317. case '+':
  318. case ',':
  319. case '=':
  320. case ':': /* special shell characters of command.com */
  321. case '\\': /* (device and directory limiters, wildcard */
  322. case '"': /* characters, stdin/stdout redirection and */
  323. case '<': /* pipe indicators and the quote sign) are */
  324. case '>': /* never allowed in filenames on (V)FAT */
  325. case '|':
  326. case '*':
  327. case '?':
  328. *pp++ = '_';
  329. break;
  330. case ';': /* start of VMS version? */
  331. lastsemi = pp;
  332. break;
  333. case ' ': /* change spaces to underscores */
  334. if (uO.sflag) /* only if requested */
  335. *pp++ = '_';
  336. else
  337. *pp++ = (char)workch;
  338. break;
  339. default:
  340. /* allow ASCII 255 and European characters in filenames: */
  341. if (isprint(workch) || workch >= 127)
  342. *pp++ = (char)workch;
  343. } /* end switch */
  344. } /* end while loop */
  345. /* Show warning when stripping insecure "parent dir" path components */
  346. if (killed_ddot && QCOND2) {
  347. Info(slide, 0, ((char *)slide, LoadFarString(WarnDirTraversSkip),
  348. FnFilter1(G.filename)));
  349. if (!(error & ~MPN_MASK))
  350. error = (error & MPN_MASK) | PK_WARN;
  351. }
  352. /*---------------------------------------------------------------------------
  353. Report if directory was created (and no file to create: filename ended
  354. in '/'), check name to be sure it exists, and combine path and name be-
  355. fore exiting.
  356. ---------------------------------------------------------------------------*/
  357. if (G.filename[strlen(G.filename) - 1] == '/') {
  358. checkdir(__G__ G.filename, GETPATH);
  359. if (created_dir) {
  360. if (QCOND2) {
  361. Info(slide, 0, ((char *)slide, LoadFarString(Creating),
  362. FnFilter1(G.filename)));
  363. }
  364. /* set dir time (note trailing '/') */
  365. return (error & ~MPN_MASK) | MPN_CREATED_DIR;
  366. }
  367. /* dir existed already; don't look for data to extract */
  368. return (error & ~MPN_MASK) | MPN_INF_SKIP;
  369. }
  370. *pp = '\0'; /* done with pathcomp: terminate it */
  371. /* if not saving them, remove VMS version numbers (appended ";###") */
  372. if (!uO.V_flag && lastsemi) {
  373. pp = lastsemi; /* semi-colon was omitted: expect all #'s */
  374. while (isdigit((uch)(*pp)))
  375. ++pp;
  376. if (*pp == '\0') /* only digits between ';' and end: nuke */
  377. *lastsemi = '\0';
  378. }
  379. map2fat(pathcomp, last_dot); /* 8.3 truncation (in place) */
  380. if (*pathcomp == '\0') {
  381. Info(slide, 1, ((char *)slide, LoadFarString(ConversionFailed),
  382. FnFilter1(G.filename)));
  383. return (error & ~MPN_MASK) | MPN_ERR_SKIP;
  384. }
  385. checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
  386. checkdir(__G__ G.filename, GETPATH);
  387. return error;
  388. } /* end function mapname() */
  389. /**********************/
  390. /* Function map2fat() */
  391. /**********************/
  392. static void map2fat(pathcomp, last_dot)
  393. char *pathcomp, *last_dot;
  394. {
  395. char *pEnd = pathcomp + strlen(pathcomp);
  396. /*---------------------------------------------------------------------------
  397. Case 1: filename has no dot, so figure out if we should add one. Note
  398. that the algorithm does not try to get too fancy: if there are no dots
  399. already, the name either gets truncated at 8 characters or the last un-
  400. derscore is converted to a dot (only if more characters are saved that
  401. way). In no case is a dot inserted between existing characters.
  402. GRR: have problem if filename is volume label??
  403. ---------------------------------------------------------------------------*/
  404. /* pEnd = pathcomp + strlen(pathcomp); */
  405. if (last_dot == (char *)NULL) { /* no dots: check for underscores... */
  406. char *plu = strrchr(pathcomp, '_'); /* pointer to last underscore */
  407. if (plu == (char *)NULL) { /* no dots, no underscores: truncate at */
  408. if (pEnd > pathcomp+8) /* 8 chars (could insert '.' and keep 11) */
  409. *(pEnd = pathcomp+8) = '\0';
  410. } else if (MIN(plu - pathcomp, 8) + MIN(pEnd - plu - 1, 3) > 8) {
  411. last_dot = plu; /* be lazy: drop through to next if-block */
  412. } else if ((pEnd - pathcomp) > 8) /* more fits into just basename */
  413. pathcomp[8] = '\0'; /* than if convert last underscore to dot */
  414. /* else whole thing fits into 8 chars or less: no change */
  415. }
  416. /*---------------------------------------------------------------------------
  417. Case 2: filename has dot in it, so truncate first half at 8 chars (shift
  418. extension if necessary) and second half at three.
  419. ---------------------------------------------------------------------------*/
  420. if (last_dot != (char *)NULL) { /* one dot (or two, in the case of */
  421. *last_dot = '.'; /* "..") is OK: put it back in */
  422. if ((last_dot - pathcomp) > 8) {
  423. char *p=last_dot, *q=pathcomp+8;
  424. int i;
  425. for (i = 0; (i < 4) && *p; ++i) /* too many chars in basename: */
  426. *q++ = *p++; /* shift extension left and */
  427. *q = '\0'; /* truncate/terminate it */
  428. } else if ((pEnd - last_dot) > 4)
  429. last_dot[4] = '\0'; /* too many chars in extension */
  430. /* else filename is fine as is: no change */
  431. }
  432. } /* end function map2fat() */
  433. /***********************/
  434. /* Function checkdir() */
  435. /***********************/
  436. int checkdir(__G__ pathcomp, flag)
  437. __GDEF
  438. char *pathcomp;
  439. int flag;
  440. /*
  441. * returns:
  442. * MPN_OK - no problem detected
  443. * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
  444. * MPN_INF_SKIP - path doesn't exist, not allowed to create
  445. * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
  446. * exists and is not a directory, but is supposed to be
  447. * MPN_ERR_TOOLONG - path is too long
  448. * MPN_NOMEM - can't allocate memory for filename buffers
  449. */
  450. {
  451. static int rootlen = 0; /* length of rootpath */
  452. static char *rootpath; /* user's "extract-to" directory */
  453. static char *buildpath; /* full path (so far) to extracted file */
  454. static char *end; /* pointer to end of buildpath ('\0') */
  455. # define FN_MASK 7
  456. # define FUNCTION (flag & FN_MASK)
  457. /*---------------------------------------------------------------------------
  458. APPEND_DIR: append the path component to the path being built and check
  459. for its existence. If doesn't exist and we are creating directories, do
  460. so for this one; else signal success or error as appropriate.
  461. ---------------------------------------------------------------------------*/
  462. if (FUNCTION == APPEND_DIR) {
  463. int too_long = FALSE;
  464. Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
  465. while ((*end = *pathcomp++) != '\0')
  466. ++end;
  467. /* GRR: could do better check, see if overrunning buffer as we go:
  468. * check end-buildpath after each append, set warning variable if
  469. * within 20 of FILNAMSIZ; then if var set, do careful check when
  470. * appending. Clear variable when begin new path. */
  471. if ((end-buildpath) > FILNAMSIZ-3) /* need '/', one-char name, '\0' */
  472. too_long = TRUE; /* check if extracting directory? */
  473. if (stat(buildpath, &G.statbuf)) /* path doesn't exist */
  474. {
  475. if (!G.create_dirs) { /* told not to create (freshening) */
  476. free(buildpath);
  477. return MPN_INF_SKIP; /* path doesn't exist: nothing to do */
  478. }
  479. if (too_long) {
  480. Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
  481. FnFilter1(buildpath)));
  482. free(buildpath);
  483. /* no room for filenames: fatal */
  484. return MPN_ERR_TOOLONG;
  485. }
  486. if (mkdir(buildpath, 0777) == -1) { /* create the directory */
  487. Info(slide, 1, ((char *)slide, LoadFarString(CantCreateDir),
  488. FnFilter2(buildpath), FnFilter1(G.filename)));
  489. free(buildpath);
  490. /* path didn't exist, tried to create, failed */
  491. return MPN_ERR_SKIP;
  492. }
  493. created_dir = TRUE;
  494. } else if (!S_ISDIR(G.statbuf.st_mode)) {
  495. Info(slide, 1, ((char *)slide, LoadFarString(DirIsntDirectory),
  496. FnFilter2(buildpath), FnFilter1(G.filename)));
  497. free(buildpath);
  498. /* path existed but wasn't dir */
  499. return MPN_ERR_SKIP;
  500. }
  501. if (too_long) {
  502. Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
  503. FnFilter1(buildpath)));
  504. free(buildpath);
  505. /* no room for filenames: fatal */
  506. return MPN_ERR_TOOLONG;
  507. }
  508. *end++ = '/';
  509. *end = '\0';
  510. Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
  511. return MPN_OK;
  512. } /* end if (FUNCTION == APPEND_DIR) */
  513. /*---------------------------------------------------------------------------
  514. GETPATH: copy full path to the string pointed at by pathcomp, and free
  515. buildpath.
  516. ---------------------------------------------------------------------------*/
  517. if (FUNCTION == GETPATH) {
  518. strcpy(pathcomp, buildpath);
  519. Trace((stderr, "getting and freeing path [%s]\n",
  520. FnFilter1(pathcomp)));
  521. free(buildpath);
  522. buildpath = end = (char *)NULL;
  523. return MPN_OK;
  524. }
  525. /*---------------------------------------------------------------------------
  526. APPEND_NAME: assume the path component is the filename; append it and
  527. return without checking for existence.
  528. ---------------------------------------------------------------------------*/
  529. if (FUNCTION == APPEND_NAME) {
  530. Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
  531. while ((*end = *pathcomp++) != '\0') {
  532. ++end;
  533. if ((end-buildpath) >= FILNAMSIZ) {
  534. *--end = '\0';
  535. Info(slide, 1, ((char *)slide, LoadFarString(PathTooLongTrunc),
  536. FnFilter1(G.filename), FnFilter2(buildpath)));
  537. return MPN_INF_TRUNC; /* filename truncated */
  538. }
  539. }
  540. Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
  541. /* could check for existence here, prompt for new name... */
  542. return MPN_OK;
  543. }
  544. /*---------------------------------------------------------------------------
  545. INIT: allocate and initialize buffer space for the file currently being
  546. extracted. If file was renamed with an absolute path, don't prepend the
  547. extract-to path.
  548. ---------------------------------------------------------------------------*/
  549. if (FUNCTION == INIT) {
  550. Trace((stderr, "initializing buildpath to "));
  551. /* allocate space for full filename, root path, and maybe "./" */
  552. if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+3)) ==
  553. (char *)NULL)
  554. return MPN_NOMEM;
  555. if (renamed_fullpath) { /* pathcomp = valid data */
  556. end = buildpath;
  557. while ((*end = *pathcomp++) != '\0')
  558. ++end;
  559. } else if (rootlen > 0) {
  560. strcpy(buildpath, rootpath);
  561. end = buildpath + rootlen;
  562. } else {
  563. *buildpath = '\0';
  564. end = buildpath;
  565. }
  566. Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
  567. return MPN_OK;
  568. }
  569. /*---------------------------------------------------------------------------
  570. ROOT: if appropriate, store the path in rootpath and create it if neces-
  571. sary; else assume it's a zipfile member and return. This path segment
  572. gets used in extracting all members from every zipfile specified on the
  573. command line. Note that under FlexOS, if a candidate extract-to
  574. directory specification includes a drive letter (leading "x:"), it is
  575. treated just as if it had a trailing '/'--that is, one directory level
  576. will be created if the path doesn't exist, unless this is otherwise pro-
  577. hibited (e.g., freshening).
  578. ---------------------------------------------------------------------------*/
  579. #if (!defined(SFX) || defined(SFX_EXDIR))
  580. if (FUNCTION == ROOT) {
  581. Trace((stderr, "initializing root path to [%s]\n",
  582. FnFilter1(pathcomp)));
  583. if (pathcomp == (char *)NULL) {
  584. rootlen = 0;
  585. return MPN_OK;
  586. }
  587. if (rootlen > 0) /* rootpath was already set, nothing to do */
  588. return MPN_OK;
  589. if ((rootlen = strlen(pathcomp)) > 0) {
  590. int had_trailing_pathsep=FALSE, add_dot=FALSE;
  591. char *tmproot;
  592. if ((tmproot = (char *)malloc(rootlen+3)) == (char *)NULL) {
  593. rootlen = 0;
  594. return MPN_NOMEM;
  595. }
  596. strcpy(tmproot, pathcomp);
  597. if (tmproot[rootlen-1] == '/' || tmproot[rootlen-1] == '\\') {
  598. tmproot[--rootlen] = '\0';
  599. had_trailing_pathsep = TRUE;
  600. }
  601. if (tmproot[rootlen-1] == ':') {
  602. if (!had_trailing_pathsep) /* i.e., original wasn't "xxx:/" */
  603. add_dot = TRUE; /* relative path: add '.' before '/' */
  604. } else if (rootlen > 0) && /* need not check "xxx:." and "xxx:/" */
  605. (SSTAT(tmproot, &G.statbuf) ||
  606. !S_ISDIR(G.statbuf.st_mode))
  607. {
  608. /* path does not exist */
  609. if (!G.create_dirs /* || iswild(tmproot) */ ) {
  610. free(tmproot);
  611. rootlen = 0;
  612. /* treat as stored file */
  613. return MPN_INF_SKIP;
  614. }
  615. /* GRR: scan for wildcard characters? OS-dependent...
  616. * if find any, return MPN_INF_SKIP: treat as stored file(s) */
  617. /* create directory (could add loop here scanning tmproot
  618. * to create more than one level, but really necessary?) */
  619. if (mkdir(tmproot, 0777) == -1) {
  620. Info(slide, 1, ((char *)slide,
  621. LoadFarString(CantCreateExtractDir),
  622. FnFilter1(tmproot)));
  623. free(tmproot);
  624. rootlen = 0;
  625. /* path didn't exist, tried to create, and failed: */
  626. /* file exists, or 2+ subdir levels required */
  627. return MPN_ERR_SKIP;
  628. }
  629. }
  630. if (add_dot) /* had just "x:", make "x:." */
  631. tmproot[rootlen++] = '.';
  632. tmproot[rootlen++] = '/';
  633. tmproot[rootlen] = '\0';
  634. if ((rootpath = (char *)realloc(tmproot, rootlen+1)) == NULL) {
  635. free(tmproot);
  636. rootlen = 0;
  637. return MPN_NOMEM;
  638. }
  639. Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
  640. }
  641. return MPN_OK;
  642. }
  643. #endif /* !SFX || SFX_EXDIR */
  644. /*---------------------------------------------------------------------------
  645. END: free rootpath, immediately prior to program exit.
  646. ---------------------------------------------------------------------------*/
  647. if (FUNCTION == END) {
  648. Trace((stderr, "freeing rootpath\n"));
  649. if (rootlen > 0) {
  650. free(rootpath);
  651. rootlen = 0;
  652. }
  653. return MPN_OK;
  654. }
  655. return MPN_INVALID; /* should never reach */
  656. } /* end function checkdir() */
  657. /****************************/
  658. /* Function close_outfile() */
  659. /****************************/
  660. void close_outfile(__G)
  661. __GDEF
  662. /*
  663. * FlexOS VERSION
  664. *
  665. * Set the output file date/time stamp according to information from the
  666. * zipfile directory record for this member, then close the file and set
  667. * its permissions (archive, hidden, read-only, system). Aside from closing
  668. * the file, this routine is optional (but most compilers support it).
  669. */
  670. {
  671. DISKFILE df;
  672. LONG fnum;
  673. struct { /* date and time words */
  674. union { /* DOS file modification time word */
  675. ush ztime;
  676. struct {
  677. unsigned zt_se : 5;
  678. unsigned zt_mi : 6;
  679. unsigned zt_hr : 5;
  680. } _tf;
  681. } _t;
  682. union { /* DOS file modification date word */
  683. ush zdate;
  684. struct {
  685. unsigned zd_dy : 5;
  686. unsigned zd_mo : 4;
  687. unsigned zd_yr : 7;
  688. } _df;
  689. } _d;
  690. } zt;
  691. #ifdef USE_EF_UT_TIME
  692. iztimes z_utime;
  693. struct tm *t;
  694. #endif /* ?USE_EF_UT_TIME */
  695. fclose(G.outfile);
  696. if ((fnum = s_open(A_SET, G.filename)) < 0) {
  697. Info(slide, 0x201, ((char *)slide,
  698. "warning: cannot open %s to set the time\n",
  699. FnFilter1(G.filename)));
  700. return;
  701. }
  702. if (s_get(T_FILE, fnum, &df, DSKFSIZE) < 0) {
  703. s_close(0, fnum);
  704. Info(slide, 0x201, ((char *)slide,
  705. "warning: cannot get info on %s\n", FnFilter1(G.filename)));
  706. return;
  707. }
  708. /* skip restoring time stamps on user's request */
  709. if (uO.D_flag <= 1) {
  710. /*---------------------------------------------------------------------------
  711. Copy and/or convert time and date variables, if necessary; then fill in
  712. the file time/date.
  713. ---------------------------------------------------------------------------*/
  714. #ifdef USE_EF_UT_TIME
  715. if (G.extra_field &&
  716. #ifdef IZ_CHECK_TZ
  717. G.tz_is_valid &&
  718. #endif
  719. (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
  720. G.lrec.last_mod_dos_datetime, &z_utime, NULL) & EB_UT_FL_MTIME))
  721. {
  722. TTrace((stderr, "close_outfile: Unix e.f. modif. time = %ld\n",
  723. z_utime.mtime));
  724. t = localtime(&(z_utime.mtime));
  725. } else
  726. t = (struct tm *)NULL;
  727. if (t != (struct tm *)NULL) {
  728. if (t->tm_year < 80) {
  729. df.df_modyear = 1980;
  730. df.df_modmonth = 1;
  731. df.df_modday = 1;
  732. df.df_modhr = 0;
  733. df.df_modmin = 0;
  734. df.df_modsec = 0;
  735. } else {
  736. df.df_modyear = t->tm_year + 1900;
  737. df.df_modmonth = t->tm_mon + 1;
  738. df.df_modday = t->tm_mday;
  739. df.df_modhr = t->tm_hour;
  740. df.df_modmin = t->tm_min;
  741. df.df_modsec = t->tm_sec;
  742. }
  743. } else
  744. #endif /* ?USE_EF_UX_TIME */
  745. {
  746. zt._t.ztime = (ush)(G.lrec.last_mod_dos_datetime) & 0xffff;
  747. zt._d.zdate = (ush)(G.lrec.last_mod_dos_datetime >> 16);
  748. df.df_modyear = 1980 + zt._d._df.zd_yr;
  749. df.df_modmonth = zt._d._df.zd_mo;
  750. df.df_modday = zt._d._df.zd_dy;
  751. df.df_modhr = zt._t._tf.zt_hr;
  752. df.df_modmin = zt._t._tf.zt_mi;
  753. df.df_modsec = zt._t._tf.zt_se << 1;
  754. }
  755. }
  756. /*---------------------------------------------------------------------------
  757. Fill in the file attributes.
  758. ---------------------------------------------------------------------------*/
  759. df.df_attr1 = (UBYTE)G.pInfo->file_attr;
  760. /*---------------------------------------------------------------------------
  761. Now we try to set the attributes & date/time.
  762. ---------------------------------------------------------------------------*/
  763. if (s_set(T_FILE, fnum, &df, DSKFSIZE) < 0)
  764. Info(slide, 0x201, ((char *)slide,
  765. "warning: cannot set info for %s\n", FnFilter1(G.filename)));
  766. s_close(0, fnum);
  767. } /* end function close_outfile() */
  768. #ifndef SFX
  769. /*************************/
  770. /* Function dateformat() */
  771. /*************************/
  772. int dateformat()
  773. {
  774. return DF_DMY; /* default for systems without locale info */
  775. }
  776. /************************/
  777. /* Function version() */
  778. /************************/
  779. void version(__G)
  780. __GDEF
  781. {
  782. int len;
  783. len = sprintf((char *)slide, LoadFarString(CompiledWith),
  784. "MetaWare High C",
  785. "",
  786. "FlexOS",
  787. " (16-bit, big)",
  788. #ifdef __DATE__
  789. " on ", __DATE__
  790. #else
  791. "", ""
  792. #endif
  793. );
  794. (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
  795. }
  796. #endif /* !SFX */
  797. /************************/
  798. /* Function _wildarg() */
  799. /************************/
  800. /* This prevents the PORTLIB startup code from preforming argument globbing */
  801. _wildarg() {}