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/*--------------------------------------------------------------------------- 10 11 theos.c (zip) 12 13 Contribution by Jean-Michel Dubois. 20-Jun-1995, 20-Dec-98 14 15 THEOS specific extra informations 16 17 ---------------------------------------------------------------------------*/ 18 19 20#include <stdio.h> 21 22#ifndef UTIL 23 24#include "zip.h" 25 26#include <stdlib.h> 27#include <ctype.h> 28#include <time.h> 29#include <sc.h> 30#include <direct.h> 31#include <sys/utime.h> 32 33#define opendir(a) _opendir(a) 34extern struct dirent* _opendir(char* fname); 35 36#define PAD 0 37 38#define RET_ERROR 1 39#define RET_SUCCESS 0 40#define RET_EOF 0 41 42extern char *label; 43local ulg label_time = 0; 44local ulg label_mode = 0; 45local time_t label_utim = 0; 46 47/* match from Phase One Systems */ 48 49int match(char *s, char *p) /*S Returns non-zero if string matches 50 the literal mask */ 51{ 52 int matched, k; 53 54 if (!(*p)) 55 return 1; 56 for(;;) { 57 if ( (!(*s)) && (!(*p)) ) 58 return(1); 59 else if ( !(*p) ) 60 return(0); 61 else if (*p == '*') { 62 if (!*(p+1)) 63 return(1); 64 k=0; 65 do { 66 matched = match(s+k,p+1); 67 k++; 68 } while ( (!matched) && *(s+k)); 69 return(matched); 70 } else if (*p == '@') { 71 if (!((*s >= 'a' && *s <= 'z') 72 ||(*s >= 'A' && *s <= 'Z'))) 73 return(0); 74 } else if (*p == '#') { 75 if (*s < '0' || *s > '9') 76 return(0); 77 } else if (*p != '?') { 78 if (tolower(*s) != tolower(*p)) 79 return(0); 80 } 81 s++; p++; 82 } 83} 84 85local char *readd(d) 86DIR *d; /* directory stream to read from */ 87/* Return a pointer to the next name in the directory stream d, or NULL if 88 no more entries or an error occurs. */ 89{ 90 struct dirent *e; 91 92 e = readdir(d); 93 return e == NULL ? (char *) NULL : e->d_name; 94} 95 96/* check if file is a member of a library */ 97 98int ismember(char* path) 99{ 100 char* p; 101 102 if ((p = strrchr(path, '/')) == NULL) 103 p = path; 104 return ((p = strchr(p, '.')) && (p = strchr(p + 1, '.'))); 105} 106 107/* extract library name from a file name */ 108 109char* libname(char* path) 110{ 111 char* p; 112 static char lib[FILENAME_MAX]; 113 char drive[3]; 114 115 strcpy(lib, path); 116 if (p = strrchr(lib, ':')) { 117 strncpy(drive, p, 2); 118 drive[2] = '\0'; 119 *p = '\0' ; 120 } else 121 drive[0] = '\0'; 122 123 if ((p = strrchr(lib, '/')) == NULL) 124 p = lib; 125 126 p = strchr(p, '.'); 127 p = strchr(p + 1, '.'); 128 *p = 0; 129 strcat(lib, drive); 130 return lib; 131} 132 133int procname(n, caseflag) 134char *n; /* name to process */ 135int caseflag; /* true to force case-sensitive match */ 136/* Process a name or sh expression to operate on (or exclude). Return 137 an error code in the ZE_ class. */ 138{ 139 char *a; /* path and name for recursion */ 140 DIR *d; /* directory stream from opendir() */ 141 char *e; /* pointer to name from readd() */ 142 int m; /* matched flag */ 143 char *p; /* path for recursion */ 144 struct stat s; /* result of stat() */ 145 struct zlist *z; /* steps through zfiles list */ 146 struct flist *f; /* steps through files list */ 147 char* path; /* full name */ 148 char drive[3]; /* drive name */ 149 int recursion; /* save recurse flag */ 150 151 if (strcmp(n, "-") == 0) /* if compressing stdin */ 152 return newname(n, 0, caseflag); 153 else if (LSSTAT(n, &s)) { 154 /* Not a file or directory--search for shell expression in zip file */ 155 p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */ 156 m = 1; 157 for (z = zfiles; z != NULL; z = z->nxt) { 158 if (match(z->iname, p)) 159 { 160 z->mark = pcount ? filter(z->zname, caseflag) : 1; 161 if (verbose) 162 fprintf(mesg, "zip diagnostic: %scluding %s\n", 163 z->mark ? "in" : "ex", z->name); 164 m = 0; 165 } 166 } 167 free((zvoid *)p); 168 return m ? ZE_MISS : ZE_OK; 169 } 170 171 /* Live name--use if file, recurse if directory or library */ 172 if (S_ISREG(s.st_mode)) { 173 if ((path = malloc(strlen(n) + 2)) == NULL) 174 return ZE_MEM; 175 176 strcpy(path, n); 177 178 /* if member name, include library name before any member name */ 179 if (ismember(path)) { 180 strcpy(path, libname(path)); 181 /* mask recursion flag to avoid endless loop recursion 182 * if -r is used with member names 183 */ 184 recursion = recurse; 185 recurse = FALSE; 186 if ((m = procname(path, caseflag)) != ZE_OK) /* recurse on name */ 187 { 188 if (m == ZE_MISS) 189 zipwarn("name not matched: ", path); 190 else 191 ziperr(m, a); 192 } 193 /* restore recursion flag */ 194 recurse = recursion; 195 } 196 197 strcpy(path, n); 198 199 if ((p = strchr(path, ':')) != NULL) { 200 p[2] = '\0'; 201 strcpy(drive, p); 202 } else 203 drive[0] = '\0'; 204 205 /* remove trailing dot in flat file name */ 206 p = strend(path) - 1; 207 if (*p == '.') 208 *p = '\0'; 209 210 strcat(path, drive); 211 /* add or remove name of file */ 212 if ((m = newname(path, 0, caseflag)) != ZE_OK) { 213 free(path); 214 return m; 215 } 216 free(path); 217 } else if (S_ISLIB(s.st_mode)) { 218 if ((path = malloc(strlen(n) + 2)) == NULL) 219 return ZE_MEM; 220 221 strcpy(path, n); 222 223 if ((p = strchr(path, ':')) != NULL) { 224 p[2] = '\0'; 225 strcpy(drive, p); 226 } else 227 drive[0] = '\0'; 228 229 /* add a trailing dot in flat file name... */ 230 p = strend(path) - 1; 231 if (*p != '/') 232 strcat(path, "/"); 233 p = strend(path); 234 /* ... then add drive name */ 235 strcpy(p, drive); 236 237 /* don't include the library name twice... or more */ 238 for (f = found; f != NULL; f = f->nxt) { 239 if (! stricmp(path, f->name)) { 240 free(path); 241 return ZE_OK; 242 } 243 } 244 /* add or remove name of library */ 245 if ((m = newname(path, 0, caseflag)) != ZE_OK) { 246 free(path); 247 return m; 248 } 249 /* recurse into library if required */ 250 strcpy(p - 1, ".*"); 251 strcat(p, drive); 252 if (recurse && diropen(path) == 0) 253 { 254 while ((e = dirread()) != NULL) { 255 if (strcmp(e, ".") && strcmp(e, "..")) 256 { 257 if (*drive == '\0') 258 *strchr(e, ':') = '\0'; 259 if ((a = malloc(strlen(e) + 1)) == NULL) 260 { 261 dirclose(); 262 free((zvoid *)p); 263 return ZE_MEM; 264 } 265 strcpy(a, e); 266 if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */ 267 { 268 if (m == ZE_MISS) 269 zipwarn("name not matched: ", a); 270 else 271 ziperr(m, a); 272 } 273 free((zvoid *)a); 274 } 275 } 276 dirclose(); 277 } 278 free(path); 279 } else { 280 /* Add trailing / to the directory name */ 281 if ((p = malloc(strlen(n)+2)) == NULL) 282 return ZE_MEM; 283 if (strcmp(n, ".") == 0) { 284 *p = '\0'; /* avoid "./" prefix and do not create zip entry */ 285 } else { 286 strcpy(p, n); 287 a = p + strlen(p); 288 if (a[-1] != '/') 289 strcpy(a, "/"); 290 if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) { 291 free((zvoid *)p); 292 return m; 293 } 294 } 295 /* recurse into directory */ 296 if (recurse && (d = opendir(n)) != NULL) 297 { 298 while ((e = readd(d)) != NULL) { 299 if (strcmp(e, ".") && strcmp(e, "..")) 300 { 301 if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL) 302 { 303 closedir(d); 304 free((zvoid *)p); 305 return ZE_MEM; 306 } 307 strcat(strcpy(a, p), e); 308 if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */ 309 { 310 if (m == ZE_MISS) 311 zipwarn("name not matched: ", a); 312 else 313 ziperr(m, a); 314 } 315 free((zvoid *)a); 316 } 317 } 318 closedir(d); 319 } 320 free((zvoid *)p); 321 } 322 return ZE_OK; 323} 324 325char *ex2in(x, isdir, pdosflag) 326char *x; /* external file name */ 327int isdir; /* input: x is a directory */ 328int *pdosflag; /* output: force MSDOS file attributes? */ 329/* Convert the external file name to a zip file name, returning the malloc'ed 330 string or NULL if not enough memory. */ 331{ 332 char *n; /* internal file name (malloc'ed) */ 333 char *t; /* shortened name */ 334 char *p; 335 int dosflag; 336 337 dosflag = dosify; /* default for non-DOS and non-OS/2 */ 338 339 /* Find starting point in name before doing malloc */ 340 for (t = x; *t == '/'; t++) 341 ; 342 343 /* Make changes, if any, to the copied name (leave original intact) */ 344 if (!pathput) 345 t = last(t, '/'); 346 347 /* Malloc space for internal name and copy it */ 348 if ((n = malloc(strlen(t) + 1)) == NULL) 349 return NULL; 350 351 strcpy(n, t); 352 if (p = strchr(n, ':')) 353 *p = '\0'; 354 for (p = n; *p = tolower(*p); p++); 355 356 if (isdir == 42) return n; /* avoid warning on unused variable */ 357 358 if (dosify) 359 msname(n); 360 /* Returned malloc'ed name */ 361 if (pdosflag) 362 *pdosflag = dosflag; 363 return n; 364} 365 366char *in2ex(n) 367char *n; /* internal file name */ 368/* Convert the zip file name to an external file name, returning the malloc'ed 369 string or NULL if not enough memory. */ 370{ 371 char *x; /* external file name */ 372 373 if ((x = malloc(strlen(n) + 1 + PAD)) == NULL) 374 return NULL; 375 strcpy(x, n); 376 return x; 377} 378 379/* 380 * XXX use ztimbuf in both POSIX and non POSIX cases ? 381 */ 382void stamp(f, d) 383char *f; /* name of file to change */ 384ulg d; /* dos-style time to change it to */ 385/* Set last updated and accessed time of file f to the DOS time d. */ 386{ 387 struct utimbuf u; /* argument for utime() const ?? */ 388 389 /* Convert DOS time to time_t format in u */ 390 u.actime = u.modtime = dos2unixtime(d); 391 utime(f, &u); 392} 393 394ulg filetime(f, a, n, t) 395char *f; /* name of file to get info on */ 396ulg *a; /* return value: file attributes */ 397long *n; /* return value: file size */ 398iztimes *t; /* return value: access, modific. and creation times */ 399/* If file *f does not exist, return 0. Else, return the file's last 400 modified date and time as an MSDOS date and time. The date and 401 time is returned in a long with the date most significant to allow 402 unsigned integer comparison of absolute times. Also, if a is not 403 a NULL pointer, store the file attributes there, with the high two 404 bytes being the Unix attributes, and the low byte being a mapping 405 of that to DOS attributes. Bits 8 to 15 contains native THEOS protection 406 code. If n is not NULL, store the file size there. If t is not NULL, 407 the file's access, modification and creation times are stored there as 408 UNIX time_t values. If f is "-", use standard input as the file. If f is 409 a device, return a file size of -1 */ 410{ 411 struct stat s; /* results of stat() */ 412 /* from FNMAX to malloc - 11/8/04 EG */ 413 char *name; 414 int len = strlen(f); 415 416 if (f == label) { 417 if (a != NULL) 418 *a = label_mode; 419 if (n != NULL) 420 *n = -2L; /* convention for a label name */ 421 if (t != NULL) 422 t->atime = t->mtime = t->ctime = label_utim; 423 return label_time; 424 } 425 if ((name = malloc(len + 1)) == NULL) { 426 ZIPERR(ZE_MEM, "filetime"); 427 } 428 strcpy(name, f); 429 430 if (name[len - 1] == '/' || name[len - 1] == '.') 431 name[len - 1] = '\0'; 432 433 /* not all systems allow stat'ing a file with / appended */ 434 if (strcmp(f, "-") == 0) { 435 if (fstat(fileno(stdin), &s) != 0) { 436 free(name); 437 error("fstat(stdin)"); 438 } 439 } else if (LSSTAT(name, &s) != 0) { 440 /* Accept about any file kind including directories 441 * (stored with trailing / with -r option) 442 */ 443 free(name); 444 return 0; 445 } 446 free(name); 447 448 if (a != NULL) { 449 *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE); 450 if ((s.st_mode & S_IFMT) == S_IFDIR 451 || (s.st_mode & S_IFMT) == S_IFLIB) { 452 *a |= MSDOS_DIR_ATTR; 453 } 454 /* Map Theos' hidden attribute to DOS's hidden attribute */ 455 if (!(st.st_protect & 0x80)) 456 *a |= MSDOS_HIDDEN_ATTR; 457 *a |= ((ulg) s.st_protect) << 8; 458 } 459 if (n != NULL) 460 *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L; 461 if (t != NULL) { 462 t->atime = s.st_atime; 463 t->mtime = s.st_mtime; 464 t->ctime = t->mtime; /* best guess, (s.st_ctime: last status change!!) */ 465 } 466 return unix2dostime(&s.st_mtime); 467} 468/* 469 * Get file THEOS attributes and store them into extent fields. 470 * On error leave z intact. 471 */ 472 473/* 474* Extra record format 475* =================== 476* signature (2 bytes) = 'T','h' 477* size (2 bytes) 478* flags (1 byte) 479* filesize (4 bytes) 480* keylen (2 bytes) 481* reclen (2 bytes) 482* filegrow (1 byte) 483* reserved (4 bytes) 484*/ 485 486#define EB_L_THSIZE 4 487#define EB_L_TH_SIZE 14 488 489int set_extra_field(z, z_utim) 490 struct zlist *z; 491 iztimes *z_utim; 492 /* store full data in local header but just modification time stamp info 493 in central header */ 494{ 495 char *extra = NULL; 496 char *p; 497 char c; 498 struct stat st; 499 int status; 500 501 if (status = stat(z->name, &st)) { 502 p = &z->name[strlen(z->name) - 1]; 503 if (*p == '/' || *p == '.') { 504 c = *p; 505 *p = '\0'; 506 status = stat(z->name, &st); 507 *p = c; 508 } 509#ifdef DEBUG 510 fprintf(stderr, "set_extra_field: stat for file %s:\n status = %d\n", 511 z->name, status); 512#endif 513 if (status) 514 return RET_ERROR; 515 } 516 517 if ((extra = malloc(EB_L_TH_SIZE)) == NULL ) { 518 fprintf(stderr, "set_extra_field: Insufficient memory.\n" ); 519 return RET_ERROR; 520 } 521 522 523 extra[0] = 'T'; 524 extra[1] = 'h'; 525 extra[2] = EB_L_TH_SIZE; 526 extra[3] = EB_L_TH_SIZE >> 8; 527 extra[4] = 0; 528 extra[5] = st.st_size; 529 extra[6] = st.st_size >> 8; 530 extra[7] = st.st_size >> 16; 531 extra[8] = st.st_size >> 24; 532 extra[9] = st.st_org; 533 extra[10] = st.st_rlen; 534 extra[11] = st.st_rlen >> 8; 535 extra[12] = st.st_klen; 536 extra[13] = st.st_klen >> 8; 537 extra[14] = st.st_grow; 538 extra[15] = st.st_protect; 539 extra[16] = 0; 540 extra[17] = 0; 541 z->ext = z->cext = EB_L_TH_SIZE + EB_HEADSIZE; 542 z->extra = z->cextra = extra; 543 return RET_SUCCESS; 544} 545#endif 546 547/******************************/ 548/* Function version_local() */ 549/******************************/ 550 551void version_local() 552{ 553 printf("Compiled with THEOS C 5.28 for THEOS 4.x on %s %s.\n\n", 554 __DATE__, __TIME__); 555} 556 557