return (ARCHIVE_FATAL);
}
+int
+__archive_read_header(struct archive_read *a, struct archive_entry *entry)
+{
+ if (a->filter->read_header)
+ return a->filter->read_header(a->filter, entry);
+ else
+ return (ARCHIVE_OK);
+}
+
/*
* Read header of next entry.
*/
int (*close)(struct archive_read_filter *self);
/* Function that handles switching from reading one block to the next/prev */
int (*sswitch)(struct archive_read_filter *self, unsigned int iindex);
+ /* Read any header metadata if available. */
+ int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry);
/* My private data. */
void *data;
int64_t __archive_read_filter_seek(struct archive_read_filter *, int64_t, int);
int64_t __archive_read_consume(struct archive_read *, int64_t);
int64_t __archive_read_filter_consume(struct archive_read_filter *, int64_t);
+int __archive_read_header(struct archive_read *, struct archive_entry *);
int __archive_read_program(struct archive_read_filter *, const char *);
void __archive_read_free_filters(struct archive_read *);
struct archive_read_extract *__archive_read_get_extract(struct archive_read *);
#endif
#include "archive.h"
+#include "archive_entry.h"
+#include "archive_endian.h"
#include "archive_private.h"
#include "archive_read_private.h"
size_t out_block_size;
int64_t total_out;
unsigned long crc;
+ uint32_t mtime;
+ char *name;
char eof; /* True = found end of compressed data. */
};
* count of bits verified, suitable for use by bidder.
*/
static ssize_t
-peek_at_header(struct archive_read_filter *filter, int *pbits)
+peek_at_header(struct archive_read_filter *filter, int *pbits,
+ struct private_data *state)
{
const unsigned char *p;
ssize_t avail, len;
return (0);
bits += 3;
header_flags = p[3];
- /* Bytes 4-7 are mod time. */
+ /* Bytes 4-7 are mod time in little endian. */
+ if (state)
+ state->mtime = archive_le32dec(p + 4);
/* Byte 8 is deflate flags. */
/* XXXX TODO: return deflate flags back to consume_header for use
in initializing the decompressor. */
/* Null-terminated optional filename. */
if (header_flags & 8) {
+ ssize_t file_start = len;
do {
++len;
if (avail < len)
if (p == NULL)
return (0);
} while (p[len - 1] != 0);
+
+ if (state)
+ state->name = strdup((const char *)&p[file_start]);
}
/* Null-terminated optional comment. */
(void)self; /* UNUSED */
- if (peek_at_header(filter, &bits_checked))
+ if (peek_at_header(filter, &bits_checked, NULL))
return (bits_checked);
return (0);
}
+static int
+gzip_read_header(struct archive_read_filter *self, struct archive_entry *entry)
+{
+ struct private_data *state;
+
+ state = (struct private_data *)self->data;
+
+ /* A mtime of 0 is considered invalid/missing. */
+ if (state->mtime != 0)
+ archive_entry_set_mtime(entry, state->mtime, 0);
+
+ /* If the name is available, extract it. */
+ if (state->name)
+ archive_entry_set_pathname(entry, state->name);
+
+ return (ARCHIVE_OK);
+}
#ifndef HAVE_ZLIB_H
self->read = gzip_filter_read;
self->skip = NULL; /* not supported */
self->close = gzip_filter_close;
+ self->read_header = gzip_read_header;
state->in_stream = 0; /* We're not actually within a stream yet. */
state = (struct private_data *)self->data;
/* If this is a real header, consume it. */
- len = peek_at_header(self->upstream, NULL);
+ len = peek_at_header(self->upstream, NULL, state);
if (len == 0)
return (ARCHIVE_EOF);
__archive_read_filter_consume(self->upstream, len);
}
}
+ free(state->name);
free(state->out_block);
free(state);
return (ret);
archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_set_perm(entry, 0644);
/* I'm deliberately leaving most fields unset here. */
- return (ARCHIVE_OK);
+
+ /* Let the filter fill out any fields it might have. */
+ return __archive_read_header(a, entry);
}
static int
const char *reffile1 = "test_read_format_raw.data";
const char *reffile2 = "test_read_format_raw.data.Z";
const char *reffile3 = "test_read_format_raw.bufr";
+ const char *reffile4 = "test_read_format_raw.data.gz";
/* First, try pulling data out of an uninterpretable file. */
extract_reference_file(reffile1);
assert(!archive_entry_ctime_is_set(ae));
assert(!archive_entry_mtime_is_set(ae));
+ /* Fourth, try with gzip which has metadata. */
+ extract_reference_file(reffile4);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_raw(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, reffile4, 1));
+
+ /* First (and only!) Entry */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("test-file-name.data", archive_entry_pathname(ae));
+ assertEqualInt(archive_entry_is_encrypted(ae), 0);
+ assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
+ assert(archive_entry_mtime_is_set(ae));
+ assertEqualIntA(a, archive_entry_mtime(ae), 0x5cbafd25);
+ /* Most fields should be unset (unknown) */
+ assert(!archive_entry_size_is_set(ae));
+ assert(!archive_entry_atime_is_set(ae));
+ assert(!archive_entry_ctime_is_set(ae));
+
/* Test EOF */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
--- /dev/null
+begin 644 test_read_format_raw.data.gz
+L'XL(""7]NEP``W1E<W0M9FEL92UN86UE+F1A=&$`2\O/YP(`J&4R?@0`````
+`
+end