tar2qfile: terminate parsing when all requested files/dirs found
Assume that all the files of directory are in continuous block (which is true in case of qvm-backup stream). This will allow to terminate before getting to the file end - especially useful when only qubes.xml requested.
This commit is contained in:
parent
42c40d399b
commit
3c43f20d9e
@ -168,6 +168,13 @@ char *gnu_hack_string; /* GNU ././@LongLink hackery */
|
||||
char untrusted_namebuf[MAX_PATH_LENGTH];
|
||||
extern int ignore_quota_error;
|
||||
|
||||
struct filters {
|
||||
int filters_count;
|
||||
char **filters;
|
||||
int *filters_matches;
|
||||
int matched_filters;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* asc_ul()
|
||||
@ -386,6 +393,7 @@ enum {
|
||||
enum {
|
||||
NEED_NOTHING,
|
||||
NEED_SKIP,
|
||||
NEED_SKIP_FILE, // distinguish between skipped file and unwanted blocks (extended headers etc)
|
||||
NEED_READ,
|
||||
NEED_SYNC_TRAIL,
|
||||
INVALID_HEADER,
|
||||
@ -405,7 +413,7 @@ int n_dirs = 0;
|
||||
char ** dirs_headers_sent = NULL;
|
||||
|
||||
int
|
||||
ustar_rd (int fd, struct file_header * untrusted_hdr, char *buf, struct stat * sb, int filter_count, char **filter)
|
||||
ustar_rd (int fd, struct file_header * untrusted_hdr, char *buf, struct stat * sb, struct filters *filters)
|
||||
{
|
||||
|
||||
register HD_USTAR *hd;
|
||||
@ -626,18 +634,23 @@ ustar_rd (int fd, struct file_header * untrusted_hdr, char *buf, struct stat * s
|
||||
|
||||
// Check if user want to extract this file
|
||||
should_extract = 1;
|
||||
for (i=1; i < filter_count; i++) {
|
||||
for (i=0; i < filters->filters_count; i++) {
|
||||
should_extract = 0;
|
||||
fprintf(stderr, "Comparing with filter %s\n", filter[i]);
|
||||
if (strstr(untrusted_namebuf, filter[i]) == untrusted_namebuf) {
|
||||
fprintf(stderr, "Match\n");
|
||||
fprintf(stderr, "Comparing with filter %s\n", filters->filters[i]);
|
||||
if (strncmp(untrusted_namebuf, filters->filters[i], strlen(filters->filters[i])) == 0) {
|
||||
fprintf(stderr, "Match (%d)\n", filters->filters_matches[i]);
|
||||
should_extract = 1;
|
||||
filters->filters_matches[i]++;
|
||||
if (filters->filters_matches[i] == 1) {
|
||||
// first match
|
||||
filters->matched_filters++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (should_extract != 1) {
|
||||
fprintf(stderr, "File should be filtered.. Skipping\n");
|
||||
return NEED_SKIP;
|
||||
return NEED_SKIP_FILE;
|
||||
}
|
||||
|
||||
// Create a copy of untrusted_namebuf to be used for strtok
|
||||
@ -775,7 +788,7 @@ ustar_rd (int fd, struct file_header * untrusted_hdr, char *buf, struct stat * s
|
||||
|
||||
|
||||
|
||||
int tar_file_processor(int fd, int filter_count, char **filter)
|
||||
void tar_file_processor(int fd, struct filters *filters)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
@ -803,11 +816,28 @@ int tar_file_processor(int fd, int filter_count, char **filter)
|
||||
}
|
||||
}
|
||||
if (current==NEED_READ) {
|
||||
current = ustar_rd(fd, &hdr, buf, &sb, filter_count, filter);
|
||||
current = ustar_rd(fd, &hdr, buf, &sb, filters);
|
||||
fprintf(stderr,"Return %d\n",ret);
|
||||
}
|
||||
if (current==NEED_SKIP) {
|
||||
fprintf(stderr,"Need to skip %ld bytes\n",hdr.filelen);
|
||||
if (current==NEED_SKIP || current==NEED_SKIP_FILE) {
|
||||
if (current==NEED_SKIP_FILE &&
|
||||
filters->filters_count > 0 &&
|
||||
filters->filters_count == filters->matched_filters) {
|
||||
// This assume that either:
|
||||
// a) files are sorted (using full path as sort key)
|
||||
// b) all the directory content is in
|
||||
// consecutive block and only directories
|
||||
// are given as filters
|
||||
// This is true for backups prepared by qvm-backup
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "All filters matched at least once - assuming end of requested data\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"Need to skip %lld bytes (matched filters %d < %d)\n",
|
||||
hdr.filelen, filters->matched_filters, filters->filters_count);
|
||||
#endif
|
||||
to_skip = hdr.filelen;
|
||||
while (to_skip > 0) {
|
||||
to_skip -= read(fd, &buf, MIN(to_skip,BLKMULT));
|
||||
@ -836,8 +866,8 @@ int main(int argc, char **argv)
|
||||
char *cwd;
|
||||
char *sep;
|
||||
int fd;
|
||||
int use_stdin = 0;
|
||||
|
||||
int use_stdin = 1;
|
||||
struct filters filters;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
// this will allow checking for possible feedback packet in the middle of transfer
|
||||
@ -856,9 +886,11 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
} else if (strcmp(argv[i], "-")==0) {
|
||||
use_stdin = 1;
|
||||
i++;
|
||||
break;
|
||||
} else {
|
||||
// Parse tar file
|
||||
use_stdin = 0;
|
||||
entry = argv[i];
|
||||
fprintf(stderr,"Parsing file %s\n",entry);
|
||||
|
||||
@ -867,24 +899,26 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr,"Error opening file %s\n",entry);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// At least two arguments can be found in the command line
|
||||
// (process name and the file to extract)
|
||||
tar_file_processor(fd, argc, argv);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
filters.filters_count = argc-i;
|
||||
filters.filters = argv+i;
|
||||
filters.filters_matches = calloc(filters.filters_count, sizeof(int));
|
||||
if (filters.filters_matches == NULL) {
|
||||
perror("calloc");
|
||||
exit(1);
|
||||
}
|
||||
filters.matched_filters = 0;
|
||||
|
||||
if (use_stdin == 1) {
|
||||
// No argument specified. Use STDIN
|
||||
fprintf(stderr,"Using STDIN\n");
|
||||
set_block(0);
|
||||
// If at least one argument has been found ( process name and - )
|
||||
if (use_stdin)
|
||||
tar_file_processor(fileno(stdin), argc, argv);
|
||||
else
|
||||
tar_file_processor(fileno(stdin), argc, argv);
|
||||
fd = 0;
|
||||
}
|
||||
tar_file_processor(fd, &filters);
|
||||
|
||||
|
||||
//notify_end_and_wait_for_result();
|
||||
|
Loading…
Reference in New Issue
Block a user