From a48f57e1c902b2e6ef2d946cfebf2da0637f9a88 Mon Sep 17 00:00:00 2001
From: Jerome Duval <jerome.duval@gmail.com>
Date: Sat, 28 Feb 2015 18:07:06 +0000
Subject: Haiku patch


diff --git a/tailor.h b/tailor.h
index 272f979..b79221c 100644
--- a/tailor.h
+++ b/tailor.h
@@ -68,6 +68,12 @@
 #include "macos/osdep.h"
 #endif
 
+#ifdef __HAIKU__
+#undef local
+#include <sys/types.h>
+#define local static
+#endif
+
 #ifdef NLM
 #include "novell/osdep.h"
 #endif
diff --git a/unix/Makefile b/unix/Makefile
index abd0c44..09b5a4f 100644
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -38,8 +38,8 @@ BINFLAGS = 755
 MANFLAGS = 644
 
 # target directories - where to install executables and man pages to
-prefix = /usr/local
-BINDIR = $(prefix)/bin
+prefix = $PREFIX
+BINDIR ?= $(prefix)/bin
 MANEXT=1
 MANDIR = $(prefix)/man/man$(MANEXT)
 ZIPMANUAL = zip.txt
diff --git a/unix/osdep.h b/unix/osdep.h
index 10f8ee9..b766e52 100644
--- a/unix/osdep.h
+++ b/unix/osdep.h
@@ -78,3 +78,9 @@
 #if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
 #  define USE_EF_UT_TIME
 #endif
+
+#ifdef __HAIKU__
+  #ifndef ZP_NEED_MEMCOMPR
+  #  define ZP_NEED_MEMCOMPR
+  #endif
+#endif
diff --git a/unix/unix.c b/unix/unix.c
index f4d655d..970af5c 100644
--- a/unix/unix.c
+++ b/unix/unix.c
@@ -42,6 +42,13 @@
 #  endif
 #endif /* HAVE_DIRENT_H || _POSIX_VERSION */
 
+#ifdef __HAIKU__
+#include <errno.h>
+#include <fs_attr.h>
+#include <Mime.h>
+#include <ByteOrder.h>
+#endif
+
 #define PAD 0
 #define PATH_END '/'
 
@@ -434,6 +441,355 @@ ulg filetime(f, a, n, t)
 
 
 #ifndef QLZIP /* QLZIP Unix2QDOS cross-Zip supplies an extended variant */
