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 21extern char *label; /* still declared in fileio.c */ 22local ulg label_time = 0; 23local ulg label_mode = 0; 24local time_t label_utim = 0; 25 26/* Local functions */ 27local char *readd OF((DIR *)); 28local int wild_recurse OF((char *, char *)); 29 30 31local char *readd(d) 32DIR *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 54local 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 136int 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 155int procname(n, caseflag) 156char *n; /* name to process */ 157int 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 235char *ex2in(x, isdir, pdosflag) 236char *x; /* external file name */ 237int isdir; /* input: x is a directory */ 238int *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 278char *in2ex(n) 279char *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 291void stamp(f, d) 292char *f; /* name of file to change */ 293ulg 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 305ulg filetime(f, a, n, t) 306char *f; /* name of file to get info on */ 307ulg *a; /* return value: file attributes */ 308long *n; /* return value: file size */ 309iztimes *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 373int 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 405int deletedir(d) 406char *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 */ 427int WBversion = (int) 428#include "ENV:Workbench" 429; 430 431void 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