1 /*
2 Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
3
4 See the accompanying file LICENSE, version 1999-Oct-05 or later
5 (the contents of which are also included in zip.h) for terms of use.
6 If, for some reason, both of these files are missing, the Info-ZIP license
7 also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
8 */
9 #include "zip.h"
10 #include "amiga/amiga.h"
11
12 #ifndef UTIL /* the companion #endif is a bit of ways down ... */
13
14 #define utime FileDate
15
16 #define PAD 0
17 #define PATH_END '/'
18
19 /* Local globals (kinda like "military intelligence" or "broadcast quality") */
20
21 extern char *label; /* still declared in fileio.c */
22 local ulg label_time = 0;
23 local ulg label_mode = 0;
24 local time_t label_utim = 0;
25
26 /* Local functions */
27 local char *readd OF((DIR *));
28 local int wild_recurse OF((char *, char *));
29
30
readd(d)31 local char *readd(d)
32 DIR *d; /* directory stream to read from */
33 /* Return a pointer to the next name in the directory stream d, or NULL if
34 no more entries or an error occurs. */
35 {
36 struct dirent *e = readdir(d);
37 return e == NULL ? (char *) NULL : e->d_name;
38 }
39
40
41 /* What we have here is a mostly-generic routine using opendir()/readd() and */
42 /* isshexp()/MATCH() to find all the files matching a multi-part filespec */
43 /* using the portable pattern syntax. It shouldn't take too much fiddling */
44 /* to make it usable for any other platform that has directory hierarchies */
45 /* but no shell-level pattern matching. It works for patterns throughout */
46 /* the pathname, such as "foo:*.?/source/x*.[ch]". */
47
48 #define ONENAMELEN 30
49 /* the length of one filename component on the Amiga */
50
51 /* whole is a pathname with wildcards, wildtail points somewhere in the */
52 /* middle of it. All wildcards to be expanded must come AFTER wildtail. */
53
wild_recurse(whole,wildtail)54 local int wild_recurse(whole, wildtail) char *whole; char *wildtail;
55 {
56 DIR *dir;
57 char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
58 ush newlen, amatch = 0;
59 BPTR lok;
60 int e = ZE_MISS;
61
62 if (!isshexp(wildtail))
63 if (lok = Lock(whole, ACCESS_READ)) { /* p exists? */
64 UnLock(lok);
65 return procname(whole, 0);
66 } else
67 return ZE_MISS; /* woops, no wildcards! */
68
69 /* back up thru path components till existing dir found */
70 do {
71 name = wildtail + strlen(wildtail) - 1;
72 for (;;)
73 if (name-- <= wildtail || *name == PATH_END) {
74 subwild = name + 1;
75 plug2 = *subwild;
76 *subwild = 0;
77 break;
78 }
79 if (glue)
80 *glue = plug;
81 glue = subwild;
82 plug = plug2;
83 dir = opendir(whole);
84 } while (!dir && !disk_not_mounted && subwild > wildtail);
85 wildtail = subwild; /* skip past non-wild components */
86
87 if ((subwild = strchr(wildtail + 1, PATH_END)) != NULL) {
88 /* this "+ 1" dodges the ^^^ hole left by *glue == 0 */
89 *(subwild++) = 0; /* wildtail = one component pattern */
90 newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
91 } else
92 newlen = strlen(whole) + (ONENAMELEN + 1);
93 if (!dir || !(newwhole = malloc(newlen))) {
94 if (glue)
95 *glue = plug;
96
97 e = dir ? ZE_MEM : ZE_MISS;
98 goto ohforgetit;
99 }
100 strcpy(newwhole, whole);
101 newlen = strlen(newwhole);
102 if (glue)
103 *glue = plug; /* repair damage to whole */
104 if (!isshexp(wildtail)) {
105 e = ZE_MISS; /* non-wild name not found */
106 goto ohforgetit;
107 }
108
109 while (name = readd(dir)) {
110 if (MATCH(wildtail, name, 0)) {
111 strcpy(newwhole + newlen, name);
112 if (subwild) {
113 name = newwhole + strlen(newwhole);
114 *(name++) = PATH_END;
115 strcpy(name, subwild);
116 e = wild_recurse(newwhole, name);
117 } else
118 e = procname(newwhole, 0);
119 newwhole[newlen] = 0;
120 if (e == ZE_OK)
121 amatch = 1;
122 else if (e != ZE_MISS)
123 break;
124 }
125 }
126
127 ohforgetit:
128 if (dir) closedir(dir);
129 if (subwild) *--subwild = PATH_END;
130 if (newwhole) free(newwhole);
131 if (e == ZE_MISS && amatch)
132 e = ZE_OK;
133 return e;
134 }
135
wild(p)136 int wild(p) char *p;
137 {
138 char *use;
139
140 /* special handling of stdin request */
141 if (strcmp(p, "-") == 0) /* if compressing stdin */
142 return newname(p, 0, 0);
143
144 /* wild_recurse() can't handle colons in wildcard part: */
145 if (use = strchr(p, ':')) {
146 if (strchr(++use, ':'))
147 return ZE_PARMS;
148 } else
149 use = p;
150
151 return wild_recurse(p, use);
152 }
153
154
procname(n,caseflag)155 int procname(n, caseflag)
156 char *n; /* name to process */
157 int caseflag; /* true to force case-sensitive match */
158 /* Process a name or sh expression to operate on (or exclude). Return
159 an error code in the ZE_ class. */
160 {
161 char *a; /* path and name for recursion */
162 DIR *d; /* directory stream from opendir() */
163 char *e; /* pointer to name from readd() */
164 int m; /* matched flag */
165 char *p; /* path for recursion */
166 struct stat s; /* result of stat() */
167 struct zlist far *z; /* steps through zfiles list */
168
169 if (strcmp(n, "-") == 0) /* if compressing stdin */
170 return newname(n, 0, caseflag);
171 else if (LSSTAT(n, &s))
172 {
173 /* Not a file or directory--search for shell expression in zip file */
174 p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
175 m = 1;
176 for (z = zfiles; z != NULL; z = z->nxt) {
177 if (MATCH(p, z->iname, caseflag))
178 {
179 z->mark = pcount ? filter(z->zname, caseflag) : 1;
180 if (verbose)
181 fprintf(mesg, "zip diagnostic: %scluding %s\n",
182 z->mark ? "in" : "ex", z->name);
183 m = 0;
184 }
185 }
186 free((zvoid *)p);
187 return m ? ZE_MISS : ZE_OK;
188 }
189
190 /* Live name--use if file, recurse if directory */
191 if ((s.st_mode & S_IFDIR) == 0)
192 {
193 /* add or remove name of file */
194 if ((m = newname(n, 0, caseflag)) != ZE_OK)
195 return m;
196 } else {
197 /* Add trailing / to the directory name */
198 if ((p = malloc(strlen(n)+2)) == NULL)
199 return ZE_MEM;
200 strcpy(p, n);
201 a = p + strlen(p);
202 if (*p && a[-1] != '/' && a[-1] != ':')
203 strcpy(a, "/");
204 if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
205 free((zvoid *)p);
206 return m;
207 }
208 /* recurse into directory */
209 if (recurse && (d = opendir(n)) != NULL)
210 {
211 while ((e = readd(d)) != NULL) {
212 if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
213 {
214 closedir(d);
215 free((zvoid *)p);
216 return ZE_MEM;
217 }
218 strcat(strcpy(a, p), e);
219 if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
220 {
221 if (m == ZE_MISS)
222 zipwarn("name not matched: ", a);
223 else
224 ziperr(m, a);
225 }
226 free((zvoid *)a);
227 }
228 closedir(d);
229 }
230 free((zvoid *)p);
231 } /* (s.st_mode & S_IFDIR) == 0) */
232 return ZE_OK;
233 }
234
ex2in(x,isdir,pdosflag)235 char *ex2in(x, isdir, pdosflag)
236 char *x; /* external file name */
237 int isdir; /* input: x is a directory */
238 int *pdosflag; /* output: force MSDOS file attributes? */
239 /* Convert the external file name to a zip file name, returning the malloc'ed
240 string or NULL if not enough memory. */
241 {
242 char *n; /* internal file name (malloc'ed) */
243 char *t; /* shortened name */
244 int dosflag;
245
246 dosflag = dosify; /* default for non-DOS and non-OS/2 */
247
248 /* Find starting point in name before doing malloc */
249 if ((t = strrchr(x, ':')) != NULL) /* reject ":" */
250 t++;
251 else
252 t = x;
253 { /* reject "//" */
254 char *tt = t;
255 while (tt = strchr(tt, '/'))
256 while (*++tt == '/')
257 t = tt;
258 }
259 while (*t == '/') /* reject leading "/" on what's left */
260 t++;
261
262 if (!pathput)
263 t = last(t, PATH_END);
264
265 /* Malloc space for internal name and copy it */
266 if ((n = malloc(strlen(t) + 1)) == NULL)
267 return NULL;
268 strcpy(n, t);
269
270 if (dosify)
271 msname(n);
272 /* Returned malloc'ed name */
273 if (pdosflag)
274 *pdosflag = dosflag;
275 return n;
276 }
277
in2ex(n)278 char *in2ex(n)
279 char *n; /* internal file name */
280 /* Convert the zip file name to an external file name, returning the malloc'ed
281 string or NULL if not enough memory. */
282 {
283 char *x; /* external file name */
284
285 if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
286 return NULL;
287 strcpy(x, n);
288 return x;
289 }
290
stamp(f,d)291 void stamp(f, d)
292 char *f; /* name of file to change */
293 ulg d; /* dos-style time to change it to */
294 /* Set last updated and accessed time of file f to the DOS time d. */
295 {
296 time_t u[2]; /* argument for utime() */
297
298 /* Convert DOS time to time_t format in u */
299 u[0] = u[1] = dos2unixtime(d);
300
301 /* Set updated and accessed times of f */
302 utime(f, u);
303 }
304
filetime(f,a,n,t)305 ulg filetime(f, a, n, t)
306 char *f; /* name of file to get info on */
307 ulg *a; /* return value: file attributes */
308 long *n; /* return value: file size */
309 iztimes *t; /* return value: access, modific. and creation times */
310 /* If file *f does not exist, return 0. Else, return the file's last
311 modified date and time as an MSDOS date and time. The date and
312 time is returned in a long with the date most significant to allow
313 unsigned integer comparison of absolute times. Also, if a is not
314 a NULL pointer, store the file attributes there, with the high two
315 bytes being the Unix attributes, and the low byte being a mapping
316 of that to DOS attributes. If n is not NULL, store the file size
317 there. If t is not NULL, the file's access, modification and creation
318 times are stored there as UNIX time_t values.
319 If f is "-", use standard input as the file. If f is a device, return
320 a file size of -1 */
321 {
322 struct stat s; /* results of stat() */
323 /* convert FNMAX to malloc - 11/8/04 EG */
324 char *name;
325 int len = strlen(f);
326
327 if (f == label) {
328 if (a != NULL)
329 *a = label_mode;
330 if (n != NULL)
331 *n = -2L; /* convention for a label name */
332 if (t != NULL)
333 t->atime = t->mtime = t->ctime = label_utim;
334 return label_time;
335 }
336 if ((name = malloc(len + 1)) == NULL) {
337 ZIPERR(ZE_MEM, "filetime");
338 }
339 strcpy(name, f);
340 if (name[len - 1] == '/')
341 name[len - 1] = '\0';
342 /* not all systems allow stat'ing a file with / appended */
343
344 if (strcmp(f, "-") == 0) {
345 if (fstat(fileno(stdin), &s) != 0)
346 error("fstat(stdin)");
347 } else if (SSTAT(name, &s) != 0) {
348 /* Accept about any file kind including directories
349 * (stored with trailing / with -r option)
350 */
351 free(name);
352 return 0;
353 }
354 free(name);
355
356 if (a != NULL) {
357 *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
358 if ((s.st_mode & S_IFDIR) != 0) {
359 *a |= MSDOS_DIR_ATTR;
360 }
361 }
362 if (n != NULL)
363 *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
364 if (t != NULL) {
365 t->atime = s.st_atime;
366 t->mtime = s.st_mtime;
367 t->ctime = s.st_ctime;
368 }
369
370 return unix2dostime(&s.st_mtime);
371 }
372
set_extra_field(z,z_utim)373 int set_extra_field(z, z_utim)
374 struct zlist far *z;
375 iztimes *z_utim;
376 /* create extra field and change z->att if desired */
377 {
378 #ifdef USE_EF_UT_TIME
379 #ifdef IZ_CHECK_TZ
380 if (!zp_tz_is_valid) return ZE_OK; /* skip silently if no valid TZ info */
381 #endif
382
383 if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
384 return ZE_MEM;
385
386 z->extra[0] = 'U';
387 z->extra[1] = 'T';
388 z->extra[2] = EB_UT_LEN(1); /* length of data part of e.f. */
389 z->extra[3] = 0;
390 z->extra[4] = EB_UT_FL_MTIME;
391 z->extra[5] = (char)(z_utim->mtime);
392 z->extra[6] = (char)(z_utim->mtime >> 8);
393 z->extra[7] = (char)(z_utim->mtime >> 16);
394 z->extra[8] = (char)(z_utim->mtime >> 24);
395
396 z->cextra = z->extra;
397 z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
398
399 return ZE_OK;
400 #else /* !USE_EF_UT_TIME */
401 return (int)(z-z);
402 #endif /* ?USE_EF_UT_TIME */
403 }
404
deletedir(d)405 int deletedir(d)
406 char *d; /* directory to delete */
407 /* Delete the directory *d if it is empty, do nothing otherwise.
408 Return the result of rmdir(), delete(), or system().
409 For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
410 */
411 {
412 return rmdir(d);
413 }
414
415 #endif /* !UTIL */
416
417
418 /******************************/
419 /* Function version_local() */
420 /******************************/
421
422
423 /* NOTE: the following include depends upon the environment
424 * variable $Workbench to be set correctly. (Set by
425 * default, by Version command in Startup-sequence.)
426 */
427 int WBversion = (int)
428 #include "ENV:Workbench"
429 ;
430
version_local()431 void version_local()
432 {
433 static ZCONST char CompiledWith[] = "Compiled with %s%s under %s%s%s%s.\n\n";
434
435 /* Define buffers. */
436
437 char buf1[16]; /* compiler name */
438 char buf2[16]; /* revstamp */
439 char buf3[16]; /* OS */
440 char buf4[16]; /* Date */
441 /* char buf5[16]; /* Time */
442
443 /* format "with" name strings */
444
445 #ifdef AMIGA
446 # ifdef __SASC
447 strcpy(buf1,"SAS/C ");
448 # else
449 # ifdef LATTICE
450 strcpy(buf1,"Lattice C ");
451 # else
452 # ifdef AZTEC_C
453 strcpy(buf1,"Manx Aztec C ");
454 # else
455 strcpy(buf1,"UNKNOWN ");
456 # endif
457 # endif
458 # endif
459 /* "under" */
460 sprintf(buf3,"AmigaDOS v%d",WBversion);
461 #else
462 strcpy(buf1,"Unknown compiler ");
463 strcpy(buf3,"Unknown OS");
464 #endif
465
466 /* Define revision, date, and time strings.
467 * NOTE: Do not calculate run time, be sure to use time compiled.
468 * Pass these strings via your makefile if undefined.
469 */
470
471 #if defined(__VERSION__) && defined(__REVISION__)
472 sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
473 #else
474 # ifdef __VERSION__
475 sprintf(buf2,"version %d",__VERSION__);
476 # else
477 sprintf(buf2,"unknown version");
478 # endif
479 #endif
480
481 #ifdef __DATE__
482 sprintf(buf4," on %s",__DATE__);
483 #else
484 strcpy(buf4," unknown date");
485 #endif
486
487 /******
488 #ifdef __TIME__
489 sprintf(buf5," at %s",__TIME__);
490 #else
491 strcpy(buf5," unknown time");
492 #endif
493 ******/
494
495 /* Print strings using "CompiledWith" mask defined above.
496 * ("Compiled with %s%s under %s%s%s%s.")
497 */
498
499 printf(CompiledWith,
500 buf1,
501 buf2,
502 buf3,
503 buf4,
504 /* buf5, */ "",
505 "" ); /* buf6 not used */
506
507 } /* end function version_local() */
508