bin/xbps-create: better error handling for writing archives

This fixes issues where if xbps-create creates a new archive on a full
disk, it will write an incomplete archive and then later fails to be
read by xbps-rindex.
This commit is contained in:
Duncan Overbruck 2019-10-25 22:46:14 +02:00 committed by Juan RP
parent 7b66a2885b
commit 04d5554ed2

View File

@ -51,11 +51,6 @@
#define _PROGNAME "xbps-create" #define _PROGNAME "xbps-create"
/* libarchive 2.x compat */
#if ARCHIVE_VERSION_NUMBER >= 3000000
# define archive_write_finish(x) archive_write_free(x)
#endif
struct xentry { struct xentry {
TAILQ_ENTRY(xentry) entries; TAILQ_ENTRY(xentry) entries;
uint64_t mtime; uint64_t mtime;
@ -136,6 +131,19 @@ die(const char *fmt, ...)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
static void __attribute__((noreturn))
die_archive(struct archive *ar, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s: ERROR: ", _PROGNAME);
vfprintf(stderr, fmt, ap);
fprintf(stderr, " %s\n", archive_error_string(ar));
va_end(ap);
exit(EXIT_FAILURE);
}
static void static void
process_array(const char *key, const char *val) process_array(const char *key, const char *val)
{ {
@ -627,19 +635,16 @@ process_destdir(const char *mutable_files)
static void static void
write_entry(struct archive *ar, struct archive_entry *entry) write_entry(struct archive *ar, struct archive_entry *entry)
{ {
const char *name; const char *name, *target;
int fd; int fd;
char buf[65536]; char buf[65536];
ssize_t len; ssize_t len;
if (archive_entry_pathname(entry) == NULL) if ((target = archive_entry_pathname(entry)) == NULL)
return; return;
if (archive_write_header(ar, entry)) { if (archive_write_header(ar, entry))
die("cannot write %s to archive: %s", die_archive(ar, "cannot write %s to archive:", target);
archive_entry_pathname(entry),
archive_error_string(ar));
}
/* Only regular files can have data. */ /* Only regular files can have data. */
if (archive_entry_filetype(entry) != AE_IFREG || if (archive_entry_filetype(entry) != AE_IFREG ||
@ -653,7 +658,8 @@ write_entry(struct archive *ar, struct archive_entry *entry)
if ((fd = open(name, O_RDONLY)) < 0) if ((fd = open(name, O_RDONLY)) < 0)
die("cannot open %s file", name); die("cannot open %s file", name);
while ((len = read(fd, buf, sizeof(buf))) > 0) while ((len = read(fd, buf, sizeof(buf))) > 0)
archive_write_data(ar, buf, len); if (archive_write_data(ar, buf, len) != len)
die_archive(ar, "cannot write %s to archive:", target);
(void)close(fd); (void)close(fd);
if(len < 0) if(len < 0)
@ -684,7 +690,9 @@ process_entry_file(struct archive *ar,
die("failed to add entry (fstat) %s to archive:", xe->file); die("failed to add entry (fstat) %s to archive:", xe->file);
entry = archive_entry_new(); entry = archive_entry_new();
assert(entry); if (entry == NULL)
die("failed to add entry %s to archive:", xe->file);
archive_entry_set_pathname(entry, xe->file); archive_entry_set_pathname(entry, xe->file);
if (st.st_uid == geteuid()) if (st.st_uid == geteuid())
st.st_uid = 0; st.st_uid = 0;
@ -700,7 +708,8 @@ process_entry_file(struct archive *ar,
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
buf = malloc(st.st_size+1); buf = malloc(st.st_size+1);
assert(buf); if (buf == NULL)
die("failed to allocate readlink buffer", xe->file);
len = readlink(p, buf, st.st_size+1); len = readlink(p, buf, st.st_size+1);
if (len < 0 || len > st.st_size) if (len < 0 || len > st.st_size)
die("failed to add entry %s (readlink) to archive:", die("failed to add entry %s (readlink) to archive:",
@ -1030,7 +1039,8 @@ main(int argc, char **argv)
* Process the binary package's archive (ustar compressed with xz). * Process the binary package's archive (ustar compressed with xz).
*/ */
ar = archive_write_new(); ar = archive_write_new();
assert(ar); if (ar == NULL)
die("cannot create new archive");
/* /*
* Set compression format, xz if unset. * Set compression format, xz if unset.
*/ */
@ -1060,7 +1070,7 @@ main(int argc, char **argv)
archive_entry_linkresolver_set_strategy(resolver, archive_entry_linkresolver_set_strategy(resolver,
archive_format(ar)); archive_format(ar));
if (archive_write_open_fd(ar, pkg_fd) != 0) if (archive_write_open_fd(ar, pkg_fd) != ARCHIVE_OK)
die("Failed to open %s fd for writing:", tname); die("Failed to open %s fd for writing:", tname);
process_archive(ar, resolver, pkgver, quiet); process_archive(ar, resolver, pkgver, quiet);
@ -1073,8 +1083,11 @@ main(int argc, char **argv)
archive_entry_linkify(resolver, &entry, &sparse_entry); archive_entry_linkify(resolver, &entry, &sparse_entry);
} }
archive_entry_linkresolver_free(resolver); archive_entry_linkresolver_free(resolver);
/* close and free archive */
archive_write_finish(ar); if (archive_write_close(ar) != ARCHIVE_OK)
die_archive(ar, "Failed to write archive %s:", tname);
if (archive_write_free(ar) != ARCHIVE_OK)
die_archive(ar, "Failed to close archive");
/* /*
* Archive was created successfully; flush data to storage, * Archive was created successfully; flush data to storage,