Support setting and querying opsys and external attributes.

For newly added files, set operating system to UNIX, permissions
to 0666 (0777 for directories).
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 5575752..a74f409 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -35,10 +35,12 @@
 	zip_file_error_clear.c \
 	zip_file_error_get.c \
 	zip_file_get_comment.c \
+	zip_file_get_external_attributes.c \
 	zip_file_get_offset.c \
 	zip_file_rename.c \
 	zip_file_replace.c \
 	zip_file_set_comment.c \
+	zip_file_set_external_attributes.c \
 	zip_file_strerror.c \
 	zip_filerange_crc.c \
 	zip_fopen.c \
diff --git a/lib/zip.h b/lib/zip.h
index 44d0ab8..d9a2b6c 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -177,6 +177,29 @@
 #endif
 #define ZIP_EM_UNKNOWN    0xffff  /* unknown algorithm */
 
+#define ZIP_OPSYS_DOS	  	0x00u
+#define ZIP_OPSYS_AMIGA	 	0x01u
+#define ZIP_OPSYS_OPENVMS	0x02u
+#define ZIP_OPSYS_UNIX	  	0x03u
+#define ZIP_OPSYS_VM_CMS	0x04u
+#define ZIP_OPSYS_ATARI_ST	0x05u
+#define ZIP_OPSYS_OS_2		0x06u
+#define ZIP_OPSYS_MACINTOSH	0x07u
+#define ZIP_OPSYS_Z_SYSTEM	0x08u
+#define ZIP_OPSYS_CPM	  	0x09u
+#define ZIP_OPSYS_WINDOWS_NTFS	0x0au
+#define ZIP_OPSYS_MVS	  	0x0bu
+#define ZIP_OPSYS_VSE	  	0x0cu
+#define ZIP_OPSYS_ACORN_RISC	0x0du
+#define ZIP_OPSYS_VFAT	  	0x0eu
+#define ZIP_OPSYS_ALTERNATE_MVS	0x0fu
+#define ZIP_OPSYS_BEOS	  	0x10u
+#define ZIP_OPSYS_TANDEM	0x11u
+#define ZIP_OPSYS_OS_400	0x12u
+#define ZIP_OPSYS_OS_X	  	0x13u
+
+#define ZIP_OPSYS_DEFAULT	ZIP_OPSYS_UNIX
+
 
 
 enum zip_source_cmd {
@@ -235,21 +258,32 @@
 #endif
 
 ZIP_EXTERN int zip_archive_set_tempdir(struct zip *, const char *);
-ZIP_EXTERN zip_int64_t zip_file_add(struct zip *, const char *, struct zip_source *, zip_flags_t);
-ZIP_EXTERN zip_int64_t zip_dir_add(struct zip *, const char *, zip_flags_t);
 ZIP_EXTERN int zip_close(struct zip *);
-ZIP_EXTERN void zip_discard(struct zip *);
 ZIP_EXTERN int zip_delete(struct zip *, zip_uint64_t);
-ZIP_EXTERN int zip_file_extra_field_delete(struct zip *, zip_uint64_t, zip_uint16_t, zip_flags_t);
-ZIP_EXTERN int zip_file_extra_field_delete_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN zip_int64_t zip_dir_add(struct zip *, const char *, zip_flags_t);
+ZIP_EXTERN void zip_discard(struct zip *);
 ZIP_EXTERN void zip_error_clear(struct zip *);
 ZIP_EXTERN void zip_error_get(struct zip *, int *, int *);
 ZIP_EXTERN int zip_error_get_sys_type(int);
 ZIP_EXTERN int zip_error_to_str(char *, zip_uint64_t, int, int);
 ZIP_EXTERN int zip_fclose(struct zip_file *);
 ZIP_EXTERN struct zip *zip_fdopen(int, int, int *);
+ZIP_EXTERN zip_int64_t zip_file_add(struct zip *, const char *, struct zip_source *, zip_flags_t);
 ZIP_EXTERN void zip_file_error_clear(struct zip_file *);
 ZIP_EXTERN void zip_file_error_get(struct zip_file *, int *, int *);
+ZIP_EXTERN int zip_file_extra_field_delete(struct zip *, zip_uint64_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_extra_field_delete_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_extra_field_set(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN zip_int16_t zip_file_extra_fields_count(struct zip *, zip_uint64_t, zip_flags_t);
+ZIP_EXTERN zip_int16_t zip_file_extra_fields_count_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN const zip_uint8_t *zip_file_extra_field_get(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t *, zip_uint16_t *, zip_flags_t);
+ZIP_EXTERN const zip_uint8_t *zip_file_extra_field_get_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *, zip_flags_t);
+ZIP_EXTERN const char *zip_file_get_comment(struct zip *, zip_uint64_t, zip_uint32_t *, zip_flags_t);
+ZIP_EXTERN int zip_file_get_external_attributes(struct zip *, zip_uint64_t, zip_flags_t, zip_uint8_t *, zip_uint32_t *);
+ZIP_EXTERN int zip_file_rename(struct zip *, zip_uint64_t, const char *, zip_flags_t);
+ZIP_EXTERN int zip_file_replace(struct zip *, zip_uint64_t, struct zip_source *, zip_flags_t);
+ZIP_EXTERN int zip_file_set_comment(struct zip *, zip_uint64_t, const char *, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_set_external_attributes(struct zip *, zip_uint64_t, zip_flags_t, zip_uint8_t, zip_uint32_t);
 ZIP_EXTERN const char *zip_file_strerror(struct zip_file *);
 ZIP_EXTERN struct zip_file *zip_fopen(struct zip *, const char *, zip_flags_t);
 ZIP_EXTERN struct zip_file *zip_fopen_encrypted(struct zip *, const char *, zip_flags_t, const char *);
@@ -258,23 +292,14 @@
 ZIP_EXTERN zip_int64_t zip_fread(struct zip_file *, void *, zip_uint64_t);
 ZIP_EXTERN const char *zip_get_archive_comment(struct zip *, int *, zip_flags_t);
 ZIP_EXTERN int zip_get_archive_flag(struct zip *, zip_flags_t, zip_flags_t);
-ZIP_EXTERN const char *zip_file_get_comment(struct zip *, zip_uint64_t, zip_uint32_t *, zip_flags_t);
-ZIP_EXTERN const zip_uint8_t *zip_file_extra_field_get(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t *, zip_uint16_t *, zip_flags_t);
-ZIP_EXTERN const zip_uint8_t *zip_file_extra_field_get_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *, zip_flags_t);
-ZIP_EXTERN zip_int16_t zip_file_extra_fields_count(struct zip *, zip_uint64_t, zip_flags_t);
-ZIP_EXTERN zip_int16_t zip_file_extra_fields_count_by_id(struct zip *, zip_uint64_t, zip_uint16_t, zip_flags_t);
 ZIP_EXTERN const char *zip_get_name(struct zip *, zip_uint64_t, zip_flags_t);
 ZIP_EXTERN zip_int64_t zip_get_num_entries(struct zip *, zip_flags_t);
 ZIP_EXTERN zip_int64_t zip_name_locate(struct zip *, const char *, zip_flags_t);
 ZIP_EXTERN struct zip *zip_open(const char *, int, int *);
-ZIP_EXTERN int zip_file_rename(struct zip *, zip_uint64_t, const char *, zip_flags_t);
-ZIP_EXTERN int zip_file_replace(struct zip *, zip_uint64_t, struct zip_source *, zip_flags_t);
 ZIP_EXTERN int zip_set_archive_comment(struct zip *, const char *, zip_uint16_t);
 ZIP_EXTERN int zip_set_archive_flag(struct zip *, zip_flags_t, int);
 ZIP_EXTERN int zip_set_default_password(struct zip *, const char *);
-ZIP_EXTERN int zip_file_set_comment(struct zip *, zip_uint64_t, const char *, zip_uint16_t, zip_flags_t);
 ZIP_EXTERN int zip_set_file_compression(struct zip *, zip_uint64_t, zip_int32_t, zip_uint32_t);
-ZIP_EXTERN int zip_file_extra_field_set(struct zip *, zip_uint64_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_uint16_t, zip_flags_t);
 ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *, zip_uint64_t, int);
 ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *, zip_uint64_t, zip_int64_t);
 ZIP_EXTERN struct zip_source *zip_source_filep(struct zip *, FILE *, zip_uint64_t, zip_int64_t);
