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