+#ifdef __HAIKU__
+
+/* Set a file's MIME type. */
+#define BE_FILE_TYPE_NAME   "BEOS:TYPE"
+
+/* ---------------------------------------------------------------------- */
+/* Set a file's MIME type.                                                */
+void setfiletype( const char *file, const char *type )
+{
+    int fd;
+    attr_info fa;
+    ssize_t wrote_bytes;
+
+    fd = open( file, O_RDWR );
+    if( fd < 0 ) {
+        zipwarn( "can't open zipfile to write file type", "" );
+        return;
+    }
+
+    fa.type = B_MIME_STRING_TYPE;
+    fa.size = (off_t)(strlen( type ) + 1);
+
+    wrote_bytes = fs_write_attr( fd, BE_FILE_TYPE_NAME, fa.type, 0,
+                                 type, fa.size );
+    if( wrote_bytes != (ssize_t)fa.size ) {
+        zipwarn( "couldn't write complete file type", "" );
+    }
+
+    close( fd );
+}
+
+/* ----------------------------------------------------------------------
+
+Return a malloc()'d buffer containing all of the attributes and their names
+for the file specified in name.  You have to free() this yourself.  The length
+of the buffer is also returned.
+
+If get_attr_dir() fails, the buffer will be NULL, total_size will be 0,
+and an error will be returned:
+
+    ZE_OK    - no errors occurred
+    ZE_LOGIC - attr_buff was pointing at a buffer
+    ZE_MEM - insufficient memory for attribute buffer
+
+Other errors are possible (whatever is returned by the fs_attr.h functions).
+
+PROBLEMS:
+
+- pointers are 32-bits; attributes are limited to off_t in size so it's
+  possible to overflow... in practice, this isn't too likely... your
+  machine will thrash like hell before that happens
+
+*/
+
+#define INITIAL_BUFF_SIZE 65536
+
+int get_attr_dir( const char *name, char **attr_buff, off_t *total_size )
+{
+    int               retval = ZE_OK;
+    int               fd;
+    DIR              *fa_dir;
+    struct dirent    *fa_ent;
+    off_t             attrs_size;
+    off_t             this_size;
+    char             *ptr;
+    struct attr_info  fa_info;
+    struct attr_info  big_fa_info;
+
+    retval      = ZE_OK;
+    attrs_size  = 0;    /* gcc still says this is used uninitialized... */
+    *total_size = 0;
+
+    /* ----------------------------------------------------------------- */
+    /* Sanity-check.                                                     */
+    if( *attr_buff != NULL ) {
+        return ZE_LOGIC;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Can we open the file/directory?                                   */
+    /*                                                                   */
+    /* linkput is a zip global; it's set to 1 if we're storing symbolic  */
+    /* links as symbolic links (instead of storing the thing the link    */
+    /* points to)... if we're storing the symbolic link as a link, we'll */
+    /* want the link's file attributes, otherwise we want the target's.  */
+    if( linkput ) {
+        fd = open( name, O_RDONLY | O_NOTRAVERSE );
+    } else {
+        fd = open( name, O_RDONLY );
+    }
+    if( fd < 0 ) {
+        return errno;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Allocate an initial buffer; 64k should usually be enough.         */
+    *attr_buff = (char *)malloc( INITIAL_BUFF_SIZE );
+    ptr        = *attr_buff;
+    if( ptr == NULL ) {
+        close( fd );
+
+        return ZE_MEM;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Open the attributes directory for this file.                      */
+    fa_dir = fs_fopen_attr_dir( fd );
+    if( fa_dir == NULL ) {
+        close( fd );
+
+        free( ptr );
+        *attr_buff = NULL;
+
+        return retval;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Read all the attributes; the buffer could grow > 64K if there are */
+    /* many and/or they are large.                                       */
+    fa_ent = fs_read_attr_dir( fa_dir );
+    while( fa_ent != NULL ) {
+        retval = fs_stat_attr( fd, fa_ent->d_name, &fa_info );
+        /* TODO: check retval != ZE_OK */
+
+        this_size  = strlen( fa_ent->d_name ) + 1;
+        this_size += sizeof( struct attr_info );
+        this_size += fa_info.size;
+
+        attrs_size += this_size;
+
+        if( attrs_size > INITIAL_BUFF_SIZE ) {
+            unsigned long offset = ptr - *attr_buff;
+
+            *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+            if( *attr_buff == NULL ) {
+                retval = fs_close_attr_dir( fa_dir );
+                /* TODO: check retval != ZE_OK */
+                close( fd );
+
+                return ZE_MEM;
+            }
+
+            ptr = *attr_buff + offset;
+        }
+
+        /* Now copy the data for this attribute into the buffer. */
+        strcpy( ptr, fa_ent->d_name );
+        ptr += strlen( fa_ent->d_name );
+        *ptr++ = '\0';
+
+        /* We need to put a big-endian version of the fa_info data into */
+        /* the archive.                                                 */
+        big_fa_info.type = B_HOST_TO_BENDIAN_INT32( fa_info.type );
+        big_fa_info.size = B_HOST_TO_BENDIAN_INT64( fa_info.size );
+        memcpy( ptr, &big_fa_info, sizeof( struct attr_info ) );
+        ptr += sizeof( struct attr_info );
+
+        if( fa_info.size > 0 ) {
+            ssize_t read_bytes;
+
+            read_bytes = fs_read_attr( fd, fa_ent->d_name, fa_info.type, 0,
+                                       ptr, fa_info.size );
+            if( read_bytes != fa_info.size ) {
+                /* print a warning about mismatched sizes */
+                char buff[80];
+
+                sprintf( buff, "read %ld, expected %ld",
+                         (ssize_t)read_bytes, (ssize_t)fa_info.size );
+                zipwarn( "attribute size mismatch: ", buff );
+            }
+
+            /* Wave my magic wand... this swaps all the Be types to big- */
+            /* endian automagically.                                     */
+            (void)swap_data( fa_info.type, ptr, fa_info.size,
+                             B_SWAP_HOST_TO_BENDIAN );
+
+            ptr += fa_info.size;
+        }
+
+        fa_ent = fs_read_attr_dir( fa_dir );
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Close the attribute directory.                                    */
+    retval = fs_close_attr_dir( fa_dir );
+    /* TODO: check retval != ZE_OK */
+
+    /* ----------------------------------------------------------------- */
+    /* If the buffer is too big, shrink it.                              */
+    if( attrs_size < INITIAL_BUFF_SIZE ) {
+        *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+        if( *attr_buff == NULL ) {
+            /* This really shouldn't happen... */
+            close( fd );
+
+            return ZE_MEM;
+        }
+    }
+
+    *total_size = attrs_size;
+
+    close( fd );
+
+    return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'Be' extra field to the zlist data pointed to by z.              */
+
+#define EB_L_BE_LEN 5           /* min size is an unsigned long and flag */
+#define EB_C_BE_LEN 5           /* Length of data in local EF and flag.  */
+
+#define EB_BE_FL_NATURAL    0x01    /* data is 'natural' (not compressed) */
+
+#define EB_L_BE_SIZE    (EB_HEADSIZE + EB_L_BE_LEN) /* + attr size */
+#define EB_C_BE_SIZE    (EB_HEADSIZE + EB_C_BE_LEN)
+
+/* maximum memcompress overhead is the sum of the compression header length */
+/* (6 = ush compression type, ulg CRC) and the worstcase deflate overhead   */
+/* when uncompressible data are kept in 2 "stored" blocks (5 per block =    */
+/* byte blocktype + 2 * ush blocklength) */
+#define MEMCOMPRESS_OVERHEAD    (EB_MEMCMPR_HSIZ + EB_DEFLAT_EXTRA)
+
+local int add_Be_ef( struct zlist far *z )
+{
+    char *l_ef       = NULL;
+    char *c_ef       = NULL;
+    char *attrbuff   = NULL;
+    off_t attrsize   = 0;
+    char *compbuff   = NULL;
+    ush   compsize   = 0;
+    uch   flags      = 0;
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + EB_L_BE_SIZE > USHRT_MAX ||
+        z->cext + EB_C_BE_SIZE > USHRT_MAX ) {
+        return ZE_MEM;
+    }
+
+    /* Attempt to load up a buffer full of the file's attributes. */
+    {
+        int retval;
+
+        retval = get_attr_dir( z->name, &attrbuff, &attrsize );
+        if( retval != ZE_OK ) {
+            return ZE_OPEN;
+        }
+        if( attrsize == 0 ) {
+            return ZE_OK;
+        }
+        if( attrbuff == NULL ) {
+            return ZE_LOGIC;
+        }
+
+        /* Check for way too much data. */
+        if( attrsize > (off_t)ULONG_MAX ) {
+            zipwarn( "uncompressed attributes truncated", "" );
+            attrsize = (off_t)(ULONG_MAX - MEMCOMPRESS_OVERHEAD);
+        }
+    }
+
+    if( verbose ) {
+        printf( "\t[in=%lu]", (unsigned long)attrsize );
+    }
+
+    /* Try compressing the data */
+    compbuff = (char *)malloc( (size_t)attrsize + MEMCOMPRESS_OVERHEAD );
+    if( compbuff == NULL ) {
+        return ZE_MEM;
+    }
+    compsize = memcompress( compbuff,
+                            (size_t)attrsize + MEMCOMPRESS_OVERHEAD,
+                            attrbuff,
+                            (size_t)attrsize );
+    if( verbose ) {
+        printf( " [out=%u]", compsize );
+    }
+
+    /* Attempt to optimise very small attributes. */
+    if( compsize > attrsize ) {
+        free( compbuff );
+        compsize = (ush)attrsize;
+        compbuff = attrbuff;
+
+        flags = EB_BE_FL_NATURAL;
+    }
+
+    /* Check to see if we really have enough room in the EF for the data. */
+    if( ( z->ext + compsize + EB_L_BE_LEN ) > USHRT_MAX ) {
+        compsize = USHRT_MAX - EB_L_BE_LEN - z->ext;
+    }
+
+    /* Allocate memory for the local and central extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_BE_SIZE + compsize );
+    } else {
+        l_ef = (char *)malloc( EB_L_BE_SIZE + compsize );
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_BE_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_BE_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /* Now add the local version of the field. */
+    *l_ef++ = 'B';
+    *l_ef++ = 'e';
+    *l_ef++ = (char)(compsize + EB_L_BE_LEN);
+    *l_ef++ = (char)((compsize + EB_L_BE_LEN) >> 8);
+    *l_ef++ = (char)((unsigned long)attrsize);
+    *l_ef++ = (char)((unsigned long)attrsize >> 8);
+    *l_ef++ = (char)((unsigned long)attrsize >> 16);
+    *l_ef++ = (char)((unsigned long)attrsize >> 24);
+    *l_ef++ = flags;
+    memcpy( l_ef, compbuff, (size_t)compsize );
+
+    z->ext += EB_L_BE_SIZE + compsize;
+
+    /* And the central version. */
+    *c_ef++ = 'B';
+    *c_ef++ = 'e';
+    *c_ef++ = (char)(EB_C_BE_LEN);
+    *c_ef++ = (char)(EB_C_BE_LEN >> 8);
+    *c_ef++ = (char)compsize;
+    *c_ef++ = (char)(compsize >> 8);
+    *c_ef++ = (char)(compsize >> 16);
+    *c_ef++ = (char)(compsize >> 24);
+    *c_ef++ = flags;
+
+    z->cext += EB_C_BE_SIZE;
+
+    return ZE_OK;
+}
+
+#endif
+
 
 int set_new_unix_extra_field(z, s)
   struct zlist far *z;
@@ -568,6 +924,7 @@ int set_extra_field(z, z_utim)
   /* store full data in local header but just modification time stamp info
      in central header */
 {
+  int retval;
   z_stat s;
   char *name;
   int len = strlen(z->name);
@@ -678,8 +1035,14 @@ int set_extra_field(z, z_utim)
 #endif /* never */
 
   /* new unix extra field */
-  set_new_unix_extra_field(z, &s);
-
+  retval = set_new_unix_extra_field(z, &s);
+  if (retval != ZE_OK)
+      return retval;
+  
+  retval = add_Be_ef(z);
+  if (retval != ZE_OK)
+      return retval;
+  
   return ZE_OK;
 }
 
diff --git a/zip.c b/zip.c
index 439821f..6682e41 100644
--- a/zip.c
+++ b/zip.c
@@ -1845,7 +1845,7 @@ int rename_split(temp_name, out_path)
 int set_filetype(out_path)
   char *out_path;
 {
-#ifdef __BEOS__
+#if defined(__BEOS__) || defined(__HAIKU__)
   /* Set the filetype of the zipfile to "application/zip" */
   setfiletype( out_path, "application/zip" );
 #endif
-- 
1.8.3.4


From d3e651b9d30d440eb46d63b8ddc4a3d1fc4ca3ad Mon Sep 17 00:00:00 2001
From: Jerome Duval <jerome.duval@gmail.com>
Date: Mon, 2 Mar 2015 19:27:01 +0000
Subject: Haiku x86_64 fixes


diff --git a/unix/unix.c b/unix/unix.c
index 970af5c..6a0cbe3 100644
--- a/unix/unix.c
+++ b/unix/unix.c
@@ -562,11 +562,14 @@ int get_attr_dir( const char *name, char **attr_buff, off_t *total_size )
     /* many and/or they are large.                                       */
     fa_ent = fs_read_attr_dir( fa_dir );
     while( fa_ent != NULL ) {
+    	uint32 attr_type;
+    	uint64 attr_size;
+
         retval = fs_stat_attr( fd, fa_ent->d_name, &fa_info );
         /* TODO: check retval != ZE_OK */
 
         this_size  = strlen( fa_ent->d_name ) + 1;
-        this_size += sizeof( struct attr_info );
+        this_size += sizeof(uint32) + sizeof(uint64);
         this_size += fa_info.size;
 
         attrs_size += this_size;
@@ -591,13 +594,13 @@ int get_attr_dir( const char *name, char **attr_buff, off_t *total_size )
         ptr += strlen( fa_ent->d_name );
         *ptr++ = '\0';
 
-        /* We need to put a big-endian version of the fa_info data into */
-        /* the archive.                                                 */
-        big_fa_info.type = B_HOST_TO_BENDIAN_INT32( fa_info.type );
-        big_fa_info.size = B_HOST_TO_BENDIAN_INT64( fa_info.size );
-        memcpy( ptr, &big_fa_info, sizeof( struct attr_info ) );
-        ptr += sizeof( struct attr_info );
-
+        /* the attr_info is stored in BigEndian because of PowerPC */
+        attr_type = B_HOST_TO_BENDIAN_INT32( fa_info.type );
+        attr_size = B_HOST_TO_BENDIAN_INT64( fa_info.size );
+        
+        memcpy( ptr, &attr_type, sizeof(uint32)); ptr += sizeof(uint32);
+        memcpy( ptr, &attr_size, sizeof(uint64)); ptr += sizeof(uint64);
+        
         if( fa_info.size > 0 ) {
             ssize_t read_bytes;
 
@@ -696,9 +699,9 @@ local int add_Be_ef( struct zlist far *z )
         }
 
         /* Check for way too much data. */
-        if( attrsize > (off_t)ULONG_MAX ) {
+        if( attrsize > OFF_MAX ) {
             zipwarn( "uncompressed attributes truncated", "" );
-            attrsize = (off_t)(ULONG_MAX - MEMCOMPRESS_OVERHEAD);
+            attrsize = OFF_MAX - MEMCOMPRESS_OVERHEAD;
         }
     }
 
-- 
1.8.3.4


From 6b6c66f091b513c313e68f35c16ad79891206521 Mon Sep 17 00:00:00 2001
From: Jerome Duval <jerome.duval@gmail.com>
Date: Sun, 22 Mar 2015 14:08:10 +0000
Subject: Haiku: warn if attrs total length exceeds extra field size


diff --git a/unix/unix.c b/unix/unix.c
index 6a0cbe3..b6d06d0 100644
--- a/unix/unix.c
+++ b/unix/unix.c
@@ -674,7 +674,7 @@ local int add_Be_ef( struct zlist far *z )
     char *attrbuff   = NULL;
     off_t attrsize   = 0;
     char *compbuff   = NULL;
-    ush   compsize   = 0;
+    ulg   compsize   = 0;
     uch   flags      = 0;
 
     /* Check to make sure we've got enough room in the extra fields. */
@@ -732,8 +732,10 @@ local int add_Be_ef( struct zlist far *z )
     }
 
     /* Check to see if we really have enough room in the EF for the data. */
-    if( ( z->ext + compsize + EB_L_BE_LEN ) > USHRT_MAX ) {
-        compsize = USHRT_MAX - EB_L_BE_LEN - z->ext;
+    if( ( z->ext + compsize + EB_L_BE_SIZE ) > USHRT_MAX ) {
+        zipwarn("not enough space in extra field for attributes\n", "");
+        free( compbuff );
+        return ZE_MEM;
     }
 
     /* Allocate memory for the local and central extra fields. */
-- 
1.8.3.4

