tar2qfile: use read_all() instead of read()

read() syscall do not guarantee to read as much data as requested. This
is especially important when reading from pipe - remote end can produce
data slower than we are reading them. Use read_all() helper to always
get requested amount of data.
This commit is contained in:
Marek Marczykowski-Górecki 2013-11-25 02:24:21 +01:00
parent 9b859c9ac5
commit 3c92cdba22

View File

@ -819,11 +819,12 @@ ustar_rd (int fd, struct file_header * untrusted_hdr, char *buf, struct stat * s
#ifdef DEBUG
fprintf(stderr,"Need to remove pad:%lld %lld\n",untrusted_hdr->filelen,BLKMULT-(untrusted_hdr->filelen%BLKMULT));
#endif
if (untrusted_hdr->filelen%BLKMULT > 0)
ret = read(fd, buf, BLKMULT-(untrusted_hdr->filelen%BLKMULT));
#ifdef DEBUG
fprintf(stderr,"Removed %d bytes of padding\n",ret);
#endif
if (untrusted_hdr->filelen%BLKMULT > 0) {
if (!read_all(fd, buf, BLKMULT-(untrusted_hdr->filelen%BLKMULT))) {
wait_for_result();
exit(1);
}
}
// Resync trailing headers in order to find next file chunck in the tar file
return NEED_SYNC_TRAIL;
@ -866,71 +867,64 @@ void tar_file_processor(int fd, struct filters *filters)
struct stat sb; /* stat buffer see stat(2) */
char buf[BLKMULT+1];
size_t size;
i=0;
current = NEED_READ;
size_t to_skip = 0;
int sync_count = 0;
while ((size = read(fd, &buf, BLKMULT))) {
if (size != -1) {
while (read_all(fd, buf, BLKMULT)) {
ret = 0;
if (current==NEED_SYNC_TRAIL) {
ret = tar_trail (buf, 1, &sync_count);
#ifdef DEBUG
fprintf(stderr,"Read %ld bytes\n",size);
fprintf(stderr,"Synchronizing trail: %d %d\n", ret, sync_count);
#endif
ret = 0;
if (current==NEED_SYNC_TRAIL) {
ret = tar_trail (buf, 1, &sync_count);
#ifdef DEBUG
fprintf(stderr,"Synchronizing trail: %d %d\n",ret,sync_count);
#endif
if (ret != 1) {
current = NEED_READ;
}
if (ret != 1) {
current = NEED_READ;
sync_count = 0;
}
if (current==NEED_READ) {
current = ustar_rd(fd, &hdr, buf, &sb, filters);
#ifdef DEBUG
fprintf(stderr,"Return %d\n",ret);
#endif
}
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));
}
// Extract extra padding
#ifdef DEBUG
fprintf(stderr,"Need to remove pad:%ld %lld %lld\n",to_skip,hdr.filelen,BLKMULT-(hdr.filelen%BLKMULT));
#endif
if (hdr.filelen%BLKMULT > 0) {
ret = read(fd, &buf, BLKMULT-(hdr.filelen%BLKMULT));
#ifdef DEBUG
fprintf(stderr,"Removed %d bytes of padding\n",ret);
#endif
}
current = NEED_SYNC_TRAIL;
}
i++;
}
if (current==NEED_READ) {
current = ustar_rd(fd, &hdr, buf, &sb, filters);
#ifdef DEBUG
fprintf(stderr,"Return %d\n", current);
#endif
}
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;
}
to_skip = hdr.filelen;
#ifdef DEBUG
fprintf(stderr,"Need to skip %lld bytes (matched filters %d < %d)\n",
hdr.filelen, filters->matched_filters, filters->filters_count);
fprintf(stderr,"Need to remove pad:%ld %lld %lld\n",to_skip,hdr.filelen,BLKMULT-(hdr.filelen%BLKMULT));
#endif
if (to_skip%BLKMULT > 0) {
to_skip += BLKMULT-(to_skip%BLKMULT);
}
while (to_skip > 0) {
ret = read_all(fd, &buf, MIN(to_skip,BLKMULT));
if (ret <= 0) {
exit(1);
}
to_skip -= MIN(to_skip,BLKMULT);
}
current = NEED_SYNC_TRAIL;
}
i++;
//if (i >= 10)
// exit(0);
}