Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fetch_uri: Use memfd for writing #139

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ifneq ($(DEVEL), 1)
CFLAGS += -O2
endif

CFLAGS += -Wall -Werror -std=c99 $(shell pkg-config --cflags $(PACKAGES))
CFLAGS += -D_GNU_SOURCE -Wall -std=c99 $(shell pkg-config --cflags $(PACKAGES))

ifeq ($(STATIC), 1)
# The right thing to do here is `pkg-config --libs --static`, which would
Expand Down
67 changes: 23 additions & 44 deletions src/fetch_uri.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
#include <glib.h>
#include <glib/gprintf.h>
#include <gio/gio.h>
#include <gio/gunixoutputstream.h>
#include <fcntl.h>
#include <archive.h>
#include <archive_entry.h>
#include <unistd.h>
#include <curl/curl.h>
#include <sys/mman.h>

#include "fetch.h"
#include "fetch_uri.h"
Expand All @@ -45,37 +47,16 @@ struct socket_data {
static size_t cwrite_callback(char *ptr, size_t size, size_t nmemb,
void *userdata)
{
GMemoryInputStream *stream = (GMemoryInputStream *)userdata;

g_memory_input_stream_add_data(stream, g_memdup(ptr, size * nmemb),
size * nmemb, g_free);
g_output_stream_write_all(userdata, ptr, size * nmemb, NULL, NULL, NULL);

return size * nmemb;
}

static ssize_t
myread(struct archive *a, void *client_data, const void **abuf)
{
FetchData *fetch_data = client_data;
gsize len = 0;
*abuf = fetch_data->buf;

GError *error = NULL;

len = g_input_stream_read (fetch_data->istream, fetch_data->buf, sizeof (fetch_data->buf),
NULL, &error);

if (error) {
archive_set_error(fetch_data->a, error->code, "%s", error->message);
return -1;
}

return len;
}

static gboolean
myopen(FetchData *fetch_data, GError **error)
{
int fd;

g_return_val_if_fail(fetch_data != NULL, FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
CURLMcode res;
Expand All @@ -84,10 +65,12 @@ myopen(FetchData *fetch_data, GError **error)
CURL *curl = curl_easy_init();
gchar *uri = soup_uri_to_string(fetch_data->url, FALSE);

fetch_data->istream = g_memory_input_stream_new();
fd = memfd_create("restraint_fetch_uri", MFD_CLOEXEC);

fetch_data->ostream = G_OUTPUT_STREAM(g_unix_output_stream_new(fd, TRUE));
curl_easy_setopt(curl, CURLOPT_URL, uri);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cwrite_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fetch_data->istream);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fetch_data->ostream);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, fetch_data->curl_error_buf);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);

Expand All @@ -108,23 +91,6 @@ myopen(FetchData *fetch_data, GError **error)
return TRUE;
}

static int
myclose(struct archive *a, void *client_data)
{
FetchData *fetch_data = client_data;
GError * error = NULL;

g_input_stream_close(fetch_data->istream,
NULL,
&error);
g_object_unref(fetch_data->istream);
if (error != NULL) {
archive_set_error(fetch_data->a, error->code, "%s", error->message);
return ARCHIVE_FATAL;
}
return ARCHIVE_OK;
}

static gboolean
archive_finish_callback (gpointer user_data)
{
Expand All @@ -144,10 +110,20 @@ archive_finish_callback (gpointer user_data)
g_warning("Failed to free archive_write_disk");
}
if (fetch_data->a != NULL) {
free_result = archive_read_close(fetch_data->a);
if (free_result != ARCHIVE_OK)
g_warning("Failed to close archive");
free_result = archive_read_free(fetch_data->a);
if (free_result != ARCHIVE_OK)
g_warning("Failed to free archive_read");
}
if (fetch_data->ostream != NULL) {
GError *error = NULL;
if (!g_output_stream_close(fetch_data->ostream, NULL, &error))
g_warning("Failed to close stream");
g_clear_error(&error);
g_clear_object(&fetch_data->ostream);
}

if (fetch_data->finish_callback) {
fetch_data->finish_callback (fetch_data->error,
Expand Down Expand Up @@ -372,14 +348,17 @@ static int update_timeout_cb(CURLM *multi, /* multi handle */
static gboolean start_unpack(gpointer data)
{
FetchData *fetch_data = data;
int fd;
struct curl_data *cd = fetch_data->private_data;

if (cd->running > 0) {
return TRUE;
}

gint r;
r = archive_read_open(fetch_data->a, fetch_data, NULL, myread, myclose);
fd = g_unix_output_stream_get_fd(G_UNIX_OUTPUT_STREAM(fetch_data->ostream));
lseek(fd, 0, SEEK_SET);
r = archive_read_open_fd(fetch_data->a, fd, 16384);
if (r != ARCHIVE_OK) {
g_set_error(&fetch_data->error, RESTRAINT_FETCH_LIBARCHIVE_ERROR, r,
"archive_read_open failed: %s", archive_error_string(fetch_data->a));
Expand Down