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