Replace slow pipe with direct memory copy for archive extraction.
Miscellaneous corrections and tweaks.
This commit is contained in:
parent
7ed532133e
commit
448890a014
4 changed files with 177 additions and 24 deletions
|
@ -95,7 +95,7 @@ pthread_mutex_t nftw_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
* Archive writer callback routines for archive creation operation.
|
* Archive writer callback routines for archive creation operation.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
creat_open_callback(struct archive *arc, void *ctx)
|
arc_open_callback(struct archive *arc, void *ctx)
|
||||||
{
|
{
|
||||||
pc_ctx_t *pctx = (pc_ctx_t *)ctx;
|
pc_ctx_t *pctx = (pc_ctx_t *)ctx;
|
||||||
|
|
||||||
|
@ -201,13 +201,79 @@ archiver_close(void *ctx)
|
||||||
pc_ctx_t *pctx = (pc_ctx_t *)ctx;
|
pc_ctx_t *pctx = (pc_ctx_t *)ctx;
|
||||||
|
|
||||||
pctx->arc_closed = 1;
|
pctx->arc_closed = 1;
|
||||||
|
pctx->arc_buf = NULL;
|
||||||
|
pctx->arc_buf_size = 0;
|
||||||
sem_post(&(pctx->write_sem));
|
sem_post(&(pctx->write_sem));
|
||||||
sem_post(&(pctx->read_sem));
|
sem_post(&(pctx->read_sem));
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
extract_close_callback(struct archive *arc, void *ctx)
|
||||||
|
{
|
||||||
|
pc_ctx_t *pctx = (pc_ctx_t *)ctx;
|
||||||
|
|
||||||
|
pctx->arc_closed = 1;
|
||||||
|
if (pctx->arc_buf) {
|
||||||
|
sem_post(&(pctx->write_sem));
|
||||||
|
} else {
|
||||||
|
pctx->arc_buf_size = 0;
|
||||||
|
}
|
||||||
|
return (ARCHIVE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
extract_read_callback(struct archive *arc, void *ctx, const void **buf)
|
||||||
|
{
|
||||||
|
pc_ctx_t *pctx = (pc_ctx_t *)ctx;
|
||||||
|
|
||||||
|
if (pctx->arc_closed) {
|
||||||
|
pctx->arc_buf_size = 0;
|
||||||
|
archive_set_error(arc, ARCHIVE_EOF, "End of file.");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pctx->arc_writing) {
|
||||||
|
sem_wait(&(pctx->read_sem));
|
||||||
|
} else {
|
||||||
|
sem_post(&(pctx->write_sem));
|
||||||
|
sem_wait(&(pctx->read_sem));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pctx->arc_buf == NULL || pctx->arc_buf_size == 0) {
|
||||||
|
pctx->arc_buf_size = 0;
|
||||||
|
archive_set_error(arc, ARCHIVE_EOF, "End of file when extracting archive.");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
pctx->arc_writing = 1;
|
||||||
|
*buf = pctx->arc_buf;
|
||||||
|
|
||||||
|
return (pctx->arc_buf_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
archiver_write(void *ctx, void *buf, uint64_t count)
|
||||||
|
{
|
||||||
|
pc_ctx_t *pctx = (pc_ctx_t *)ctx;
|
||||||
|
|
||||||
|
if (pctx->arc_closed)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
if (pctx->arc_buf != NULL) {
|
||||||
|
log_msg(LOG_ERR, 0, "Incorrect sequencing of archiver_read() call.");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pctx->arc_buf = buf;
|
||||||
|
pctx->arc_buf_size = count;
|
||||||
|
sem_post(&(pctx->read_sem));
|
||||||
|
sem_wait(&(pctx->write_sem));
|
||||||
|
pctx->arc_buf = NULL;
|
||||||
|
return (pctx->arc_buf_size);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Comparison function for sorting pathname mambers. Sort by name/extension and then
|
* Comparison function for sorting pathname members. Sort by name/extension and then
|
||||||
* by size.
|
* by size.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
@ -255,7 +321,7 @@ compare_members_lt(member_entry_t *mem1, member_entry_t *mem2) {
|
||||||
* fetches the next entry in ascending order of the predetermined sort keys.
|
* fetches the next entry in ascending order of the predetermined sort keys.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
read_next_path(pc_ctx_t *pctx, char *fpath)
|
read_next_path(pc_ctx_t *pctx, char *fpath, char **namechars)
|
||||||
{
|
{
|
||||||
short namelen;
|
short namelen;
|
||||||
ssize_t rbytes;
|
ssize_t rbytes;
|
||||||
|
@ -300,6 +366,10 @@ read_next_path(pc_ctx_t *pctx, char *fpath)
|
||||||
pctx->temp_file_pos = mem1->file_pos;
|
pctx->temp_file_pos = mem1->file_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment popped position of the current buffer and check if it is empty.
|
||||||
|
* The empty buffer is freed and is taken out of the linked list of buffers.
|
||||||
|
*/
|
||||||
srt1->pos++;
|
srt1->pos++;
|
||||||
if (srt1->pos > srt1->max) {
|
if (srt1->pos > srt1->max) {
|
||||||
if (srt1 == pctx->archive_sort_buf) {
|
if (srt1 == pctx->archive_sort_buf) {
|
||||||
|
@ -317,7 +387,7 @@ read_next_path(pc_ctx_t *pctx, char *fpath)
|
||||||
* new mmap.
|
* new mmap.
|
||||||
*/
|
*/
|
||||||
if (pctx->temp_mmap_len > 0) {
|
if (pctx->temp_mmap_len > 0) {
|
||||||
int retried;
|
int retried, n;
|
||||||
|
|
||||||
if (pctx->temp_file_pos < pctx->temp_mmap_pos ||
|
if (pctx->temp_file_pos < pctx->temp_mmap_pos ||
|
||||||
pctx->temp_file_pos - pctx->temp_mmap_pos > pctx->temp_mmap_len ||
|
pctx->temp_file_pos - pctx->temp_mmap_pos > pctx->temp_mmap_len ||
|
||||||
|
@ -364,6 +434,12 @@ do_mmap:
|
||||||
buf = pctx->temp_mmap_buf + (pctx->temp_file_pos - pctx->temp_mmap_pos);
|
buf = pctx->temp_mmap_buf + (pctx->temp_file_pos - pctx->temp_mmap_pos);
|
||||||
memcpy(fpath, buf, namelen);
|
memcpy(fpath, buf, namelen);
|
||||||
fpath[namelen] = '\0';
|
fpath[namelen] = '\0';
|
||||||
|
|
||||||
|
n = namelen-1;
|
||||||
|
while (fpath[n] == '/' && n > 0) n--;
|
||||||
|
while (fpath[n] != '/' && fpath[n] != '\\' && n > 0) n--;
|
||||||
|
*namechars = &fpath[n+1];
|
||||||
|
|
||||||
pctx->temp_file_pos += namelen;
|
pctx->temp_file_pos += namelen;
|
||||||
return (namelen);
|
return (namelen);
|
||||||
}
|
}
|
||||||
|
@ -646,7 +722,7 @@ setup_archiver(pc_ctx_t *pctx, struct stat *sbuf)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
archive_write_set_format_pax_restricted(arc);
|
archive_write_set_format_pax_restricted(arc);
|
||||||
archive_write_open(arc, pctx, creat_open_callback,
|
archive_write_open(arc, pctx, arc_open_callback,
|
||||||
creat_write_callback, creat_close_callback);
|
creat_write_callback, creat_close_callback);
|
||||||
pctx->archive_ctx = arc;
|
pctx->archive_ctx = arc;
|
||||||
pctx->archive_members_fd = fd;
|
pctx->archive_members_fd = fd;
|
||||||
|
@ -677,9 +753,6 @@ setup_extractor(pc_ctx_t *pctx)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pctx->uncompfd = pipefd[1]; // Write side
|
|
||||||
pctx->archive_data_fd = pipefd[0]; // Read side
|
|
||||||
|
|
||||||
arc = archive_read_new();
|
arc = archive_read_new();
|
||||||
if (!arc) {
|
if (!arc) {
|
||||||
log_msg(LOG_ERR, 1, "Unable to create libarchive context.\n");
|
log_msg(LOG_ERR, 1, "Unable to create libarchive context.\n");
|
||||||
|
@ -782,12 +855,13 @@ write_entry(pc_ctx_t *pctx, struct archive *arc, struct archive *in_arc,
|
||||||
static void *
|
static void *
|
||||||
archiver_thread_func(void *dat) {
|
archiver_thread_func(void *dat) {
|
||||||
pc_ctx_t *pctx = (pc_ctx_t *)dat;
|
pc_ctx_t *pctx = (pc_ctx_t *)dat;
|
||||||
char fpath[PATH_MAX], *name;
|
char fpath[PATH_MAX], *name, *bnchars = NULL; // Silence compiler
|
||||||
int warn, rbytes;
|
int warn, rbytes;
|
||||||
uint32_t ctr;
|
uint32_t ctr;
|
||||||
struct archive_entry *entry, *spare_entry, *ent;
|
struct archive_entry *entry, *spare_entry, *ent;
|
||||||
struct archive *arc, *ard;
|
struct archive *arc, *ard;
|
||||||
struct archive_entry_linkresolver *resolver;
|
struct archive_entry_linkresolver *resolver;
|
||||||
|
int readdisk_flags;
|
||||||
|
|
||||||
warn = 1;
|
warn = 1;
|
||||||
entry = archive_entry_new();
|
entry = archive_entry_new();
|
||||||
|
@ -800,14 +874,18 @@ archiver_thread_func(void *dat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctr = 1;
|
ctr = 1;
|
||||||
|
readdisk_flags = ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS;
|
||||||
|
readdisk_flags |= ARCHIVE_READDISK_HONOR_NODUMP;
|
||||||
|
|
||||||
ard = archive_read_disk_new();
|
ard = archive_read_disk_new();
|
||||||
|
archive_read_disk_set_behavior(ard, readdisk_flags);
|
||||||
archive_read_disk_set_standard_lookup(ard);
|
archive_read_disk_set_standard_lookup(ard);
|
||||||
archive_read_disk_set_symlink_physical(ard);
|
archive_read_disk_set_symlink_physical(ard);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read next path entry from list file. read_next_path() also handles sorted reading.
|
* Read next path entry from list file. read_next_path() also handles sorted reading.
|
||||||
*/
|
*/
|
||||||
while ((rbytes = read_next_path(pctx, fpath)) != 0) {
|
while ((rbytes = read_next_path(pctx, fpath, &bnchars)) != 0) {
|
||||||
if (rbytes == -1) break;
|
if (rbytes == -1) break;
|
||||||
archive_entry_copy_sourcepath(entry, fpath);
|
archive_entry_copy_sourcepath(entry, fpath);
|
||||||
if (archive_read_disk_entry_from_file(ard, entry, -1, NULL) != ARCHIVE_OK) {
|
if (archive_read_disk_entry_from_file(ard, entry, -1, NULL) != ARCHIVE_OK) {
|
||||||
|
@ -831,6 +909,29 @@ archiver_thread_func(void *dat) {
|
||||||
name += 1;
|
name += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
|
/*
|
||||||
|
* Workaround for libarchive weirdness on Non MAC OS X platforms. The files
|
||||||
|
* with names matching pattern: ._* are MAC OS X resource forks which contain
|
||||||
|
* extended attributes, ACLs etc. They should be handled accordingly on MAC
|
||||||
|
* platforms and treated as normal files on others. For some reason beyond me
|
||||||
|
* libarchive refuses to extract these files on Linux, no matter what I try.
|
||||||
|
* Bug?
|
||||||
|
*
|
||||||
|
* In this case the file basename is changed and a custom extended attribute
|
||||||
|
* is set to indicate extraction to change it back.
|
||||||
|
*/
|
||||||
|
if (bnchars[0] == '.' && bnchars[1] == '_') {
|
||||||
|
char *pos = strstr(name, "._");
|
||||||
|
char name[] = "@.", value[] = "m";
|
||||||
|
if (pos) {
|
||||||
|
*pos = '|';
|
||||||
|
archive_entry_xattr_add_entry(entry, name, value, strlen(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (name != archive_entry_pathname(entry))
|
if (name != archive_entry_pathname(entry))
|
||||||
archive_entry_copy_pathname(entry, name);
|
archive_entry_copy_pathname(entry, name);
|
||||||
|
|
||||||
|
@ -862,7 +963,6 @@ done:
|
||||||
archive_read_free(ard);
|
archive_read_free(ard);
|
||||||
archive_write_free(arc);
|
archive_write_free(arc);
|
||||||
close(pctx->archive_members_fd);
|
close(pctx->archive_members_fd);
|
||||||
close(pctx->archive_data_fd);
|
|
||||||
unlink(pctx->archive_members_file);
|
unlink(pctx->archive_members_file);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
@ -886,9 +986,21 @@ extractor_thread_func(void *dat) {
|
||||||
struct archive *awd, *arc;
|
struct archive *awd, *arc;
|
||||||
|
|
||||||
flags = ARCHIVE_EXTRACT_TIME;
|
flags = ARCHIVE_EXTRACT_TIME;
|
||||||
|
flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS;
|
||||||
|
flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT;
|
||||||
|
flags |= ARCHIVE_EXTRACT_SPARSE;
|
||||||
|
|
||||||
|
if (pctx->force_archive_perms || geteuid() == 0) {
|
||||||
|
flags |= ARCHIVE_EXTRACT_OWNER;
|
||||||
flags |= ARCHIVE_EXTRACT_PERM;
|
flags |= ARCHIVE_EXTRACT_PERM;
|
||||||
flags |= ARCHIVE_EXTRACT_ACL;
|
flags |= ARCHIVE_EXTRACT_ACL;
|
||||||
|
flags |= ARCHIVE_EXTRACT_XATTR;
|
||||||
flags |= ARCHIVE_EXTRACT_FFLAGS;
|
flags |= ARCHIVE_EXTRACT_FFLAGS;
|
||||||
|
flags |= ARCHIVE_EXTRACT_MAC_METADATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pctx->no_overwrite_newer)
|
||||||
|
flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
|
||||||
|
|
||||||
got_cwd = 1;
|
got_cwd = 1;
|
||||||
if (getcwd(cwd, PATH_MAX) == NULL) {
|
if (getcwd(cwd, PATH_MAX) == NULL) {
|
||||||
|
@ -906,12 +1018,15 @@ extractor_thread_func(void *dat) {
|
||||||
archive_write_disk_set_options(awd, flags);
|
archive_write_disk_set_options(awd, flags);
|
||||||
archive_write_disk_set_standard_lookup(awd);
|
archive_write_disk_set_standard_lookup(awd);
|
||||||
arc = (struct archive *)(pctx->archive_ctx);
|
arc = (struct archive *)(pctx->archive_ctx);
|
||||||
archive_read_open_fd(arc, pctx->archive_data_fd, MMAP_SIZE);
|
archive_read_open(arc, pctx, arc_open_callback, extract_read_callback, extract_close_callback);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read archive entries and extract to disk.
|
* Read archive entries and extract to disk.
|
||||||
*/
|
*/
|
||||||
while ((rv = archive_read_next_header(arc, &entry)) != ARCHIVE_EOF) {
|
while ((rv = archive_read_next_header(arc, &entry)) != ARCHIVE_EOF) {
|
||||||
|
const char *xt_name, *xt_value;
|
||||||
|
size_t xt_size;
|
||||||
|
|
||||||
if (rv != ARCHIVE_OK)
|
if (rv != ARCHIVE_OK)
|
||||||
log_msg(LOG_WARN, 0, "%s", archive_error_string(arc));
|
log_msg(LOG_WARN, 0, "%s", archive_error_string(arc));
|
||||||
|
|
||||||
|
@ -925,6 +1040,29 @@ extractor_thread_func(void *dat) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Workaround for libarchive weirdness on Non MAC OS X platforms for filenames
|
||||||
|
* starting with '._'. See above ...
|
||||||
|
*/
|
||||||
|
#ifndef __APPLE__
|
||||||
|
if (archive_entry_xattr_reset(entry) > 0) {
|
||||||
|
while (archive_entry_xattr_next(entry, &xt_name, (const void **)&xt_value,
|
||||||
|
&xt_size) == ARCHIVE_OK) {
|
||||||
|
if (xt_name[0] == '@' && xt_name[1] == '.' && xt_value[0] == 'm') {
|
||||||
|
const char *name;
|
||||||
|
char *pos;
|
||||||
|
name = archive_entry_pathname(entry);
|
||||||
|
pos = strstr(name, "|_");
|
||||||
|
if (pos) {
|
||||||
|
*pos = '.';
|
||||||
|
archive_entry_set_pathname(entry, name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
rv = archive_read_extract2(arc, entry, awd);
|
rv = archive_read_extract2(arc, entry, awd);
|
||||||
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),
|
||||||
|
@ -948,7 +1086,6 @@ extractor_thread_func(void *dat) {
|
||||||
archive_read_free(arc);
|
archive_read_free(arc);
|
||||||
archive_write_free(awd);
|
archive_write_free(awd);
|
||||||
done:
|
done:
|
||||||
close(pctx->archive_data_fd);
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ int start_archiver(pc_ctx_t *pctx);
|
||||||
int setup_extractor(pc_ctx_t *pctx);
|
int setup_extractor(pc_ctx_t *pctx);
|
||||||
int start_extractor(pc_ctx_t *pctx);
|
int start_extractor(pc_ctx_t *pctx);
|
||||||
int64_t archiver_read(void *ctx, void *buf, uint64_t count);
|
int64_t archiver_read(void *ctx, void *buf, uint64_t count);
|
||||||
|
int64_t archiver_write(void *ctx, void *buf, uint64_t count);
|
||||||
int archiver_close(void *ctx);
|
int archiver_close(void *ctx);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
24
pcompress.c
24
pcompress.c
|
@ -1127,11 +1127,11 @@ start_decompress(pc_ctx_t *pctx, const char *filename, char *to_filename)
|
||||||
}
|
}
|
||||||
add_fname(pctx->archive_temp_file);
|
add_fname(pctx->archive_temp_file);
|
||||||
}
|
}
|
||||||
|
uncompfd = -1;
|
||||||
if (setup_extractor(pctx) == -1) {
|
if (setup_extractor(pctx) == -1) {
|
||||||
log_msg(LOG_ERR, 0, "Setup of extraction context failed.");
|
log_msg(LOG_ERR, 0, "Setup of extraction context failed.");
|
||||||
UNCOMP_BAIL;
|
UNCOMP_BAIL;
|
||||||
}
|
}
|
||||||
uncompfd = pctx->uncompfd;
|
|
||||||
|
|
||||||
if (start_extractor(pctx) == -1) {
|
if (start_extractor(pctx) == -1) {
|
||||||
log_msg(LOG_ERR, 0, "Unable to start extraction thread.");
|
log_msg(LOG_ERR, 0, "Unable to start extraction thread.");
|
||||||
|
@ -1402,7 +1402,7 @@ uncomp_done:
|
||||||
/*
|
/*
|
||||||
* Ownership and mode of target should be same as original.
|
* Ownership and mode of target should be same as original.
|
||||||
*/
|
*/
|
||||||
if (filename != NULL) {
|
if (filename != NULL && uncompfd != -1) {
|
||||||
fchmod(uncompfd, sbuf.st_mode);
|
fchmod(uncompfd, sbuf.st_mode);
|
||||||
if (fchown(uncompfd, sbuf.st_uid, sbuf.st_gid) == -1)
|
if (fchown(uncompfd, sbuf.st_uid, sbuf.st_gid) == -1)
|
||||||
log_msg(LOG_ERR, 1, "Chown ");
|
log_msg(LOG_ERR, 1, "Chown ");
|
||||||
|
@ -1737,12 +1737,17 @@ repeat:
|
||||||
pctx->avg_chunk += tdat->len_cmp;
|
pctx->avg_chunk += tdat->len_cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pctx->archive_mode && tdat->decompressing) {
|
||||||
|
wbytes = archiver_write(pctx, tdat->cmp_seg, tdat->len_cmp);
|
||||||
|
} else {
|
||||||
wbytes = Write(w->wfd, tdat->cmp_seg, tdat->len_cmp);
|
wbytes = Write(w->wfd, tdat->cmp_seg, tdat->len_cmp);
|
||||||
|
}
|
||||||
if (pctx->archive_temp_fd != -1 && wbytes == tdat->len_cmp) {
|
if (pctx->archive_temp_fd != -1 && wbytes == tdat->len_cmp) {
|
||||||
wbytes = Write(pctx->archive_temp_fd, tdat->cmp_seg, tdat->len_cmp);
|
wbytes = Write(pctx->archive_temp_fd, tdat->cmp_seg, tdat->len_cmp);
|
||||||
}
|
}
|
||||||
if (unlikely(wbytes != tdat->len_cmp)) {
|
if (unlikely(wbytes != tdat->len_cmp)) {
|
||||||
log_msg(LOG_ERR, 1, "Chunk Write: ");
|
log_msg(LOG_ERR, 1, "Chunk Write (expected: %" PRIu64 ", written: %" PRIu64 ") : ",
|
||||||
|
tdat->len_cmp, wbytes);
|
||||||
do_cancel:
|
do_cancel:
|
||||||
pctx->main_cancel = 1;
|
pctx->main_cancel = 1;
|
||||||
tdat->cancel = 1;
|
tdat->cancel = 1;
|
||||||
|
@ -2720,7 +2725,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
strcpy(pctx->exec_name, pos);
|
strcpy(pctx->exec_name, pos);
|
||||||
|
|
||||||
pthread_mutex_lock(&opt_parse);
|
pthread_mutex_lock(&opt_parse);
|
||||||
while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDGEe:w:rLPS:B:Fk:avn")) != -1) {
|
while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDGEe:w:LPS:B:Fk:avnmK")) != -1) {
|
||||||
int ovr;
|
int ovr;
|
||||||
int64_t chunksize;
|
int64_t chunksize;
|
||||||
|
|
||||||
|
@ -2865,6 +2870,14 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
pctx->enable_archive_sort = -1;
|
pctx->enable_archive_sort = -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
pctx->force_archive_perms = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'K':
|
||||||
|
pctx->no_overwrite_newer = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
return (2);
|
return (2);
|
||||||
|
@ -2972,8 +2985,9 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
||||||
if ((filename = realpath(argv[my_optind], NULL)) != NULL) {
|
if ((filename = realpath(argv[my_optind], NULL)) != NULL) {
|
||||||
|
free(filename);
|
||||||
*fn = slab_alloc(NULL, sizeof (struct fn_list));
|
*fn = slab_alloc(NULL, sizeof (struct fn_list));
|
||||||
(*fn)->filename = filename;
|
(*fn)->filename = strdup(argv[my_optind]);
|
||||||
(*fn)->next = NULL;
|
(*fn)->next = NULL;
|
||||||
fn = &((*fn)->next);
|
fn = &((*fn)->next);
|
||||||
valid_paths++;
|
valid_paths++;
|
||||||
|
|
|
@ -202,13 +202,14 @@ typedef struct pc_ctx {
|
||||||
int verbose;
|
int verbose;
|
||||||
int enable_archive_sort;
|
int enable_archive_sort;
|
||||||
int pagesize;
|
int pagesize;
|
||||||
int uncompfd, compfd;
|
int force_archive_perms;
|
||||||
|
int no_overwrite_newer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Archiving related context data.
|
* Archiving related context data.
|
||||||
*/
|
*/
|
||||||
char archive_members_file[MAXPATHLEN];
|
char archive_members_file[MAXPATHLEN];
|
||||||
int archive_members_fd, archive_data_fd;
|
int archive_members_fd;
|
||||||
uint32_t archive_members_count;
|
uint32_t archive_members_count;
|
||||||
void *archive_ctx, *archive_sort_buf;
|
void *archive_ctx, *archive_sort_buf;
|
||||||
pthread_t archive_thread;
|
pthread_t archive_thread;
|
||||||
|
|
Loading…
Reference in a new issue