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