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 This AtheOS - specific file is based on unix.c and beos.c; 10 changes by Ruslan Nickolaev (nruslan@hotbox.ru) 11*/ 12 13#include "zip.h" 14 15#ifndef UTIL /* the companion #endif is a bit of ways down ... */ 16 17#include <time.h> 18#include <dirent.h> 19#include <sys/types.h> 20#include <sys/errno.h> 21#include <limits.h> 22#include <sys/stat.h> 23#include <sys/fcntl.h> 24#include <stdlib.h> 25#include <string.h> 26 27#include <atheos/fs_attribs.h> 28 29 30#define PAD 0 31#define PATH_END '/' 32 33/* Library functions not in (most) header files */ 34 35#ifdef _POSIX_VERSION 36# include <utime.h> 37#else 38 int utime OF((char *, time_t *)); 39#endif 40 41extern char *label; 42local ulg label_time = 0; 43local ulg label_mode = 0; 44local time_t label_utim = 0; 45 46/* Local functions */ 47local char *readd OF((DIR *)); 48local int get_attr_dir( const char *, char **, off_t * ); 49local int add_UT_ef( struct zlist far * ); 50local int add_Ux_ef( struct zlist far * ); 51local int add_At_ef( struct zlist far * ); 52 53local char *readd(d) 54DIR *d; /* directory stream to read from */ 55/* Return a pointer to the next name in the directory stream d, or NULL if 56 no more entries or an error occurs. */ 57{ 58 struct dirent *e; 59 60 e = readdir(d); 61 return e == NULL ? (char *) NULL : e->d_name; 62} 63 64int procname(n, caseflag) 65char *n; /* name to process */ 66int caseflag; /* true to force case-sensitive match */ 67/* Process a name or sh expression to operate on (or exclude). Return 68 an error code in the ZE_ class. */ 69{ 70 char *a; /* path and name for recursion */ 71 DIR *d; /* directory stream from opendir() */ 72 char *e; /* pointer to name from readd() */ 73 int m; /* matched flag */ 74 char *p; /* path for recursion */ 75 struct stat s; /* result of stat() */ 76 struct zlist far *z; /* steps through zfiles list */ 77 78 if (strcmp(n, "-") == 0) /* if compressing stdin */ 79 return newname(n, 0, caseflag); 80 else if (LSSTAT(n, &s)) 81 { 82 /* Not a file or directory--search for shell expression in zip file */ 83 p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */ 84 m = 1; 85 for (z = zfiles; z != NULL; z = z->nxt) { 86 if (MATCH(p, z->iname, caseflag)) 87 { 88 z->mark = pcount ? filter(z->zname, caseflag) : 1; 89 if (verbose) 90 fprintf(mesg, "zip diagnostic: %scluding %s\n", 91 z->mark ? "in" : "ex", z->name); 92 m = 0; 93 } 94 } 95 free((zvoid *)p); 96 return m ? ZE_MISS : ZE_OK; 97 } 98 99 /* Live name--use if file, recurse if directory */ 100 if ((s.st_mode & S_IFREG) == S_IFREG || 101 (s.st_mode & S_IFLNK) == S_IFLNK) 102 { 103 /* add or remove name of file */ 104 if ((m = newname(n, 0, caseflag)) != ZE_OK) 105 return m; 106 } 107 else if ((s.st_mode & S_IFDIR) == S_IFDIR) 108 { 109 /* Add trailing / to the directory name */ 110 if ((p = malloc(strlen(n)+2)) == NULL) 111 return ZE_MEM; 112 if (strcmp(n, ".") == 0) { 113 *p = '\0'; /* avoid "./" prefix and do not create zip entry */ 114 } else { 115 strcpy(p, n); 116 a = p + strlen(p); 117 if (a[-1] != '/') 118 strcpy(a, "/"); 119 if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) { 120 free((zvoid *)p); 121 return m; 122 } 123 } 124 /* recurse into directory */ 125 if (recurse && (d = opendir(n)) != NULL) 126 { 127 while ((e = readd(d)) != NULL) { 128 if (strcmp(e, ".") && strcmp(e, "..")) 129 { 130 if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL) 131 { 132 closedir(d); 133 free((zvoid *)p); 134 return ZE_MEM; 135 } 136 strcat(strcpy(a, p), e); 137 if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */ 138 { 139 if (m == ZE_MISS) 140 zipwarn("name not matched: ", a); 141 else 142 ziperr(m, a); 143 } 144 free((zvoid *)a); 145 } 146 } 147 closedir(d); 148 } 149 free((zvoid *)p); 150 } /* (s.st_mode & S_IFDIR) */ 151 else 152 zipwarn("ignoring special file: ", n); 153 return ZE_OK; 154} 155 156char *ex2in(x, isdir, pdosflag) 157char *x; /* external file name */ 158int isdir; /* input: x is a directory */ 159int *pdosflag; /* output: force MSDOS file attributes? */ 160/* Convert the external file name to a zip file name, returning the malloc'ed 161 string or NULL if not enough memory. */ 162{ 163 char *n; /* internal file name (malloc'ed) */ 164 char *t = NULL; /* shortened name */ 165 int dosflag; 166 167 dosflag = dosify; /* default for non-DOS and non-OS/2 */ 168 169 /* Find starting point in name before doing malloc */ 170 /* Strip "//host/share/" part of a UNC name */ 171 if (!strncmp(x,"//",2) && (x[2] != '\0' && x[2] != '/')) { 172 n = x + 2; 173 while (*n != '\0' && *n != '/') 174 n++; /* strip host name */ 175 if (*n != '\0') { 176 n++; 177 while (*n != '\0' && *n != '/') 178 n++; /* strip `share' name */ 179 } 180 if (*n != '\0') 181 t = n + 1; 182 } else 183 t = x; 184 while (*t == '/') 185 t++; /* strip leading '/' chars to get a relative path */ 186 while (*t == '.' && t[1] == '/') 187 t += 2; /* strip redundant leading "./" sections */ 188 189 /* Make changes, if any, to the copied name (leave original intact) */ 190 if (!pathput) 191 t = last(t, PATH_END); 192 193 /* Malloc space for internal name and copy it */ 194 if ((n = malloc(strlen(t) + 1)) == NULL) 195 return NULL; 196 strcpy(n, t); 197 198 if (isdir == 42) return n; /* avoid warning on unused variable */ 199 200 if (dosify) 201 msname(n); 202 203 /* Returned malloc'ed name */ 204 if (pdosflag) 205 *pdosflag = dosflag; 206 return n; 207} 208 209char *in2ex(n) 210char *n; /* internal file name */ 211/* Convert the zip file name to an external file name, returning the malloc'ed 212 string or NULL if not enough memory. */ 213{ 214 char *x; /* external file name */ 215 216 if ((x = malloc(strlen(n) + 1 + PAD)) == NULL) 217 return NULL; 218 strcpy(x, n); 219 return x; 220} 221 222/* 223 * XXX use ztimbuf in both POSIX and non POSIX cases ? 224 */ 225void stamp(f, d) 226char *f; /* name of file to change */ 227ulg d; /* dos-style time to change it to */ 228/* Set last updated and accessed time of file f to the DOS time d. */ 229{ 230#ifdef _POSIX_VERSION 231 struct utimbuf u; /* argument for utime() const ?? */ 232#else 233 time_t u[2]; /* argument for utime() */ 234#endif 235 236 /* Convert DOS time to time_t format in u */ 237#ifdef _POSIX_VERSION 238 u.actime = u.modtime = dos2unixtime(d); 239 utime(f, &u); 240#else 241 u[0] = u[1] = dos2unixtime(d); 242 utime(f, u); 243#endif 244 245} 246 247ulg filetime(f, a, n, t) 248char *f; /* name of file to get info on */ 249ulg *a; /* return value: file attributes */ 250long *n; /* return value: file size */ 251iztimes *t; /* return value: access, modific. and creation times */ 252/* If file *f does not exist, return 0. Else, return the file's last 253 modified date and time as an MSDOS date and time. The date and 254 time is returned in a long with the date most significant to allow 255 unsigned integer comparison of absolute times. Also, if a is not 256 a NULL pointer, store the file attributes there, with the high two 257 bytes being the Unix attributes, and the low byte being a mapping 258 of that to DOS attributes. If n is not NULL, store the file size 259 there. If t is not NULL, the file's access, modification and creation 260 times are stored there as UNIX time_t values. 261 If f is "-", use standard input as the file. If f is a device, return 262 a file size of -1 */ 263{ 264 struct stat s; /* results of stat() */ 265 char *name; 266 int len = strlen(f); 267 268 if (f == label) { 269 if (a != NULL) 270 *a = label_mode; 271 if (n != NULL) 272 *n = -2L; /* convention for a label name */ 273 if (t != NULL) 274 t->atime = t->mtime = t->ctime = label_utim; 275 return label_time; 276 } 277 if ((name = malloc(len + 1)) == NULL { 278 ZIPERR(ZE_MEM, "filetime"); 279 } 280 strcpy(name, f); 281 if (name[len - 1] == '/') 282 name[len - 1] = '\0'; 283 /* not all systems allow stat'ing a file with / appended */ 284 if (strcmp(f, "-") == 0) { 285 if (fstat(fileno(stdin), &s) != 0) { 286 free(name); 287 error("fstat(stdin)"); 288 } 289 } 290 else if (LSSTAT(name, &s) != 0) { 291 /* Accept about any file kind including directories 292 * (stored with trailing / with -r option) 293 */ 294 free(name); 295 return 0; 296 } 297 free(name); 298 299 if (a != NULL) { 300#ifndef OS390 301 *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE); 302#else 303/* 304** The following defines are copied from the unizip source and represent the 305** legacy Unix mode flags. These fixed bit masks are no longer required 306** by XOPEN standards - the S_IS### macros being the new recommended method. 307** The approach here of setting the legacy flags by testing the macros should 308** work under any _XOPEN_SOURCE environment (and will just rebuild the same bit 309** mask), but is required if the legacy bit flags differ from legacy Unix. 310*/ 311#define UNX_IFDIR 0040000 /* Unix directory */ 312#define UNX_IFREG 0100000 /* Unix regular file */ 313#define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */ 314#define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */ 315#define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */ 316#define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */ 317#define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */ 318 { 319 mode_t legacy_modes; 320 321 /* Initialize with permission bits - which are not implementation optional */ 322 legacy_modes = s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); 323 if (S_ISDIR(s.st_mode)) 324 legacy_modes |= UNX_IFDIR; 325 if (S_ISREG(s.st_mode)) 326 legacy_modes |= UNX_IFREG; 327 if (S_ISLNK(s.st_mode)) 328 legacy_modes |= UNX_IFLNK; 329 if (S_ISBLK(s.st_mode)) 330 legacy_modes |= UNX_IFBLK; 331 if (S_ISCHR(s.st_mode)) 332 legacy_modes |= UNX_IFCHR; 333 if (S_ISFIFO(s.st_mode)) 334 legacy_modes |= UNX_IFIFO; 335 if (S_ISSOCK(s.st_mode)) 336 legacy_modes |= UNX_IFSOCK; 337 *a = ((ulg)legacy_modes << 16) | !(s.st_mode & S_IWRITE); 338 } 339#endif 340 if ((s.st_mode & S_IFMT) == S_IFDIR) { 341 *a |= MSDOS_DIR_ATTR; 342 } 343 } 344 if (n != NULL) 345 *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L; 346 if (t != NULL) { 347 t->atime = s.st_atime; 348 t->mtime = s.st_mtime; 349 t->ctime = t->mtime; /* best guess, (s.st_ctime: last status change!!) */ 350 } 351 return unix2dostime(&s.st_mtime); 352} 353 354/* ---------------------------------------------------------------------- 355 356Return a malloc()'d buffer containing all of the attributes and their names 357for the file specified in name. You have to free() this yourself. The length 358of the buffer is also returned. 359 360If get_attr_dir() fails, the buffer will be NULL, total_size will be 0, 361and an error will be returned: 362 363 EOK - no errors occurred 364 EINVAL - attr_buff was pointing at a buffer 365 ENOMEM - insufficient memory for attribute buffer 366 367Other errors are possible (whatever is returned by the fs_attrib.h functions). 368 369PROBLEMS: 370 371- pointers are 32-bits; attributes are limited to ssize_t in size so it's 372 possible to overflow... in practice, this isn't too likely... your 373 machine will thrash like hell before that happens 374 375*/ 376 377#define INITIAL_BUFF_SIZE 65536 378 379int get_attr_dir( const char *name, char **attr_buff, off_t *total_size ) 380{ 381 int retval = EOK; 382 int fd; 383 DIR *fa_dir; 384 struct dirent *fa_ent; 385 off_t attrs_size = 0; 386 size_t entname_size; 387 char *ptr; 388 struct attr_info fa_info; 389 390 *total_size = 0; 391 392 /* ----------------------------------------------------------------- */ 393 /* Sanity-check. */ 394 if( *attr_buff != NULL ) { 395 return EINVAL; 396 } 397 398 /* ----------------------------------------------------------------- */ 399 /* Can we open the file/directory? */ 400 /* */ 401 /* linkput is a zip global; it's set to 1 if we're storing symbolic */ 402 /* links as symbolic links (instead of storing the thing the link */ 403 /* points to)... if we're storing the symbolic link as a link, we'll */ 404 /* want the link's file attributes, otherwise we want the target's. */ 405 406 fd = open( name, linkput ? O_RDONLY | O_NOTRAVERSE : O_RDONLY ); 407 if( fd < 0 ) { 408 return errno; 409 } 410 411 /* ----------------------------------------------------------------- */ 412 /* Allocate an initial buffer; 64k should usually be enough. */ 413 *attr_buff = (char *)malloc( INITIAL_BUFF_SIZE ); 414 ptr = *attr_buff; 415 if( ptr == NULL ) { 416 close( fd ); 417 418 return ENOMEM; 419 } 420 421 /* ----------------------------------------------------------------- */ 422 /* Open the attributes directory for this file. */ 423 fa_dir = open_attrdir( fd ); 424 if( fa_dir == NULL ) { 425 close( fd ); 426 427 free( ptr ); 428 *attr_buff = NULL; 429 430 return retval; 431 } 432 433 /* ----------------------------------------------------------------- */ 434 /* Read all the attributes; the buffer could grow > 64K if there are */ 435 /* many and/or they are large. */ 436 while( ( fa_ent = read_attrdir( fa_dir ) ) != NULL ) { 437 retval = stat_attr( fd, fa_ent->d_name, &fa_info ); 438 /* TODO: check retval != EOK */ 439 440 entname_size = strlen( fa_ent->d_name ) + 1; 441 attrs_size += entname_size + sizeof( struct attr_info ) + fa_info.ai_size; 442 443 if( attrs_size > INITIAL_BUFF_SIZE ) { 444 unsigned long offset = ptr - *attr_buff; 445 446 *attr_buff = (char *)realloc( *attr_buff, attrs_size ); 447 if( *attr_buff == NULL ) { 448 retval = close_attrdir( fa_dir ); 449 /* TODO: check retval != EOK */ 450 close( fd ); 451 return ENOMEM; 452 } 453 454 ptr = *attr_buff + offset; 455 } 456 457 /* Now copy the data for this attribute into the buffer. */ 458 strcpy( ptr, fa_ent->d_name ); 459 ptr += entname_size; 460 461 memcpy( ptr, &fa_info, sizeof( struct attr_info ) ); 462 ptr += sizeof( struct attr_info ); 463 464 if( fa_info.ai_size > 0 ) { 465 ssize_t read_bytes = read_attr( fd, fa_ent->d_name, fa_info.ai_type, ptr, 0, fa_info.ai_size ); 466 if( read_bytes != fa_info.ai_size ) { 467 /* print a warning about mismatched sizes */ 468 char buff[80]; 469 sprintf( buff, "read %d, expected %d", read_bytes, (ssize_t)fa_info.ai_size ); 470 zipwarn( "attribute size mismatch: ", buff ); 471 } 472 473 ptr += fa_info.ai_size; 474 } 475 } 476 477 /* ----------------------------------------------------------------- */ 478 /* Close the attribute directory. */ 479 retval = close_attrdir( fa_dir ); 480 /* TODO: check retval != EOK */ 481 482 /* ----------------------------------------------------------------- */ 483 /* If the buffer is too big, shrink it. */ 484 if( attrs_size < INITIAL_BUFF_SIZE ) { 485 *attr_buff = (char *)realloc( *attr_buff, attrs_size ); 486 if( *attr_buff == NULL ) { 487 close( fd ); 488 return ENOMEM; 489 } 490 } 491 492 *total_size = attrs_size; 493 494 close( fd ); 495 496 return EOK; 497} 498 499/* ---------------------------------------------------------------------- */ 500/* Add a 'UT' extra field to the zlist data pointed to by z. */ 501 502#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(2)) 503#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1)) 504 505local int add_UT_ef( struct zlist far *z ) 506{ 507 char *l_ef = NULL; 508 char *c_ef = NULL; 509 struct stat s; 510 511#ifdef IZ_CHECK_TZ 512 if (!zp_tz_is_valid) 513 return ZE_OK; /* skip silently if no valid TZ info */ 514#endif 515 516 /* We can't work if there's no entry to work on. */ 517 if( z == NULL ) { 518 return ZE_LOGIC; 519 } 520 521 /* Check to make sure we've got enough room in the extra fields. */ 522 if( z->ext + EB_L_UT_SIZE > USHRT_MAX || 523 z->cext + EB_C_UT_SIZE > USHRT_MAX ) { 524 return ZE_MEM; 525 } 526 527 /* stat() the file (or the symlink) to get the data; if we can't get */ 528 /* the data, there's no point in trying to fill out the fields. */ 529 if(LSSTAT( z->name, &s ) ) { 530 return ZE_OPEN; 531 } 532 533 /* Allocate memory for the local and central extra fields. */ 534 if( z->extra && z->ext != 0 ) { 535 l_ef = (char *)realloc( z->extra, z->ext + EB_L_UT_SIZE ); 536 } else { 537 l_ef = (char *)malloc( EB_L_UT_SIZE ); 538 z->ext = 0; 539 } 540 if( l_ef == NULL ) { 541 return ZE_MEM; 542 } 543 z->extra = l_ef; 544 l_ef += z->ext; 545 546 if( z->cextra && z->cext != 0 ) { 547 c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UT_SIZE ); 548 } else { 549 c_ef = (char *)malloc( EB_C_UT_SIZE ); 550 z->cext = 0; 551 } 552 if( c_ef == NULL ) { 553 return ZE_MEM; 554 } 555 z->cextra = c_ef; 556 c_ef += z->cext; 557 558 /* Now add the local version of the field. */ 559 *l_ef++ = 'U'; 560 *l_ef++ = 'T'; 561 *l_ef++ = (char)(EB_UT_LEN(2)); /* length of data in local EF */ 562 *l_ef++ = (char)0; 563 *l_ef++ = (char)(EB_UT_FL_MTIME | EB_UT_FL_ATIME); 564 *l_ef++ = (char)(s.st_mtime); 565 *l_ef++ = (char)(s.st_mtime >> 8); 566 *l_ef++ = (char)(s.st_mtime >> 16); 567 *l_ef++ = (char)(s.st_mtime >> 24); 568 *l_ef++ = (char)(s.st_atime); 569 *l_ef++ = (char)(s.st_atime >> 8); 570 *l_ef++ = (char)(s.st_atime >> 16); 571 *l_ef++ = (char)(s.st_atime >> 24); 572 573 z->ext += EB_L_UT_SIZE; 574 575 /* Now add the central version. */ 576 memcpy(c_ef, l_ef-EB_L_UT_SIZE, EB_C_UT_SIZE); 577 c_ef[EB_LEN] = (char)(EB_UT_LEN(1)); /* length of data in central EF */ 578 579 z->cext += EB_C_UT_SIZE; 580 581 return ZE_OK; 582} 583 584/* ---------------------------------------------------------------------- */ 585/* Add a 'Ux' extra field to the zlist data pointed to by z. */ 586 587#define EB_L_UX2_SIZE (EB_HEADSIZE + EB_UX2_MINLEN) 588#define EB_C_UX2_SIZE (EB_HEADSIZE) 589 590local int add_Ux_ef( struct zlist far *z ) 591{ 592 char *l_ef = NULL; 593 char *c_ef = NULL; 594 struct stat s; 595 596 /* Check to make sure we've got enough room in the extra fields. */ 597 if( z->ext + EB_L_UX2_SIZE > USHRT_MAX || 598 z->cext + EB_C_UX2_SIZE > USHRT_MAX ) { 599 return ZE_MEM; 600 } 601 602 /* stat() the file (or the symlink) to get the data; if we can't get */ 603 /* the data, there's no point in trying to fill out the fields. */ 604 if(LSSTAT( z->name, &s ) ) { 605 return ZE_OPEN; 606 } 607 608 /* Allocate memory for the local and central extra fields. */ 609 if( z->extra && z->ext != 0 ) { 610 l_ef = (char *)realloc( z->extra, z->ext + EB_L_UX2_SIZE ); 611 } else { 612 l_ef = (char *)malloc( EB_L_UX2_SIZE ); 613 z->ext = 0; 614 } 615 if( l_ef == NULL ) { 616 return ZE_MEM; 617 } 618 z->extra = l_ef; 619 l_ef += z->ext; 620 621 if( z->cextra && z->cext != 0 ) { 622 c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UX2_SIZE ); 623 } else { 624 c_ef = (char *)malloc( EB_C_UX2_SIZE ); 625 z->cext = 0; 626 } 627 if( c_ef == NULL ) { 628 return ZE_MEM; 629 } 630 z->cextra = c_ef; 631 c_ef += z->cext; 632 633 /* Now add the local version of the field. */ 634 *l_ef++ = 'U'; 635 *l_ef++ = 'x'; 636 *l_ef++ = (char)(EB_UX2_MINLEN); 637 *l_ef++ = (char)(EB_UX2_MINLEN >> 8); 638 *l_ef++ = (char)(s.st_uid); 639 *l_ef++ = (char)(s.st_uid >> 8); 640 *l_ef++ = (char)(s.st_gid); 641 *l_ef++ = (char)(s.st_gid >> 8); 642 643 z->ext += EB_L_UX2_SIZE; 644 645 /* Now add the central version of the field. */ 646 *c_ef++ = 'U'; 647 *c_ef++ = 'x'; 648 *c_ef++ = 0; 649 *c_ef++ = 0; 650 651 z->cext += EB_C_UX2_SIZE; 652 653 return ZE_OK; 654} 655 656/* ---------------------------------------------------------------------- */ 657/* Add a 'At' extra field to the zlist data pointed to by z. */ 658 659#define EB_L_AT_SIZE (EB_HEADSIZE + EB_L_AT_LEN) /* + attr size */ 660#define EB_C_AT_SIZE (EB_HEADSIZE + EB_C_AT_LEN) 661 662#define MEMCOMPRESS_HEADER 6 /* ush compression type, ulg CRC */ 663#define DEFLAT_WORSTCASE_ADD 5 /* byte blocktype, 2 * ush blocklength */ 664#define MEMCOMPRESS_OVERHEAD (MEMCOMPRESS_HEADER + DEFLAT_WORSTCASE_ADD) 665 666local int add_At_ef( struct zlist far *z ) 667{ 668 char *l_ef = NULL; 669 char *c_ef = NULL; 670 char *attrbuff = NULL; 671 off_t attrsize = 0; 672 char *compbuff = NULL; 673 ush compsize = 0; 674 uch flags = 0; 675 676 /* Check to make sure we've got enough room in the extra fields. */ 677 if( z->ext + EB_L_AT_SIZE > USHRT_MAX || 678 z->cext + EB_C_AT_SIZE > USHRT_MAX ) { 679 return ZE_MEM; 680 } 681 682 /* Attempt to load up a buffer full of the file's attributes. */ 683 { 684 if (get_attr_dir( z->name, &attrbuff, &attrsize) != EOK ) { 685 return ZE_OPEN; 686 } 687 if (attrsize == 0) { 688 return ZE_OK; 689 } 690 if (attrbuff == NULL) { 691 return ZE_LOGIC; 692 } 693 694 /* Check for way too much data. */ 695 if (attrsize > (off_t)ULONG_MAX) { 696 zipwarn( "uncompressed attributes truncated", "" ); 697 attrsize = (off_t)(ULONG_MAX - MEMCOMPRESS_OVERHEAD); 698 } 699 } 700 701 if (verbose) { 702 printf( "\t[in=%lu]", (unsigned long)attrsize ); 703 } 704 705 /* Try compressing the data */ 706 compbuff = (char *)malloc( (size_t)attrsize + MEMCOMPRESS_OVERHEAD ); 707 if( compbuff == NULL ) { 708 return ZE_MEM; 709 } 710 compsize = memcompress( compbuff, 711 (size_t)attrsize + MEMCOMPRESS_OVERHEAD, 712 attrbuff, 713 (size_t)attrsize ); 714 if (verbose) { 715 printf( " [out=%u]", compsize ); 716 } 717 718 /* Attempt to optimise very small attributes. */ 719 if (compsize > attrsize) { 720 free( compbuff ); 721 compsize = (ush)attrsize; 722 compbuff = attrbuff; 723 724 flags = EB_AT_FL_NATURAL; 725 } 726 727 /* Check to see if we really have enough room in the EF for the data. */ 728 if( ( z->ext + compsize + EB_L_AT_LEN ) > USHRT_MAX ) { 729 compsize = USHRT_MAX - EB_L_AT_LEN - z->ext; 730 } 731 732 /* Allocate memory for the local and central extra fields. */ 733 if( z->extra && z->ext != 0 ) { 734 l_ef = (char *)realloc( z->extra, z->ext + EB_L_AT_SIZE + compsize ); 735 } else { 736 l_ef = (char *)malloc( EB_L_AT_SIZE + compsize ); 737 z->ext = 0; 738 } 739 if( l_ef == NULL ) { 740 return ZE_MEM; 741 } 742 z->extra = l_ef; 743 l_ef += z->ext; 744 745 if( z->cextra && z->cext != 0 ) { 746 c_ef = (char *)realloc( z->cextra, z->cext + EB_C_AT_SIZE ); 747 } else { 748 c_ef = (char *)malloc( EB_C_AT_SIZE ); 749 z->cext = 0; 750 } 751 if( c_ef == NULL ) { 752 return ZE_MEM; 753 } 754 z->cextra = c_ef; 755 c_ef += z->cext; 756 757 /* Now add the local version of the field. */ 758 *l_ef++ = 'A'; 759 *l_ef++ = 't'; 760 *l_ef++ = (char)(compsize + EB_L_AT_LEN); 761 *l_ef++ = (char)((compsize + EB_L_AT_LEN) >> 8); 762 *l_ef++ = (char)((unsigned long)attrsize); 763 *l_ef++ = (char)((unsigned long)attrsize >> 8); 764 *l_ef++ = (char)((unsigned long)attrsize >> 16); 765 *l_ef++ = (char)((unsigned long)attrsize >> 24); 766 *l_ef++ = flags; 767 memcpy( l_ef, compbuff, (size_t)compsize ); 768 769 z->ext += EB_L_AT_SIZE + compsize; 770 771 /* And the central version. */ 772 *c_ef++ = 'A'; 773 *c_ef++ = 't'; 774 *c_ef++ = (char)(EB_C_AT_LEN); 775 *c_ef++ = (char)(EB_C_AT_LEN >> 8); 776 *c_ef++ = (char)compsize; 777 *c_ef++ = (char)(compsize >> 8); 778 *c_ef++ = (char)(compsize >> 16); 779 *c_ef++ = (char)(compsize >> 24); 780 *c_ef++ = flags; 781 782 z->cext += EB_C_AT_SIZE; 783 784 return ZE_OK; 785} 786 787/* Extra field info: 788 - 'UT' - UNIX time extra field 789 - 'Ux' - UNIX uid/gid extra field 790 - 'At' - AtheOS file attributes extra field 791 792 This is done the same way ../unix/unix.c stores the 'UT'/'Ux' fields 793 (full data in local header, only modification time in central header), 794 with the 'At' field added to the end and the size of the 'At' field 795 in the central header. 796 797 See the end of atheos/osdep.h for a simple explanation of the 'At' EF 798 layout. 799 */ 800int set_extra_field(z, z_utim) 801 struct zlist far *z; 802 iztimes *z_utim; 803 /* store full data in local header but just modification time stamp info 804 in central header */ 805{ 806 int retval; 807 808 /* Check to make sure z is valid. */ 809 if( z == NULL ) { 810 return ZE_LOGIC; 811 } 812 813 retval = add_UT_ef(z); 814 if( retval != ZE_OK ) { 815 return retval; 816 } 817 818 retval = add_Ux_ef(z); 819 if( retval != ZE_OK ) { 820 return retval; 821 } 822 823 return add_At_ef(z); /* last function; we can use return value directly */ 824} 825 826/* ---------------------------------------------------------------------- */ 827/* Set a file's MIME type. */ 828void setfiletype(const char *file, const char *type) 829{ 830 int fd; 831 off_t nLen; 832 ssize_t nError; 833 834 fd = open( file, O_RDWR ); 835 836 if (fd < 0) { 837 zipwarn( "can't open zipfile to write file type", "" ); 838 } 839 840 else 841 { 842 nLen = strlen( type ); 843 /* FIXME: write_attr() should return count of writed bytes */ 844 nError = write_attr( fd, "os::MimeType", O_TRUNC, ATTR_TYPE_STRING, type, 0, nLen ); 845 if (nError < 0) { 846 zipwarn( "couldn't write complete file type", "" ); 847 } 848 close( fd ); 849 } 850} 851 852#endif /* !UTIL */ 853 854/******************************/ 855/* Function version_local() */ 856/******************************/ 857 858void version_local() 859{ 860 static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n"; 861 862 printf(CompiledWith, 863 864#ifdef __GNUC__ 865 "gcc ", __VERSION__, 866#else 867 "(unknown compiler)", "", 868#endif 869 870 "Syllable", 871 872#if defined(i486) || defined(__i486) || defined(__i486__) || defined(i386) || defined(__i386) || defined(__i386__) 873 " (x86)", 874#else 875 " (unknown platform)", 876#endif 877 878#ifdef __DATE__ 879 " on ", __DATE__ 880#else 881 "", "" 882#endif 883 ); 884 885} /* end function version_local() */ 886