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
41 extern char *label;
42 local ulg label_time = 0;
43 local ulg label_mode = 0;
44 local time_t label_utim = 0;
45
46 /* Local functions */
47 local char *readd OF((DIR *));
48 local int get_attr_dir( const char *, char **, off_t * );
49 local int add_UT_ef( struct zlist far * );
50 local int add_Ux_ef( struct zlist far * );
51 local int add_At_ef( struct zlist far * );
52
readd(d)53 local char *readd(d)
54 DIR *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
procname(n,caseflag)64 int procname(n, caseflag)
65 char *n; /* name to process */
66 int 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
ex2in(x,isdir,pdosflag)156 char *ex2in(x, isdir, pdosflag)
157 char *x; /* external file name */
158 int isdir; /* input: x is a directory */
159 int *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
in2ex(n)209 char *in2ex(n)
210 char *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 */
stamp(f,d)225 void stamp(f, d)
226 char *f; /* name of file to change */
227 ulg 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
filetime(f,a,n,t)247 ulg filetime(f, a, n, t)
248 char *f; /* name of file to get info on */
249 ulg *a; /* return value: file attributes */
250 long *n; /* return value: file size */
251 iztimes *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
356 Return a malloc()'d buffer containing all of the attributes and their names
357 for the file specified in name. You have to free() this yourself. The length
358 of the buffer is also returned.
359
360 If get_attr_dir() fails, the buffer will be NULL, total_size will be 0,
361 and 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
367 Other errors are possible (whatever is returned by the fs_attrib.h functions).
368
369 PROBLEMS:
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
379 int 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
505 local 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
590 local 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
666 local 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 */
800 int 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. */
828 void 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
858 void 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