Basic capability to list contents of an archive without extracting to disk.

This commit is contained in:
Moinak Ghosh 2014-01-12 20:38:20 +05:30
parent 3ddaf6d45f
commit 62568e9066
4 changed files with 90 additions and 38 deletions

View file

@ -147,13 +147,13 @@ Standard Usage
Decompression and Archive extraction Decompression and Archive extraction
------------------------------------ ------------------------------------
pcompress -d <compressed file or '-'> [-m] [-K] [<target file or directory>] pcompress -d <compressed file or '-'> [-m] [-K] [-i] [<target file or directory>]
-m Enable restoring *all* permissions, ACLs, Extended Attributes etc. -m Enable restoring *all* permissions, ACLs, Extended Attributes etc.
Equivalent to the '-p' option in tar. Ownership is only extracted if run as Equivalent to the '-p' option in tar. Ownership is only extracted if run as
root user. root user.
-K Do not overwrite newer files. -K Do not overwrite newer files.
-i Only list contents of the archive, do not extract.
-m and -K are only meaningful if the compressed file is an archive. For single file -m and -K are only meaningful if the compressed file is an archive. For single file
compressed mode these options are ignored. compressed mode these options are ignored.

View file

@ -1205,6 +1205,7 @@ copy_data_out(struct archive *ar, struct archive *aw, struct archive_entry *entr
return (r); return (r);
} }
} }
return (ARCHIVE_OK);
} }
static int static int
@ -1235,6 +1236,34 @@ archive_extract_entry(struct archive *a, struct archive_entry *entry,
return (r); return (r);
} }
static int
copy_data_skip(struct archive *ar, struct archive_entry *entry, int typ)
{
int64_t offset;
const void *buff;
size_t size;
int r;
for (;;) {
r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF)
return (ARCHIVE_OK);
if (r != ARCHIVE_OK)
return (r);
}
return (ARCHIVE_OK);
}
static int
archive_list_entry(struct archive *a, struct archive_entry *entry, int typ)
{
printf("%s\n", archive_entry_pathname(entry));
if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) {
return (copy_data_skip(a, entry, typ));
}
return (ARCHIVE_OK);
}
/* /*
* Extract Thread function. Read an uncompressed archive from the decompressor stage * Extract Thread function. Read an uncompressed archive from the decompressor stage
* and extract members to disk. * and extract members to disk.
@ -1248,37 +1277,43 @@ extractor_thread_func(void *dat) {
struct archive_entry *entry; struct archive_entry *entry;
struct archive *awd, *arc; struct archive *awd, *arc;
flags = ARCHIVE_EXTRACT_TIME; /* Silence compiler. */
flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS; awd = NULL;
flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT; got_cwd = 0;
flags |= ARCHIVE_EXTRACT_SPARSE;
/* if (!pctx->list_mode) {
* Extract all security attributes if we are root. flags = ARCHIVE_EXTRACT_TIME;
*/ flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS;
if (pctx->force_archive_perms || geteuid() == 0) { flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT;
if (geteuid() == 0) flags |= ARCHIVE_EXTRACT_SPARSE;
flags |= ARCHIVE_EXTRACT_OWNER;
flags |= ARCHIVE_EXTRACT_PERM; /*
flags |= ARCHIVE_EXTRACT_ACL; * Extract all security attributes if we are root.
flags |= ARCHIVE_EXTRACT_XATTR; */
flags |= ARCHIVE_EXTRACT_FFLAGS; if (pctx->force_archive_perms || geteuid() == 0) {
flags |= ARCHIVE_EXTRACT_MAC_METADATA; if (geteuid() == 0)
flags |= ARCHIVE_EXTRACT_OWNER;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_XATTR;
flags |= ARCHIVE_EXTRACT_FFLAGS;
flags |= ARCHIVE_EXTRACT_MAC_METADATA;
}
if (pctx->no_overwrite_newer)
flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
got_cwd = 1;
if (getcwd(cwd, PATH_MAX) == NULL) {
log_msg(LOG_WARN, 1, "Cannot get current directory.");
got_cwd = 0;
}
awd = archive_write_disk_new();
archive_write_disk_set_options(awd, flags);
archive_write_disk_set_standard_lookup(awd);
} }
if (pctx->no_overwrite_newer)
flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
got_cwd = 1;
if (getcwd(cwd, PATH_MAX) == NULL) {
log_msg(LOG_WARN, 1, "Cannot get current directory.");
got_cwd = 0;
}
ctr = 1; ctr = 1;
awd = archive_write_disk_new();
archive_write_disk_set_options(awd, flags);
archive_write_disk_set_standard_lookup(awd);
arc = (struct archive *)(pctx->archive_ctx); arc = (struct archive *)(pctx->archive_ctx);
archive_read_open(arc, pctx, arc_open_callback, extract_read_callback, extract_close_callback); archive_read_open(arc, pctx, arc_open_callback, extract_read_callback, extract_close_callback);
@ -1286,9 +1321,11 @@ extractor_thread_func(void *dat) {
* Change directory after opening the archive, otherwise archive_read_open() can fail * Change directory after opening the archive, otherwise archive_read_open() can fail
* for relative paths. * for relative paths.
*/ */
if (chdir(pctx->to_filename) == -1) { if (!pctx->list_mode) {
log_msg(LOG_ERR, 1, "Cannot change to dir: %s", pctx->to_filename); if (chdir(pctx->to_filename) == -1) {
goto done; log_msg(LOG_ERR, 1, "Cannot change to dir: %s", pctx->to_filename);
goto done;
}
} }
/* /*
@ -1342,7 +1379,11 @@ extractor_thread_func(void *dat) {
} }
#endif #endif
rv = archive_extract_entry(arc, entry, awd, typ); if (!pctx->list_mode) {
rv = archive_extract_entry(arc, entry, awd, typ);
} else {
rv = archive_list_entry(arc, entry, typ);
}
if (rv != ARCHIVE_OK) { if (rv != ARCHIVE_OK) {
log_msg(LOG_WARN, 0, "%s: %s", archive_entry_pathname(entry), log_msg(LOG_WARN, 0, "%s: %s", archive_entry_pathname(entry),
archive_error_string(arc)); archive_error_string(arc));
@ -1359,8 +1400,10 @@ extractor_thread_func(void *dat) {
ctr++; ctr++;
} }
if (got_cwd) { if (!pctx->list_mode) {
rv = chdir(cwd); if (got_cwd) {
rv = chdir(cwd);
}
} }
archive_read_free(arc); archive_read_free(arc);
archive_write_free(awd); archive_write_free(awd);

View file

@ -137,7 +137,8 @@ usage(pc_ctx_t *pctx)
" %s -d <compressed file or '-'> [-m] [-K] [<target file or directory>]\n\n" " %s -d <compressed file or '-'> [-m] [-K] [<target file or directory>]\n\n"
" -m Enable restoring *all* permissions, ACLs, Extended Attributes etc.\n" " -m Enable restoring *all* permissions, ACLs, Extended Attributes etc.\n"
" Equivalent to the '-p' option in tar.\n" " Equivalent to the '-p' option in tar.\n"
" -K Do not overwrite newer files.\n\n" " -K Do not overwrite newer files.\n"
" -i Only list contents of the archive, do not extract.\n\n"
" -m and -K are only meaningful if the compressed file is an archive. For single file\n" " -m and -K are only meaningful if the compressed file is an archive. For single file\n"
" compressed mode these options are ignored.\n\n" " compressed mode these options are ignored.\n\n"
" <compressed file>\n" " <compressed file>\n"
@ -848,6 +849,11 @@ start_decompress(pc_ctx_t *pctx, const char *filename, char *to_filename)
} else { } else {
const char *origf; const char *origf;
if (pctx->list_mode) {
log_msg(LOG_ERR, 0, "Nothing to list. The compressed file is not an archive.");
err = 1;
goto uncomp_done;
}
if (to_filename == NULL) { if (to_filename == NULL) {
char *pos; char *pos;
@ -2827,11 +2833,13 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
ff.enable_packjpg = 0; ff.enable_packjpg = 0;
pthread_mutex_lock(&opt_parse); pthread_mutex_lock(&opt_parse);
while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDGEe:w:LPS:B:Fk:avmKjx")) != -1) { while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDGEe:w:LPS:B:Fk:avmKjxi")) != -1) {
int ovr; int ovr;
int64_t chunksize; int64_t chunksize;
switch (opt) { switch (opt) {
case 'i':
pctx->list_mode = 1; // List mode also sets decompress flag
case 'd': case 'd':
pctx->do_uncompress = 1; pctx->do_uncompress = 1;
break; break;

View file

@ -239,6 +239,7 @@ typedef struct pc_ctx {
int btype, ctype; int btype, ctype;
int min_chunk; int min_chunk;
int enable_packjpg; int enable_packjpg;
int list_mode;
unsigned int chunk_num; unsigned int chunk_num;
uint64_t largest_chunk, smallest_chunk, avg_chunk; uint64_t largest_chunk, smallest_chunk, avg_chunk;