archive: Use libarchive to check for tar contents

Stop using binary tar to check for tar contents. Use libarchive instead

Signed-off-by: Otavio Pontes <otavio.pontes@intel.com>
This commit is contained in:
Otavio Pontes
2019-04-10 16:52:19 -07:00
parent a688c1e77d
commit d4f34bc1a9
4 changed files with 83 additions and 67 deletions
+6 -50
View File
@@ -906,58 +906,14 @@ int link_or_rename(const char *orig, const char *dest)
return 0;
}
/* list the tarfile content, and verify it contains only one line equal to the expected hash.
* loop through all the content to detect the case where archive contains more than one file.
*/
static int check_tarfile_content(struct file *file, const char *tarfilename)
static int check_single_file_tarball(const char *tarfilename, struct file *file)
{
int err;
char *tarcommand;
FILE *tar;
int count = 0;
char *filename;
string_or_die(&tarcommand, TAR_COMMAND " -tf %s/download/%s.tar 2> /dev/null", state_dir, file->hash);
err = access(tarfilename, R_OK);
if (err) {
goto free_tarcommand;
}
tar = popen(tarcommand, "r");
if (tar == NULL) {
err = -1;
goto free_tarcommand;
}
while (!feof(tar)) {
char *c;
char buffer[PATH_MAXLEN];
if (fgets(buffer, PATH_MAXLEN, tar) == NULL) {
if (count != 1) {
err = -1;
}
break;
}
c = strchr(buffer, '\n');
if (c) {
*c = 0;
}
if (c && (c != buffer) && (*(c - 1) == '/')) {
/* strip trailing '/' from directory tar */
*(c - 1) = 0;
}
if (strcmp(buffer, file->hash) != 0) {
err = -1;
break;
}
count++;
}
pclose(tar);
free_tarcommand:
free_string(&tarcommand);
string_or_die(&filename, "%s%s", file->hash, file->is_dir ? "/" : "");
err = archives_check_single_file_tarball(tarfilename, filename);
free(filename);
return err;
}
@@ -1004,7 +960,7 @@ int untar_full_download(void *data)
}
free_string(&tar_dotfile);
err = check_tarfile_content(file, tarfile);
err = check_single_file_tarball(tarfile, file);
if (err) {
goto exit;
}
+70 -16
View File
@@ -86,6 +86,43 @@ static int copy_data(struct archive *ar, struct archive *aw)
return 0;
}
static int archive_from_filename(struct archive **a, const char *tarfile)
{
int r = 0;
if (!a) {
return -EINVAL;
}
*a = archive_read_new();
if (!*a) {
return -ENOMEM;
}
r = archive_read_support_format_tar(*a);
if (_archive_check_err(*a, r)) {
goto error;
}
r = archive_read_support_filter_all(*a);
if (_archive_check_err(*a, r)) {
goto error;
}
r = archive_read_open_filename(*a, tarfile, 10240);
if (_archive_check_err(*a, r)) {
/* could not open archive for read */
goto error;
}
return 0;
error:
archive_read_close(*a);
archive_read_free(*a);
return r;
}
int archives_extract_to(const char *tarfile, const char *outputdir)
{
struct archive *a, *ext;
@@ -104,15 +141,9 @@ int archives_extract_to(const char *tarfile, const char *outputdir)
flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT;
/* set up read */
a = archive_read_new();
r = archive_read_support_format_tar(a);
if (_archive_check_err(a, r)) {
goto out_read;
}
r = archive_read_support_filter_all(a);
if (_archive_check_err(a, r)) {
goto out_read;
r = archive_from_filename(&a, tarfile);
if (r < 0) {
return r;
}
/* set up write */
@@ -127,12 +158,6 @@ int archives_extract_to(const char *tarfile, const char *outputdir)
goto out;
}
r = archive_read_open_filename(a, tarfile, 10240);
if (_archive_check_err(a, r)) {
/* could not open archive for read */
goto out;
}
/* read and write loop */
for (;;) {
r = archive_read_next_header(a, &entry);
@@ -191,8 +216,37 @@ out:
* error. If 'goto out' is called, we already have an error we are handling
* so don't overwrite that returncode. */
archive_write_free(ext);
out_read:
archive_read_close(a);
archive_read_free(a);
return r;
}
int archives_check_single_file_tarball(const char *tarfilename, const char *file)
{
struct archive *a;
struct archive_entry *entry;
int r;
bool found = false;
/* set up read */
r = archive_from_filename(&a, tarfilename);
if (r < 0) {
return r;
}
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
if (!found && strcmp(archive_entry_pathname(entry), file) == 0) {
found = true;
} else {
found = false;
goto end;
}
archive_read_data_skip(a);
}
end:
archive_read_close(a);
archive_read_free(a);
return found ? 0 : -ENOENT;
}
+6
View File
@@ -11,6 +11,12 @@ extern "C" {
*/
int archives_extract_to(const char *tarfile, const char *outputdir);
/*
* Check if this tarball is valid and if it contains only one file with the
* specified name.
*/
int archives_check_single_file_tarball(const char *tarfilename, const char *file);
#ifdef __cplusplus
}
#endif
+1 -1
View File
@@ -11,6 +11,7 @@
#include <stdio.h>
#include <string.h>
#include "lib/archives.h"
#include "lib/formatter_json.h"
#include "lib/list.h"
#include "lib/log.h"
@@ -18,7 +19,6 @@
#include "lib/progress.h"
#include "lib/strings.h"
#include "lib/sys.h"
#include "lib/archives.h"
#include "manifest.h"
#include "scripts.h"
#include "swupd_curl.h"