#include "archive_private.h"
#include "archive_read_disk_private.h"
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
/*-
* This is a new directory-walking system that addresses a number
* of problems I've had with fts(3). In particular, it has no
a->archive.vtable = archive_read_disk_vtable();
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
+ a->entry_fd = -1;
return (&a->archive);
}
_archive_read_free(struct archive *_a)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ int r;
if (_a == NULL)
return (ARCHIVE_OK);
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");
+
+ if (a->archive.state != ARCHIVE_STATE_CLOSED)
+ r = _archive_read_close(&a->archive);
+ else
+ r = ARCHIVE_OK;
+
if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
(a->cleanup_gname)(a->lookup_gname_data);
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
(a->cleanup_uname)(a->lookup_uname_data);
archive_string_free(&a->archive.error_string);
- if (a->tree != NULL)
- tree_close(a->tree);
+ free(a->entry_buff);
a->archive.magic = 0;
free(a);
- return (ARCHIVE_OK);
+ return (r);
}
static int
_archive_read_close(struct archive *_a)
{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");
- (void)_a; /* UNUSED */
+
+ if (a->archive.state != ARCHIVE_STATE_FATAL)
+ a->archive.state = ARCHIVE_STATE_CLOSED;
+
+ if (a->tree != NULL) {
+ tree_close(a->tree);
+ a->tree = NULL;
+ }
+ if (a->entry_fd >= 0) {
+ close(a->entry_fd);
+ a->entry_fd = -1;
+ }
+
return (ARCHIVE_OK);
}
_archive_read_data_block(struct archive *_a, const void **buff,
size_t *size, int64_t *offset)
{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ int r;
+ ssize_t bytes;
+ size_t buffbytes;
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
"archive_read_data_block");
- (void)buff; /* UNUSED */
- (void)size; /* UNUSED */
- (void)offset; /* UNUSED */
- /* Not implemented yet. */
- return (ARCHIVE_FAILED);
+ if (a->entry_eof || a->entry_remaining_bytes <= 0) {
+ r = ARCHIVE_EOF;
+ goto abort_read_data;
+ }
+
+ if (a->entry_fd < 0) {
+ a->entry_fd = open(tree_current_access_path(a->tree),
+ O_RDONLY | O_BINARY);
+ if (a->entry_fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't open %s", tree_current_path(a->tree));
+ r = ARCHIVE_FAILED;
+ goto abort_read_data;
+ }
+ }
+ if (a->entry_buff == NULL) {
+ a->entry_buff = malloc(1024 * 64);
+ if (a->entry_buff == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Couldn't allocate memory");
+ r = ARCHIVE_FATAL;
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ goto abort_read_data;
+ }
+ a->entry_buff_size = 1024 * 64;
+ }
+
+ buffbytes = a->entry_buff_size;
+ if ((int64_t)buffbytes > a->entry_remaining_bytes)
+ buffbytes = (size_t)a->entry_remaining_bytes;
+ bytes = read(a->entry_fd, a->entry_buff, buffbytes);
+ if (bytes < 0) {
+ archive_set_error(&a->archive, errno,
+ "Read error");
+ r = ARCHIVE_FATAL;
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ goto abort_read_data;
+ }
+ if (bytes == 0) {
+ /* Get EOF */
+ a->entry_eof = 1;
+ r = ARCHIVE_EOF;
+ goto abort_read_data;
+ }
+ *buff = a->entry_buff;
+ *size = bytes;
+ *offset = a->entry_total;
+ a->entry_total += bytes;
+ a->entry_remaining_bytes -= bytes;
+ if (a->entry_remaining_bytes == 0) {
+ /* Close the current file descriptor */
+ close(a->entry_fd);
+ a->entry_fd = -1;
+ a->entry_eof = 1;
+ }
+ return (ARCHIVE_OK);
+
+abort_read_data:
+ *buff = NULL;
+ *size = 0;
+ *offset = a->entry_total;
+ if (a->entry_fd >= 0) {
+ /* Close the current file descriptor */
+ close(a->entry_fd);
+ a->entry_fd = -1;
+ }
+ return (r);
}
static int
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_read_next_header2");
+ if (a->entry_fd >= 0) {
+ close(a->entry_fd);
+ a->entry_fd = -1;
+ }
t = a->tree;
st = NULL;
lst = NULL;
a->archive.state = ARCHIVE_STATE_EOF;
break;
case ARCHIVE_OK:
- a->archive.state = ARCHIVE_STATE_DATA;
- break;
case ARCHIVE_WARN:
+ a->entry_fd = -1;
+ a->entry_total = 0;
+ if (archive_entry_filetype(entry) == AE_IFREG) {
+ a->entry_remaining_bytes = archive_entry_size(entry);
+ a->entry_eof = (a->entry_remaining_bytes == 0)? 1: 0;
+ } else {
+ a->entry_remaining_bytes = 0;
+ a->entry_eof = 1;
+ }
a->archive.state = ARCHIVE_STATE_DATA;
break;
case ARCHIVE_RETRY:
tree->dev_recorded = 0;
a->tree = tree;
a->archive.state = ARCHIVE_STATE_HEADER;
+ a->entry_eof = 0;
+ a->entry_fd = -1;
return (ARCHIVE_OK);
}
{
struct archive *a;
struct archive_entry *ae;
- //const void *p;
- //size_t size;
- //int64_t offset;
+ const void *p;
+ size_t size;
+ int64_t offset;
assertMakeDir("dir1", 0755);
assertMakeFile("dir1/file1", 0644, "0123456789");
- assertMakeFile("dir1/file2", 0644, "0123456789");
+ assertMakeFile("dir1/file2", 0644, "hello world");
assertMakeDir("dir1/sub1", 0755);
assertMakeFile("dir1/sub1/file1", 0644, "0123456789");
assertMakeDir("dir1/sub2", 0755);
assertMakeDir("dir1/sub2/sub1", 0755);
assertMakeDir("dir1/sub2/sub2", 0755);
assertMakeDir("dir1/sub2/sub3", 0755);
- assertMakeFile("dir1/sub2/sub3/file", 0644, "0123456789");
+ assertMakeFile("dir1/sub2/sub3/file", 0644, "xyz");
assert((ae = archive_entry_new()) != NULL);
assert((a = archive_read_disk_new()) != NULL);
assertEqualString(archive_entry_pathname(ae), "dir1/file1");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 10);
/* dir1/file2 */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
assertEqualString(archive_entry_pathname(ae), "dir1/file2");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
- assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualInt(archive_entry_size(ae), 11);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 11);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "hello world", 11), 0);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 11);
/* dir1/sub1 */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
assertEqualString(archive_entry_pathname(ae), "dir1/sub2/file1");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 10);
/* dir1/sub2/file2 */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
assertEqualString(archive_entry_pathname(ae), "dir1/sub2/file2");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 10);
/* dir1/sub2/sub1 */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
assertEqualString(archive_entry_pathname(ae), "dir1/sub2/sub3/file");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
- assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualInt(archive_entry_size(ae), 3);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 3);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "xyz", 3), 0);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 3);
/* dir1/sub1/file1 */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
assertEqualString(archive_entry_pathname(ae), "dir1/sub1/file1");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 10);
/* There is no entry. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
assertEqualString(archive_entry_pathname(ae), "dir1/file1");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "0123456789", 10), 0);
/* There is no entry. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
assertEqualString(archive_entry_pathname(ae), "dir1/file1");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "0123456789", 10), 0);
/* dir1/sub1 */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
assertEqualString(archive_entry_pathname(ae), "dir1/sub1/file1");
assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
assertEqualInt(archive_entry_size(ae), 10);
- //assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
- //assertEqualInt((int)size, 10);
- //assertEqualInt((int)offset, 0);
- //assertEqualInt(memcmp(p, "0123456789", 10), 0);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualInt(memcmp(p, "0123456789", 10), 0);
/* There is no entry. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));