int verify;
};
-static FILE* pakfire_archive_clone_file(struct pakfire_archive* archive) {
- int fd = fileno(archive->f);
- if (fd < 0) {
- CTX_ERROR(archive->ctx, "Could not fetch the archive's file descriptor: %m\n");
- return NULL;
+struct pakfire_archive_file {
+ FILE* f;
+
+ // Buffer to store a block of data
+ char buffer[128 * 1024];
+
+ enum {
+ PAKFIRE_ARCHIVE_FILE_CANT_SEEK = (1 << 0),
+ } flags;
+};
+
+static ssize_t archive_file_read(struct archive* a, void* data, const void** buffer) {
+ struct pakfire_archive_file* file = data;
+
+ // Read a block of data into the buffer
+ size_t bytes_read = fread(file->buffer, 1, sizeof(file->buffer), file->f);
+
+ if (bytes_read < sizeof(file->buffer) && ferror(file->f)) {
+ archive_set_error(a, errno, "Error reading file");
+ }
+
+ // Return the buffer
+ *buffer = file->buffer;
+
+ return bytes_read;
+}
+
+static int64_t archive_file_skip(struct archive* a, void* data, off_t skip) {
+ struct pakfire_archive_file* file = data;
+ int r;
+
+ // Skip if we don't support seek
+ if (file->flags & PAKFIRE_ARCHIVE_FILE_CANT_SEEK)
+ return 0;
+
+ // Skip if we have been asked to do nothing
+ if (skip == 0)
+ return 0;
+
+ // Perform seek()
+ r = fseeko(file->f, skip, SEEK_CUR);
+ if (r < 0) {
+ file->flags |= PAKFIRE_ARCHIVE_FILE_CANT_SEEK;
+ return 0;
}
+ return skip;
+}
+
+static int archive_file_close(struct archive* a, void* data) {
+ struct pakfire_archive_file* file = data;
+
+ // Close the file
+ if (file->f)
+ fclose(file->f);
+
+ free(file);
+
+ return ARCHIVE_OK;
+}
+
+/*
+ This is a custom open function to an archive.
+
+ I clones the file descriptor so that we can have an independent
+ file descriptor for multiple operations.
+*/
+static int archive_read_file_open(struct archive* a, FILE* f) {
+ struct pakfire_archive_file* file = NULL;
+ int fd = -EBADF;
+
+ // Fetch the underlying file descriptor
+ fd = fileno(f);
+ if (fd < 0)
+ goto ERROR;
+
// Duplicate the file descriptor
fd = dup(fd);
- if (fd < 0) {
- CTX_ERROR(archive->ctx, "Could not duplicate the file descriptor: %m\n");
- return NULL;
- }
+ if (fd < 0)
+ goto ERROR;
+
+ // Re-open the file handle
+ f = fdopen(fd, "r");
+ if (!f)
+ goto ERROR;
+
+ // Start reading at the beginning
+ rewind(f);
+
+ // Allocate an object
+ file = calloc(1, sizeof(*file));
+ if (!file)
+ goto ERROR;
+
+ // Store the file handle
+ file->f = f;
+
+ // Let the kernel know, that we will read the file sequentially
+ posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+
+ // Open the archive
+ return archive_read_open2(a,
+ file, NULL, archive_file_read, archive_file_skip, archive_file_close);
+
+ERROR:
+ // Store an error message
+ archive_set_error(a, errno, "%m");
+
+ if (fd >= 0)
+ close(fd);
- // Re-open a file handle
- return fdopen(fd, "r");
+ return ARCHIVE_FATAL;
}
static int pakfire_archive_compute_digests(struct pakfire_archive* archive) {
/*
A helper function that opens the archive for reading
*/
-static struct archive* open_archive(struct pakfire_archive* archive, FILE* f) {
- // If no special file descriptor has been given we use the open one
- if (!f)
- f = archive->f;
-
+static struct archive* open_archive(struct pakfire_archive* archive) {
// Create a new archive object
struct archive* a = archive_read_new();
if (!a)
// Archives are compressed using Zstandard
archive_read_support_filter_zstd(a);
- // Start reading from the beginning
- rewind(f);
-
// Try opening the archive file
- int r = archive_read_open_FILE(a, f);
+ int r = archive_read_file_open(a, archive->f);
if (r)
goto ERROR;
return a;
ERROR:
+ CTX_ERROR(archive->ctx, "Could not open archive %s: %s\n",
+ archive->path, archive_error_string(a));
+
if (a)
archive_read_free(a);
int r;
// Open the archive
- a = open_archive(archive, NULL);
+ a = open_archive(archive);
if (!a)
return -errno;
CTX_DEBUG(archive->ctx, "Reading archive metadata...\n");
// Open the archive
- a = open_archive(archive, NULL);
+ a = open_archive(archive);
if (!a) {
r = -errno;
goto ERROR;
// The path we are reading
char path[PATH_MAX];
- // A copy of the underlying file descriptor
- FILE* f;
-
// The opened archive
struct archive* a;
pakfire_archive_unref(cookie->archive);
if (cookie->a)
archive_read_free(cookie->a);
- if (cookie->f)
- fclose(cookie->f);
// Free the cookie
free(cookie);
goto ERROR;
}
- // Clone the archive file descriptor to read the file independently
- cookie->f = pakfire_archive_clone_file(archive);
- if (!cookie->f) {
- CTX_ERROR(archive->ctx, "Could not duplicate file descriptor for %s: %m\n",
- archive->path);
- goto ERROR;
- }
-
// Open the archive
AGAIN:
- cookie->a = open_archive(archive, cookie->f);
+ cookie->a = open_archive(archive);
if (!cookie->a)
goto ERROR;
case EAGAIN:
if (cookie->a)
archive_read_free(cookie->a);
- if (cookie->f)
- rewind(cookie->f);
goto AGAIN;
default:
}
// Open the archive
- a = open_archive(archive, NULL);
+ a = open_archive(archive);
if (!a) {
r = -errno;
goto ERROR;
struct archive* a = NULL;
// Open the archive
- a = open_archive(archive, NULL);
+ a = open_archive(archive);
if (!a)
return -errno;