diff --git a/lib/libarchive/archive.h b/lib/libarchive/archive.h index f0489eb01c72..b8f03a373b7b 100644 --- a/lib/libarchive/archive.h +++ b/lib/libarchive/archive.h @@ -200,6 +200,8 @@ ssize_t archive_read_data_into_fd(struct archive *, int fd); int archive_read_extract(struct archive *, struct archive_entry *, int flags); +void archive_read_extract_set_progress_callback(struct archive *, + void (*_progress_func)(void *), void *_user_data); /* Close the file, release any resources, and destroy the object. */ void archive_read_finish(struct archive *); diff --git a/lib/libarchive/archive.h.in b/lib/libarchive/archive.h.in index f0489eb01c72..b8f03a373b7b 100644 --- a/lib/libarchive/archive.h.in +++ b/lib/libarchive/archive.h.in @@ -200,6 +200,8 @@ ssize_t archive_read_data_into_fd(struct archive *, int fd); int archive_read_extract(struct archive *, struct archive_entry *, int flags); +void archive_read_extract_set_progress_callback(struct archive *, + void (*_progress_func)(void *), void *_user_data); /* Close the file, release any resources, and destroy the object. */ void archive_read_finish(struct archive *); diff --git a/lib/libarchive/archive_private.h b/lib/libarchive/archive_private.h index f7f4158df7f2..f3d3b870c25f 100644 --- a/lib/libarchive/archive_private.h +++ b/lib/libarchive/archive_private.h @@ -192,6 +192,8 @@ struct archive { */ struct archive_string extract_mkdirpath; struct archive_extract_dir_entry *archive_extract_dir_list; + void (*extract_progress)(void *); + void *extract_progress_user_data; void (*cleanup_archive_extract)(struct archive *); int archive_error_number; diff --git a/lib/libarchive/archive_read.3 b/lib/libarchive/archive_read.3 index 28131cd4cb07..421b3f671673 100644 --- a/lib/libarchive/archive_read.3 +++ b/lib/libarchive/archive_read.3 @@ -47,6 +47,7 @@ .Nm archive_read_data_into_buffer , .Nm archive_read_data_into_file , .Nm archive_read_extract , +.Nm archive_read_extract_set_progress_callback , .Nm archive_read_finish .Nd functions for reading tar archives .Sh SYNOPSIS @@ -90,6 +91,8 @@ .Ft int .Fn archive_read_extract "struct archive *" "int flags" .Ft void +.Fn archive_read_extract_set_progress_callback "struct archive *" "void (*func)(void *)" "void *user_data" +.Ft void .Fn archive_read_finish "struct archive *" .Sh DESCRIPTION These functions provide a complete API for reading streaming archives. @@ -202,6 +205,15 @@ By default, existing files are truncated and rewritten, but the file is not recreated. In particular, the default behavior does not break existing hard links. .El +.It Fn archive_read_extract_set_progress_callback +Sets a pointer to a user-defined callback that can be used +for updating progress displays during extraction. +The progress function will be invoked during the extraction of large +regular files. +The progress function will be invoked with the pointer provided to this call. +Generally, the data pointed to should include a reference to the archive +object and the archive_entry object so that various statistics +can be retrieved for the progress display. .It Fn archive_read_finish Complete the archive, invoke the close callback, and release all resources. diff --git a/lib/libarchive/archive_read_data_into_fd.c b/lib/libarchive/archive_read_data_into_fd.c index 71fdedc07b37..9bdad4d2a7e3 100644 --- a/lib/libarchive/archive_read_data_into_fd.c +++ b/lib/libarchive/archive_read_data_into_fd.c @@ -44,12 +44,16 @@ archive_read_data_into_fd(struct archive *a, int fd) total_written = 0; while (a->entry_bytes_remaining > 0) { - bytes_read = (a->compression_read_ahead)(a, &buff, - a->entry_bytes_remaining); + /* Remember: '1' here is minimum, not maximum. */ + /* Read-ahead function will return as much as is convenient. */ + bytes_read = (a->compression_read_ahead)(a, &buff, 1); if (bytes_read < 0) return (-1); if (bytes_read > a->entry_bytes_remaining) bytes_read = (ssize_t)a->entry_bytes_remaining; + /* Don't copy more than 1 megabyte at a time. */ + if (bytes_read > (1024*1024)) + bytes_read = 1024*1024; bytes_written = write(fd, buff, bytes_read); if (bytes_written < 0) @@ -57,6 +61,8 @@ archive_read_data_into_fd(struct archive *a, int fd) (a->compression_read_consume)(a, bytes_written); total_written += bytes_written; a->entry_bytes_remaining -= bytes_written; + if (a->extract_progress != NULL) + (*a->extract_progress)(a->extract_progress_user_data); } return (total_written); } diff --git a/lib/libarchive/archive_read_extract.c b/lib/libarchive/archive_read_extract.c index fa3974ffbdfa..0d49f6f56b84 100644 --- a/lib/libarchive/archive_read_extract.c +++ b/lib/libarchive/archive_read_extract.c @@ -1078,3 +1078,11 @@ lookup_uid(struct archive *a, const char *uname, uid_t uid) } return (uid); } + +void +archive_read_extract_set_progress_callback(struct archive *a, + void (*progress_func)(void *), void *user_data) +{ + a->extract_progress = progress_func; + a->extract_progress_user_data = user_data; +}