diff --git a/lib/zip_dir_add.c b/lib/zip_dir_add.c
index 0a74bd6..1a662f4 100644
--- a/lib/zip_dir_add.c
+++ b/lib/zip_dir_add.c
@@ -1,6 +1,6 @@
 /*
   zip_dir_add.c -- add directory
-  Copyright (C) 1999-2012 Dieter Baron and Thomas Klausner
+  Copyright (C) 1999-2013 Dieter Baron and Thomas Klausner
 
   This file is part of libzip, a library to manipulate ZIP archives.
   The authors can be contacted at <libzip@nih.at>
@@ -46,7 +46,7 @@
 zip_dir_add(struct zip *za, const char *name, zip_flags_t flags)
 {
     size_t len;
-    zip_int64_t ret;
+    zip_int64_t idx;
     char *s;
     struct zip_source *source;
 
@@ -78,11 +78,18 @@
 	return -1;
     }
 	
-    ret = _zip_file_replace(za, ZIP_UINT64_MAX, s ? s : name, source, flags);
+    idx = _zip_file_replace(za, ZIP_UINT64_MAX, s ? s : name, source, flags);
 
     free(s);
-    if (ret < 0)
-	zip_source_free(source);
 
-    return ret;
+    if (idx < 0)
+	zip_source_free(source);
+    else {
+	if (zip_file_set_external_attributes(za, (zip_uint64_t)idx, 0, ZIP_OPSYS_DEFAULT, ZIP_EXT_ATTRIB_DEFAULT_DIR) < 0) {
+	    zip_delete(za, (zip_uint64_t)idx);
+	    return -1;
+	}
+    }
+
+    return idx;
 }
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
index 99573a9..77069ae 100644
--- a/lib/zip_dirent.c
+++ b/lib/zip_dirent.c
@@ -260,7 +260,7 @@
     de->local_extra_fields_read = 0;
     de->cloned = 0;
 
-    de->version_madeby = 20;
+    de->version_madeby = 20 | (ZIP_OPSYS_DEFAULT << 8);
     de->version_needed = 20; /* 2.0 */
     de->bitflags = 0;
     de->comp_method = ZIP_CM_DEFAULT;
