Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

unix.c 61KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876
  1. /*
  2. Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
  3. See the accompanying file LICENSE, version 2009-Jan-02 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. unix.c
  10. Unix-specific routines for use with Info-ZIP's UnZip 5.41 and later.
  11. Contains: readdir()
  12. do_wild() <-- generic enough to put in fileio.c?
  13. mapattr()
  14. mapname()
  15. checkdir()
  16. mkdir()
  17. close_outfile()
  18. defer_dir_attribs()
  19. set_direc_attribs()
  20. stamp_file()
  21. version()
  22. ---------------------------------------------------------------------------*/
  23. #define UNZIP_INTERNAL
  24. #include "unzip.h"
  25. #ifdef SCO_XENIX
  26. # define SYSNDIR
  27. #else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
  28. # if defined(__convexc__) || defined(SYSV) || defined(CRAY) || defined(BSD4_4)
  29. # define DIRENT
  30. # endif
  31. #endif
  32. #if defined(_AIX) || defined(__mpexl)
  33. # define DIRENT
  34. #endif
  35. #ifdef COHERENT
  36. # if defined(_I386) || (defined(__COHERENT__) && (__COHERENT__ >= 0x420))
  37. # define DIRENT
  38. # endif
  39. #endif
  40. #ifdef _POSIX_VERSION
  41. # ifndef DIRENT
  42. # define DIRENT
  43. # endif
  44. #endif
  45. #ifdef DIRENT
  46. # include <dirent.h>
  47. #else
  48. # ifdef SYSV
  49. # ifdef SYSNDIR
  50. # include <sys/ndir.h>
  51. # else
  52. # include <ndir.h>
  53. # endif
  54. # else /* !SYSV */
  55. # ifndef NO_SYSDIR
  56. # include <sys/dir.h>
  57. # endif
  58. # endif /* ?SYSV */
  59. # ifndef dirent
  60. # define dirent direct
  61. # endif
  62. #endif /* ?DIRENT */
  63. #ifdef SET_DIR_ATTRIB
  64. typedef struct uxdirattr { /* struct for holding unix style directory */
  65. struct uxdirattr *next; /* info until can be sorted and set at end */
  66. char *fn; /* filename of directory */
  67. union {
  68. iztimes t3; /* mtime, atime, ctime */
  69. ztimbuf t2; /* modtime, actime */
  70. } u;
  71. unsigned perms; /* same as min_info.file_attr */
  72. int have_uidgid; /* flag */
  73. ulg uidgid[2];
  74. char fnbuf[1]; /* buffer stub for directory name */
  75. } uxdirattr;
  76. #define UxAtt(d) ((uxdirattr *)d) /* typecast shortcut */
  77. #endif /* SET_DIR_ATTRIB */
  78. #ifdef ACORN_FTYPE_NFS
  79. /* Acorn bits for NFS filetyping */
  80. typedef struct {
  81. uch ID[2];
  82. uch size[2];
  83. uch ID_2[4];
  84. uch loadaddr[4];
  85. uch execaddr[4];
  86. uch attr[4];
  87. } RO_extra_block;
  88. #endif /* ACORN_FTYPE_NFS */
  89. /* static int created_dir; */ /* used in mapname(), checkdir() */
  90. /* static int renamed_fullpath; */ /* ditto */
  91. static unsigned filtattr OF((__GPRO__ unsigned perms));
  92. /*****************************/
  93. /* Strings used multiple */
  94. /* times in unix.c */
  95. /*****************************/
  96. #ifndef MTS
  97. /* messages of code for setting file/directory attributes */
  98. static ZCONST char CannotSetItemUidGid[] =
  99. "warning: cannot set UID %lu and/or GID %lu for %s\n %s\n";
  100. static ZCONST char CannotSetUidGid[] =
  101. " (warning) cannot set UID %lu and/or GID %lu\n %s";
  102. static ZCONST char CannotSetItemTimestamps[] =
  103. "warning: cannot set modif./access times for %s\n %s\n";
  104. static ZCONST char CannotSetTimestamps[] =
  105. " (warning) cannot set modif./access times\n %s";
  106. #endif /* !MTS */
  107. #ifndef SFX
  108. #ifdef NO_DIR /* for AT&T 3B1 */
  109. #define opendir(path) fopen(path,"r")
  110. #define closedir(dir) fclose(dir)
  111. typedef FILE DIR;
  112. typedef struct zdir {
  113. FILE *dirhandle;
  114. struct dirent *entry;
  115. } DIR
  116. DIR *opendir OF((ZCONST char *dirspec));
  117. void closedir OF((DIR *dirp));
  118. struct dirent *readdir OF((DIR *dirp));
  119. DIR *opendir(dirspec)
  120. ZCONST char *dirspec;
  121. {
  122. DIR *dirp;
  123. if ((dirp = malloc(sizeof(DIR)) != NULL) {
  124. if ((dirp->dirhandle = fopen(dirspec, "r")) == NULL) {
  125. free(dirp);
  126. dirp = NULL;
  127. }
  128. }
  129. return dirp;
  130. }
  131. void closedir(dirp)
  132. DIR *dirp;
  133. {
  134. fclose(dirp->dirhandle);
  135. free(dirp);
  136. }
  137. /*
  138. * Apparently originally by Rich Salz.
  139. * Cleaned up and modified by James W. Birdsall.
  140. */
  141. struct dirent *readdir(dirp)
  142. DIR *dirp;
  143. {
  144. if (dirp == NULL)
  145. return NULL;
  146. for (;;)
  147. if (fread(&(dirp->entry), sizeof (struct dirent), 1,
  148. dirp->dirhandle) == 0)
  149. return (struct dirent *)NULL;
  150. else if ((dirp->entry).d_ino)
  151. return &(dirp->entry);
  152. } /* end function readdir() */
  153. #endif /* NO_DIR */
  154. /**********************/
  155. /* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */
  156. /**********************/
  157. char *do_wild(__G__ wildspec)
  158. __GDEF
  159. ZCONST char *wildspec; /* only used first time on a given dir */
  160. {
  161. /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in unxcfg.h:
  162. static DIR *wild_dir = (DIR *)NULL;
  163. static ZCONST char *wildname;
  164. static char *dirname, matchname[FILNAMSIZ];
  165. static int notfirstcall=FALSE, have_dirname, dirnamelen;
  166. */
  167. struct dirent *file;
  168. /* Even when we're just returning wildspec, we *always* do so in
  169. * matchname[]--calling routine is allowed to append four characters
  170. * to the returned string, and wildspec may be a pointer to argv[].
  171. */
  172. if (!G.notfirstcall) { /* first call: must initialize everything */
  173. G.notfirstcall = TRUE;
  174. if (!iswild(wildspec)) {
  175. strncpy(G.matchname, wildspec, FILNAMSIZ);
  176. G.matchname[FILNAMSIZ-1] = '\0';
  177. G.have_dirname = FALSE;
  178. G.wild_dir = NULL;
  179. return G.matchname;
  180. }
  181. /* break the wildspec into a directory part and a wildcard filename */
  182. if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL) {
  183. G.dirname = ".";
  184. G.dirnamelen = 1;
  185. G.have_dirname = FALSE;
  186. G.wildname = wildspec;
  187. } else {
  188. ++G.wildname; /* point at character after '/' */
  189. G.dirnamelen = G.wildname - wildspec;
  190. if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == (char *)NULL) {
  191. Info(slide, 0x201, ((char *)slide,
  192. "warning: cannot allocate wildcard buffers\n"));
  193. strncpy(G.matchname, wildspec, FILNAMSIZ);
  194. G.matchname[FILNAMSIZ-1] = '\0';
  195. return G.matchname; /* but maybe filespec was not a wildcard */
  196. }
  197. strncpy(G.dirname, wildspec, G.dirnamelen);
  198. G.dirname[G.dirnamelen] = '\0'; /* terminate for strcpy below */
  199. G.have_dirname = TRUE;
  200. }
  201. if ((G.wild_dir = (zvoid *)opendir(G.dirname)) != (zvoid *)NULL) {
  202. while ((file = readdir((DIR *)G.wild_dir)) !=
  203. (struct dirent *)NULL) {
  204. Trace((stderr, "do_wild: readdir returns %s\n",
  205. FnFilter1(file->d_name)));
  206. if (file->d_name[0] == '.' && G.wildname[0] != '.')
  207. continue; /* Unix: '*' and '?' do not match leading dot */
  208. if (match(file->d_name, G.wildname, 0 WISEP) &&/*0=case sens.*/
  209. /* skip "." and ".." directory entries */
  210. strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
  211. Trace((stderr, "do_wild: match() succeeds\n"));
  212. if (G.have_dirname) {
  213. strcpy(G.matchname, G.dirname);
  214. strcpy(G.matchname+G.dirnamelen, file->d_name);
  215. } else
  216. strcpy(G.matchname, file->d_name);
  217. return G.matchname;
  218. }
  219. }
  220. /* if we get to here directory is exhausted, so close it */
  221. closedir((DIR *)G.wild_dir);
  222. G.wild_dir = (zvoid *)NULL;
  223. }
  224. Trace((stderr, "do_wild: opendir(%s) returns NULL\n",
  225. FnFilter1(G.dirname)));
  226. /* return the raw wildspec in case that works (e.g., directory not
  227. * searchable, but filespec was not wild and file is readable) */
  228. strncpy(G.matchname, wildspec, FILNAMSIZ);
  229. G.matchname[FILNAMSIZ-1] = '\0';
  230. return G.matchname;
  231. }
  232. /* last time through, might have failed opendir but returned raw wildspec */
  233. if ((DIR *)G.wild_dir == (DIR *)NULL) {
  234. G.notfirstcall = FALSE; /* nothing left--reset for new wildspec */
  235. if (G.have_dirname)
  236. free(G.dirname);
  237. return (char *)NULL;
  238. }
  239. /* If we've gotten this far, we've read and matched at least one entry
  240. * successfully (in a previous call), so dirname has been copied into
  241. * matchname already.
  242. */
  243. while ((file = readdir((DIR *)G.wild_dir)) != (struct dirent *)NULL) {
  244. Trace((stderr, "do_wild: readdir returns %s\n",
  245. FnFilter1(file->d_name)));
  246. if (file->d_name[0] == '.' && G.wildname[0] != '.')
  247. continue; /* Unix: '*' and '?' do not match leading dot */
  248. if (match(file->d_name, G.wildname, 0 WISEP)) { /* 0 == case sens. */
  249. Trace((stderr, "do_wild: match() succeeds\n"));
  250. if (G.have_dirname) {
  251. /* strcpy(G.matchname, G.dirname); */
  252. strcpy(G.matchname+G.dirnamelen, file->d_name);
  253. } else
  254. strcpy(G.matchname, file->d_name);
  255. return G.matchname;
  256. }
  257. }
  258. closedir((DIR *)G.wild_dir); /* at least one entry read; nothing left */
  259. G.wild_dir = (zvoid *)NULL;
  260. G.notfirstcall = FALSE; /* reset for new wildspec */
  261. if (G.have_dirname)
  262. free(G.dirname);
  263. return (char *)NULL;
  264. } /* end function do_wild() */
  265. #endif /* !SFX */
  266. #ifndef S_ISUID
  267. # define S_ISUID 0004000 /* set user id on execution */
  268. #endif
  269. #ifndef S_ISGID
  270. # define S_ISGID 0002000 /* set group id on execution */
  271. #endif
  272. #ifndef S_ISVTX
  273. # define S_ISVTX 0001000 /* save swapped text even after use */
  274. #endif
  275. /************************/
  276. /* Function filtattr() */
  277. /************************/
  278. /* This is used to clear or keep the SUID and SGID bits on file permissions.
  279. * It's possible that a file in an archive could have one of these bits set
  280. * and, unknown to the person unzipping, could allow others to execute the
  281. * file as the user or group. The new option -K bypasses this check.
  282. */
  283. static unsigned filtattr(__G__ perms)
  284. __GDEF
  285. unsigned perms;
  286. {
  287. /* keep setuid/setgid/tacky perms? */
  288. if (!uO.K_flag)
  289. perms &= ~(S_ISUID | S_ISGID | S_ISVTX);
  290. return (0xffff & perms);
  291. } /* end function filtattr() */
  292. /**********************/
  293. /* Function mapattr() */
  294. /**********************/
  295. int mapattr(__G)
  296. __GDEF
  297. {
  298. int r;
  299. ulg tmp = G.crec.external_file_attributes;
  300. G.pInfo->file_attr = 0;
  301. /* initialized to 0 for check in "default" branch below... */
  302. switch (G.pInfo->hostnum) {
  303. case AMIGA_:
  304. tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */
  305. G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
  306. break;
  307. case THEOS_:
  308. tmp &= 0xF1FFFFFFL;
  309. if ((tmp & 0xF0000000L) != 0x40000000L)
  310. tmp &= 0x01FFFFFFL; /* not a dir, mask all ftype bits */
  311. else
  312. tmp &= 0x41FFFFFFL; /* leave directory bit as set */
  313. /* fall through! */
  314. case UNIX_:
  315. case VMS_:
  316. case ACORN_:
  317. case ATARI_:
  318. case ATHEOS_:
  319. case BEOS_:
  320. case QDOS_:
  321. case TANDEM_:
  322. r = FALSE;
  323. G.pInfo->file_attr = (unsigned)(tmp >> 16);
  324. if (G.pInfo->file_attr == 0 && G.extra_field) {
  325. /* Some (non-Info-ZIP) implementations of Zip for Unix and
  326. * VMS (and probably others ??) leave 0 in the upper 16-bit
  327. * part of the external_file_attributes field. Instead, they
  328. * store file permission attributes in some extra field.
  329. * As a work-around, we search for the presence of one of
  330. * these extra fields and fall back to the MSDOS compatible
  331. * part of external_file_attributes if one of the known
  332. * e.f. types has been detected.
  333. * Later, we might implement extraction of the permission
  334. * bits from the VMS extra field. But for now, the work-around
  335. * should be sufficient to provide "readable" extracted files.
  336. * (For ASI Unix e.f., an experimental remap of the e.f.
  337. * mode value IS already provided!)
  338. */
  339. ush ebID;
  340. unsigned ebLen;
  341. uch *ef = G.extra_field;
  342. unsigned ef_len = G.crec.extra_field_length;
  343. while (!r && ef_len >= EB_HEADSIZE) {
  344. ebID = makeword(ef);
  345. ebLen = (unsigned)makeword(ef+EB_LEN);
  346. if (ebLen > (ef_len - EB_HEADSIZE))
  347. /* discoverd some e.f. inconsistency! */
  348. break;
  349. switch (ebID) {
  350. case EF_ASIUNIX:
  351. if (ebLen >= (EB_ASI_MODE+2)) {
  352. G.pInfo->file_attr =
  353. (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
  354. /* force stop of loop: */
  355. ef_len = (ebLen + EB_HEADSIZE);
  356. break;
  357. }
  358. /* else: fall through! */
  359. case EF_PKVMS:
  360. /* "found nondecypherable e.f. with perm. attr" */
  361. r = TRUE;
  362. default:
  363. break;
  364. }
  365. ef_len -= (ebLen + EB_HEADSIZE);
  366. ef += (ebLen + EB_HEADSIZE);
  367. }
  368. }
  369. if (!r) {
  370. #ifdef SYMLINKS
  371. /* Check if the file is a (POSIX-compatible) symbolic link.
  372. * We restrict symlink support to those "made-by" hosts that
  373. * are known to support symbolic links.
  374. */
  375. G.pInfo->symlink = S_ISLNK(G.pInfo->file_attr) &&
  376. SYMLINK_HOST(G.pInfo->hostnum);
  377. #endif
  378. return 0;
  379. }
  380. /* fall through! */
  381. /* all remaining cases: expand MSDOS read-only bit into write perms */
  382. case FS_FAT_:
  383. /* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the
  384. * Unix attributes in the upper 16 bits of the external attributes
  385. * field, just like Info-ZIP's Zip for Unix. We try to use that
  386. * value, after a check for consistency with the MSDOS attribute
  387. * bits (see below).
  388. */
  389. G.pInfo->file_attr = (unsigned)(tmp >> 16);
  390. /* fall through! */
  391. case FS_HPFS_:
  392. case FS_NTFS_:
  393. case MAC_:
  394. case TOPS20_:
  395. default:
  396. /* Ensure that DOS subdir bit is set when the entry's name ends
  397. * in a '/'. Some third-party Zip programs fail to set the subdir
  398. * bit for directory entries.
  399. */
  400. if ((tmp & 0x10) == 0) {
  401. extent fnlen = strlen(G.filename);
  402. if (fnlen > 0 && G.filename[fnlen-1] == '/')
  403. tmp |= 0x10;
  404. }
  405. /* read-only bit --> write perms; subdir bit --> dir exec bit */
  406. tmp = !(tmp & 1) << 1 | (tmp & 0x10) >> 4;
  407. if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6)) {
  408. /* keep previous G.pInfo->file_attr setting, when its "owner"
  409. * part appears to be consistent with DOS attribute flags!
  410. */
  411. #ifdef SYMLINKS
  412. /* Entries "made by FS_FAT_" could have been zipped on a
  413. * system that supports POSIX-style symbolic links.
  414. */
  415. G.pInfo->symlink = S_ISLNK(G.pInfo->file_attr) &&
  416. (G.pInfo->hostnum == FS_FAT_);
  417. #endif
  418. return 0;
  419. }
  420. G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
  421. break;
  422. } /* end switch (host-OS-created-by) */
  423. /* for originating systems with no concept of "group," "other," "system": */
  424. umask( (int)(tmp=umask(0)) ); /* apply mask to expanded r/w(/x) perms */
  425. G.pInfo->file_attr &= ~tmp;
  426. return 0;
  427. } /* end function mapattr() */
  428. /************************/
  429. /* Function mapname() */
  430. /************************/
  431. int mapname(__G__ renamed)
  432. __GDEF
  433. int renamed;
  434. /*
  435. * returns:
  436. * MPN_OK - no problem detected
  437. * MPN_INF_TRUNC - caution (truncated filename)
  438. * MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
  439. * MPN_ERR_SKIP - error -> skip entry
  440. * MPN_ERR_TOOLONG - error -> path is too long
  441. * MPN_NOMEM - error (memory allocation failed) -> skip entry
  442. * [also MPN_VOL_LABEL, MPN_CREATED_DIR]
  443. */
  444. {
  445. char pathcomp[FILNAMSIZ]; /* path-component buffer */
  446. char *pp, *cp=(char *)NULL; /* character pointers */
  447. char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  448. #ifdef ACORN_FTYPE_NFS
  449. char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */
  450. RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */
  451. #endif
  452. int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
  453. int error = MPN_OK;
  454. register unsigned workch; /* hold the character being tested */
  455. /*---------------------------------------------------------------------------
  456. Initialize various pointers and counters and stuff.
  457. ---------------------------------------------------------------------------*/
  458. if (G.pInfo->vollabel)
  459. return MPN_VOL_LABEL; /* can't set disk volume labels in Unix */
  460. /* can create path as long as not just freshening, or if user told us */
  461. G.create_dirs = (!uO.fflag || renamed);
  462. G.created_dir = FALSE; /* not yet */
  463. /* user gave full pathname: don't prepend rootpath */
  464. G.renamed_fullpath = (renamed && (*G.filename == '/'));
  465. if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
  466. return MPN_NOMEM; /* initialize path buffer, unless no memory */
  467. *pathcomp = '\0'; /* initialize translation buffer */
  468. pp = pathcomp; /* point to translation buffer */
  469. if (uO.jflag) /* junking directories */
  470. cp = (char *)strrchr(G.filename, '/');
  471. if (cp == (char *)NULL) /* no '/' or not junking dirs */
  472. cp = G.filename; /* point to internal zipfile-member pathname */
  473. else
  474. ++cp; /* point to start of last component of path */
  475. /*---------------------------------------------------------------------------
  476. Begin main loop through characters in filename.
  477. ---------------------------------------------------------------------------*/
  478. while ((workch = (uch)*cp++) != 0) {
  479. switch (workch) {
  480. case '/': /* can assume -j flag not given */
  481. *pp = '\0';
  482. if (strcmp(pathcomp, ".") == 0) {
  483. /* don't bother appending "./" to the path */
  484. *pathcomp = '\0';
  485. } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
  486. /* "../" dir traversal detected, skip over it */
  487. *pathcomp = '\0';
  488. killed_ddot = TRUE; /* set "show message" flag */
  489. }
  490. /* when path component is not empty, append it now */
  491. if (*pathcomp != '\0' &&
  492. ((error = checkdir(__G__ pathcomp, APPEND_DIR))
  493. & MPN_MASK) > MPN_INF_TRUNC)
  494. return error;
  495. pp = pathcomp; /* reset conversion buffer for next piece */
  496. lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
  497. break;
  498. #ifdef __CYGWIN__ /* Cygwin runs on Win32, apply FAT/NTFS filename rules */
  499. case ':': /* drive spec not stored, so no colon allowed */
  500. case '\\': /* '\\' may come as normal filename char (not */
  501. case '<': /* dir sep char!) from unix-like file system */
  502. case '>': /* no redirection symbols allowed either */
  503. case '|': /* no pipe signs allowed */
  504. case '"': /* no double quotes allowed */
  505. case '?': /* no wildcards allowed */
  506. case '*':
  507. *pp++ = '_'; /* these rules apply equally to FAT and NTFS */
  508. break;
  509. #endif
  510. case ';': /* VMS version (or DEC-20 attrib?) */
  511. lastsemi = pp;
  512. *pp++ = ';'; /* keep for now; remove VMS ";##" */
  513. break; /* later, if requested */
  514. #ifdef ACORN_FTYPE_NFS
  515. case ',': /* NFS filetype extension */
  516. lastcomma = pp;
  517. *pp++ = ','; /* keep for now; may need to remove */
  518. break; /* later, if requested */
  519. #endif
  520. #ifdef MTS
  521. case ' ': /* change spaces to underscore under */
  522. *pp++ = '_'; /* MTS; leave as spaces under Unix */
  523. break;
  524. #endif
  525. default:
  526. /* disable control character filter when requested,
  527. * else allow 8-bit characters (e.g. UTF-8) in filenames:
  528. */
  529. if (uO.cflxflag ||
  530. (isprint(workch) || (128 <= workch && workch <= 254)))
  531. *pp++ = (char)workch;
  532. } /* end switch */
  533. } /* end while loop */
  534. /* Show warning when stripping insecure "parent dir" path components */
  535. if (killed_ddot && QCOND2) {
  536. Info(slide, 0, ((char *)slide,
  537. "warning: skipped \"../\" path component(s) in %s\n",
  538. FnFilter1(G.filename)));
  539. if (!(error & ~MPN_MASK))
  540. error = (error & MPN_MASK) | PK_WARN;
  541. }
  542. /*---------------------------------------------------------------------------
  543. Report if directory was created (and no file to create: filename ended
  544. in '/'), check name to be sure it exists, and combine path and name be-
  545. fore exiting.
  546. ---------------------------------------------------------------------------*/
  547. if (G.filename[strlen(G.filename) - 1] == '/') {
  548. checkdir(__G__ G.filename, GETPATH);
  549. if (G.created_dir) {
  550. if (QCOND2) {
  551. Info(slide, 0, ((char *)slide, " creating: %s\n",
  552. FnFilter1(G.filename)));
  553. }
  554. #ifndef NO_CHMOD
  555. /* Filter out security-relevant attributes bits. */
  556. G.pInfo->file_attr = filtattr(__G__ G.pInfo->file_attr);
  557. /* When extracting non-UNIX directories or when extracting
  558. * without UID/GID restoration or SGID preservation, any
  559. * SGID flag inherited from the parent directory should be
  560. * maintained to allow files extracted into this new folder
  561. * to inherit the GID setting from the parent directory.
  562. */
  563. if (G.pInfo->hostnum != UNIX_ || !(uO.X_flag || uO.K_flag)) {
  564. /* preserve SGID bit when inherited from parent dir */
  565. if (!SSTAT(G.filename, &G.statbuf)) {
  566. G.pInfo->file_attr |= G.statbuf.st_mode & S_ISGID;
  567. } else {
  568. perror("Could not read directory attributes");
  569. }
  570. }
  571. /* set approx. dir perms (make sure can still read/write in dir) */
  572. if (chmod(G.filename, G.pInfo->file_attr | 0700))
  573. perror("chmod (directory attributes) error");
  574. #endif
  575. /* set dir time (note trailing '/') */
  576. return (error & ~MPN_MASK) | MPN_CREATED_DIR;
  577. }
  578. /* dir existed already; don't look for data to extract */
  579. return (error & ~MPN_MASK) | MPN_INF_SKIP;
  580. }
  581. *pp = '\0'; /* done with pathcomp: terminate it */
  582. /* if not saving them, remove VMS version numbers (appended ";###") */
  583. if (!uO.V_flag && lastsemi) {
  584. pp = lastsemi + 1;
  585. while (isdigit((uch)(*pp)))
  586. ++pp;
  587. if (*pp == '\0') /* only digits between ';' and end: nuke */
  588. *lastsemi = '\0';
  589. }
  590. /* On UNIX (and compatible systems), "." and ".." are reserved for
  591. * directory navigation and cannot be used as regular file names.
  592. * These reserved one-dot and two-dot names are mapped to "_" and "__".
  593. */
  594. if (strcmp(pathcomp, ".") == 0)
  595. *pathcomp = '_';
  596. else if (strcmp(pathcomp, "..") == 0)
  597. strcpy(pathcomp, "__");
  598. #ifdef ACORN_FTYPE_NFS
  599. /* translate Acorn filetype information if asked to do so */
  600. if (uO.acorn_nfs_ext &&
  601. (ef_spark = (RO_extra_block *)
  602. getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
  603. != (RO_extra_block *)NULL)
  604. {
  605. /* file *must* have a RISC OS extra field */
  606. long ft = (long)makelong(ef_spark->loadaddr);
  607. /*32-bit*/
  608. if (lastcomma) {
  609. pp = lastcomma + 1;
  610. while (isxdigit((uch)(*pp))) ++pp;
  611. if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
  612. }
  613. if ((ft & 1<<31)==0) ft=0x000FFD00;
  614. sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
  615. }
  616. #endif /* ACORN_FTYPE_NFS */
  617. if (*pathcomp == '\0') {
  618. Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
  619. FnFilter1(G.filename)));
  620. return (error & ~MPN_MASK) | MPN_ERR_SKIP;
  621. }
  622. checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
  623. checkdir(__G__ G.filename, GETPATH);
  624. return error;
  625. } /* end function mapname() */
  626. #if 0 /*========== NOTES ==========*/
  627. extract-to dir: a:path/
  628. buildpath: path1/path2/ ... (NULL-terminated)
  629. pathcomp: filename
  630. mapname():
  631. loop over chars in zipfile member name
  632. checkdir(path component, COMPONENT | CREATEDIR) --> map as required?
  633. (d:/tmp/unzip/) (disk:[tmp.unzip.)
  634. (d:/tmp/unzip/jj/) (disk:[tmp.unzip.jj.)
  635. (d:/tmp/unzip/jj/temp/) (disk:[tmp.unzip.jj.temp.)
  636. finally add filename itself and check for existence? (could use with rename)
  637. (d:/tmp/unzip/jj/temp/msg.outdir) (disk:[tmp.unzip.jj.temp]msg.outdir)
  638. checkdir(name, GETPATH) --> copy path to name and free space
  639. #endif /* 0 */
  640. /***********************/
  641. /* Function checkdir() */
  642. /***********************/
  643. int checkdir(__G__ pathcomp, flag)
  644. __GDEF
  645. char *pathcomp;
  646. int flag;
  647. /*
  648. * returns:
  649. * MPN_OK - no problem detected
  650. * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
  651. * MPN_INF_SKIP - path doesn't exist, not allowed to create
  652. * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
  653. * exists and is not a directory, but is supposed to be
  654. * MPN_ERR_TOOLONG - path is too long
  655. * MPN_NOMEM - can't allocate memory for filename buffers
  656. */
  657. {
  658. /* static int rootlen = 0; */ /* length of rootpath */
  659. /* static char *rootpath; */ /* user's "extract-to" directory */
  660. /* static char *buildpath; */ /* full path (so far) to extracted file */
  661. /* static char *end; */ /* pointer to end of buildpath ('\0') */
  662. # define FN_MASK 7
  663. # define FUNCTION (flag & FN_MASK)
  664. /*---------------------------------------------------------------------------
  665. APPEND_DIR: append the path component to the path being built and check
  666. for its existence. If doesn't exist and we are creating directories, do
  667. so for this one; else signal success or error as appropriate.
  668. ---------------------------------------------------------------------------*/
  669. if (FUNCTION == APPEND_DIR) {
  670. int too_long = FALSE;
  671. #ifdef SHORT_NAMES
  672. char *old_end = end;
  673. #endif
  674. Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
  675. while ((*G.end = *pathcomp++) != '\0')
  676. ++G.end;
  677. #ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */
  678. if ((G.end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
  679. *(G.end = old_end + FILENAME_MAX) = '\0';
  680. #endif
  681. /* GRR: could do better check, see if overrunning buffer as we go:
  682. * check end-buildpath after each append, set warning variable if
  683. * within 20 of FILNAMSIZ; then if var set, do careful check when
  684. * appending. Clear variable when begin new path. */
  685. /* next check: need to append '/', at least one-char name, '\0' */
  686. if ((G.end-G.buildpath) > FILNAMSIZ-3)
  687. too_long = TRUE; /* check if extracting dir? */
  688. if (SSTAT(G.buildpath, &G.statbuf)) { /* path doesn't exist */
  689. if (!G.create_dirs) { /* told not to create (freshening) */
  690. free(G.buildpath);
  691. return MPN_INF_SKIP; /* path doesn't exist: nothing to do */
  692. }
  693. if (too_long) {
  694. Info(slide, 1, ((char *)slide,
  695. "checkdir error: path too long: %s\n",
  696. FnFilter1(G.buildpath)));
  697. free(G.buildpath);
  698. /* no room for filenames: fatal */
  699. return MPN_ERR_TOOLONG;
  700. }
  701. if (mkdir(G.buildpath, 0777) == -1) { /* create the directory */
  702. Info(slide, 1, ((char *)slide,
  703. "checkdir error: cannot create %s\n\
  704. %s\n\
  705. unable to process %s.\n",
  706. FnFilter2(G.buildpath),
  707. strerror(errno),
  708. FnFilter1(G.filename)));
  709. free(G.buildpath);
  710. /* path didn't exist, tried to create, failed */
  711. return MPN_ERR_SKIP;
  712. }
  713. G.created_dir = TRUE;
  714. } else if (!S_ISDIR(G.statbuf.st_mode)) {
  715. Info(slide, 1, ((char *)slide,
  716. "checkdir error: %s exists but is not directory\n\
  717. unable to process %s.\n",
  718. FnFilter2(G.buildpath), FnFilter1(G.filename)));
  719. free(G.buildpath);
  720. /* path existed but wasn't dir */
  721. return MPN_ERR_SKIP;
  722. }
  723. if (too_long) {
  724. Info(slide, 1, ((char *)slide,
  725. "checkdir error: path too long: %s\n", FnFilter1(G.buildpath)));
  726. free(G.buildpath);
  727. /* no room for filenames: fatal */
  728. return MPN_ERR_TOOLONG;
  729. }
  730. *G.end++ = '/';
  731. *G.end = '\0';
  732. Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
  733. return MPN_OK;
  734. } /* end if (FUNCTION == APPEND_DIR) */
  735. /*---------------------------------------------------------------------------
  736. GETPATH: copy full path to the string pointed at by pathcomp, and free
  737. G.buildpath.
  738. ---------------------------------------------------------------------------*/
  739. if (FUNCTION == GETPATH) {
  740. strcpy(pathcomp, G.buildpath);
  741. Trace((stderr, "getting and freeing path [%s]\n",
  742. FnFilter1(pathcomp)));
  743. free(G.buildpath);
  744. G.buildpath = G.end = (char *)NULL;
  745. return MPN_OK;
  746. }
  747. /*---------------------------------------------------------------------------
  748. APPEND_NAME: assume the path component is the filename; append it and
  749. return without checking for existence.
  750. ---------------------------------------------------------------------------*/
  751. if (FUNCTION == APPEND_NAME) {
  752. #ifdef SHORT_NAMES
  753. char *old_end = end;
  754. #endif
  755. Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
  756. while ((*G.end = *pathcomp++) != '\0') {
  757. ++G.end;
  758. #ifdef SHORT_NAMES /* truncate name at 14 characters, typically */
  759. if ((G.end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
  760. *(G.end = old_end + FILENAME_MAX) = '\0';
  761. #endif
  762. if ((G.end-G.buildpath) >= FILNAMSIZ) {
  763. *--G.end = '\0';
  764. Info(slide, 0x201, ((char *)slide,
  765. "checkdir warning: path too long; truncating\n\
  766. %s\n -> %s\n",
  767. FnFilter1(G.filename), FnFilter2(G.buildpath)));
  768. return MPN_INF_TRUNC; /* filename truncated */
  769. }
  770. }
  771. Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
  772. /* could check for existence here, prompt for new name... */
  773. return MPN_OK;
  774. }
  775. /*---------------------------------------------------------------------------
  776. INIT: allocate and initialize buffer space for the file currently being
  777. extracted. If file was renamed with an absolute path, don't prepend the
  778. extract-to path.
  779. ---------------------------------------------------------------------------*/
  780. /* GRR: for VMS and TOPS-20, add up to 13 to strlen */
  781. if (FUNCTION == INIT) {
  782. Trace((stderr, "initializing buildpath to "));
  783. #ifdef ACORN_FTYPE_NFS
  784. if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+
  785. (uO.acorn_nfs_ext ? 5 : 1)))
  786. #else
  787. if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1))
  788. #endif
  789. == (char *)NULL)
  790. return MPN_NOMEM;
  791. if ((G.rootlen > 0) && !G.renamed_fullpath) {
  792. strcpy(G.buildpath, G.rootpath);
  793. G.end = G.buildpath + G.rootlen;
  794. } else {
  795. *G.buildpath = '\0';
  796. G.end = G.buildpath;
  797. }
  798. Trace((stderr, "[%s]\n", FnFilter1(G.buildpath)));
  799. return MPN_OK;
  800. }
  801. /*---------------------------------------------------------------------------
  802. ROOT: if appropriate, store the path in rootpath and create it if
  803. necessary; else assume it's a zipfile member and return. This path
  804. segment gets used in extracting all members from every zipfile specified
  805. on the command line.
  806. ---------------------------------------------------------------------------*/
  807. #if (!defined(SFX) || defined(SFX_EXDIR))
  808. if (FUNCTION == ROOT) {
  809. Trace((stderr, "initializing root path to [%s]\n",
  810. FnFilter1(pathcomp)));
  811. if (pathcomp == (char *)NULL) {
  812. G.rootlen = 0;
  813. return MPN_OK;
  814. }
  815. if (G.rootlen > 0) /* rootpath was already set, nothing to do */
  816. return MPN_OK;
  817. if ((G.rootlen = strlen(pathcomp)) > 0) {
  818. char *tmproot;
  819. if ((tmproot = (char *)malloc(G.rootlen+2)) == (char *)NULL) {
  820. G.rootlen = 0;
  821. return MPN_NOMEM;
  822. }
  823. strcpy(tmproot, pathcomp);
  824. if (tmproot[G.rootlen-1] == '/') {
  825. tmproot[--G.rootlen] = '\0';
  826. }
  827. if (G.rootlen > 0 && (SSTAT(tmproot, &G.statbuf) ||
  828. !S_ISDIR(G.statbuf.st_mode)))
  829. { /* path does not exist */
  830. if (!G.create_dirs /* || iswild(tmproot) */ ) {
  831. free(tmproot);
  832. G.rootlen = 0;
  833. /* skip (or treat as stored file) */
  834. return MPN_INF_SKIP;
  835. }
  836. /* create the directory (could add loop here scanning tmproot
  837. * to create more than one level, but why really necessary?) */
  838. if (mkdir(tmproot, 0777) == -1) {
  839. Info(slide, 1, ((char *)slide,
  840. "checkdir: cannot create extraction directory: %s\n\
  841. %s\n",
  842. FnFilter1(tmproot), strerror(errno)));
  843. free(tmproot);
  844. G.rootlen = 0;
  845. /* path didn't exist, tried to create, and failed: */
  846. /* file exists, or 2+ subdir levels required */
  847. return MPN_ERR_SKIP;
  848. }
  849. }
  850. tmproot[G.rootlen++] = '/';
  851. tmproot[G.rootlen] = '\0';
  852. if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
  853. free(tmproot);
  854. G.rootlen = 0;
  855. return MPN_NOMEM;
  856. }
  857. Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
  858. }
  859. return MPN_OK;
  860. }
  861. #endif /* !SFX || SFX_EXDIR */
  862. /*---------------------------------------------------------------------------
  863. END: free rootpath, immediately prior to program exit.
  864. ---------------------------------------------------------------------------*/
  865. if (FUNCTION == END) {
  866. Trace((stderr, "freeing rootpath\n"));
  867. if (G.rootlen > 0) {
  868. free(G.rootpath);
  869. G.rootlen = 0;
  870. }
  871. return MPN_OK;
  872. }
  873. return MPN_INVALID; /* should never reach */
  874. } /* end function checkdir() */
  875. #ifdef NO_MKDIR
  876. /********************/
  877. /* Function mkdir() */
  878. /********************/
  879. int mkdir(path, mode)
  880. ZCONST char *path;
  881. int mode; /* ignored */
  882. /*
  883. * returns: 0 - successful
  884. * -1 - failed (errno not set, however)
  885. */
  886. {
  887. char command[FILNAMSIZ+40]; /* buffer for system() call */
  888. /* GRR 930416: added single quotes around path to avoid bug with
  889. * creating directories with ampersands in name; not yet tested */
  890. sprintf(command, "IFS=\" \t\n\" /bin/mkdir '%s' 2>/dev/null", path);
  891. if (system(command))
  892. return -1;
  893. return 0;
  894. }
  895. #endif /* NO_MKDIR */
  896. #if (!defined(MTS) || defined(SET_DIR_ATTRIB))
  897. static int get_extattribs OF((__GPRO__ iztimes *pzt, ulg z_uidgid[2]));
  898. static int get_extattribs(__G__ pzt, z_uidgid)
  899. __GDEF
  900. iztimes *pzt;
  901. ulg z_uidgid[2];
  902. {
  903. /*---------------------------------------------------------------------------
  904. Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
  905. time: adjust base year from 1980 to 1970, do usual conversions from
  906. yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
  907. light savings time differences. If we have a Unix extra field, however,
  908. we're laughing: both mtime and atime are ours. On the other hand, we
  909. then have to check for restoration of UID/GID.
  910. ---------------------------------------------------------------------------*/
  911. int have_uidgid_flg;
  912. unsigned eb_izux_flg;
  913. eb_izux_flg = (G.extra_field ? ef_scan_for_izux(G.extra_field,
  914. G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
  915. #ifdef IZ_CHECK_TZ
  916. (G.tz_is_valid ? pzt : NULL),
  917. #else
  918. pzt,
  919. #endif
  920. z_uidgid) : 0);
  921. if (eb_izux_flg & EB_UT_FL_MTIME) {
  922. TTrace((stderr, "\nget_extattribs: Unix e.f. modif. time = %ld\n",
  923. pzt->mtime));
  924. } else {
  925. pzt->mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  926. }
  927. if (eb_izux_flg & EB_UT_FL_ATIME) {
  928. TTrace((stderr, "get_extattribs: Unix e.f. access time = %ld\n",
  929. pzt->atime));
  930. } else {
  931. pzt->atime = pzt->mtime;
  932. TTrace((stderr, "\nget_extattribs: modification/access times = %ld\n",
  933. pzt->mtime));
  934. }
  935. /* if -X option was specified and we have UID/GID info, restore it */
  936. have_uidgid_flg =
  937. #ifdef RESTORE_UIDGID
  938. (uO.X_flag && (eb_izux_flg & EB_UX2_VALID));
  939. #else
  940. 0;
  941. #endif
  942. return have_uidgid_flg;
  943. }
  944. #endif /* !MTS || SET_DIR_ATTRIB */
  945. #ifndef MTS
  946. /****************************/
  947. /* Function close_outfile() */
  948. /****************************/
  949. void close_outfile(__G) /* GRR: change to return PK-style warning level */
  950. __GDEF
  951. {
  952. union {
  953. iztimes t3; /* mtime, atime, ctime */
  954. ztimbuf t2; /* modtime, actime */
  955. } zt;
  956. ulg z_uidgid[2];
  957. int have_uidgid_flg;
  958. have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid);
  959. /*---------------------------------------------------------------------------
  960. If symbolic links are supported, allocate storage for a symlink control
  961. structure, put the uncompressed "data" and other required info in it, and
  962. add the structure to the "deferred symlinks" chain. Since we know it's a
  963. symbolic link to start with, we shouldn't have to worry about overflowing
  964. unsigned ints with unsigned longs.
  965. ---------------------------------------------------------------------------*/
  966. #ifdef SYMLINKS
  967. if (G.symlnk) {
  968. extent ucsize = (extent)G.lrec.ucsize;
  969. # ifdef SET_SYMLINK_ATTRIBS
  970. extent attribsize = sizeof(unsigned) +
  971. (have_uidgid_flg ? sizeof(z_uidgid) : 0);
  972. # else
  973. extent attribsize = 0;
  974. # endif
  975. /* size of the symlink entry is the sum of
  976. * (struct size (includes 1st '\0') + 1 additional trailing '\0'),
  977. * system specific attribute data size (might be 0),
  978. * and the lengths of name and link target.
  979. */
  980. extent slnk_entrysize = (sizeof(slinkentry) + 1) + attribsize +
  981. ucsize + strlen(G.filename);
  982. slinkentry *slnk_entry;
  983. if (slnk_entrysize < ucsize) {
  984. Info(slide, 0x201, ((char *)slide,
  985. "warning: symbolic link (%s) failed: mem alloc overflow\n",
  986. FnFilter1(G.filename)));
  987. fclose(G.outfile);
  988. return;
  989. }
  990. if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) {
  991. Info(slide, 0x201, ((char *)slide,
  992. "warning: symbolic link (%s) failed: no mem\n",
  993. FnFilter1(G.filename)));
  994. fclose(G.outfile);
  995. return;
  996. }
  997. slnk_entry->next = NULL;
  998. slnk_entry->targetlen = ucsize;
  999. slnk_entry->attriblen = attribsize;
  1000. # ifdef SET_SYMLINK_ATTRIBS
  1001. memcpy(slnk_entry->buf, &(G.pInfo->file_attr),
  1002. sizeof(unsigned));
  1003. if (have_uidgid_flg)
  1004. memcpy(slnk_entry->buf + 4, z_uidgid, sizeof(z_uidgid));
  1005. # endif
  1006. slnk_entry->target = slnk_entry->buf + slnk_entry->attriblen;
  1007. slnk_entry->fname = slnk_entry->target + ucsize + 1;
  1008. strcpy(slnk_entry->fname, G.filename);
  1009. /* move back to the start of the file to re-read the "link data" */
  1010. rewind(G.outfile);
  1011. if (fread(slnk_entry->target, 1, ucsize, G.outfile) != ucsize)
  1012. {
  1013. Info(slide, 0x201, ((char *)slide,
  1014. "warning: symbolic link (%s) failed\n",
  1015. FnFilter1(G.filename)));
  1016. free(slnk_entry);
  1017. fclose(G.outfile);
  1018. return;
  1019. }
  1020. fclose(G.outfile); /* close "link" file for good... */
  1021. slnk_entry->target[ucsize] = '\0';
  1022. if (QCOND2)
  1023. Info(slide, 0, ((char *)slide, "-> %s ",
  1024. FnFilter1(slnk_entry->target)));
  1025. /* add this symlink record to the list of deferred symlinks */
  1026. if (G.slink_last != NULL)
  1027. G.slink_last->next = slnk_entry;
  1028. else
  1029. G.slink_head = slnk_entry;
  1030. G.slink_last = slnk_entry;
  1031. return;
  1032. }
  1033. #endif /* SYMLINKS */
  1034. #ifdef QLZIP
  1035. if (G.extra_field) {
  1036. static void qlfix OF((__GPRO__ uch *ef_ptr, unsigned ef_len));
  1037. qlfix(__G__ G.extra_field, G.lrec.extra_field_length);
  1038. }
  1039. #endif
  1040. #if (defined(NO_FCHOWN))
  1041. fclose(G.outfile);
  1042. #endif
  1043. /* if -X option was specified and we have UID/GID info, restore it */
  1044. if (have_uidgid_flg
  1045. /* check that both uid and gid values fit into their data sizes */
  1046. && ((ulg)(uid_t)(z_uidgid[0]) == z_uidgid[0])
  1047. && ((ulg)(gid_t)(z_uidgid[1]) == z_uidgid[1])) {
  1048. TTrace((stderr, "close_outfile: restoring Unix UID/GID info\n"));
  1049. #if (defined(NO_FCHOWN))
  1050. if (chown(G.filename, (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
  1051. #else
  1052. if (fchown(fileno(G.outfile), (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
  1053. #endif
  1054. {
  1055. if (uO.qflag)
  1056. Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
  1057. z_uidgid[0], z_uidgid[1], FnFilter1(G.filename),
  1058. strerror(errno)));
  1059. else
  1060. Info(slide, 0x201, ((char *)slide, CannotSetUidGid,
  1061. z_uidgid[0], z_uidgid[1], strerror(errno)));
  1062. }
  1063. }
  1064. #if (!defined(NO_FCHOWN) && defined(NO_FCHMOD))
  1065. fclose(G.outfile);
  1066. #endif
  1067. #if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD))
  1068. /*---------------------------------------------------------------------------
  1069. Change the file permissions from default ones to those stored in the
  1070. zipfile.
  1071. ---------------------------------------------------------------------------*/
  1072. if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr)))
  1073. perror("fchmod (file attributes) error");
  1074. fclose(G.outfile);
  1075. #endif /* !NO_FCHOWN && !NO_FCHMOD */
  1076. /* skip restoring time stamps on user's request */
  1077. if (uO.D_flag <= 1) {
  1078. /* set the file's access and modification times */
  1079. if (utime(G.filename, &(zt.t2))) {
  1080. if (uO.qflag)
  1081. Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps,
  1082. FnFilter1(G.filename), strerror(errno)));
  1083. else
  1084. Info(slide, 0x201, ((char *)slide, CannotSetTimestamps,
  1085. strerror(errno)));
  1086. }
  1087. }
  1088. #if (defined(NO_FCHOWN) || defined(NO_FCHMOD))
  1089. /*---------------------------------------------------------------------------
  1090. Change the file permissions from default ones to those stored in the
  1091. zipfile.
  1092. ---------------------------------------------------------------------------*/
  1093. #ifndef NO_CHMOD
  1094. if (chmod(G.filename, filtattr(__G__ G.pInfo->file_attr)))
  1095. perror("chmod (file attributes) error");
  1096. #endif
  1097. #endif /* NO_FCHOWN || NO_FCHMOD */
  1098. } /* end function close_outfile() */
  1099. #endif /* !MTS */
  1100. #if (defined(SYMLINKS) && defined(SET_SYMLINK_ATTRIBS))
  1101. int set_symlnk_attribs(__G__ slnk_entry)
  1102. __GDEF
  1103. slinkentry *slnk_entry;
  1104. {
  1105. if (slnk_entry->attriblen > 0) {
  1106. # if (!defined(NO_LCHOWN))
  1107. if (slnk_entry->attriblen > sizeof(unsigned)) {
  1108. ulg *z_uidgid_p = (zvoid *)(slnk_entry->buf + sizeof(unsigned));
  1109. /* check that both uid and gid values fit into their data sizes */
  1110. if (((ulg)(uid_t)(z_uidgid_p[0]) == z_uidgid_p[0]) &&
  1111. ((ulg)(gid_t)(z_uidgid_p[1]) == z_uidgid_p[1])) {
  1112. TTrace((stderr,
  1113. "set_symlnk_attribs: restoring Unix UID/GID info for\n\
  1114. %s\n",
  1115. FnFilter1(slnk_entry->fname)));
  1116. if (lchown(slnk_entry->fname,
  1117. (uid_t)z_uidgid_p[0], (gid_t)z_uidgid_p[1]))
  1118. {
  1119. Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
  1120. z_uidgid_p[0], z_uidgid_p[1], FnFilter1(slnk_entry->fname),
  1121. strerror(errno)));
  1122. }
  1123. }
  1124. }
  1125. # endif /* !NO_LCHOWN */
  1126. # if (!defined(NO_LCHMOD))
  1127. TTrace((stderr,
  1128. "set_symlnk_attribs: restoring Unix attributes for\n %s\n",
  1129. FnFilter1(slnk_entry->fname)));
  1130. if (lchmod(slnk_entry->fname,
  1131. filtattr(__G__ *(unsigned *)(zvoid *)slnk_entry->buf)))
  1132. perror("lchmod (file attributes) error");
  1133. # endif /* !NO_LCHMOD */
  1134. }
  1135. /* currently, no error propagation... */
  1136. return PK_OK;
  1137. } /* end function set_symlnk_attribs() */
  1138. #endif /* SYMLINKS && SET_SYMLINK_ATTRIBS */
  1139. #ifdef SET_DIR_ATTRIB
  1140. /* messages of code for setting directory attributes */
  1141. # ifndef NO_CHMOD
  1142. static ZCONST char DirlistChmodFailed[] =
  1143. "warning: cannot set permissions for %s\n %s\n";
  1144. # endif
  1145. int defer_dir_attribs(__G__ pd)
  1146. __GDEF
  1147. direntry **pd;
  1148. {
  1149. uxdirattr *d_entry;
  1150. d_entry = (uxdirattr *)malloc(sizeof(uxdirattr) + strlen(G.filename));
  1151. *pd = (direntry *)d_entry;
  1152. if (d_entry == (uxdirattr *)NULL) {
  1153. return PK_MEM;
  1154. }
  1155. d_entry->fn = d_entry->fnbuf;
  1156. strcpy(d_entry->fn, G.filename);
  1157. d_entry->perms = G.pInfo->file_attr;
  1158. d_entry->have_uidgid = get_extattribs(__G__ &(d_entry->u.t3),
  1159. d_entry->uidgid);
  1160. return PK_OK;
  1161. } /* end function defer_dir_attribs() */
  1162. int set_direc_attribs(__G__ d)
  1163. __GDEF
  1164. direntry *d;
  1165. {
  1166. int errval = PK_OK;
  1167. if (UxAtt(d)->have_uidgid &&
  1168. /* check that both uid and gid values fit into their data sizes */
  1169. ((ulg)(uid_t)(UxAtt(d)->uidgid[0]) == UxAtt(d)->uidgid[0]) &&
  1170. ((ulg)(gid_t)(UxAtt(d)->uidgid[1]) == UxAtt(d)->uidgid[1]) &&
  1171. chown(UxAtt(d)->fn, (uid_t)UxAtt(d)->uidgid[0],
  1172. (gid_t)UxAtt(d)->uidgid[1]))
  1173. {
  1174. Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
  1175. UxAtt(d)->uidgid[0], UxAtt(d)->uidgid[1], FnFilter1(d->fn),
  1176. strerror(errno)));
  1177. if (!errval)
  1178. errval = PK_WARN;
  1179. }
  1180. /* Skip restoring directory time stamps on user' request. */
  1181. if (uO.D_flag <= 0) {
  1182. /* restore directory timestamps */
  1183. if (utime(d->fn, &UxAtt(d)->u.t2)) {
  1184. Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps,
  1185. FnFilter1(d->fn), strerror(errno)));
  1186. if (!errval)
  1187. errval = PK_WARN;
  1188. }
  1189. }
  1190. #ifndef NO_CHMOD
  1191. if (chmod(d->fn, UxAtt(d)->perms)) {
  1192. Info(slide, 0x201, ((char *)slide, DirlistChmodFailed,
  1193. FnFilter1(d->fn), strerror(errno)));
  1194. if (!errval)
  1195. errval = PK_WARN;
  1196. }
  1197. #endif /* !NO_CHMOD */
  1198. return errval;
  1199. } /* end function set_direc_attribs() */
  1200. #endif /* SET_DIR_ATTRIB */
  1201. #ifdef TIMESTAMP
  1202. /***************************/
  1203. /* Function stamp_file() */
  1204. /***************************/
  1205. int stamp_file(fname, modtime)
  1206. ZCONST char *fname;
  1207. time_t modtime;
  1208. {
  1209. ztimbuf tp;
  1210. tp.modtime = tp.actime = modtime;
  1211. return (utime(fname, &tp));
  1212. } /* end function stamp_file() */
  1213. #endif /* TIMESTAMP */
  1214. #ifndef SFX
  1215. /************************/
  1216. /* Function version() */
  1217. /************************/
  1218. void version(__G)
  1219. __GDEF
  1220. {
  1221. #if (defined(__GNUC__) && defined(NX_CURRENT_COMPILER_RELEASE))
  1222. char cc_namebuf[40];
  1223. char cc_versbuf[40];
  1224. #else
  1225. #if (defined(__SUNPRO_C))
  1226. char cc_versbuf[17];
  1227. #else
  1228. #if (defined(__HP_cc) || defined(__IBMC__))
  1229. char cc_versbuf[25];
  1230. #else
  1231. #if (defined(__DECC_VER))
  1232. char cc_versbuf[17];
  1233. int cc_verstyp;
  1234. #else
  1235. #if (defined(CRAY) && defined(_RELEASE))
  1236. char cc_versbuf[40];
  1237. #endif /* (CRAY && _RELEASE) */
  1238. #endif /* __DECC_VER */
  1239. #endif /* __HP_cc || __IBMC__ */
  1240. #endif /* __SUNPRO_C */
  1241. #endif /* (__GNUC__ && NX_CURRENT_COMPILER_RELEASE) */
  1242. #if ((defined(CRAY) || defined(cray)) && defined(_UNICOS))
  1243. char os_namebuf[40];
  1244. #else
  1245. #if defined(__NetBSD__)
  1246. char os_namebuf[40];
  1247. #endif
  1248. #endif
  1249. /* Pyramid, NeXT have problems with huge macro expansion, too: no Info() */
  1250. sprintf((char *)slide, LoadFarString(CompiledWith),
  1251. #ifdef __GNUC__
  1252. # ifdef NX_CURRENT_COMPILER_RELEASE
  1253. (sprintf(cc_namebuf, "NeXT DevKit %d.%02d ",
  1254. NX_CURRENT_COMPILER_RELEASE/100, NX_CURRENT_COMPILER_RELEASE%100),
  1255. cc_namebuf),
  1256. (strlen(__VERSION__) > 8)? "(gcc)" :
  1257. (sprintf(cc_versbuf, "(gcc %s)", __VERSION__), cc_versbuf),
  1258. # else
  1259. "gcc ", __VERSION__,
  1260. # endif
  1261. #else
  1262. #if defined(__SUNPRO_C)
  1263. "Sun C ", (sprintf(cc_versbuf, "version %x", __SUNPRO_C), cc_versbuf),
  1264. #else
  1265. #if (defined(__HP_cc))
  1266. "HP C ",
  1267. (((__HP_cc% 100) == 0) ?
  1268. (sprintf(cc_versbuf, "version A.%02d.%02d",
  1269. (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100))) :
  1270. (sprintf(cc_versbuf, "version A.%02d.%02d.%02d",
  1271. (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100), (__HP_cc% 100))),
  1272. cc_versbuf),
  1273. #else
  1274. #if (defined(__DECC_VER))
  1275. "DEC C ",
  1276. (sprintf(cc_versbuf, "%c%d.%d-%03d",
  1277. ((cc_verstyp = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
  1278. (cc_verstyp == 8 ? 'S' : 'V')),
  1279. __DECC_VER / 10000000,
  1280. (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000),
  1281. cc_versbuf),
  1282. #else
  1283. #if defined(CRAY) && defined(_RELEASE)
  1284. "cc ", (sprintf(cc_versbuf, "version %d", _RELEASE), cc_versbuf),
  1285. #else
  1286. #ifdef __IBMC__
  1287. "IBM C ",
  1288. (sprintf(cc_versbuf, "version %d.%d.%d",
  1289. (__IBMC__ / 100), ((__IBMC__ / 10) % 10), (__IBMC__ % 10)),
  1290. cc_versbuf),
  1291. #else
  1292. #ifdef __VERSION__
  1293. # ifndef IZ_CC_NAME
  1294. # define IZ_CC_NAME "cc "
  1295. # endif
  1296. IZ_CC_NAME, __VERSION__
  1297. #else
  1298. # ifndef IZ_CC_NAME
  1299. # define IZ_CC_NAME "cc"
  1300. # endif
  1301. IZ_CC_NAME, "",
  1302. #endif /* ?__VERSION__ */
  1303. #endif /* ?__IBMC__ */
  1304. #endif /* ?(CRAY && _RELEASE) */
  1305. #endif /* ?__DECC_VER */
  1306. #endif /* ?__HP_cc */
  1307. #endif /* ?__SUNPRO_C */
  1308. #endif /* ?__GNUC__ */
  1309. #ifndef IZ_OS_NAME
  1310. # define IZ_OS_NAME "Unix"
  1311. #endif
  1312. IZ_OS_NAME,
  1313. #if defined(sgi) || defined(__sgi)
  1314. " (Silicon Graphics IRIX)",
  1315. #else
  1316. #ifdef sun
  1317. # ifdef sparc
  1318. # ifdef __SVR4
  1319. " (Sun SPARC/Solaris)",
  1320. # else /* may or may not be SunOS */
  1321. " (Sun SPARC)",
  1322. # endif
  1323. # else
  1324. # if defined(sun386) || defined(i386)
  1325. " (Sun 386i)",
  1326. # else
  1327. # if defined(mc68020) || defined(__mc68020__)
  1328. " (Sun 3)",
  1329. # else /* mc68010 or mc68000: Sun 2 or earlier */
  1330. " (Sun 2)",
  1331. # endif
  1332. # endif
  1333. # endif
  1334. #else
  1335. #ifdef __hpux
  1336. " (HP-UX)",
  1337. #else
  1338. #ifdef __osf__
  1339. " (DEC OSF/1)",
  1340. #else
  1341. #ifdef _AIX
  1342. " (IBM AIX)",
  1343. #else
  1344. #ifdef aiws
  1345. " (IBM RT/AIX)",
  1346. #else
  1347. #if defined(CRAY) || defined(cray)
  1348. # ifdef _UNICOS
  1349. (sprintf(os_namebuf, " (Cray UNICOS release %d)", _UNICOS), os_namebuf),
  1350. # else
  1351. " (Cray UNICOS)",
  1352. # endif
  1353. #else
  1354. #if defined(uts) || defined(UTS)
  1355. " (Amdahl UTS)",
  1356. #else
  1357. #ifdef NeXT
  1358. # ifdef mc68000
  1359. " (NeXTStep/black)",
  1360. # else
  1361. " (NeXTStep for Intel)",
  1362. # endif
  1363. #else /* the next dozen or so are somewhat order-dependent */
  1364. #ifdef LINUX
  1365. # ifdef __ELF__
  1366. " (Linux ELF)",
  1367. # else
  1368. " (Linux a.out)",
  1369. # endif
  1370. #else
  1371. #ifdef MINIX
  1372. " (Minix)",
  1373. #else
  1374. #ifdef M_UNIX
  1375. " (SCO Unix)",
  1376. #else
  1377. #ifdef M_XENIX
  1378. " (SCO Xenix)",
  1379. #else
  1380. #ifdef __NetBSD__
  1381. # ifdef NetBSD0_8
  1382. (sprintf(os_namebuf, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')),
  1383. os_namebuf),
  1384. # else
  1385. # ifdef NetBSD0_9
  1386. (sprintf(os_namebuf, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')),
  1387. os_namebuf),
  1388. # else
  1389. # ifdef NetBSD1_0
  1390. (sprintf(os_namebuf, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')),
  1391. os_namebuf),
  1392. # else
  1393. (BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)",
  1394. # endif
  1395. # endif
  1396. # endif
  1397. #else
  1398. #ifdef __FreeBSD__
  1399. (BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)",
  1400. #else
  1401. #ifdef __bsdi__
  1402. (BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)",
  1403. #else
  1404. #ifdef __386BSD__
  1405. (BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)",
  1406. #else
  1407. #ifdef __CYGWIN__
  1408. " (Cygwin)",
  1409. #else
  1410. #if defined(i686) || defined(__i686) || defined(__i686__)
  1411. " (Intel 686)",
  1412. #else
  1413. #if defined(i586) || defined(__i586) || defined(__i586__)
  1414. " (Intel 586)",
  1415. #else
  1416. #if defined(i486) || defined(__i486) || defined(__i486__)
  1417. " (Intel 486)",
  1418. #else
  1419. #if defined(i386) || defined(__i386) || defined(__i386__)
  1420. " (Intel 386)",
  1421. #else
  1422. #ifdef pyr
  1423. " (Pyramid)",
  1424. #else
  1425. #ifdef ultrix
  1426. # ifdef mips
  1427. " (DEC/MIPS)",
  1428. # else
  1429. # ifdef vax
  1430. " (DEC/VAX)",
  1431. # else /* __alpha? */
  1432. " (DEC/Alpha)",
  1433. # endif
  1434. # endif
  1435. #else
  1436. #ifdef gould
  1437. " (Gould)",
  1438. #else
  1439. #ifdef MTS
  1440. " (MTS)",
  1441. #else
  1442. #ifdef __convexc__
  1443. " (Convex)",
  1444. #else
  1445. #ifdef __QNX__
  1446. " (QNX 4)",
  1447. #else
  1448. #ifdef __QNXNTO__
  1449. " (QNX Neutrino)",
  1450. #else
  1451. #ifdef Lynx
  1452. " (LynxOS)",
  1453. #else
  1454. #ifdef __APPLE__
  1455. # ifdef __i386__
  1456. " Mac OS X Intel i32",
  1457. # else
  1458. # ifdef __ppc__
  1459. " Mac OS X PowerPC",
  1460. # else
  1461. # ifdef __ppc64__
  1462. " Mac OS X PowerPC64",
  1463. # else
  1464. " Mac OS X",
  1465. # endif /* __ppc64__ */
  1466. # endif /* __ppc__ */
  1467. # endif /* __i386__ */
  1468. #else
  1469. "",
  1470. #endif /* Apple */
  1471. #endif /* Lynx */
  1472. #endif /* QNX Neutrino */
  1473. #endif /* QNX 4 */
  1474. #endif /* Convex */
  1475. #endif /* MTS */
  1476. #endif /* Gould */
  1477. #endif /* DEC */
  1478. #endif /* Pyramid */
  1479. #endif /* 386 */
  1480. #endif /* 486 */
  1481. #endif /* 586 */
  1482. #endif /* 686 */
  1483. #endif /* Cygwin */
  1484. #endif /* 386BSD */
  1485. #endif /* BSDI BSD/386 */
  1486. #endif /* NetBSD */
  1487. #endif /* FreeBSD */
  1488. #endif /* SCO Xenix */
  1489. #endif /* SCO Unix */
  1490. #endif /* Minix */
  1491. #endif /* Linux */
  1492. #endif /* NeXT */
  1493. #endif /* Amdahl */
  1494. #endif /* Cray */
  1495. #endif /* RT/AIX */
  1496. #endif /* AIX */
  1497. #endif /* OSF/1 */
  1498. #endif /* HP-UX */
  1499. #endif /* Sun */
  1500. #endif /* SGI */
  1501. #ifdef __DATE__
  1502. " on ", __DATE__
  1503. #else
  1504. "", ""
  1505. #endif
  1506. );
  1507. (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
  1508. } /* end function version() */
  1509. #endif /* !SFX */
  1510. #ifdef QLZIP
  1511. struct qdirect {
  1512. long d_length __attribute__ ((packed)); /* file length */
  1513. unsigned char d_access __attribute__ ((packed)); /* file access type */
  1514. unsigned char d_type __attribute__ ((packed)); /* file type */
  1515. long d_datalen __attribute__ ((packed)); /* data length */
  1516. long d_reserved __attribute__ ((packed));/* Unused */
  1517. short d_szname __attribute__ ((packed)); /* size of name */
  1518. char d_name[36] __attribute__ ((packed));/* name area */
  1519. long d_update __attribute__ ((packed)); /* last update */
  1520. long d_refdate __attribute__ ((packed));
  1521. long d_backup __attribute__ ((packed)); /* EOD */
  1522. };
  1523. #define LONGID "QDOS02"
  1524. #define EXTRALEN (sizeof(struct qdirect) + 8)
  1525. #define JBLONGID "QZHD"
  1526. #define JBEXTRALEN (sizeof(jbextra) - 4 * sizeof(char))
  1527. typedef struct {
  1528. char eb_header[4] __attribute__ ((packed)); /* place_holder */
  1529. char longid[8] __attribute__ ((packed));
  1530. struct qdirect header __attribute__ ((packed));
  1531. } qdosextra;
  1532. typedef struct {
  1533. char eb_header[4]; /* place_holder */
  1534. char longid[4];
  1535. struct qdirect header;
  1536. } jbextra;
  1537. /* The following two functions SH() and LG() convert big-endian short
  1538. * and long numbers into native byte order. They are some kind of
  1539. * counterpart to the generic UnZip's makeword() and makelong() functions.
  1540. */
  1541. static ush SH(ush val)
  1542. {
  1543. uch swapbuf[2];
  1544. swapbuf[1] = (uch)(val & 0xff);
  1545. swapbuf[0] = (uch)(val >> 8);
  1546. return (*(ush *)swapbuf);
  1547. }
  1548. static ulg LG(ulg val)
  1549. {
  1550. /* convert the big-endian unsigned long number `val' to the machine
  1551. * dependent representation
  1552. */
  1553. ush swapbuf[2];
  1554. swapbuf[1] = SH((ush)(val & 0xffff));
  1555. swapbuf[0] = SH((ush)(val >> 16));
  1556. return (*(ulg *)swapbuf);
  1557. }
  1558. static void qlfix(__G__ ef_ptr, ef_len)
  1559. __GDEF
  1560. uch *ef_ptr;
  1561. unsigned ef_len;
  1562. {
  1563. while (ef_len >= EB_HEADSIZE)
  1564. {
  1565. unsigned eb_id = makeword(EB_ID + ef_ptr);
  1566. unsigned eb_len = makeword(EB_LEN + ef_ptr);
  1567. if (eb_len > (ef_len - EB_HEADSIZE)) {
  1568. /* discovered some extra field inconsistency! */
  1569. Trace((stderr,
  1570. "qlfix: block length %u > rest ef_size %u\n", eb_len,
  1571. ef_len - EB_HEADSIZE));
  1572. break;
  1573. }
  1574. switch (eb_id) {
  1575. case EF_QDOS:
  1576. {
  1577. struct _ntc_
  1578. {
  1579. long id;
  1580. long dlen;
  1581. } ntc;
  1582. long dlen = 0;
  1583. qdosextra *extra = (qdosextra *)ef_ptr;
  1584. jbextra *jbp = (jbextra *)ef_ptr;
  1585. if (!strncmp(extra->longid, LONGID, strlen(LONGID)))
  1586. {
  1587. if (eb_len != EXTRALEN)
  1588. if (uO.qflag)
  1589. Info(slide, 0x201, ((char *)slide,
  1590. "warning: invalid length in Qdos field for %s\n",
  1591. FnFilter1(G.filename)));
  1592. else
  1593. Info(slide, 0x201, ((char *)slide,
  1594. "warning: invalid length in Qdos field"));
  1595. if (extra->header.d_type)
  1596. {
  1597. dlen = extra->header.d_datalen;
  1598. }
  1599. }
  1600. if (!strncmp(jbp->longid, JBLONGID, strlen(JBLONGID)))
  1601. {
  1602. if (eb_len != JBEXTRALEN)
  1603. if (uO.qflag)
  1604. Info(slide, 0x201, ((char *)slide,
  1605. "warning: invalid length in QZ field for %s\n",
  1606. FnFilter1(G.filename)));
  1607. else
  1608. Info(slide, 0x201, ((char *)slide,
  1609. "warning: invalid length in QZ field"));
  1610. if (jbp->header.d_type)
  1611. {
  1612. dlen = jbp->header.d_datalen;
  1613. }
  1614. }
  1615. if ((long)LG(dlen) > 0)
  1616. {
  1617. zfseeko(G.outfile, -8, SEEK_END);
  1618. fread(&ntc, 8, 1, G.outfile);
  1619. if (ntc.id != *(long *)"XTcc")
  1620. {
  1621. ntc.id = *(long *)"XTcc";
  1622. ntc.dlen = dlen;
  1623. fwrite (&ntc, 8, 1, G.outfile);
  1624. }
  1625. Info(slide, 0x201, ((char *)slide, "QData = %d", LG(dlen)));
  1626. }
  1627. return; /* finished, cancel further extra field scanning */
  1628. }
  1629. default:
  1630. Trace((stderr,"qlfix: unknown extra field block, ID=%d\n",
  1631. eb_id));
  1632. }
  1633. /* Skip this extra field block */
  1634. ef_ptr += (eb_len + EB_HEADSIZE);
  1635. ef_len -= (eb_len + EB_HEADSIZE);
  1636. }
  1637. }
  1638. #endif /* QLZIP */