/* Info-Zip Unix Extra Field (type 3) "ux". */
int uidsize = 0, gidsize = 0;
+ /* TODO: support arbitrary uidsize/gidsize. */
if (datasize >= 1 && p[offset] == 1) {/* version=1 */
if (datasize >= 4) {
/* get a uid size. */
#include "archive_crc32.h"
#endif
-#define ZIP_SIGNATURE_LOCAL_FILE_HEADER 0x04034b50
-#define ZIP_SIGNATURE_DATA_DESCRIPTOR 0x08074b50
-#define ZIP_SIGNATURE_FILE_HEADER 0x02014b50
-#define ZIP_SIGNATURE_CENTRAL_DIRECTORY_END 0x06054b50
-#define ZIP_SIGNATURE_EXTRA_TIMESTAMP 0x5455
-#define ZIP_SIGNATURE_EXTRA_NEW_UNIX 0x7875
-#define ZIP_VERSION_EXTRACT 0x0014 /* ZIP version 2.0 is needed. */
-#define ZIP_VERSION_BY 0x0314 /* Made by UNIX, using ZIP version 2.0. */
-#define ZIP_FLAGS 0x08 /* Flagging bit 3 (count from 0) for using data descriptor. */
+#define ZIP_FLAGS_LENGTH_AT_END (1<<3)
#define ZIP_FLAGS_UTF8_NAME (1 << 11)
+
enum compression {
- COMPRESSION_STORE = 0
-#ifdef HAVE_ZLIB_H
- ,
+ COMPRESSION_UNSPECIFIED = -1,
+ COMPRESSION_STORE = 0,
COMPRESSION_DEFLATE = 8
+};
+
+#ifdef HAVE_ZLIB_H
+#define COMPRESSION_DEFAULT COMPRESSION_DEFLATE
+#else
+#define COMPRESSION_DEFAULT COMPRESSION_STORE
+#endif
+
+struct cd_segment {
+ struct cd_segment *next;
+ size_t buff_size;
+ unsigned char *buff;
+ unsigned char *p;
+};
+
+struct zip {
+
+ int64_t entry_offset;
+ int64_t entry_compressed_size;
+ int64_t entry_uncompressed_size;
+ int64_t entry_compressed_written;
+ int64_t entry_uncompressed_written;
+ int64_t entry_uncompressed_limit;
+ struct archive_entry *entry;
+ uint32_t entry_crc32;
+ enum compression entry_compression;
+ int entry_flags;
+
+ unsigned char *file_header;
+ size_t file_header_extra_offset;
+
+ struct cd_segment *central_directory;
+ struct cd_segment *central_directory_last;
+ size_t central_directory_bytes;
+ size_t central_directory_entries;
+
+ int64_t written_bytes; /* Overall position in file. */
+
+ struct archive_string_conv *opt_sconv;
+ struct archive_string_conv *sconv_default;
+ enum compression requested_compression;
+ int init_default_conversion;
+ char force_zip64;
+
+#ifdef HAVE_ZLIB_H
+ z_stream stream;
+ size_t len_buf;
+ unsigned char *buf;
#endif
};
+/* Don't call this min or MIN, since those are already defined
+ on lots of platforms (but not all). */
+#define zipmin(a, b) ((a) > (b) ? (b) : (a))
+
static ssize_t archive_write_zip_data(struct archive_write *,
const void *buff, size_t s);
static int archive_write_zip_close(struct archive_write *);
static unsigned int dos_time(const time_t);
static size_t path_length(struct archive_entry *);
static int write_path(struct archive_entry *, struct archive_write *);
+static void copy_path(struct archive_entry *, unsigned char *);
+static struct archive_string_conv *get_sconv(struct archive_write *, struct zip *);
-#define LOCAL_FILE_HEADER_SIGNATURE 0
-#define LOCAL_FILE_HEADER_VERSION 4
-#define LOCAL_FILE_HEADER_FLAGS 6
-#define LOCAL_FILE_HEADER_COMPRESSION 8
-#define LOCAL_FILE_HEADER_TIMEDATE 10
-#define LOCAL_FILE_HEADER_CRC32 14
-#define LOCAL_FILE_HEADER_COMPRESSED_SIZE 18
-#define LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE 22
-#define LOCAL_FILE_HEADER_FILENAME_LENGTH 26
-#define LOCAL_FILE_HEADER_EXTRA_LENGTH 28
-#define SIZE_LOCAL_FILE_HEADER 30
-
-#define FILE_HEADER_SIGNATURE 0
-#define FILE_HEADER_VERSION_BY 4
-#define FILE_HEADER_VERSION_EXTRACT 6
-#define FILE_HEADER_FLAGS 8
-#define FILE_HEADER_COMPRESSION 10
-#define FILE_HEADER_TIMEDATE 12
-#define FILE_HEADER_CRC32 16
-#define FILE_HEADER_COMPRESSED_SIZE 20
-#define FILE_HEADER_UNCOMPRESSED_SIZE 24
-#define FILE_HEADER_FILENAME_LENGTH 28
-#define FILE_HEADER_EXTRA_LENGTH 30
-#define FILE_HEADER_COMMENT_LENGTH 32
-#define FILE_HEADER_DISK_NUMBER 34
-#define FILE_HEADER_ATTRIBUTES_INTERNAL 36
-#define FILE_HEADER_ATTRIBUTES_EXTERNAL 38
-#define FILE_HEADER_OFFSET 42
-#define SIZE_FILE_HEADER 46
-
- /* Not mandatory, but recommended by specification. */
-#define DATA_DESCRIPTOR_SIGNATURE 0
-#define DATA_DESCRIPTOR_CRC32 4
-#define DATA_DESCRIPTOR_COMPRESSED_SIZE 8
-#define DATA_DESCRIPTOR_UNCOMPRESSED_SIZE 12
-#define SIZE_DATA_DESCRIPTOR 16
-
-#define EXTRA_DATA_LOCAL_TIME_ID 0
-#define EXTRA_DATA_LOCAL_TIME_SIZE 2
-#define EXTRA_DATA_LOCAL_TIME_FLAG 4
-#define EXTRA_DATA_LOCAL_MTIME 5
-#define EXTRA_DATA_LOCAL_ATIME 9
-#define EXTRA_DATA_LOCAL_CTIME 13
-#define EXTRA_DATA_LOCAL_UNIX_ID 17
-#define EXTRA_DATA_LOCAL_UNIX_SIZE 19
-#define EXTRA_DATA_LOCAL_UNIX_VERSION 21
-#define EXTRA_DATA_LOCAL_UNIX_UID_SIZE 22
-#define EXTRA_DATA_LOCAL_UNIX_UID 23
-#define EXTRA_DATA_LOCAL_UNIX_GID_SIZE 27
-#define EXTRA_DATA_LOCAL_UNIX_GID 28
-#define SIZE_EXTRA_DATA_LOCAL 32
-
-#define EXTRA_DATA_CENTRAL_TIME_ID 0
-#define EXTRA_DATA_CENTRAL_TIME_SIZE 2
-#define EXTRA_DATA_CENTRAL_TIME_FLAG 4
-#define EXTRA_DATA_CENTRAL_MTIME 5
-#define EXTRA_DATA_CENTRAL_UNIX_ID 9
-#define EXTRA_DATA_CENTRAL_UNIX_SIZE 11
-#define SIZE_EXTRA_DATA_CENTRAL 13
-
-#define CENTRAL_DIRECTORY_END_SIGNATURE 0
-#define CENTRAL_DIRECTORY_END_DISK 4
-#define CENTRAL_DIRECTORY_END_START_DISK 6
-#define CENTRAL_DIRECTORY_END_ENTRIES_DISK 8
-#define CENTRAL_DIRECTORY_END_ENTRIES 10
-#define CENTRAL_DIRECTORY_END_SIZE 12
-#define CENTRAL_DIRECTORY_END_OFFSET 16
-#define CENTRAL_DIRECTORY_END_COMMENT_LENGTH 20
-#define SIZE_CENTRAL_DIRECTORY_END 22
-
-struct zip_entry {
- int64_t offset;
- int64_t compressed_size;
- struct zip_entry *next;
- struct archive_entry *entry;
- uint32_t crc32;
- enum compression compression;
- int flags;
-};
+static unsigned char *
+cd_alloc(struct zip *zip, size_t length)
+{
+ unsigned char *p;
+
+ if (zip->central_directory == NULL
+ || (zip->central_directory_last->p + length
+ > zip->central_directory_last->buff + zip->central_directory_last->buff_size)) {
+ struct cd_segment *segment = calloc(1, sizeof(*segment));
+ if (segment == NULL)
+ return NULL;
+ segment->buff_size = 64 * 1024;
+ segment->buff = malloc(segment->buff_size);
+ if (segment->buff == NULL) {
+ free(segment);
+ return NULL;
+ }
+ segment->p = segment->buff;
-struct zip {
- struct zip_entry entry; // Details about current entry.
-
- uint8_t data_descriptor[SIZE_DATA_DESCRIPTOR];
- int64_t offset;
- int64_t written_bytes;
- int64_t remaining_data_bytes;
- struct zip_entry *central_directory;
- struct zip_entry *central_directory_end;
- struct archive_string_conv *opt_sconv;
- struct archive_string_conv *sconv_default;
- enum compression default_compression;
- int flags;
- int init_default_conversion;
- char force_zip64;
+ if (zip->central_directory == NULL) {
+ zip->central_directory
+ = zip->central_directory_last
+ = segment;
+ } else {
+ zip->central_directory_last->next = segment;
+ zip->central_directory_last = segment;
+ }
+ }
-#ifdef HAVE_ZLIB_H
- z_stream stream;
- size_t len_buf;
- unsigned char *buf;
-#endif
-};
+ p = zip->central_directory_last->p;
+ zip->central_directory_last->p += length;
+ zip->central_directory_bytes += length;
+ return (p);
+}
static int
archive_write_zip_options(struct archive_write *a, const char *key,
a->format_name);
} else if (strcmp(val, "deflate") == 0) {
#ifdef HAVE_ZLIB_H
- zip->default_compression = COMPRESSION_DEFLATE;
+ zip->requested_compression = COMPRESSION_DEFLATE;
ret = ARCHIVE_OK;
#else
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"deflate compression not supported");
#endif
} else if (strcmp(val, "store") == 0) {
- zip->default_compression = COMPRESSION_STORE;
+ zip->requested_compression = COMPRESSION_STORE;
ret = ARCHIVE_OK;
}
return (ret);
int ret = ARCHIVE_FAILED;
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
+ ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_zip_set_compression_deflate");
if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
} else {
#ifdef HAVE_ZLIB_H
struct zip *zip = a->format_data;
- zip->default_compression = COMPRESSION_DEFLATE;
+ zip->requested_compression = COMPRESSION_DEFLATE;
ret = ARCHIVE_OK;
#else
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"deflate compression not supported");
+ ret = ARCHIVE_FAILED;
#endif
}
return (ret);
int ret = ARCHIVE_FAILED;
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
+ ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_zip_set_compression_deflate");
if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
" with zip format");
ret = ARCHIVE_FATAL;
} else {
- zip->default_compression = COMPRESSION_STORE;
+ zip->requested_compression = COMPRESSION_STORE;
ret = ARCHIVE_OK;
}
return (ret);
"Can't allocate zip data");
return (ARCHIVE_FATAL);
}
- zip->central_directory = NULL;
- zip->central_directory_end = NULL;
- zip->offset = 0;
- zip->written_bytes = 0;
- zip->remaining_data_bytes = 0;
+
+ /* "Unspecified" lets us choose the appropriate compression. */
+ zip->requested_compression = COMPRESSION_UNSPECIFIED;
#ifdef HAVE_ZLIB_H
- zip->default_compression = COMPRESSION_DEFLATE;
zip->len_buf = 65536;
zip->buf = malloc(zip->len_buf);
if (zip->buf == NULL) {
"Can't allocate compression buffer");
return (ARCHIVE_FATAL);
}
-#else
- zip->default_compression = COMPRESSION_STORE;
#endif
a->format_data = zip;
a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
a->archive.archive_format_name = "ZIP";
- archive_le32enc(&zip->data_descriptor[DATA_DESCRIPTOR_SIGNATURE],
- ZIP_SIGNATURE_DATA_DESCRIPTOR);
-
return (ARCHIVE_OK);
}
static int
archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
{
- struct zip *zip;
- uint8_t h[SIZE_LOCAL_FILE_HEADER];
- uint8_t e[SIZE_EXTRA_DATA_LOCAL];
- uint8_t *d;
- struct archive_string_conv *sconv;
+ struct zip *zip = a->format_data;
+ unsigned char local_header[30];
+ unsigned char local_extra[64];
+ unsigned char *e;
+ unsigned char *cd_extra;
+ size_t filename_length;
+ const char *symlink = NULL;
+ size_t symlink_size;
+ struct archive_string_conv *sconv = get_sconv(a, zip);
int ret, ret2 = ARCHIVE_OK;
int64_t size;
mode_t type;
+ int version_needed = 10;
- /* Entries other than a regular file or a folder are skipped. */
+ /* Ignore types of entries that we don't support. */
type = archive_entry_filetype(entry);
if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
return ARCHIVE_FAILED;
};
- /* Directory entries should have a size of 0. */
- if (type == AE_IFDIR)
+ /* Only regular files can have size > 0. */
+ if (type != AE_IFREG)
archive_entry_set_size(entry, 0);
- zip = a->format_data;
- /* Setup default conversion. */
- if (zip->opt_sconv == NULL && !zip->init_default_conversion) {
- zip->sconv_default =
- archive_string_default_conversion_for_write(&(a->archive));
- zip->init_default_conversion = 1;
- }
- if (zip->flags == 0) {
- /* Initialize the general purpose flags. */
- zip->flags = ZIP_FLAGS;
- if (zip->opt_sconv != NULL) {
- if (strcmp(archive_string_conversion_charset_name(
- zip->opt_sconv), "UTF-8") == 0)
- zip->flags |= ZIP_FLAGS_UTF8_NAME;
-#if HAVE_NL_LANGINFO
- } else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
- zip->flags |= ZIP_FLAGS_UTF8_NAME;
-#endif
- }
+ /* Reset information from last entry. */
+ zip->entry_offset = zip->written_bytes;
+ zip->entry_uncompressed_limit = INT64_MAX;
+ zip->entry_compressed_size = 0;
+ zip->entry_uncompressed_size = 0;
+ zip->entry_compressed_written = 0;
+ zip->entry_uncompressed_written = 0;
+ zip->entry_flags = 0;
+ zip->entry_crc32 = crc32(0, NULL, 0);
+ if (zip->entry != NULL) {
+ archive_entry_free(zip->entry);
+ zip->entry = NULL;
}
- d = zip->data_descriptor;
- size = archive_entry_size(entry);
- zip->remaining_data_bytes = size;
-
- /* Clear out old entry information. */
- if (zip->entry.entry != NULL) {
- archive_entry_free(zip->entry.entry);
- }
- memset(&zip->entry, 0, sizeof(zip->entry));
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Make sure the path separators in pahtname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
- zip->entry.entry = __la_win_entry_in_posix_pathseparator(entry);
- if (zip->entry.entry == entry)
- zip->entry.entry = archive_entry_clone(entry);
+ zip->entry = __la_win_entry_in_posix_pathseparator(entry);
+ if (zip->entry == entry)
+ zip->entry = archive_entry_clone(entry);
#else
- zip->entry.entry = archive_entry_clone(entry);
+ zip->entry = archive_entry_clone(entry);
#endif
- if (zip->entry.entry == NULL) {
+ if (zip->entry == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate zip header data");
return (ARCHIVE_FATAL);
}
- zip->entry.flags = zip->flags;
- if (zip->opt_sconv != NULL)
- sconv = zip->opt_sconv;
- else
- sconv = zip->sconv_default;
+
if (sconv != NULL) {
const char *p;
size_t len;
ret2 = ARCHIVE_WARN;
}
if (len > 0)
- archive_entry_set_pathname(zip->entry.entry, p);
+ archive_entry_set_pathname(zip->entry, p);
/*
- * Although there is no character-set regulation for Symlink,
- * it is suitable to convert a character-set of Symlinke to
- * what those of the Pathname has been converted to.
+ * There is no standard for symlink handling; we convert
+ * it using the same character-set translation that we use
+ * for filename.
*/
if (type == AE_IFLNK) {
if (archive_entry_symlink_l(entry, &p, &len, sconv)) {
" for Symlink");
return (ARCHIVE_FATAL);
}
- /*
- * Even if the strng conversion failed,
- * we should not report the error since
- * thre is no regulation for.
- */
+ /* No error if we can't convert. */
} else if (len > 0)
- archive_entry_set_symlink(zip->entry.entry, p);
+ archive_entry_set_symlink(zip->entry, p);
+ }
+ }
+
+ /* If filename isn't ASCII and we can use UTF-8, set the UTF-8 flag. */
+ if (!is_all_ascii(archive_entry_pathname(zip->entry))) {
+ if (zip->opt_sconv != NULL) {
+ if (strcmp(archive_string_conversion_charset_name(
+ zip->opt_sconv), "UTF-8") == 0)
+ zip->entry_flags |= ZIP_FLAGS_UTF8_NAME;
+#if HAVE_NL_LANGINFO
+ } else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
+ zip->entry_flags |= ZIP_FLAGS_UTF8_NAME;
+#endif
}
}
- /* If all characters in a filename are ASCII, Reset UTF-8 Name flag. */
- if ((zip->entry.flags & ZIP_FLAGS_UTF8_NAME) != 0 &&
- is_all_ascii(archive_entry_pathname(zip->entry.entry)))
- zip->entry.flags &= ~ZIP_FLAGS_UTF8_NAME;
+ filename_length = path_length(zip->entry);
- /* Initialize the CRC variable and potentially the local crc32(). */
- zip->entry.crc32 = crc32(0, NULL, 0);
+ /* Determine appropriate compression and size for this entry. */
if (type == AE_IFLNK) {
- const char *p = archive_entry_symlink(zip->entry.entry);
- if (p != NULL)
- size = strlen(p);
+ symlink = archive_entry_symlink(zip->entry);
+ if (symlink != NULL)
+ symlink_size = strlen(symlink);
else
- size = 0;
- zip->remaining_data_bytes = 0;
- archive_entry_set_size(zip->entry.entry, size);
- zip->entry.compression = COMPRESSION_STORE;
- zip->entry.compressed_size = size;
+ symlink_size = 0;
+ zip->entry_uncompressed_limit = symlink_size;
+ zip->entry_compressed_size = symlink_size;
+ zip->entry_uncompressed_size = symlink_size;
+ zip->entry_crc32 = crc32(zip->entry_crc32,
+ (const unsigned char *)symlink, symlink_size);
+ zip->entry_compression = COMPRESSION_STORE;
+ version_needed = 20;
+ } else if (type != AE_IFREG) {
+ zip->entry_compression = COMPRESSION_STORE;
+ zip->entry_uncompressed_limit = 0;
+ size = 0;
+ version_needed = 20;
+ } else if (archive_entry_size_is_set(zip->entry)) {
+ size = archive_entry_size(zip->entry);
+ zip->entry_uncompressed_limit = size;
+ zip->entry_compression = zip->requested_compression;
+ if (zip->entry_compression == COMPRESSION_UNSPECIFIED) {
+ zip->entry_compression = COMPRESSION_DEFAULT;
+ }
+ if (zip->entry_compression == COMPRESSION_STORE) {
+ zip->entry_compressed_size = size;
+ zip->entry_uncompressed_size = size;
+ version_needed = 10;
+ } else {
+ version_needed = 20;
+ }
+ /* We may know the size, but never the CRC. */
+ zip->entry_flags |= ZIP_FLAGS_LENGTH_AT_END;
} else {
- zip->entry.compression = zip->default_compression;
- zip->entry.compressed_size = 0;
+ /* Prefer deflate if it's available. */
+ zip->entry_compression = COMPRESSION_DEFAULT;
+ zip->entry_flags |= ZIP_FLAGS_LENGTH_AT_END;
+ if (zip->entry_compression == COMPRESSION_STORE) {
+ version_needed = 10;
+ } else {
+ version_needed = 20;
+ }
}
- /* Store the offset of this header for later use in central
- * directory. */
- zip->entry.offset = zip->written_bytes;
-
- memset(h, 0, sizeof(h));
- archive_le32enc(&h[LOCAL_FILE_HEADER_SIGNATURE],
- ZIP_SIGNATURE_LOCAL_FILE_HEADER);
- archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT);
- archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], zip->entry.flags);
- archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], zip->entry.compression);
- archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE],
- dos_time(archive_entry_mtime(zip->entry.entry)));
- archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH],
- (uint16_t)path_length(zip->entry.entry));
-
- switch (zip->entry.compression) {
- case COMPRESSION_STORE:
- /* Setting compressed and uncompressed sizes even when
- * specification says to set to zero when using data
- * descriptors. Otherwise the end of the data for an
- * entry is rather difficult to find. */
- archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE],
- (uint32_t)size);
- archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)size);
- break;
-#ifdef HAVE_ZLIB_H
- case COMPRESSION_DEFLATE:
- archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)size);
+ /* TODO: Set version_needed = 45 if zip64 gets triggered. */
+
+ /* Format the local header. */
+ memset(local_header, 0, sizeof(local_header));
+ memcpy(local_header, "PK\003\004", 4);
+ archive_le16enc(local_header + 4, version_needed);
+ archive_le16enc(local_header + 6, zip->entry_flags);
+ archive_le16enc(local_header + 8, zip->entry_compression);
+ archive_le32enc(local_header + 10, dos_time(archive_entry_mtime(zip->entry)));
+ archive_le32enc(local_header + 14, zip->entry_crc32);
+ archive_le32enc(local_header + 18,
+ zipmin(zip->entry_compressed_size, 0xffffffffLL));
+ archive_le32enc(local_header + 22,
+ zipmin(zip->entry_uncompressed_size, 0xffffffffLL));
+ archive_le16enc(local_header + 26, filename_length);
+
+ /* Format as much of central directory file header as we can: */
+ zip->file_header = cd_alloc(zip, 46);
+ /* If (zip->file_header == NULL) XXXX */
+ ++zip->central_directory_entries;
+ memset(zip->file_header, 0, 46);
+ /* "Made by PKZip 2.0 on Unix." */
+ /* TODO: Change extract-version to 4.5 if Zip64 gets triggered. */
+ memcpy(zip->file_header, "PK\001\002", 4);
+ archive_le16enc(zip->file_header + 4, 3 * 256 + version_needed);
+ archive_le16enc(zip->file_header + 6, version_needed);
+ archive_le16enc(zip->file_header + 8, zip->entry_flags);
+ archive_le16enc(zip->file_header + 10, zip->entry_compression);
+ archive_le32enc(zip->file_header + 12, dos_time(archive_entry_mtime(zip->entry)));
+ archive_le16enc(zip->file_header + 28, filename_length);
+ /* Following Info-Zip, store mode in the "external attributes" field. */
+ archive_le32enc(zip->file_header + 38,
+ archive_entry_mode(zip->entry) << 16);
+ unsigned char *fn = cd_alloc(zip, filename_length);
+ /* If (fn == NULL) XXXX */
+ copy_path(zip->entry, fn);
+
+ /* Format extra data. */
+ memset(local_extra, 0, sizeof(local_extra));
+ e = local_extra;
+
+ /* UT timestamp, length depends on what timestamps are set. */
+ memcpy(e, "UT", 2);
+ archive_le16enc(e + 2,
+ 1
+ + (archive_entry_mtime_is_set(entry) ? 4 : 0)
+ + (archive_entry_atime_is_set(entry) ? 4 : 0)
+ + (archive_entry_ctime_is_set(entry) ? 4 : 0));
+ e += 4;
+ *e++ =
+ (archive_entry_mtime_is_set(entry) ? 1 : 0)
+ | (archive_entry_atime_is_set(entry) ? 2 : 0)
+ | (archive_entry_ctime_is_set(entry) ? 4 : 0);
+ if (archive_entry_mtime_is_set(entry)) {
+ archive_le32enc(e, (uint32_t)archive_entry_mtime(entry));
+ e += 4;
+ }
+ if (archive_entry_atime_is_set(entry)) {
+ archive_le32enc(e, (uint32_t)archive_entry_atime(entry));
+ e += 4;
+ }
+ if (archive_entry_ctime_is_set(entry)) {
+ archive_le32enc(e, (uint32_t)archive_entry_ctime(entry));
+ e += 4;
+ }
- zip->stream.zalloc = Z_NULL;
- zip->stream.zfree = Z_NULL;
- zip->stream.opaque = Z_NULL;
- zip->stream.next_out = zip->buf;
- zip->stream.avail_out = (uInt)zip->len_buf;
- if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
- Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't init deflate compressor");
- return (ARCHIVE_FATAL);
- }
- break;
-#endif
+ /* ux Unix extra data, length 11, version 1 */
+ /* TODO: If uid < 64k, use 2 bytes, ditto for gid. */
+ memcpy(e, "ux\013\000\001", 5);
+ e += 5;
+ *e++ = 4; /* Length of following UID */
+ archive_le32enc(e, (uint32_t)archive_entry_uid(entry));
+ e += 4;
+ *e++ = 4; /* Length of following GID */
+ archive_le32enc(e, (uint32_t)archive_entry_gid(entry));
+ e += 4;
+
+ /* Copy UT and ux into central directory as well. */
+ /* (Zip64 extended data varies between local header and
+ * central directory, so we cannot just copy it.) */
+ zip->file_header_extra_offset = zip->central_directory_bytes;
+ cd_extra = cd_alloc(zip, e - local_extra);
+ memcpy(cd_extra, local_extra, e - local_extra);
+
+ /* Zip64 field with variable size. */
+#if 0 /* XXX THIS IS WRONG XXX */
+ if ((zip->entry_flags & ZIP_FLAGS_LENGTH_AT_END) == 0
+ && size > 0xffffffffLL) {
+ unsigned char *zip64_start = e;
+ memcpy(e, "\001\000\020\000", 4);
+ e += 4;
+ if (zip->entry_uncompressed_size > 0xffffffffLL)
+ archive_le64enc(e, zip->entry_uncompressed_size);
+ e += 8;
+ if (zip->entry_compressed_size > 0xffffffffLL)
+ archive_le64enc(e, zip->entry_compressed_size);
+ e += 8;
+ archive_le16enc(zip64_start + 2, e - zip64_start + 4);
}
+#endif
- /* Formatting extra data. */
- archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e));
- archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID],
- ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3);
- e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME],
- (uint32_t)archive_entry_mtime(entry));
- archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME],
- (uint32_t)archive_entry_atime(entry));
- archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME],
- (uint32_t)archive_entry_ctime(entry));
-
- archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID],
- ZIP_SIGNATURE_EXTRA_NEW_UNIX);
- archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2);
- e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1;
- e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID],
- (uint32_t)archive_entry_uid(zip->entry.entry));
- e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID],
- (uint32_t)archive_entry_gid(zip->entry.entry));
-
- archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE],
- (uint32_t)size);
-
- ret = __archive_write_output(a, h, sizeof(h));
+ /* Update local header with size of extra data and write it all out: */
+ archive_le16enc(local_header + 28, e - local_extra);
+
+ ret = __archive_write_output(a, local_header, 30);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(h);
+ zip->written_bytes += 30;
- ret = write_path(zip->entry.entry, a);
+ ret = write_path(zip->entry, a);
if (ret <= ARCHIVE_OK)
return (ARCHIVE_FATAL);
zip->written_bytes += ret;
- ret = __archive_write_output(a, e, sizeof(e));
+ ret = __archive_write_output(a, local_extra, e - local_extra);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(e);
-
- if (type == AE_IFLNK) {
- const unsigned char *p;
+ zip->written_bytes += e - local_extra;
- p = (const unsigned char *)archive_entry_symlink(zip->entry.entry);
- ret = __archive_write_output(a, p, (size_t)size);
+ /* For symlinks, write the body now. */
+ if (symlink != NULL) {
+ ret = __archive_write_output(a, symlink, (size_t)symlink_size);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- zip->written_bytes += size;
- zip->entry.crc32 = crc32(zip->entry.crc32, p, (unsigned)size);
+ zip->entry_compressed_written += symlink_size;
+ zip->entry_uncompressed_written += symlink_size;
+ zip->written_bytes += symlink_size;
}
- if (ret2 != ARCHIVE_OK)
- return (ret2);
- return (ARCHIVE_OK);
+#ifdef HAVE_ZLIB_H
+ if (zip->entry_compression == COMPRESSION_DEFLATE) {
+ zip->stream.zalloc = Z_NULL;
+ zip->stream.zfree = Z_NULL;
+ zip->stream.opaque = Z_NULL;
+ zip->stream.next_out = zip->buf;
+ zip->stream.avail_out = (uInt)zip->len_buf;
+ if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't init deflate compressor");
+ return (ARCHIVE_FATAL);
+ }
+ }
+#endif
+
+ return (ret2);
}
static ssize_t
int ret;
struct zip *zip = a->format_data;
- if ((int64_t)s > zip->remaining_data_bytes)
- s = (size_t)zip->remaining_data_bytes;
+ if ((int64_t)s > zip->entry_uncompressed_limit)
+ s = (size_t)zip->entry_uncompressed_limit;
+ zip->entry_uncompressed_written += s;
if (s == 0) return 0;
- switch (zip->entry.compression) {
+ switch (zip->entry_compression) {
case COMPRESSION_STORE:
ret = __archive_write_output(a, buff, s);
if (ret != ARCHIVE_OK) return (ret);
zip->written_bytes += s;
- zip->remaining_data_bytes -= s;
- zip->entry.compressed_size += s;
- zip->entry.crc32 = crc32(zip->entry.crc32, buff, (unsigned)s);
- return (s);
+ zip->entry_compressed_written += s;
+ break;
#if HAVE_ZLIB_H
case COMPRESSION_DEFLATE:
zip->stream.next_in = (unsigned char*)(uintptr_t)buff;
zip->len_buf);
if (ret != ARCHIVE_OK)
return (ret);
- zip->entry.compressed_size += zip->len_buf;
+ zip->entry_compressed_written += zip->len_buf;
zip->written_bytes += zip->len_buf;
zip->stream.next_out = zip->buf;
zip->stream.avail_out = (uInt)zip->len_buf;
}
} while (zip->stream.avail_in != 0);
- zip->remaining_data_bytes -= s;
- /* If we have it, use zlib's fast crc32() */
- zip->entry.crc32 = crc32(zip->entry.crc32, buff, (uInt)s);
- return (s);
+ break;
#endif
default:
"Invalid ZIP compression type");
return ARCHIVE_FATAL;
}
+
+ zip->entry_uncompressed_limit -= s;
+ zip->entry_crc32 = crc32(zip->entry_crc32, buff, (unsigned)s);
+ return (s);
+
}
static int
archive_write_zip_finish_entry(struct archive_write *a)
{
- /* Write the data descripter after file data has been written. */
- int ret;
struct zip *zip = a->format_data;
- uint8_t *d = zip->data_descriptor;
- struct zip_entry *l;
-#if HAVE_ZLIB_H
- size_t reminder;
-#endif
+ int ret;
- switch(zip->entry.compression) {
- case COMPRESSION_STORE:
- break;
#if HAVE_ZLIB_H
- case COMPRESSION_DEFLATE:
+ if (zip->entry_compression == COMPRESSION_DEFLATE) {
for (;;) {
+ size_t remainder;
ret = deflate(&zip->stream, Z_FINISH);
if (ret == Z_STREAM_ERROR)
return (ARCHIVE_FATAL);
- reminder = zip->len_buf - zip->stream.avail_out;
- ret = __archive_write_output(a, zip->buf, reminder);
+ remainder = zip->len_buf - zip->stream.avail_out;
+ ret = __archive_write_output(a, zip->buf, remainder);
if (ret != ARCHIVE_OK)
return (ret);
- zip->entry.compressed_size += reminder;
- zip->written_bytes += reminder;
+ zip->entry_compressed_written += remainder;
+ zip->written_bytes += remainder;
zip->stream.next_out = zip->buf;
if (zip->stream.avail_out != 0)
break;
zip->stream.avail_out = (uInt)zip->len_buf;
}
deflateEnd(&zip->stream);
- break;
-#endif
}
+#endif
- archive_le32enc(&d[DATA_DESCRIPTOR_CRC32], zip->entry.crc32);
- archive_le32enc(&d[DATA_DESCRIPTOR_COMPRESSED_SIZE],
- (uint32_t)zip->entry.compressed_size);
- ret = __archive_write_output(a, d, SIZE_DATA_DESCRIPTOR);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += SIZE_DATA_DESCRIPTOR;
-
- /* Add details to list for formatting central directory. */
- /* TODO: Actually format it now and store the central dir data
- * as a block of bytes. */
- l = calloc(1, sizeof(*l));
- if (l == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate zip header data");
- return (ARCHIVE_FATAL);
+ /* Write trailing data descriptor. */
+ /* XXX IF ZIP64 XXX */
+ if ((zip->entry_flags & ZIP_FLAGS_LENGTH_AT_END) != 0) {
+ char d[24];
+ memcpy(d, "PK\007\010", 4);
+ archive_le32enc(d + 4, zip->entry_crc32);
+ archive_le32enc(d + 8, (uint32_t)zip->entry_compressed_written);
+ archive_le32enc(d + 12, (uint32_t)zip->entry_uncompressed_written);
+ ret = __archive_write_output(a, d, 16);
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ zip->written_bytes += 16;
}
- *l = zip->entry;
- zip->entry.entry = NULL; // This has moved.
- if (zip->central_directory == NULL) {
- zip->central_directory = l;
- } else {
- zip->central_directory_end->next = l;
+
+ /* Append Zip64 extra data to central directory information. */
+ if (zip->entry_compressed_written > 0xffffffffLL
+ || zip->entry_uncompressed_written > 0xffffffffLL
+ || zip->entry_offset > 0xffffffffLL) {
+ unsigned char zip64[32];
+ unsigned char *z = zip64, *zd;
+ memcpy(z, "\001\000\000\000", 4);
+ z += 4;
+ if (zip->entry_uncompressed_written > 0xffffffffLL)
+ archive_le64enc(z, zip->entry_uncompressed_written);
+ z += 8;
+ if (zip->entry_compressed_written > 0xffffffffLL)
+ archive_le64enc(z, zip->entry_compressed_written);
+ z += 8;
+ if (zip->entry_offset > 0xffffffffLL)
+ archive_le64enc(z, zip->entry_offset);
+ z += 8;
+ archive_le16enc(zip64 + 2, z - zip64 + 4);
+ zd = cd_alloc(zip, z - zip64);
+ if (zd == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate zip data");
+ return (ARCHIVE_FATAL);
+ }
+ memcpy(zd, zip64, z - zip64);
}
- zip->central_directory_end = l;
+
+ /* Fix up central directory file header. */
+ archive_le32enc(zip->file_header + 16, zip->entry_crc32);
+ archive_le32enc(zip->file_header + 20,
+ zipmin(zip->entry_compressed_written, 0xffffffffLL));
+ archive_le32enc(zip->file_header + 24,
+ zipmin(zip->entry_uncompressed_written, 0xffffffffLL));
+ archive_le16enc(zip->file_header + 30,
+ zip->central_directory_bytes - zip->file_header_extra_offset);
+ archive_le32enc(zip->file_header + 42,
+ zipmin(zip->entry_offset, 0xffffffffLL));
return (ARCHIVE_OK);
}
static int
archive_write_zip_close(struct archive_write *a)
{
- struct zip *zip;
- struct zip_entry *l;
- uint8_t h[SIZE_FILE_HEADER];
- uint8_t end[SIZE_CENTRAL_DIRECTORY_END];
- uint8_t e[SIZE_EXTRA_DATA_CENTRAL];
+ uint8_t end[22];
int64_t offset_start, offset_end;
- int entries;
+ struct zip *zip = a->format_data;
+ struct cd_segment *segment;
int ret;
- zip = a->format_data;
- l = zip->central_directory;
-
- /*
- * Formatting central directory file header fields that are
- * fixed for all entries.
- * Fields not used (and therefor 0) are:
- *
- * - comment_length
- * - disk_number
- * - attributes_internal
- */
- memset(h, 0, sizeof(h));
- archive_le32enc(&h[FILE_HEADER_SIGNATURE], ZIP_SIGNATURE_FILE_HEADER);
- archive_le16enc(&h[FILE_HEADER_VERSION_BY], ZIP_VERSION_BY);
- archive_le16enc(&h[FILE_HEADER_VERSION_EXTRACT], ZIP_VERSION_EXTRACT);
-
- entries = 0;
offset_start = zip->written_bytes;
-
- /* Formatting individual header fields per entry and
- * writing each entry. */
- while (l != NULL) {
- archive_le16enc(&h[FILE_HEADER_FLAGS], l->flags);
- archive_le16enc(&h[FILE_HEADER_COMPRESSION], l->compression);
- archive_le32enc(&h[FILE_HEADER_TIMEDATE],
- dos_time(archive_entry_mtime(l->entry)));
- archive_le32enc(&h[FILE_HEADER_CRC32], l->crc32);
- archive_le32enc(&h[FILE_HEADER_COMPRESSED_SIZE],
- (uint32_t)l->compressed_size);
- archive_le32enc(&h[FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)archive_entry_size(l->entry));
- archive_le16enc(&h[FILE_HEADER_FILENAME_LENGTH],
- (uint16_t)path_length(l->entry));
- archive_le16enc(&h[FILE_HEADER_EXTRA_LENGTH], sizeof(e));
- archive_le16enc(&h[FILE_HEADER_ATTRIBUTES_EXTERNAL+2],
- archive_entry_mode(l->entry));
- archive_le32enc(&h[FILE_HEADER_OFFSET], (uint32_t)l->offset);
-
- /* Formatting extra data. */
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_ID],
- ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_SIZE], 1 + 4);
- e[EXTRA_DATA_CENTRAL_TIME_FLAG] = 0x07;
- archive_le32enc(&e[EXTRA_DATA_CENTRAL_MTIME],
- (uint32_t)archive_entry_mtime(l->entry));
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_ID],
- ZIP_SIGNATURE_EXTRA_NEW_UNIX);
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_SIZE], 0x0000);
-
- ret = __archive_write_output(a, h, sizeof(h));
+ segment = zip->central_directory;
+ while (segment != NULL) {
+ ret = __archive_write_output(a,
+ segment->buff, segment->p - segment->buff);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(h);
-
- ret = write_path(l->entry, a);
- if (ret <= ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += ret;
-
- ret = __archive_write_output(a, e, sizeof(e));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(e);
-
- l = l->next;
- entries++;
+ zip->written_bytes += segment->p - segment->buff;
+ segment = segment->next;
}
offset_end = zip->written_bytes;
- /* Formatting end of central directory. */
+ /* TODO: If central dir info is too large, write Zip64 end-of-cd */
+
+ /* Format and write end of central directory. */
memset(end, 0, sizeof(end));
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIGNATURE],
- ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
- archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES_DISK], entries);
- archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES], entries);
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIZE],
- (uint32_t)(offset_end - offset_start));
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_OFFSET],
- (uint32_t)offset_start);
-
- /* Writing end of central directory. */
+ memcpy(end, "PK\005\006", 4);
+ archive_le16enc(end + 8, zip->central_directory_entries);
+ archive_le16enc(end + 10, zip->central_directory_entries);
+ archive_le32enc(end + 12, (uint32_t)(offset_end - offset_start));
+ archive_le32enc(end + 16, (uint32_t)offset_start);
ret = __archive_write_output(a, end, sizeof(end));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
archive_write_zip_free(struct archive_write *a)
{
struct zip *zip;
- struct zip_entry *l;
+ struct cd_segment *segment;
zip = a->format_data;
while (zip->central_directory != NULL) {
- l = zip->central_directory;
- zip->central_directory = l->next;
- archive_entry_free(l->entry);
- free(l);
+ segment = zip->central_directory;
+ zip->central_directory = segment->next;
+ free(segment->buff);
+ free(segment);
}
#ifdef HAVE_ZLIB_H
free(zip->buf);
#endif
+ archive_entry_free(zip->entry);
+ /* TODO: Free opt_sconv, sconv_default */
+
free(zip);
a->format_data = NULL;
return (ARCHIVE_OK);
return (ARCHIVE_FATAL);
written_bytes += strlen(path);
- /* Folders are recognized by a traling slash. */
+ /* Folders are recognized by a trailing slash. */
if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
ret = __archive_write_output(archive, "/", 1);
if (ret != ARCHIVE_OK)
return ((int)written_bytes);
}
+
+static void
+copy_path(struct archive_entry *entry, unsigned char *p)
+{
+ int ret;
+ const char *path;
+ size_t pathlen;
+ mode_t type;
+
+ path = archive_entry_pathname(entry);
+ pathlen = strlen(path);
+ type = archive_entry_filetype(entry);
+
+ memcpy(p, path, pathlen);
+
+ /* Folders are recognized by a trailing slash. */
+ if ((type == AE_IFDIR) & (path[pathlen - 1] != '/')) {
+ p[pathlen] = '/';
+ p[pathlen + 1] = '\0';
+ }
+}
+
+
+static struct archive_string_conv *
+get_sconv(struct archive_write *a, struct zip *zip)
+{
+ struct archive_string_conv *sconv;
+
+ if (zip->opt_sconv != NULL)
+ return (zip->opt_sconv);
+
+ if (!zip->init_default_conversion) {
+ zip->sconv_default =
+ archive_string_default_conversion_for_write(&(a->archive));
+ zip->init_default_conversion = 1;
+ }
+ return (zip->sconv_default);
+}
return (p);
}
+/*
+ * Slurp a file into memory for ease of comparison and testing.
+ * Returns size of file in 'sizep' if non-NULL, null-terminates
+ * data in memory for ease of use.
+ */
+void
+dumpfile(const char *filename, void *data, size_t len)
+{
+ ssize_t bytes_written;
+ FILE *f;
+
+ f = fopen(filename, "wb");
+ if (f == NULL) {
+ logprintf("Can't open file %s for writing\n", filename);
+ return;
+ }
+ bytes_written = fwrite(data, 1, len, f);
+ if (bytes_written < len)
+ logprintf("Can't write file %s\n", filename);
+ fclose(f);
+}
+
/* Read a uuencoded file from the reference directory, decode, and
* write the result into the current directory. */
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
char *slurpfile(size_t *, const char *fmt, ...);
+/* Dump block of bytes to a file. */
+void dumpfile(const char *filename, void *, size_t);
+
/* Extracts named reference file to the current directory. */
void extract_reference_file(const char *);
__FBSDID("$FreeBSD: head/lib/libarchive/test/test_write_format_zip.c 201247 2009-12-30 05:59:21Z kientzle $");
static void
-verify_contents(struct archive *a, int expect_details)
+verify_contents(struct archive *a, int seeking)
{
char filedata[64];
struct archive_entry *ae;
/*
- * Read and verify first file.
+ * Default compression options:
*/
+
+ /* Read and verify first file. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualInt(1, archive_entry_mtime(ae));
/* Zip doesn't store high-resolution mtime. */
assertEqualInt(0, archive_entry_atime(ae));
assertEqualInt(0, archive_entry_ctime(ae));
assertEqualString("file", archive_entry_pathname(ae));
- if (expect_details) {
+ if (seeking) {
assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
assertEqualInt(8, archive_entry_size(ae));
} else {
- assertEqualInt(0, archive_entry_size(ae));
+ assertEqualInt(0, archive_entry_size_is_set(ae));
}
assertEqualIntA(a, 8,
archive_read_data(a, filedata, sizeof(filedata)));
assertEqualMem(filedata, "12345678", 8);
- /*
- * Read the second file back.
- */
+ /* Read the second file back. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualInt(1, archive_entry_mtime(ae));
assertEqualInt(0, archive_entry_mtime_nsec(ae));
assertEqualInt(0, archive_entry_atime(ae));
assertEqualInt(0, archive_entry_ctime(ae));
assertEqualString("file2", archive_entry_pathname(ae));
- if (expect_details) {
+ if (seeking) {
assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
assertEqualInt(4, archive_entry_size(ae));
} else {
- assertEqualInt(0, archive_entry_size(ae));
+ assertEqualInt(0, archive_entry_size_is_set(ae));
}
assertEqualIntA(a, 4,
archive_read_data(a, filedata, sizeof(filedata)));
assertEqualMem(filedata, "1234", 4);
- /*
- * Read the third file back.
- */
+ /* Read the third file back. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(2, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file3", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(5, archive_entry_size(ae));
+ assertEqualInt(AE_IFREG | 0621, archive_entry_mode(ae));
+ } else {
+ assertEqualInt(0, archive_entry_size_is_set(ae));
+ }
+ assertEqualIntA(a, 5,
+ archive_read_data(a, filedata, sizeof(filedata)));
+ assertEqualMem(filedata, "mnopq", 5);
+
+ /* Read symlink. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualInt(1, archive_entry_mtime(ae));
assertEqualInt(0, archive_entry_mtime_nsec(ae));
assertEqualInt(0, archive_entry_atime(ae));
assertEqualInt(0, archive_entry_ctime(ae));
assertEqualString("symlink", archive_entry_pathname(ae));
- if (expect_details) {
+ if (seeking) {
assertEqualInt(AE_IFLNK | 0755, archive_entry_mode(ae));
assertEqualInt(0, archive_entry_size(ae));
assertEqualString("file1", archive_entry_symlink(ae));
} else {
+ /* Streaming cannot read file type, so
+ * symlink body shows as regular file contents. */
assertEqualInt(AE_IFREG | 0664, archive_entry_mode(ae));
+ assertEqualInt(5, archive_entry_size(ae));
+ }
+
+ /* Read the dir entry back. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(11, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("dir/", archive_entry_pathname(ae));
+ if (seeking)
+ assertEqualInt(AE_IFDIR | 0755, archive_entry_mode(ae));
+ assertEqualInt(0, archive_entry_size(ae));
+ assertEqualIntA(a, 0, archive_read_data(a, filedata, 10));
+
+#ifdef HAVE_ZLIB_H
+ /*
+ * Deflate compression option:
+ */
+
+ /* Read and verify first file. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ /* Zip doesn't store high-resolution mtime. */
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file_deflate", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
+ assertEqualInt(8, archive_entry_size(ae));
+ } else {
+ assertEqualInt(0, archive_entry_size(ae));
+ }
+ assertEqualIntA(a, 8,
+ archive_read_data(a, filedata, sizeof(filedata)));
+ assertEqualMem(filedata, "12345678", 8);
+
+
+ /* Read the second file back. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file2_deflate", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
+ assertEqualInt(4, archive_entry_size(ae));
+ } else {
assertEqualInt(0, archive_entry_size(ae));
}
+ assertEqualIntA(a, 4,
+ archive_read_data(a, filedata, sizeof(filedata)));
+ assertEqualMem(filedata, "1234", 4);
+
+ /* Read the third file back. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(2, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file3_deflate", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(5, archive_entry_size(ae));
+ assertEqualInt(AE_IFREG | 0621, archive_entry_mode(ae));
+ } else {
+ assertEqualInt(0, archive_entry_size_is_set(ae));
+ }
+ assertEqualIntA(a, 5,
+ archive_read_data(a, filedata, sizeof(filedata)));
+ assertEqualMem(filedata, "ghijk", 4);
+
+ /* Read symlink. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("symlink_deflate", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(AE_IFLNK | 0755, archive_entry_mode(ae));
+ assertEqualInt(0, archive_entry_size(ae));
+ assertEqualString("file1", archive_entry_symlink(ae));
+ } else {
+ assertEqualInt(AE_IFREG | 0664, archive_entry_mode(ae));
+ assertEqualInt(5, archive_entry_size(ae));
+ assertEqualIntA(a, 5, archive_read_data(a, filedata, 10));
+ assertEqualMem(filedata, "file1", 5);
+ }
+
+ /* Read the dir entry back. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(11, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("dir_deflate/", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(AE_IFDIR | 0755, archive_entry_mode(ae));
+ }
+ assertEqualInt(0, archive_entry_size(ae));
+ assertEqualIntA(a, 0, archive_read_data(a, filedata, 10));
+#endif
/*
- * Read the dir entry back.
+ * Store compression option:
*/
+
+ /* Read and verify first file. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ /* Zip doesn't store high-resolution mtime. */
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file_stored", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
+ assert(archive_entry_size_is_set(ae));
+ assertEqualInt(8, archive_entry_size(ae));
+ } else {
+ assertEqualInt(0, archive_entry_size_is_set(ae));
+ }
+ assertEqualIntA(a, 8,
+ archive_read_data(a, filedata, sizeof(filedata)));
+ assertEqualMem(filedata, "12345678", 8);
+
+
+ /* Read the second file back. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file2_stored", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(4, archive_entry_size(ae));
+ assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
+ } else {
+ assertEqualInt(0, archive_entry_size_is_set(ae));
+ }
+ assertEqualIntA(a, 4,
+ archive_read_data(a, filedata, sizeof(filedata)));
+ assertEqualMem(filedata, "ACEG", 4);
+
+ /* Read the third file back. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(2, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file3_stored", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(5, archive_entry_size(ae));
+ assertEqualInt(AE_IFREG | 0621, archive_entry_mode(ae));
+ } else {
+ assertEqualInt(0, archive_entry_size_is_set(ae));
+ }
+ assertEqualIntA(a, 5,
+ archive_read_data(a, filedata, sizeof(filedata)));
+ assertEqualMem(filedata, "ijklm", 4);
+
+ /* Read symlink. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("symlink_stored", archive_entry_pathname(ae));
+ if (seeking) {
+ assertEqualInt(AE_IFLNK | 0755, archive_entry_mode(ae));
+ assertEqualInt(0, archive_entry_size(ae));
+ assertEqualString("file1", archive_entry_symlink(ae));
+ } else {
+ assertEqualInt(AE_IFREG | 0664, archive_entry_mode(ae));
+ assertEqualInt(5, archive_entry_size(ae));
+ assertEqualIntA(a, 5, archive_read_data(a, filedata, 10));
+ assertEqualMem(filedata, "file1", 5);
+ }
+
+ /* Read the dir entry back. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualInt(11, archive_entry_mtime(ae));
assertEqualInt(0, archive_entry_mtime_nsec(ae));
assertEqualInt(0, archive_entry_atime(ae));
assertEqualInt(0, archive_entry_ctime(ae));
- assertEqualString("dir/", archive_entry_pathname(ae));
- if (expect_details)
+ assertEqualString("dir_stored/", archive_entry_pathname(ae));
+ if (seeking)
assertEqualInt(AE_IFDIR | 0755, archive_entry_mode(ae));
assertEqualInt(0, archive_entry_size(ae));
assertEqualIntA(a, 0, archive_read_data(a, filedata, 10));
/* Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a));
-#ifdef HAVE_ZLIB_H
- compression_type = "deflate";
-#else
- compression_type = "store";
-#endif
- assertEqualIntA(a, ARCHIVE_OK,
- archive_write_set_format_option(a, "zip", "compression", compression_type));
assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
assertEqualIntA(a, ARCHIVE_OK,
archive_write_open_memory(a, buff, buffsize, &used));
+ /*
+ * First write things with the "default" compression.
+ * The library will choose "deflate" for most things if it's
+ * available, else "store".
+ */
+
/*
* Write a file to it.
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_mtime(ae, 1, 10);
- assertEqualInt(1, archive_entry_mtime(ae));
- assertEqualInt(10, archive_entry_mtime_nsec(ae));
archive_entry_copy_pathname(ae, "file");
- assertEqualString("file", archive_entry_pathname(ae));
archive_entry_set_mode(ae, AE_IFREG | 0755);
- assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));
archive_entry_set_size(ae, 8);
-
assertEqualInt(0, archive_write_header(a, ae));
archive_entry_free(ae);
assertEqualInt(8, archive_write_data(a, "12345678", 9));
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_mtime(ae, 1, 10);
- assertEqualInt(1, archive_entry_mtime(ae));
- assertEqualInt(10, archive_entry_mtime_nsec(ae));
archive_entry_copy_pathname(ae, "file2");
- assertEqualString("file2", archive_entry_pathname(ae));
archive_entry_set_mode(ae, AE_IFREG | 0755);
- assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));
archive_entry_set_size(ae, 4);
+ assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualInt(4, archive_write_data(a, "1234", 4));
+ /*
+ * Write a file with an unknown size.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 2, 15);
+ archive_entry_copy_pathname(ae, "file3");
+ archive_entry_set_mode(ae, AE_IFREG | 0621);
+ archive_entry_unset_size(ae);
assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
archive_entry_free(ae);
- assertEqualInt(4, archive_write_data(a, "1234", 5));
+ assertEqualInt(5, archive_write_data(a, "mnopq", 5));
/*
- * Write symbolic like file to it.
+ * Write symbolic link.
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_mtime(ae, 1, 10);
archive_entry_copy_pathname(ae, "dir");
archive_entry_set_mode(ae, S_IFDIR | 0755);
archive_entry_set_size(ae, 512);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ failure("size should be zero so that applications know not to write");
+ assertEqualInt(0, archive_entry_size(ae));
+ archive_entry_free(ae);
+ assertEqualIntA(a, 0, archive_write_data(a, "12345678", 9));
+
+ /*
+ * Force "deflate" compression if the platform supports it.
+ */
+#ifdef HAVE_ZLIB_H
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_zip_set_compression_deflate(a));
+
+ /*
+ * Write a file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 10);
+ archive_entry_copy_pathname(ae, "file_deflate");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+ archive_entry_set_size(ae, 8);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualInt(8, archive_write_data(a, "12345678", 9));
+ assertEqualInt(0, archive_write_data(a, "1", 1));
+ /*
+ * Write another file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 10);
+ archive_entry_copy_pathname(ae, "file2_deflate");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+ archive_entry_set_size(ae, 4);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualInt(4, archive_write_data(a, "1234", 4));
+
+ /*
+ * Write a file with an unknown size.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 2, 15);
+ archive_entry_copy_pathname(ae, "file3_deflate");
+ archive_entry_set_mode(ae, AE_IFREG | 0621);
+ archive_entry_unset_size(ae);
+ assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualInt(5, archive_write_data(a, "ghijk", 5));
+
+ /*
+ * Write symbolic like file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 10);
+ archive_entry_copy_pathname(ae, "symlink_deflate");
+ archive_entry_copy_symlink(ae, "file1");
+ archive_entry_set_mode(ae, AE_IFLNK | 0755);
+ archive_entry_set_size(ae, 4);
+ assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+ /*
+ * Write a directory to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 11, 110);
+ archive_entry_copy_pathname(ae, "dir_deflate");
+ archive_entry_set_mode(ae, S_IFDIR | 0755);
+ archive_entry_set_size(ae, 512);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
failure("size should be zero so that applications know not to write");
assertEqualInt(0, archive_entry_size(ae));
archive_entry_free(ae);
assertEqualIntA(a, 0, archive_write_data(a, "12345678", 9));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
+#endif
+
+ /*
+ * Now write a bunch of entries with "store" compression.
+ */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_zip_set_compression_store(a));
+
+ /*
+ * Write a file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 10);
+ archive_entry_copy_pathname(ae, "file_stored");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+ archive_entry_set_size(ae, 8);
+ assertEqualInt(0, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualInt(8, archive_write_data(a, "12345678", 9));
+ assertEqualInt(0, archive_write_data(a, "1", 1));
+
+ /*
+ * Write another file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 10);
+ archive_entry_copy_pathname(ae, "file2_stored");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+ archive_entry_set_size(ae, 4);
+ assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualInt(4, archive_write_data(a, "ACEG", 4));
+
+ /*
+ * Write a file with an unknown size.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 2, 15);
+ archive_entry_copy_pathname(ae, "file3_stored");
+ archive_entry_set_mode(ae, AE_IFREG | 0621);
+ archive_entry_unset_size(ae);
+ assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualInt(5, archive_write_data(a, "ijklm", 5));
+
+ /*
+ * Write symbolic like file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 10);
+ archive_entry_copy_pathname(ae, "symlink_stored");
+ archive_entry_copy_symlink(ae, "file1");
+ archive_entry_set_mode(ae, AE_IFLNK | 0755);
+ archive_entry_set_size(ae, 4);
+ assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+ /*
+ * Write a directory to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 11, 110);
+ archive_entry_copy_pathname(ae, "dir_stored");
+ archive_entry_set_mode(ae, S_IFDIR | 0755);
+ archive_entry_set_size(ae, 512);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ failure("size should be zero so that applications know not to write");
+ assertEqualInt(0, archive_entry_size(ae));
+ archive_entry_free(ae);
+ assertEqualIntA(a, 0, archive_write_data(a, "12345678", 9));
+
/* Close out the archive. */
assertEqualInt(ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+ dumpfile("constructed.zip", buff, used);
+
/*
* Now, read the data back.
*/
archive_entry_set_uid(entry, file_uid);
archive_entry_set_gid(entry, file_gid);
archive_entry_set_mtime(entry, t, 0);
- archive_entry_set_atime(entry, t, 0);
- archive_entry_set_ctime(entry, t, 0);
+ archive_entry_set_atime(entry, t + 3, 0);
assertEqualIntA(a, 0, archive_write_header(a, entry));
assertEqualIntA(a, sizeof(file_data1), archive_write_data(a, file_data1, sizeof(file_data1)));
assertEqualIntA(a, sizeof(file_data2), archive_write_data(a, file_data2, sizeof(file_data2)));
archive_entry_set_uid(entry, folder_uid);
archive_entry_set_gid(entry, folder_gid);
archive_entry_set_mtime(entry, t, 0);
- archive_entry_set_atime(entry, t, 0);
- archive_entry_set_ctime(entry, t, 0);
+ archive_entry_set_ctime(entry, t + 5, 0);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+ dumpfile("constructed.zip", buff, used);
+
/* Remember the end of the archive in memory. */
buffend = buff + used;
/* Verify file entry in central directory. */
assertEqualMem(p, "PK\001\002", 4); /* Signature */
- assertEqualInt(i2(p + 4), 3 * 256 + 20); /* Version made by */
- assertEqualInt(i2(p + 6), 20); /* Version needed to extract */
+ assertEqualInt(i2(p + 4), 3 * 256 + 10); /* Version made by */
+ assertEqualInt(i2(p + 6), 10); /* Version needed to extract */
assertEqualInt(i2(p + 8), 8); /* Flags */
assertEqualInt(i2(p + 10), 0); /* Compression method */
assertEqualInt(i2(p + 12), (tm->tm_hour * 2048) + (tm->tm_min * 32) + (tm->tm_sec / 2)); /* File time */
assertEqualInt(i4(p + 20), sizeof(file_data1) + sizeof(file_data2)); /* Compressed size */
assertEqualInt(i4(p + 24), sizeof(file_data1) + sizeof(file_data2)); /* Uncompressed size */
assertEqualInt(i2(p + 28), strlen(file_name)); /* Pathname length */
- assertEqualInt(i2(p + 30), 13); /* Extra field length */
+ assertEqualInt(i2(p + 30), 28); /* Extra field length */
assertEqualInt(i2(p + 32), 0); /* File comment length */
assertEqualInt(i2(p + 34), 0); /* Disk number start */
assertEqualInt(i2(p + 36), 0); /* Internal file attrs */
assertEqualMem(p + 46, file_name, strlen(file_name)); /* Pathname */
p = p + 46 + strlen(file_name);
assertEqualInt(i2(p), 0x5455); /* 'UT' extension header */
- assertEqualInt(i2(p + 2), 5); /* 'UT' size */
- assertEqualInt(p[4], 7); /* 'UT' flags */
+ assertEqualInt(i2(p + 2), 9); /* 'UT' size */
+ assertEqualInt(p[4], 3); /* 'UT' flags */
assertEqualInt(i4(p + 5), t); /* 'UT' mtime */
- p = p + 9;
+ assertEqualInt(i4(p + 9), t + 3); /* 'UT' atime */
+ p = p + 4 + i2(p + 2);
assertEqualInt(i2(p), 0x7875); /* 'ux' extension header */
- assertEqualInt(i2(p + 2), 0); /* 'ux' size */
- p = p + 4;
+ assertEqualInt(i2(p + 2), 11); /* 'ux' size */
+/* TODO */
+ p = p + 4 + i2(p + 2);
/* Verify local header of file entry. */
q = buff;
assertEqualMem(q, "PK\003\004", 4); /* Signature */
- assertEqualInt(i2(q + 4), 20); /* Version needed to extract */
+ assertEqualInt(i2(q + 4), 10); /* Version needed to extract */
assertEqualInt(i2(q + 6), 8); /* Flags */
assertEqualInt(i2(q + 8), 0); /* Compression method */
assertEqualInt(i2(q + 10), (tm->tm_hour * 2048) + (tm->tm_min * 32) + (tm->tm_sec / 2)); /* File time */
assertEqualInt(i4(q + 18), sizeof(file_data1) + sizeof(file_data2)); /* Compressed size */
assertEqualInt(i4(q + 22), sizeof(file_data1) + sizeof(file_data2)); /* Uncompressed size */
assertEqualInt(i2(q + 26), strlen(file_name)); /* Pathname length */
- assertEqualInt(i2(q + 28), 32); /* Extra field length */
+ assertEqualInt(i2(q + 28), 28); /* Extra field length */
assertEqualMem(q + 30, file_name, strlen(file_name)); /* Pathname */
q = q + 30 + strlen(file_name);
assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */
- assertEqualInt(i2(q + 2), 13); /* 'UT' size */
- assertEqualInt(q[4], 7); /* 'UT' flags */
+ assertEqualInt(i2(q + 2), 9); /* 'UT' size */
+ assertEqualInt(q[4], 3); /* 'UT' flags */
assertEqualInt(i4(q + 5), t); /* 'UT' mtime */
- assertEqualInt(i4(q + 9), t); /* 'UT' atime */
- assertEqualInt(i4(q + 13), t); /* 'UT' ctime */
- q = q + 17;
+ assertEqualInt(i4(q + 9), t + 3); /* 'UT' atime */
+ q = q + 4 + i2(q + 2);
assertEqualInt(i2(q), 0x7875); /* 'ux' extension header */
assertEqualInt(i2(q + 2), 11); /* 'ux' size */
assertEqualInt(q[4], 1); /* 'ux' version */
assertEqualInt(i4(q + 6), file_uid); /* 'Ux' UID */
assertEqualInt(q[10], 4); /* 'ux' gid size */
assertEqualInt(i4(q + 11), file_gid); /* 'Ux' GID */
- q = q + 15;
+ q = q + 4 + i2(q + 2);
/* Verify data of file entry. */
assertEqualMem(q, file_data1, sizeof(file_data1));
assertEqualMem(p, "PK\001\002", 4); /* Signature */
assertEqualInt(i2(p + 4), 3 * 256 + 20); /* Version made by */
assertEqualInt(i2(p + 6), 20); /* Version needed to extract */
- assertEqualInt(i2(p + 8), 8); /* Flags */
+ assertEqualInt(i2(p + 8), 0); /* Flags */
assertEqualInt(i2(p + 10), 0); /* Compression method */
assertEqualInt(i2(p + 12), (tm->tm_hour * 2048) + (tm->tm_min * 32) + (tm->tm_sec / 2)); /* File time */
assertEqualInt(i2(p + 14), ((tm->tm_year - 80) * 512) + ((tm->tm_mon + 1) * 32) + tm->tm_mday); /* File date */
assertEqualInt(i4(p + 20), 0); /* Compressed size */
assertEqualInt(i4(p + 24), 0); /* Uncompressed size */
assertEqualInt(i2(p + 28), strlen(folder_name)); /* Pathname length */
- assertEqualInt(i2(p + 30), 13); /* Extra field length */
+ assertEqualInt(i2(p + 30), 28); /* Extra field length */
assertEqualInt(i2(p + 32), 0); /* File comment length */
assertEqualInt(i2(p + 34), 0); /* Disk number start */
assertEqualInt(i2(p + 36), 0); /* Internal file attrs */
assertEqualMem(p + 46, folder_name, strlen(folder_name)); /* Pathname */
p = p + 46 + strlen(folder_name);
assertEqualInt(i2(p), 0x5455); /* 'UT' extension header */
- assertEqualInt(i2(p + 2), 5); /* 'UT' size */
- assertEqualInt(p[4], 7); /* 'UT' flags */
+ assertEqualInt(i2(p + 2), 9); /* 'UT' size */
+ assertEqualInt(p[4], 5); /* 'UT' flags */
assertEqualInt(i4(p + 5), t); /* 'UT' mtime */
- p = p + 9;
+ assertEqualInt(i4(p + 9), t + 5); /* 'UT' atime */
+ p = p + 4 + i2(p + 2);
assertEqualInt(i2(p), 0x7875); /* 'ux' extension header */
- assertEqualInt(i2(p + 2), 0); /* 'ux' size */
- /*p = p + 4;*/
+ assertEqualInt(i2(p + 2), 11); /* 'ux' size */
+ assertEqualInt(p[4], 1); /* 'ux' version */
+ assertEqualInt(p[5], 4); /* 'ux' uid size */
+ assertEqualInt(i4(p + 6), folder_uid); /* 'ux' UID */
+ assertEqualInt(p[10], 4); /* 'ux' gid size */
+ assertEqualInt(i4(p + 11), folder_gid); /* 'ux' GID */
+ /*p = p + 4 + i2(p + 2);*/
/* Verify local header of folder entry. */
assertEqualMem(q, "PK\003\004", 4); /* Signature */
assertEqualInt(i2(q + 4), 20); /* Version needed to extract */
- assertEqualInt(i2(q + 6), 8); /* Flags */
+ assertEqualInt(i2(q + 6), 0); /* Flags */
assertEqualInt(i2(q + 8), 0); /* Compression method */
assertEqualInt(i2(q + 10), (tm->tm_hour * 2048) + (tm->tm_min * 32) + (tm->tm_sec / 2)); /* File time */
assertEqualInt(i2(q + 12), ((tm->tm_year - 80) * 512) + ((tm->tm_mon + 1) * 32) + tm->tm_mday); /* File date */
assertEqualInt(i4(q + 18), 0); /* Compressed size */
assertEqualInt(i4(q + 22), 0); /* Uncompressed size */
assertEqualInt(i2(q + 26), strlen(folder_name)); /* Pathname length */
- assertEqualInt(i2(q + 28), 32); /* Extra field length */
+ assertEqualInt(i2(q + 28), 28); /* Extra field length */
assertEqualMem(q + 30, folder_name, strlen(folder_name)); /* Pathname */
q = q + 30 + strlen(folder_name);
assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */
- assertEqualInt(i2(q + 2), 13); /* 'UT' size */
- assertEqualInt(q[4], 7); /* 'UT' flags */
+ assertEqualInt(i2(q + 2), 9); /* 'UT' size */
+ assertEqualInt(q[4], 5); /* 'UT' flags */
assertEqualInt(i4(q + 5), t); /* 'UT' mtime */
- assertEqualInt(i4(q + 9), t); /* 'UT' atime */
- assertEqualInt(i4(q + 13), t); /* 'UT' ctime */
- q = q + 17;
+ assertEqualInt(i4(q + 9), t + 5); /* 'UT' atime */
+ q = q + 4 + i2(q + 2);
assertEqualInt(i2(q), 0x7875); /* 'ux' extension header */
assertEqualInt(i2(q + 2), 11); /* 'ux' size */
assertEqualInt(q[4], 1); /* 'ux' version */
assertEqualInt(i4(q + 6), folder_uid); /* 'ux' UID */
assertEqualInt(q[10], 4); /* 'ux' gid size */
assertEqualInt(i4(q + 11), folder_gid); /* 'ux' GID */
- q = q + 15;
+ q = q + 4 + i2(q + 2);
/* There should not be any data in the folder entry,
- * meaning next is the data descriptor header. */
-
- /* Verify data descriptor of folder entry. */
- assertEqualMem(q, "PK\007\010", 4); /* Signature */
- assertEqualInt(i4(q + 4), crc); /* CRC-32 */
- assertEqualInt(i4(q + 8), 0); /* Compressed size */
- assertEqualInt(i4(q + 12), 0); /* Uncompressed size */
- /*q = q + 16;*/
+ * so the first central directory entry should be next: */
+ assertEqualMem(q, "PK\001\002", 4); /* Signature */
}
/*-
- * Copyright (c) 2012 Matthias Brantner
+ * Copyright (c) 2008 Anselm Strauss
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/*
+ * Development supported by Google Summer of Code 2008.
+ */
+
#include "test.h"
+__FBSDID("$FreeBSD: head/lib/libarchive/test/test_write_format_zip_no_compression.c 201247 2009-12-30 05:59:21Z kientzle $");
static unsigned long
bitcrc32(unsigned long c, void *_p, size_t s)
/* Create new ZIP archive in memory without padding. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_zip(a));
+ assertA(0 == archive_write_set_options(a, "zip:compression=store"));
assertA(0 == archive_write_add_filter_none(a));
assertA(0 == archive_write_set_bytes_per_block(a, 1));
assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
archive_entry_set_uid(entry, file_uid);
archive_entry_set_gid(entry, file_gid);
archive_entry_set_mtime(entry, t, 0);
- archive_entry_set_atime(entry, t, 0);
- archive_entry_set_ctime(entry, t, 0);
- archive_write_zip_set_compression_store(a);
+ archive_entry_set_atime(entry, t + 3, 0);
assertEqualIntA(a, 0, archive_write_header(a, entry));
assertEqualIntA(a, sizeof(file_data1), archive_write_data(a, file_data1, sizeof(file_data1)));
assertEqualIntA(a, sizeof(file_data2), archive_write_data(a, file_data2, sizeof(file_data2)));
archive_entry_free(entry);
- archive_write_finish_entry(a);
/* Folder */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_uid(entry, folder_uid);
archive_entry_set_gid(entry, folder_gid);
archive_entry_set_mtime(entry, t, 0);
- archive_entry_set_atime(entry, t, 0);
- archive_entry_set_ctime(entry, t, 0);
- archive_write_zip_set_compression_store(a);
+ archive_entry_set_ctime(entry, t + 5, 0);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
- archive_write_finish_entry(a);
/* Close the archive . */
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+ dumpfile("constructed.zip", buff, used);
+
/* Remember the end of the archive in memory. */
buffend = buff + used;
/* Verify file entry in central directory. */
assertEqualMem(p, "PK\001\002", 4); /* Signature */
- assertEqualInt(i2(p + 4), 3 * 256 + 20); /* Version made by */
- assertEqualInt(i2(p + 6), 20); /* Version needed to extract */
+ assertEqualInt(i2(p + 4), 3 * 256 + 10); /* Version made by */
+ assertEqualInt(i2(p + 6), 10); /* Version needed to extract */
assertEqualInt(i2(p + 8), 8); /* Flags */
assertEqualInt(i2(p + 10), 0); /* Compression method */
assertEqualInt(i2(p + 12), (tm->tm_hour * 2048) + (tm->tm_min * 32) + (tm->tm_sec / 2)); /* File time */
assertEqualInt(i4(p + 20), sizeof(file_data1) + sizeof(file_data2)); /* Compressed size */
assertEqualInt(i4(p + 24), sizeof(file_data1) + sizeof(file_data2)); /* Uncompressed size */
assertEqualInt(i2(p + 28), strlen(file_name)); /* Pathname length */
- assertEqualInt(i2(p + 30), 13); /* Extra field length */
+ assertEqualInt(i2(p + 30), 28); /* Extra field length */
assertEqualInt(i2(p + 32), 0); /* File comment length */
assertEqualInt(i2(p + 34), 0); /* Disk number start */
assertEqualInt(i2(p + 36), 0); /* Internal file attrs */
assertEqualMem(p + 46, file_name, strlen(file_name)); /* Pathname */
p = p + 46 + strlen(file_name);
assertEqualInt(i2(p), 0x5455); /* 'UT' extension header */
- assertEqualInt(i2(p + 2), 5); /* 'UT' size */
- assertEqualInt(p[4], 7); /* 'UT' flags */
+ assertEqualInt(i2(p + 2), 9); /* 'UT' size */
+ assertEqualInt(p[4], 3); /* 'UT' flags */
assertEqualInt(i4(p + 5), t); /* 'UT' mtime */
- p = p + 9;
+ assertEqualInt(i4(p + 9), t + 3); /* 'UT' atime */
+ p = p + 4 + i2(p + 2);
assertEqualInt(i2(p), 0x7875); /* 'ux' extension header */
- assertEqualInt(i2(p + 2), 0); /* 'ux' size */
- p = p + 4;
+ assertEqualInt(i2(p + 2), 11); /* 'ux' size */
+/* TODO */
+ p = p + 4 + i2(p + 2);
/* Verify local header of file entry. */
q = buff;
assertEqualMem(q, "PK\003\004", 4); /* Signature */
- assertEqualInt(i2(q + 4), 20); /* Version needed to extract */
+ assertEqualInt(i2(q + 4), 10); /* Version needed to extract */
assertEqualInt(i2(q + 6), 8); /* Flags */
assertEqualInt(i2(q + 8), 0); /* Compression method */
assertEqualInt(i2(q + 10), (tm->tm_hour * 2048) + (tm->tm_min * 32) + (tm->tm_sec / 2)); /* File time */
assertEqualInt(i4(q + 18), sizeof(file_data1) + sizeof(file_data2)); /* Compressed size */
assertEqualInt(i4(q + 22), sizeof(file_data1) + sizeof(file_data2)); /* Uncompressed size */
assertEqualInt(i2(q + 26), strlen(file_name)); /* Pathname length */
- assertEqualInt(i2(q + 28), 32); /* Extra field length */
+ assertEqualInt(i2(q + 28), 28); /* Extra field length */
assertEqualMem(q + 30, file_name, strlen(file_name)); /* Pathname */
q = q + 30 + strlen(file_name);
assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */
- assertEqualInt(i2(q + 2), 13); /* 'UT' size */
- assertEqualInt(q[4], 7); /* 'UT' flags */
+ assertEqualInt(i2(q + 2), 9); /* 'UT' size */
+ assertEqualInt(q[4], 3); /* 'UT' flags */
assertEqualInt(i4(q + 5), t); /* 'UT' mtime */
- assertEqualInt(i4(q + 9), t); /* 'UT' atime */
- assertEqualInt(i4(q + 13), t); /* 'UT' ctime */
- q = q + 17;
+ assertEqualInt(i4(q + 9), t + 3); /* 'UT' atime */
+ q = q + 4 + i2(q + 2);
assertEqualInt(i2(q), 0x7875); /* 'ux' extension header */
assertEqualInt(i2(q + 2), 11); /* 'ux' size */
assertEqualInt(q[4], 1); /* 'ux' version */
assertEqualInt(i4(q + 6), file_uid); /* 'Ux' UID */
assertEqualInt(q[10], 4); /* 'ux' gid size */
assertEqualInt(i4(q + 11), file_gid); /* 'Ux' GID */
- q = q + 15;
+ q = q + 4 + i2(q + 2);
/* Verify data of file entry. */
assertEqualMem(q, file_data1, sizeof(file_data1));
assertEqualMem(p, "PK\001\002", 4); /* Signature */
assertEqualInt(i2(p + 4), 3 * 256 + 20); /* Version made by */
assertEqualInt(i2(p + 6), 20); /* Version needed to extract */
- assertEqualInt(i2(p + 8), 8); /* Flags */
+ assertEqualInt(i2(p + 8), 0); /* Flags */
assertEqualInt(i2(p + 10), 0); /* Compression method */
assertEqualInt(i2(p + 12), (tm->tm_hour * 2048) + (tm->tm_min * 32) + (tm->tm_sec / 2)); /* File time */
assertEqualInt(i2(p + 14), ((tm->tm_year - 80) * 512) + ((tm->tm_mon + 1) * 32) + tm->tm_mday); /* File date */
assertEqualInt(i4(p + 20), 0); /* Compressed size */
assertEqualInt(i4(p + 24), 0); /* Uncompressed size */
assertEqualInt(i2(p + 28), strlen(folder_name)); /* Pathname length */
- assertEqualInt(i2(p + 30), 13); /* Extra field length */
+ assertEqualInt(i2(p + 30), 28); /* Extra field length */
assertEqualInt(i2(p + 32), 0); /* File comment length */
assertEqualInt(i2(p + 34), 0); /* Disk number start */
assertEqualInt(i2(p + 36), 0); /* Internal file attrs */
assertEqualMem(p + 46, folder_name, strlen(folder_name)); /* Pathname */
p = p + 46 + strlen(folder_name);
assertEqualInt(i2(p), 0x5455); /* 'UT' extension header */
- assertEqualInt(i2(p + 2), 5); /* 'UT' size */
- assertEqualInt(p[4], 7); /* 'UT' flags */
+ assertEqualInt(i2(p + 2), 9); /* 'UT' size */
+ assertEqualInt(p[4], 5); /* 'UT' flags */
assertEqualInt(i4(p + 5), t); /* 'UT' mtime */
- p = p + 9;
+ assertEqualInt(i4(p + 9), t + 5); /* 'UT' atime */
+ p = p + 4 + i2(p + 2);
assertEqualInt(i2(p), 0x7875); /* 'ux' extension header */
- assertEqualInt(i2(p + 2), 0); /* 'ux' size */
- /*p = p + 4;*/
+ assertEqualInt(i2(p + 2), 11); /* 'ux' size */
+ assertEqualInt(p[4], 1); /* 'ux' version */
+ assertEqualInt(p[5], 4); /* 'ux' uid size */
+ assertEqualInt(i4(p + 6), folder_uid); /* 'ux' UID */
+ assertEqualInt(p[10], 4); /* 'ux' gid size */
+ assertEqualInt(i4(p + 11), folder_gid); /* 'ux' GID */
+ /*p = p + 4 + i2(p + 2);*/
/* Verify local header of folder entry. */
assertEqualMem(q, "PK\003\004", 4); /* Signature */
assertEqualInt(i2(q + 4), 20); /* Version needed to extract */
- assertEqualInt(i2(q + 6), 8); /* Flags */
+ assertEqualInt(i2(q + 6), 0); /* Flags */
assertEqualInt(i2(q + 8), 0); /* Compression method */
assertEqualInt(i2(q + 10), (tm->tm_hour * 2048) + (tm->tm_min * 32) + (tm->tm_sec / 2)); /* File time */
assertEqualInt(i2(q + 12), ((tm->tm_year - 80) * 512) + ((tm->tm_mon + 1) * 32) + tm->tm_mday); /* File date */
assertEqualInt(i4(q + 18), 0); /* Compressed size */
assertEqualInt(i4(q + 22), 0); /* Uncompressed size */
assertEqualInt(i2(q + 26), strlen(folder_name)); /* Pathname length */
- assertEqualInt(i2(q + 28), 32); /* Extra field length */
+ assertEqualInt(i2(q + 28), 28); /* Extra field length */
assertEqualMem(q + 30, folder_name, strlen(folder_name)); /* Pathname */
q = q + 30 + strlen(folder_name);
assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */
- assertEqualInt(i2(q + 2), 13); /* 'UT' size */
- assertEqualInt(q[4], 7); /* 'UT' flags */
+ assertEqualInt(i2(q + 2), 9); /* 'UT' size */
+ assertEqualInt(q[4], 5); /* 'UT' flags */
assertEqualInt(i4(q + 5), t); /* 'UT' mtime */
- assertEqualInt(i4(q + 9), t); /* 'UT' atime */
- assertEqualInt(i4(q + 13), t); /* 'UT' ctime */
- q = q + 17;
+ assertEqualInt(i4(q + 9), t + 5); /* 'UT' atime */
+ q = q + 4 + i2(q + 2);
assertEqualInt(i2(q), 0x7875); /* 'ux' extension header */
assertEqualInt(i2(q + 2), 11); /* 'ux' size */
assertEqualInt(q[4], 1); /* 'ux' version */
assertEqualInt(i4(q + 6), folder_uid); /* 'ux' UID */
assertEqualInt(q[10], 4); /* 'ux' gid size */
assertEqualInt(i4(q + 11), folder_gid); /* 'ux' GID */
- q = q + 15;
+ q = q + 4 + i2(q + 2);
/* There should not be any data in the folder entry,
- * meaning next is the data descriptor header. */
-
- /* Verify data descriptor of folder entry. */
- assertEqualMem(q, "PK\007\010", 4); /* Signature */
- assertEqualInt(i4(q + 4), crc); /* CRC-32 */
- assertEqualInt(i4(q + 8), 0); /* Compressed size */
- assertEqualInt(i4(q + 12), 0); /* Uncompressed size */
- /*q = q + 16;*/
+ * so the first central directory entry should be next: */
+ assertEqualMem(q, "PK\001\002", 4); /* Signature */
}