@@ -273,7 +273,7 @@
     de->comment = NULL;
     de->disk_number = 0;
     de->int_attrib = 0;
-    de->ext_attrib = 0;
+    de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT;
     de->offset = 0;
 }
 
diff --git a/lib/zip_file_get_external_attributes.c b/lib/zip_file_get_external_attributes.c
new file mode 100644
index 0000000..f1ad66a
--- /dev/null
+++ b/lib/zip_file_get_external_attributes.c
@@ -0,0 +1,53 @@
+/*
+  zip_file_get_external_attributes.c -- get opsys/external attributes
+  Copyright (C) 2013 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zipint.h"
+
+int
+zip_file_get_external_attributes(struct zip *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t *opsys, zip_uint32_t *attributes)
+{
+    struct zip_dirent *de;
+    zip_uint32_t len;
+    const zip_uint8_t *str;
+
+    if ((de=_zip_get_dirent(za, idx, flags, NULL)) == NULL)
+	return -1;
+
+    if (opsys)
+	*opsys = (de->version_madeby >> 8) & 0xff;
+
+    if (attributes)
+	*attributes = de->ext_attrib;
+
+    return 0;
+}
diff --git a/lib/zip_file_set_external_attributes.c b/lib/zip_file_set_external_attributes.c
new file mode 100644
index 0000000..0820d6f
--- /dev/null
+++ b/lib/zip_file_set_external_attributes.c
@@ -0,0 +1,83 @@
+/*
+  zip_file_set_external_attributes.c -- set external attributes for entry
+  Copyright (C) 2013 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zipint.h"
+
+int
+zip_file_set_external_attributes(struct zip *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t opsys, zip_uint32_t attributes)
+{
+    struct zip_entry *e;
+    int changed;
+    zip_uint8_t unchanged_opsys;
+    zip_uint32_t unchanged_attributes;
+
+    if (_zip_get_dirent(za, idx, 0, NULL) == NULL)
+	return -1;
+
+    if (ZIP_IS_RDONLY(za)) {
+	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
+	return -1;
+    }
+
+    e = za->entry+idx;
+
+    unchanged_opsys = e->orig ? e->orig->version_madeby>>8 : ZIP_OPSYS_DEFAULT;
+    unchanged_attributes = e->orig ? e->orig->ext_attrib : ZIP_EXT_ATTRIB_DEFAULT;
+
+    changed = (opsys != unchanged_opsys || attributes != unchanged_attributes);
+
+    if (changed) {
+        if (e->changes == NULL) {
+            if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) {
+                _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+                return -1;
+            }
+        }
+        e->changes->version_madeby = (opsys << 8) | (e->changes->version_madeby & 0xff);
+	e->changes->ext_attrib = attributes;
+        e->changes->changed |= ZIP_DIRENT_ATTRIBUTES;
+    }
+    else if (e->changes) {
+	e->changes->changed &= ~ZIP_DIRENT_ATTRIBUTES;
+	if (e->changes->changed == 0) {
+	    _zip_dirent_free(e->changes);
+	    e->changes = NULL;
+	}
+	else {
+	    e->changes->version_madeby = (unchanged_opsys << 8) | (e->changes->version_madeby & 0xff);
+	    e->changes->ext_attrib = unchanged_attributes;
+	}
+    }
+
+    return 0;
+}
diff --git a/lib/zipint.h b/lib/zipint.h
index c5d0fd4..81c0179 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -157,7 +157,12 @@
 #define ZIP_EF_ZIP64		0x0001
 
 #define ZIP_EF_IS_INTERNAL(id)	((id) == ZIP_EF_UTF_8_COMMENT || (id) == ZIP_EF_UTF_8_NAME || (id) == ZIP_EF_ZIP64)
-
+
+/* according to unzip-6.0's zipinfo.c, this corresponds to a regular file with rw permissions for everyone */
+#define ZIP_EXT_ATTRIB_DEFAULT		0100666
+/* according to unzip-6.0's zipinfo.c, this corresponds to a directory with rwx permissions for everyone */
+#define ZIP_EXT_ATTRIB_DEFAULT_DIR	0040777
+
 
 /* This section contains API that won't materialize like this.  It's
    placed in the internal section, pending cleanup. */
@@ -302,6 +307,7 @@
 #define ZIP_DIRENT_FILENAME	0x0002u
 #define ZIP_DIRENT_COMMENT	0x0004u
 #define ZIP_DIRENT_EXTRA_FIELD	0x0008u
+#define ZIP_DIRENT_ATTRIBUTES	0x0010u
 #define ZIP_DIRENT_ALL		0xffffu
 
 struct zip_dirent {