New upstream version 2017.1

This commit is contained in:
Simon McVittie committed 2017-01-27 08:58:11 +00:00
commit 6ee013cea0
90 files changed
+2259 -1414

No files matched your search

+2 -4
View File
@@ -371,12 +371,10 @@ global:
* NOTE NOTE NOTE
*/
/* Remove comment when first new symbol is added
LIBOSTREE_2016.XX {
LIBOSTREE_2017.1 {
global:
someostree_symbol_deleteme;
ostree_repo_prune_from_reachable;
} LIBOSTREE_2016.14;
*/
/* Stub section for the stable release *after* this development one; don't
* edit this other than to update the last number. This is just a copy/paste
+24
View File
@@ -57,6 +57,30 @@ _ostree_fetcher_config_flags_get_type (void)
return the_type__volatile;
}
GType
_ostree_fetcher_request_flags_get_type (void)
{
static volatile gsize the_type__volatile = 0;
if (g_once_init_enter (&the_type__volatile))
{
static const GFlagsValue values[] = {
{ OSTREE_FETCHER_REQUEST_NUL_TERMINATION,
"OSTREE_FETCHER_REQUEST_NUL_TERMINATION",
"termination" },
{ 0, NULL, NULL }
};
GType the_type = g_flags_register_static (
g_intern_static_string ("OstreeFetcherRequestFlags"),
values);
g_once_init_leave (&the_type__volatile, the_type);
}
return the_type__volatile;
}
/* Generated data ends here */
+3
View File
@@ -31,6 +31,9 @@ G_BEGIN_DECLS
#define OSTREE_TYPE_FETCHER_CONFIG_FLAGS (_ostree_fetcher_config_flags_get_type ())
GType _ostree_fetcher_config_flags_get_type (void) G_GNUC_CONST;
#define OSTREE_TYPE_FETCHER_REQUEST_FLAGS (_ostree_fetcher_request_flags_get_type ())
GType _ostree_fetcher_request_flags_get_type (void) G_GNUC_CONST;
G_END_DECLS
+124
View File
@@ -0,0 +1,124 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <gio/gfiledescriptorbased.h>
#include <gio/gunixoutputstream.h>
#include "ostree-fetcher-util.h"
#include "otutil.h"
typedef struct
{
GBytes *result_buf;
gboolean done;
GError **error;
}
FetchUriSyncData;
static void
fetch_uri_sync_on_complete (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
FetchUriSyncData *data = user_data;
(void)_ostree_fetcher_request_to_membuf_finish ((OstreeFetcher*)object,
result, &data->result_buf,
data->error);
data->done = TRUE;
}
gboolean
_ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
GPtrArray *mirrorlist,
const char *filename,
gboolean add_nul,
gboolean allow_noent,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GMainContext) mainctx = NULL;
FetchUriSyncData data;
g_assert (error != NULL);
memset (&data, 0, sizeof (data));
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
mainctx = g_main_context_new ();
g_main_context_push_thread_default (mainctx);
data.done = FALSE;
data.error = error;
_ostree_fetcher_request_to_membuf (fetcher, mirrorlist, filename,
add_nul ? OSTREE_FETCHER_REQUEST_NUL_TERMINATION : 0,
max_size, OSTREE_FETCHER_DEFAULT_PRIORITY,
cancellable, fetch_uri_sync_on_complete, &data);
while (!data.done)
g_main_context_iteration (mainctx, TRUE);
if (!data.result_buf)
{
if (allow_noent)
{
if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (error);
ret = TRUE;
*out_contents = NULL;
}
}
goto out;
}
ret = TRUE;
*out_contents = g_steal_pointer (&data.result_buf);
out:
if (mainctx)
g_main_context_pop_thread_default (mainctx);
g_clear_pointer (&data.result_buf, (GDestroyNotify)g_bytes_unref);
return ret;
}
/* Helper for callers who just want to fetch single one-off URIs */
gboolean
_ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher,
OstreeFetcherURI *uri,
gboolean add_nul,
gboolean allow_noent,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GPtrArray) mirrorlist = g_ptr_array_new ();
g_ptr_array_add (mirrorlist, uri); /* no transfer */
return _ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist, NULL,
add_nul, allow_noent,
out_contents, max_size,
cancellable, error);
}
+49
View File
@@ -0,0 +1,49 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2016 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#pragma once
#ifndef __GI_SCANNER__
#include "ostree-fetcher.h"
G_BEGIN_DECLS
gboolean _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
GPtrArray *mirrorlist,
const char *filename,
gboolean add_nul,
gboolean allow_noent,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
GError **error);
gboolean _ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher,
OstreeFetcherURI *uri,
gboolean add_nul,
gboolean allow_noent,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
GError **error);
G_END_DECLS
#endif
+191 -241
View File
@@ -22,6 +22,7 @@
#include "config.h"
#include <gio/gio.h>
#include <gio/gfiledescriptorbased.h>
#include <gio/gunixoutputstream.h>
#define LIBSOUP_USE_UNSTABLE_REQUEST_API
@@ -51,6 +52,7 @@ typedef struct {
SoupSession *session; /* not referenced */
GMainContext *main_context;
volatile gint running;
GError *initialization_error; /* Any failure to load the db */
int tmpdir_dfd;
char *tmpdir_name;
@@ -90,7 +92,8 @@ typedef struct {
SoupRequest *request;
gboolean is_stream;
gboolean is_membuf;
OstreeFetcherRequestFlags flags;
GInputStream *request_body;
char *out_tmpfile;
GOutputStream *out_stream;
@@ -355,12 +358,14 @@ static void
session_thread_set_tls_interaction_cb (ThreadClosure *thread_closure,
gpointer data)
{
GTlsCertificate *cert = data;
const char *cert_and_key_path = data; /* str\0str\0 in one malloc buf */
const char *cert_path = cert_and_key_path;
const char *key_path = cert_and_key_path + strlen (cert_and_key_path) + 1;
glnx_unref_object OstreeTlsCertInteraction *interaction = NULL;
/* The GTlsInteraction instance must be created in the
* session thread so it uses the correct GMainContext. */
interaction = _ostree_tls_cert_interaction_new (cert);
interaction = _ostree_tls_cert_interaction_new (cert_path, key_path);
g_object_set (thread_closure->session,
SOUP_SESSION_TLS_INTERACTION,
@@ -372,13 +377,19 @@ static void
session_thread_set_tls_database_cb (ThreadClosure *thread_closure,
gpointer data)
{
GTlsDatabase *database = data;
const char *db_path = data;
if (database != NULL)
if (db_path != NULL)
{
g_object_set (thread_closure->session,
SOUP_SESSION_TLS_DATABASE,
database, NULL);
glnx_unref_object GTlsDatabase *tlsdb = NULL;
g_clear_error (&thread_closure->initialization_error);
tlsdb = g_tls_file_database_new (db_path, &thread_closure->initialization_error);
if (tlsdb)
g_object_set (thread_closure->session,
SOUP_SESSION_TLS_DATABASE,
tlsdb, NULL);
}
else
{
@@ -450,6 +461,13 @@ session_thread_request_uri (ThreadClosure *thread_closure,
pending = g_task_get_task_data (task);
cancellable = g_task_get_cancellable (task);
/* If we caught an error in init, re-throw it for every request */
if (thread_closure->initialization_error)
{
g_task_return_error (task, g_error_copy (thread_closure->initialization_error));
return;
}
create_pending_soup_request (pending, &local_error);
if (local_error != NULL)
{
@@ -468,7 +486,7 @@ session_thread_request_uri (ThreadClosure *thread_closure,
soup_message_headers_append (msg->request_headers, key, value);
}
if (pending->is_stream)
if (pending->is_membuf)
{
soup_request_send_async (pending->request,
cancellable,
@@ -795,16 +813,24 @@ _ostree_fetcher_set_cookie_jar (OstreeFetcher *self,
void
_ostree_fetcher_set_client_cert (OstreeFetcher *self,
GTlsCertificate *cert)
const char *cert_path,
const char *key_path)
{
g_autoptr(GString) buf = NULL;
g_return_if_fail (OSTREE_IS_FETCHER (self));
g_return_if_fail (G_IS_TLS_CERTIFICATE (cert));
if (cert_path)
{
buf = g_string_new (cert_path);
g_string_append_c (buf, '\0');
g_string_append (buf, key_path);
}
#ifdef HAVE_LIBSOUP_CLIENT_CERTS
session_thread_idle_add (self->thread_closure,
session_thread_set_tls_interaction_cb,
g_object_ref (cert),
(GDestroyNotify) g_object_unref);
g_string_free (g_steal_pointer (&buf), FALSE),
(GDestroyNotify) g_free);
#else
g_warning ("This version of OSTree is compiled without client side certificate support");
#endif
@@ -812,24 +838,14 @@ _ostree_fetcher_set_client_cert (OstreeFetcher *self,
void
_ostree_fetcher_set_tls_database (OstreeFetcher *self,
GTlsDatabase *db)
const char *tlsdb_path)
{
g_return_if_fail (OSTREE_IS_FETCHER (self));
g_return_if_fail (db == NULL || G_IS_TLS_DATABASE (db));
if (db != NULL)
{
session_thread_idle_add (self->thread_closure,
session_thread_set_tls_database_cb,
g_object_ref (db),
(GDestroyNotify) g_object_unref);
}
else
{
session_thread_idle_add (self->thread_closure,
session_thread_set_tls_database_cb,
NULL, (GDestroyNotify) NULL);
}
session_thread_idle_add (self->thread_closure,
session_thread_set_tls_database_cb,
g_strdup (tlsdb_path),
(GDestroyNotify) g_free);
}
void
@@ -855,6 +871,16 @@ finish_stream (OstreeFetcherPendingURI *pending,
*/
if (pending->out_stream)
{
if ((pending->flags & OSTREE_FETCHER_REQUEST_NUL_TERMINATION) > 0)
{
const guint8 nulchar = 0;
gsize bytes_written;
if (!g_output_stream_write_all (pending->out_stream, &nulchar, 1, &bytes_written,
cancellable, error))
goto out;
}
if (!g_output_stream_close (pending->out_stream, cancellable, error))
goto out;
@@ -864,30 +890,37 @@ finish_stream (OstreeFetcherPendingURI *pending,
g_mutex_unlock (&pending->thread_closure->output_stream_set_lock);
}
pending->state = OSTREE_FETCHER_STATE_COMPLETE;
if (fstatat (pending->thread_closure->tmpdir_dfd,
pending->out_tmpfile,
&stbuf, AT_SYMLINK_NOFOLLOW) != 0)
if (!pending->is_membuf)
{
glnx_set_error_from_errno (error);
goto out;
if (fstatat (pending->thread_closure->tmpdir_dfd,
pending->out_tmpfile,
&stbuf, AT_SYMLINK_NOFOLLOW) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
}
pending->state = OSTREE_FETCHER_STATE_COMPLETE;
/* Now that we've finished downloading, continue with other queued
* requests.
*/
session_thread_process_pending_queue (pending->thread_closure);
if (stbuf.st_size < pending->content_length)
if (!pending->is_membuf)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Download incomplete");
goto out;
}
else
{
g_mutex_lock (&pending->thread_closure->output_stream_set_lock);
pending->thread_closure->total_downloaded += stbuf.st_size;
g_mutex_unlock (&pending->thread_closure->output_stream_set_lock);
if (stbuf.st_size < pending->content_length)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Download incomplete");
goto out;
}
else
{
g_mutex_lock (&pending->thread_closure->output_stream_set_lock);
pending->thread_closure->total_downloaded += stbuf.st_size;
g_mutex_unlock (&pending->thread_closure->output_stream_set_lock);
}
}
ret = TRUE;
@@ -973,9 +1006,18 @@ on_stream_read (GObject *object,
{
if (!finish_stream (pending, cancellable, &local_error))
goto out;
g_task_return_pointer (task,
g_strdup (pending->out_tmpfile),
(GDestroyNotify) g_free);
if (pending->is_membuf)
{
g_task_return_pointer (task,
g_memory_output_stream_steal_as_bytes ((GMemoryOutputStream*)pending->out_stream),
(GDestroyNotify) g_bytes_unref);
}
else
{
g_task_return_pointer (task,
g_strdup (pending->out_tmpfile),
(GDestroyNotify) g_free);
}
remove_pending_rerun_queue (pending);
}
else
@@ -1045,23 +1087,15 @@ on_request_sent (GObject *object,
if (SOUP_IS_REQUEST_HTTP (object))
{
msg = soup_request_http_get_message ((SoupRequestHTTP*) object);
if (msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE)
if (!pending->is_membuf &&
msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE)
{
// We already have the whole file, so just use it.
pending->state = OSTREE_FETCHER_STATE_COMPLETE;
(void) g_input_stream_close (pending->request_body, NULL, NULL);
if (pending->is_stream)
{
g_task_return_pointer (task,
g_object_ref (pending->request_body),
(GDestroyNotify) g_object_unref);
}
else
{
g_task_return_pointer (task,
g_strdup (pending->out_tmpfile),
(GDestroyNotify) g_free);
}
g_task_return_pointer (task,
g_strdup (pending->out_tmpfile),
(GDestroyNotify) g_free);
remove_pending_rerun_queue (pending);
goto out;
}
@@ -1126,7 +1160,7 @@ on_request_sent (GObject *object,
pending->content_length = soup_request_get_content_length (pending->request);
if (!pending->is_stream)
if (!pending->is_membuf)
{
int oflags = O_CREAT | O_WRONLY | O_CLOEXEC;
int fd;
@@ -1147,26 +1181,23 @@ on_request_sent (GObject *object,
goto out;
}
pending->out_stream = g_unix_output_stream_new (fd, TRUE);
g_mutex_lock (&pending->thread_closure->output_stream_set_lock);
g_hash_table_add (pending->thread_closure->output_stream_set,
g_object_ref (pending->out_stream));
g_mutex_unlock (&pending->thread_closure->output_stream_set_lock);
g_input_stream_read_bytes_async (pending->request_body,
8192, G_PRIORITY_DEFAULT,
cancellable,
on_stream_read,
g_object_ref (task));
}
else
{
g_task_return_pointer (task,
g_object_ref (pending->request_body),
(GDestroyNotify) g_object_unref);
remove_pending_rerun_queue (pending);
pending->out_stream = g_memory_output_stream_new_resizable ();
}
g_mutex_lock (&pending->thread_closure->output_stream_set_lock);
g_hash_table_add (pending->thread_closure->output_stream_set,
g_object_ref (pending->out_stream));
g_mutex_unlock (&pending->thread_closure->output_stream_set_lock);
g_input_stream_read_bytes_async (pending->request_body,
8192, G_PRIORITY_DEFAULT,
cancellable,
on_stream_read,
g_object_ref (task));
out:
if (local_error)
{
@@ -1180,16 +1211,16 @@ on_request_sent (GObject *object,
}
static void
ostree_fetcher_mirrored_request_internal (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
gboolean is_stream,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data,
gpointer source_tag)
_ostree_fetcher_request_async (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
OstreeFetcherRequestFlags flags,
gboolean is_membuf,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
OstreeFetcherPendingURI *pending;
@@ -1204,11 +1235,12 @@ ostree_fetcher_mirrored_request_internal (OstreeFetcher *self,
pending->thread_closure = thread_closure_ref (self->thread_closure);
pending->mirrorlist = g_ptr_array_ref (mirrorlist);
pending->filename = g_strdup (filename);
pending->flags = flags;
pending->max_size = max_size;
pending->is_stream = is_stream;
pending->is_membuf = is_membuf;
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, source_tag);
g_task_set_source_tag (task, _ostree_fetcher_request_async);
g_task_set_task_data (task, pending, (GDestroyNotify) pending_uri_unref);
/* We'll use the GTask priority for our own priority queue. */
@@ -1221,61 +1253,91 @@ ostree_fetcher_mirrored_request_internal (OstreeFetcher *self,
}
void
_ostree_fetcher_mirrored_request_with_partial_async (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
_ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
ostree_fetcher_mirrored_request_internal (self, mirrorlist, filename, FALSE,
max_size, priority, cancellable,
callback, user_data,
_ostree_fetcher_mirrored_request_with_partial_async);
_ostree_fetcher_request_async (self, mirrorlist, filename, 0, FALSE,
max_size, priority, cancellable,
callback, user_data);
}
char *
_ostree_fetcher_mirrored_request_with_partial_finish (OstreeFetcher *self,
GAsyncResult *result,
GError **error)
gboolean
_ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
GAsyncResult *result,
char **out_filename,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, self), NULL);
g_return_val_if_fail (g_async_result_is_tagged (result,
_ostree_fetcher_mirrored_request_with_partial_async), NULL);
GTask *task;
OstreeFetcherPendingURI *pending;
gpointer ret;
return g_task_propagate_pointer (G_TASK (result), error);
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE);
task = (GTask*)result;
pending = g_task_get_task_data (task);
ret = g_task_propagate_pointer (task, error);
if (!ret)
return FALSE;
g_assert (!pending->is_membuf);
g_assert (out_filename);
*out_filename = ret;
return TRUE;
}
static void
ostree_fetcher_stream_mirrored_uri_async (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
void
_ostree_fetcher_request_to_membuf (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
OstreeFetcherRequestFlags flags,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
ostree_fetcher_mirrored_request_internal (self, mirrorlist, filename, TRUE,
max_size, priority, cancellable,
callback, user_data,
ostree_fetcher_stream_mirrored_uri_async);
_ostree_fetcher_request_async (self, mirrorlist, filename, flags, TRUE,
max_size, priority, cancellable,
callback, user_data);
}
static GInputStream *
ostree_fetcher_stream_mirrored_uri_finish (OstreeFetcher *self,
GAsyncResult *result,
GError **error)
gboolean
_ostree_fetcher_request_to_membuf_finish (OstreeFetcher *self,
GAsyncResult *result,
GBytes **out_buf,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, self), NULL);
g_return_val_if_fail (g_async_result_is_tagged (result,
ostree_fetcher_stream_mirrored_uri_async), NULL);
GTask *task;
OstreeFetcherPendingURI *pending;
gpointer ret;
return g_task_propagate_pointer (G_TASK (result), error);
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE);
task = (GTask*)result;
pending = g_task_get_task_data (task);
ret = g_task_propagate_pointer (task, error);
if (!ret)
return FALSE;
g_assert (pending->is_membuf);
g_assert (out_buf);
*out_buf = ret;
return TRUE;
}
guint64
_ostree_fetcher_bytes_transferred (OstreeFetcher *self)
{
@@ -1307,118 +1369,6 @@ _ostree_fetcher_bytes_transferred (OstreeFetcher *self)
return ret;
}
typedef struct
{
GInputStream *result_stream;
gboolean done;
GError **error;
}
FetchUriSyncData;
static void
fetch_uri_sync_on_complete (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
FetchUriSyncData *data = user_data;
data->result_stream = ostree_fetcher_stream_mirrored_uri_finish ((OstreeFetcher*)object,
result, data->error);
data->done = TRUE;
}
gboolean
_ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
GPtrArray *mirrorlist,
const char *filename,
gboolean add_nul,
gboolean allow_noent,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
const guint8 nulchar = 0;
g_autoptr(GMemoryOutputStream) buf = NULL;
g_autoptr(GMainContext) mainctx = NULL;
FetchUriSyncData data;
g_assert (error != NULL);
data.result_stream = NULL;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
mainctx = g_main_context_new ();
g_main_context_push_thread_default (mainctx);
data.done = FALSE;
data.error = error;
ostree_fetcher_stream_mirrored_uri_async (fetcher, mirrorlist, filename, max_size,
OSTREE_FETCHER_DEFAULT_PRIORITY, cancellable,
fetch_uri_sync_on_complete, &data);
while (!data.done)
g_main_context_iteration (mainctx, TRUE);
if (!data.result_stream)
{
if (allow_noent)
{
if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (error);
ret = TRUE;
*out_contents = NULL;
}
}
goto out;
}
buf = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
if (g_output_stream_splice ((GOutputStream*)buf, data.result_stream,
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
cancellable, error) < 0)
goto out;
if (add_nul)
{
if (!g_output_stream_write ((GOutputStream*)buf, &nulchar, 1, cancellable, error))
goto out;
}
if (!g_output_stream_close ((GOutputStream*)buf, cancellable, error))
goto out;
ret = TRUE;
*out_contents = g_memory_output_stream_steal_as_bytes (buf);
out:
if (mainctx)
g_main_context_pop_thread_default (mainctx);
g_clear_object (&(data.result_stream));
return ret;
}
/* Helper for callers who just want to fetch single one-off URIs */
gboolean
_ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher,
OstreeFetcherURI *uri,
gboolean add_nul,
gboolean allow_noent,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GPtrArray) mirrorlist = g_ptr_array_new ();
g_ptr_array_add (mirrorlist, uri); /* no transfer */
return _ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist, NULL,
add_nul, allow_noent,
out_contents, max_size,
cancellable, error);
}
void
_ostree_fetcher_uri_free (OstreeFetcherURI *uri)
{
+34 -30
View File
@@ -93,47 +93,51 @@ void _ostree_fetcher_set_proxy (OstreeFetcher *fetcher,
const char *proxy);
void _ostree_fetcher_set_client_cert (OstreeFetcher *fetcher,
GTlsCertificate *cert);
const char *cert_path,
const char *key_path);
void _ostree_fetcher_set_tls_database (OstreeFetcher *self,
GTlsDatabase *db);
const char *tlsdb_path);
void _ostree_fetcher_set_extra_headers (OstreeFetcher *self,
GVariant *extra_headers);
guint64 _ostree_fetcher_bytes_transferred (OstreeFetcher *self);
void _ostree_fetcher_mirrored_request_with_partial_async (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void _ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
char *_ostree_fetcher_mirrored_request_with_partial_finish (OstreeFetcher *self,
GAsyncResult *result,
GError **error);
gboolean _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
GAsyncResult *result,
char **out_filename,
GError **error);
typedef enum {
OSTREE_FETCHER_REQUEST_NUL_TERMINATION = (1 << 0)
} OstreeFetcherRequestFlags;
void _ostree_fetcher_request_to_membuf (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
OstreeFetcherRequestFlags flags,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean _ostree_fetcher_request_to_membuf_finish (OstreeFetcher *self,
GAsyncResult *result,
GBytes **out_buf,
GError **error);
gboolean _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
GPtrArray *mirrorlist,
const char *filename,
gboolean add_nul,
gboolean allow_noent,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
GError **error);
gboolean _ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher,
OstreeFetcherURI *uri,
gboolean add_nul,
gboolean allow_noent,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
GError **error);
G_END_DECLS
#endif
+1
View File
@@ -21,6 +21,7 @@
#include "config.h"
#include "ostree-metalink.h"
#include "ostree-fetcher-util.h"
#include <gio/gfiledescriptorbased.h>
#include "otutil.h"
+114 -44
View File
@@ -254,6 +254,61 @@ ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
return ret;
}
static gboolean
repo_prune_internal (OstreeRepo *self,
GHashTable *objects,
OstreeRepoPruneOptions *options,
gint *out_objects_total,
gint *out_objects_pruned,
guint64 *out_pruned_object_size_total,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GHashTableIter hash_iter;
gpointer key, value;
OtPruneData data = { 0, };
data.repo = self;
data.reachable = g_hash_table_ref (options->reachable);
g_hash_table_iter_init (&hash_iter, objects);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
GVariant *serialized_key = key;
GVariant *objdata = value;
const char *checksum;
OstreeObjectType objtype;
gboolean is_loose;
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
g_variant_get_child (objdata, 0, "b", &is_loose);
if (!is_loose)
continue;
if (!maybe_prune_loose_object (&data, options->flags, checksum, objtype,
cancellable, error))
goto out;
}
if (!ostree_repo_prune_static_deltas (self, NULL, cancellable, error))
goto out;
if (!_ostree_repo_prune_tmp (self, cancellable, error))
goto out;
ret = TRUE;
*out_objects_total = (data.n_reachable_meta + data.n_unreachable_meta +
data.n_reachable_content + data.n_unreachable_content);
*out_objects_pruned = (data.n_unreachable_meta + data.n_unreachable_content);
*out_pruned_object_size_total = data.freed_bytes;
out:
if (data.reachable)
g_hash_table_unref (data.reachable);
return ret;
}
/**
* ostree_repo_prune:
* @self: Repo
@@ -289,39 +344,42 @@ ostree_repo_prune (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GHashTableIter hash_iter;
gpointer key, value;
g_autoptr(GHashTable) objects = NULL;
g_autoptr(GHashTable) all_refs = NULL;
OtPruneData data = { 0, };
g_autoptr(GHashTable) reachable = NULL;
gboolean refs_only = flags & OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY;
data.repo = self;
data.reachable = ostree_repo_traverse_new_reachable ();
reachable = ostree_repo_traverse_new_reachable ();
/* This original prune API has fixed logic for traversing refs or all commits
* combined with actually deleting content. The newer backend API just does
* the deletion.
*/
if (refs_only)
{
if (!ostree_repo_list_refs (self, NULL, &all_refs,
cancellable, error))
goto out;
return FALSE;
g_hash_table_iter_init (&hash_iter, all_refs);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *checksum = value;
g_debug ("Finding objects to keep for commit %s", checksum);
if (!ostree_repo_traverse_commit_union (self, checksum, depth, data.reachable,
if (!ostree_repo_traverse_commit_union (self, checksum, depth, reachable,
cancellable, error))
goto out;
return FALSE;
}
}
if (!ostree_repo_list_objects (self, OSTREE_REPO_LIST_OBJECTS_ALL | OSTREE_REPO_LIST_OBJECTS_NO_PARENTS,
&objects, cancellable, error))
goto out;
return FALSE;
if (!refs_only)
{
@@ -338,45 +396,57 @@ ostree_repo_prune (OstreeRepo *self,
continue;
g_debug ("Finding objects to keep for commit %s", checksum);
if (!ostree_repo_traverse_commit_union (self, checksum, depth, data.reachable,
if (!ostree_repo_traverse_commit_union (self, checksum, depth, reachable,
cancellable, error))
goto out;
return FALSE;
}
}
g_hash_table_iter_init (&hash_iter, objects);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
GVariant *serialized_key = key;
GVariant *objdata = value;
const char *checksum;
OstreeObjectType objtype;
gboolean is_loose;
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
g_variant_get_child (objdata, 0, "b", &is_loose);
{ OstreeRepoPruneOptions opts = { flags, reachable };
return repo_prune_internal (self, objects, &opts,
out_objects_total, out_objects_pruned,
out_pruned_object_size_total, cancellable, error);
}
}
if (!is_loose)
continue;
/**
* ostree_repo_prune_from_reachable:
* @self: Repo
* @options: Options controlling prune process
* @out_objects_total: (out): Number of objects found
* @out_objects_pruned: (out): Number of objects deleted
* @out_pruned_object_size_total: (out): Storage size in bytes of objects deleted
* @cancellable: Cancellable
* @error: Error
*
* Delete content from the repository. This function is the "backend"
* half of the higher level ostree_repo_prune(). To use this function,
* you determine the root set yourself, and this function finds all other
* unreferenced objects and deletes them.
*
* Use this API when you want to perform more selective pruning - for example,
* retain all commits from a production branch, but just GC some history from
* your dev branch.
*
* The %OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE flag may be specified to just determine
* statistics on objects that would be deleted, without actually deleting them.
*/
gboolean
ostree_repo_prune_from_reachable (OstreeRepo *self,
OstreeRepoPruneOptions *options,
gint *out_objects_total,
gint *out_objects_pruned,
guint64 *out_pruned_object_size_total,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GHashTable) objects = NULL;
if (!maybe_prune_loose_object (&data, flags, checksum, objtype,
cancellable, error))
goto out;
}
if (!ostree_repo_list_objects (self, OSTREE_REPO_LIST_OBJECTS_ALL | OSTREE_REPO_LIST_OBJECTS_NO_PARENTS,
&objects, cancellable, error))
return FALSE;
if (!ostree_repo_prune_static_deltas (self, NULL, cancellable, error))
goto out;
if (!_ostree_repo_prune_tmp (self, cancellable, error))
goto out;
ret = TRUE;
*out_objects_total = (data.n_reachable_meta + data.n_unreachable_meta +
data.n_reachable_content + data.n_unreachable_content);
*out_objects_pruned = (data.n_unreachable_meta + data.n_unreachable_content);
*out_pruned_object_size_total = data.freed_bytes;
out:
if (data.reachable)
g_hash_table_unref (data.reachable);
return ret;
return repo_prune_internal (self, objects, options, out_objects_total,
out_objects_pruned, out_pruned_object_size_total,
cancellable, error);
}
+147 -143
View File
@@ -32,6 +32,7 @@
#include "ostree-repo-private.h"
#include "ostree-repo-static-delta-private.h"
#include "ostree-metalink.h"
#include "ostree-fetcher-util.h"
#include "ot-fs-utils.h"
#include <gio/gunixinputstream.h>
@@ -66,6 +67,7 @@ typedef struct {
gint n_scanned_metadata;
gboolean gpg_verify;
gboolean require_static_deltas;
gboolean gpg_verify_summary;
gboolean has_tombstone_commits;
@@ -78,7 +80,7 @@ typedef struct {
GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */
GHashTable *scanned_metadata; /* Maps object name to itself */
GHashTable *requested_metadata; /* Maps object name to itself */
GHashTable *requested_content; /* Maps object name to itself */
GHashTable *requested_content; /* Maps checksum to itself */
guint n_outstanding_metadata_fetches;
guint n_outstanding_metadata_write_requests;
guint n_outstanding_content_fetches;
@@ -177,6 +179,10 @@ update_progress (gpointer user_data)
if (! pull_data->progress)
return FALSE;
/* In dry run, we only emit progress once metadata is done */
if (pull_data->dry_run && pull_data->n_outstanding_metadata_fetches > 0)
return TRUE;
outstanding_writes = pull_data->n_outstanding_content_write_requests +
pull_data->n_outstanding_metadata_write_requests +
pull_data->n_outstanding_deltapart_write_requests;
@@ -707,8 +713,7 @@ content_fetch_on_complete (GObject *object,
OstreeObjectType objtype;
gboolean free_fetch_data = TRUE;
temp_path = _ostree_fetcher_mirrored_request_with_partial_finish (fetcher, result, error);
if (!temp_path)
if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &temp_path, error))
goto out;
ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype);
@@ -841,8 +846,7 @@ meta_fetch_on_complete (GObject *object,
g_debug ("fetch of %s%s complete", checksum_obj,
fetch_data->is_detached_meta ? " (detached)" : "");
temp_path = _ostree_fetcher_mirrored_request_with_partial_finish (fetcher, result, error);
if (!temp_path)
if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &temp_path, error))
{
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
@@ -982,8 +986,7 @@ static_deltapart_fetch_on_complete (GObject *object,
g_debug ("fetch static delta part %s complete", fetch_data->expected_checksum);
temp_path = _ostree_fetcher_mirrored_request_with_partial_finish (fetcher, result, error);
if (!temp_path)
if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &temp_path, error))
goto out;
fd = openat (_ostree_fetcher_get_dfd (fetcher), temp_path, O_RDONLY | O_CLOEXEC);
@@ -1264,7 +1267,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
if (g_hash_table_lookup (pull_data->scanned_metadata, object))
return TRUE;
is_requested = g_hash_table_lookup (pull_data->requested_metadata, tmp_checksum) != NULL;
is_requested = g_hash_table_lookup (pull_data->requested_metadata, object) != NULL;
if (!ostree_repo_has_object (pull_data->repo, objtype, tmp_checksum, &is_stored,
cancellable, error))
goto out;
@@ -1289,10 +1292,9 @@ scan_one_metadata_object_c (OtPullData *pull_data,
if (!is_stored && !is_requested)
{
char *duped_checksum = g_strdup (tmp_checksum);
gboolean do_fetch_detached;
g_hash_table_add (pull_data->requested_metadata, duped_checksum);
g_hash_table_add (pull_data->requested_metadata, g_variant_ref (object));
do_fetch_detached = (objtype == OSTREE_OBJECT_TYPE_COMMIT);
enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, do_fetch_detached, FALSE);
@@ -1382,12 +1384,12 @@ enqueue_one_object_request (OtPullData *pull_data,
else
expected_max_size = 0;
_ostree_fetcher_mirrored_request_with_partial_async (pull_data->fetcher, mirrorlist,
obj_subpath, expected_max_size,
is_meta ? OSTREE_REPO_PULL_METADATA_PRIORITY
: OSTREE_REPO_PULL_CONTENT_PRIORITY,
pull_data->cancellable,
is_meta ? meta_fetch_on_complete : content_fetch_on_complete, fetch_data);
_ostree_fetcher_request_to_tmpfile (pull_data->fetcher, mirrorlist,
obj_subpath, expected_max_size,
is_meta ? OSTREE_REPO_PULL_METADATA_PRIORITY
: OSTREE_REPO_PULL_CONTENT_PRIORITY,
pull_data->cancellable,
is_meta ? meta_fetch_on_complete : content_fetch_on_complete, fetch_data);
}
static gboolean
@@ -1418,75 +1420,6 @@ load_remote_repo_config (OtPullData *pull_data,
return ret;
}
static gboolean
request_static_delta_superblock_sync (OtPullData *pull_data,
const char *from_revision,
const char *to_revision,
GVariant **out_delta_superblock,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GVariant) ret_delta_superblock = NULL;
g_autofree char *delta_name =
_ostree_get_relative_static_delta_superblock_path (from_revision, to_revision);
g_autoptr(GBytes) delta_superblock_data = NULL;
if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher,
pull_data->content_mirrorlist,
delta_name, FALSE, TRUE,
&delta_superblock_data,
OSTREE_MAX_METADATA_SIZE,
pull_data->cancellable, error))
goto out;
if (delta_superblock_data)
{
{
g_autofree gchar *delta = NULL;
g_autofree guchar *ret_csum = NULL;
guchar *summary_csum;
g_autoptr (GInputStream) summary_is = NULL;
summary_is = g_memory_input_stream_new_from_data (g_bytes_get_data (delta_superblock_data, NULL),
g_bytes_get_size (delta_superblock_data),
NULL);
if (!ot_gio_checksum_stream (summary_is, &ret_csum, cancellable, error))
goto out;
delta = g_strconcat (from_revision ? from_revision : "", from_revision ? "-" : "", to_revision, NULL);
summary_csum = g_hash_table_lookup (pull_data->summary_deltas_checksums, delta);
/* At this point we've GPG verified the data, so in theory
* could trust that they provided the right data, but let's
* make this a hard error.
*/
if (pull_data->gpg_verify_summary && !summary_csum)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)");
goto out;
}
if (summary_csum && memcmp (summary_csum, ret_csum, 32))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid checksum for static delta %s", delta);
goto out;
}
}
ret_delta_superblock = g_variant_ref_sink (g_variant_new_from_bytes ((GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
delta_superblock_data, FALSE));
}
ret = TRUE;
if (out_delta_superblock)
*out_delta_superblock = g_steal_pointer (&ret_delta_superblock);
out:
return ret;
}
static gboolean
process_one_static_delta_fallback (OtPullData *pull_data,
gboolean delta_byteswap,
@@ -1533,10 +1466,11 @@ process_one_static_delta_fallback (OtPullData *pull_data,
{
if (OSTREE_OBJECT_TYPE_IS_META (objtype))
{
if (!g_hash_table_lookup (pull_data->requested_metadata, checksum))
g_autoptr(GVariant) objname = ostree_object_name_serialize (checksum, objtype);
if (!g_hash_table_lookup (pull_data->requested_metadata, objname))
{
gboolean do_fetch_detached;
g_hash_table_add (pull_data->requested_metadata, checksum);
g_hash_table_add (pull_data->requested_metadata, g_variant_ref (objname));
do_fetch_detached = (objtype == OSTREE_OBJECT_TYPE_COMMIT);
enqueue_one_object_request (pull_data, checksum, objtype, NULL, do_fetch_detached, FALSE);
@@ -1735,13 +1669,13 @@ process_one_static_delta (OtPullData *pull_data,
}
else
{
_ostree_fetcher_mirrored_request_with_partial_async (pull_data->fetcher,
pull_data->content_mirrorlist,
deltapart_path, size,
OSTREE_FETCHER_DEFAULT_PRIORITY,
pull_data->cancellable,
static_deltapart_fetch_on_complete,
fetch_data);
_ostree_fetcher_request_to_tmpfile (pull_data->fetcher,
pull_data->content_mirrorlist,
deltapart_path, size,
OSTREE_FETCHER_DEFAULT_PRIORITY,
pull_data->cancellable,
static_deltapart_fetch_on_complete,
fetch_data);
pull_data->n_outstanding_deltapart_fetches++;
}
}
@@ -1751,6 +1685,100 @@ process_one_static_delta (OtPullData *pull_data,
return ret;
}
typedef struct {
OtPullData *pull_data;
char *from_revision;
char *to_revision;
} FetchDeltaSuperData;
static void
on_superblock_fetched (GObject *src,
GAsyncResult *res,
gpointer data)
{
FetchDeltaSuperData *fdata = data;
OtPullData *pull_data = fdata->pull_data;
GError *local_error = NULL;
GError **error = &local_error;
g_autoptr(GBytes) delta_superblock_data = NULL;
const char *from_revision = fdata->from_revision;
const char *to_revision = fdata->to_revision;
if (!_ostree_fetcher_request_to_membuf_finish ((OstreeFetcher*)src,
res,
&delta_superblock_data,
error))
{
if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
goto out;
g_clear_error (&local_error);
if (pull_data->require_static_deltas)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Static deltas required, but none found for %s to %s",
from_revision, to_revision);
goto out;
}
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
}
else
{
g_autofree gchar *delta = NULL;
g_autofree guchar *ret_csum = NULL;
guchar *summary_csum;
g_autoptr (GInputStream) summary_is = NULL;
g_autoptr(GVariant) delta_superblock = NULL;
summary_is = g_memory_input_stream_new_from_data (g_bytes_get_data (delta_superblock_data, NULL),
g_bytes_get_size (delta_superblock_data),
NULL);
if (!ot_gio_checksum_stream (summary_is, &ret_csum, pull_data->cancellable, error))
goto out;
delta = g_strconcat (from_revision ? from_revision : "", from_revision ? "-" : "", to_revision, NULL);
summary_csum = g_hash_table_lookup (pull_data->summary_deltas_checksums, delta);
/* At this point we've GPG verified the data, so in theory
* could trust that they provided the right data, but let's
* make this a hard error.
*/
if (pull_data->gpg_verify_summary && !summary_csum)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)");
goto out;
}
if (summary_csum && memcmp (summary_csum, ret_csum, 32))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid checksum for static delta %s", delta);
goto out;
}
delta_superblock = g_variant_ref_sink (g_variant_new_from_bytes ((GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
delta_superblock_data, FALSE));
g_ptr_array_add (pull_data->static_delta_superblocks, g_variant_ref (delta_superblock));
if (!process_one_static_delta (pull_data, from_revision, to_revision, delta_superblock,
pull_data->cancellable, error))
goto out;
}
out:
g_free (fdata->from_revision);
g_free (fdata->to_revision);
g_free (fdata);
g_assert (pull_data->n_outstanding_metadata_fetches > 0);
pull_data->n_outstanding_metadata_fetches--;
pull_data->n_fetched_metadata++;
check_outstanding_requests_handle_error (pull_data, local_error);
}
static gboolean
validate_variant_is_csum (GVariant *csum,
GError **error)
@@ -1923,17 +1951,7 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self,
}
else if (tls_client_cert_path != NULL)
{
g_autoptr(GTlsCertificate) client_cert = NULL;
g_assert (tls_client_key_path != NULL);
client_cert = g_tls_certificate_new_from_files (tls_client_cert_path,
tls_client_key_path,
error);
if (client_cert == NULL)
goto out;
_ostree_fetcher_set_client_cert (fetcher, client_cert);
_ostree_fetcher_set_client_cert (fetcher, tls_client_cert_path, tls_client_key_path);
}
}
@@ -1947,13 +1965,7 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self,
if (tls_ca_path != NULL)
{
g_autoptr(GTlsDatabase) db = NULL;
db = g_tls_file_database_new (tls_ca_path, error);
if (db == NULL)
goto out;
_ostree_fetcher_set_tls_database (fetcher, db);
_ostree_fetcher_set_tls_database (fetcher, tls_ca_path);
}
}
@@ -2346,7 +2358,6 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_autofree char **override_commit_ids = NULL;
GSource *update_timeout = NULL;
gboolean disable_static_deltas = FALSE;
gboolean require_static_deltas = FALSE;
gboolean opt_gpg_verify_set = FALSE;
gboolean opt_gpg_verify_summary_set = FALSE;
const char *url_override = NULL;
@@ -2370,7 +2381,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_variant_lookup (options, "gpg-verify-summary", "b", &pull_data->gpg_verify_summary);
(void) g_variant_lookup (options, "depth", "i", &pull_data->maxdepth);
(void) g_variant_lookup (options, "disable-static-deltas", "b", &disable_static_deltas);
(void) g_variant_lookup (options, "require-static-deltas", "b", &require_static_deltas);
(void) g_variant_lookup (options, "require-static-deltas", "b", &pull_data->require_static_deltas);
(void) g_variant_lookup (options, "override-commit-ids", "^a&s", &override_commit_ids);
(void) g_variant_lookup (options, "dry-run", "b", &pull_data->dry_run);
(void) g_variant_lookup (options, "override-url", "&s", &url_override);
@@ -2388,11 +2399,11 @@ ostree_repo_pull_with_options (OstreeRepo *self,
for (i = 0; dirs_to_pull != NULL && dirs_to_pull[i] != NULL; i++)
g_return_val_if_fail (dirs_to_pull[i][0] == '/', FALSE);
g_return_val_if_fail (!(disable_static_deltas && require_static_deltas), FALSE);
g_return_val_if_fail (!(disable_static_deltas && pull_data->require_static_deltas), FALSE);
/* We only do dry runs with static deltas, because we don't really have any
* in-advance information for bare fetches.
*/
g_return_val_if_fail (!pull_data->dry_run || require_static_deltas, FALSE);
g_return_val_if_fail (!pull_data->dry_run || pull_data->require_static_deltas, FALSE);
pull_data->is_mirror = (flags & OSTREE_REPO_PULL_FLAGS_MIRROR) > 0;
pull_data->is_commit_only = (flags & OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY) > 0;
@@ -2424,8 +2435,8 @@ ostree_repo_pull_with_options (OstreeRepo *self,
(GDestroyNotify)g_variant_unref, NULL);
pull_data->requested_content = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL);
pull_data->requested_metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL);
pull_data->requested_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
(GDestroyNotify)g_variant_unref, NULL);
if (dir_to_pull != NULL || dirs_to_pull != NULL)
{
pull_data->dirs = g_ptr_array_new_with_free_func (g_free);
@@ -2657,7 +2668,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
/* For local pulls, default to disabling static deltas so that the
* exact object files are copied.
*/
if (pull_data->remote_repo_local && !require_static_deltas)
if (pull_data->remote_repo_local && !pull_data->require_static_deltas)
disable_static_deltas = TRUE;
pull_data->static_delta_superblocks = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref);
@@ -2712,7 +2723,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
goto out;
}
if (!bytes_summary && require_static_deltas)
if (!bytes_summary && pull_data->require_static_deltas)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Fetch configured to require static deltas, but no summary found");
@@ -2941,7 +2952,6 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_autofree char *from_revision = NULL;
const char *ref = key;
const char *to_revision = value;
g_autoptr(GVariant) delta_superblock = NULL;
if (!ostree_repo_resolve_rev (pull_data->repo, ref, TRUE,
&from_revision, error))
@@ -2950,31 +2960,25 @@ ostree_repo_pull_with_options (OstreeRepo *self,
if (!(disable_static_deltas || mirroring_into_archive || pull_data->is_commit_only) &&
(from_revision == NULL || g_strcmp0 (from_revision, to_revision) != 0))
{
if (!request_static_delta_superblock_sync (pull_data, from_revision, to_revision,
&delta_superblock, cancellable, error))
goto out;
}
if (!delta_superblock)
{
if (require_static_deltas)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Static deltas required, but none found for %s to %s",
from_revision, to_revision);
goto out;
}
g_debug ("no delta superblock for %s-%s", from_revision ? from_revision : "empty", to_revision);
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
g_autofree char *delta_name =
_ostree_get_relative_static_delta_superblock_path (from_revision, to_revision);
FetchDeltaSuperData *fdata = g_new0(FetchDeltaSuperData, 1);
fdata->pull_data = pull_data;
fdata->from_revision = g_strdup (from_revision);
fdata->to_revision = g_strdup (to_revision);
_ostree_fetcher_request_to_membuf (pull_data->fetcher,
pull_data->content_mirrorlist,
delta_name, 0,
OSTREE_MAX_METADATA_SIZE,
0, pull_data->cancellable,
on_superblock_fetched, fdata);
pull_data->n_outstanding_metadata_fetches++;
pull_data->n_requested_metadata++;
}
else
{
g_debug ("processing delta superblock for %s-%s", from_revision ? from_revision : "empty", to_revision);
g_ptr_array_add (pull_data->static_delta_superblocks, g_variant_ref (delta_superblock));
if (!process_one_static_delta (pull_data, from_revision, to_revision,
delta_superblock,
cancellable, error))
goto out;
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
}
}
@@ -843,6 +843,25 @@ process_one_bsdiff (OstreeRepo *repo,
return ret;
}
static gboolean
check_object_world_readable (OstreeRepo *repo,
const char *checksum,
gboolean *out_readable,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GFileInfo) finfo = NULL;
guint32 mode;
if (!ostree_repo_load_file (repo, checksum, NULL, &finfo, NULL,
cancellable, error))
return FALSE;
mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
*out_readable = (mode & S_IROTH);
return TRUE;
}
static gboolean
generate_delta_lowlatency (OstreeRepo *repo,
const char *from,
@@ -973,6 +992,22 @@ generate_delta_lowlatency (OstreeRepo *repo,
const char *from_checksum = value;
ContentRollsum *rollsum;
ContentBsdiff *bsdiff;
gboolean from_world_readable = FALSE;
/* We only want to include in the delta objects that we are sure will
* be readable by the client when applying the delta, regardless its
* access privileges, so that we don't run into permissions problems
* when the client is trying to update a bare-user repository with a
* bare repository defined as its parent.
*/
if (!check_object_world_readable (repo, from_checksum, &from_world_readable, cancellable, error))
goto out;
if (!from_world_readable)
{
g_hash_table_iter_steal (&hashiter);
g_hash_table_add (new_reachable_regfile_content, (char*)from_checksum);
continue;
}
if (!try_content_rollsum (repo, opts, from_checksum, to_checksum,
&rollsum, cancellable, error))
+10 -8
View File
@@ -2456,12 +2456,12 @@ list_loose_objects_at (OstreeRepo *self,
continue;
}
key = ostree_object_name_serialize (buf, objtype);
value = g_variant_new ("(b@as)",
TRUE, g_variant_new_strv (NULL, 0));
/* transfer ownership */
g_hash_table_replace (inout_objects, key,
g_variant_ref_sink (value));
key = ostree_object_name_serialize (buf, objtype);
value = g_variant_new ("(b@as)",
TRUE, g_variant_new_strv (NULL, 0));
/* transfer ownership */
g_hash_table_replace (inout_objects, g_variant_ref_sink (key),
g_variant_ref_sink (value));
}
ret = TRUE;
@@ -3548,7 +3548,8 @@ ostree_repo_load_commit (OstreeRepo *self,
* ostree_repo_list_objects:
* @self: Repo
* @flags: Flags controlling enumeration
* @out_objects: (out): Map of serialized object name to variant data
* @out_objects: (out) (transfer container) (element-type GVariant GVariant):
* Map of serialized object name to variant data
* @cancellable: Cancellable
* @error: Error
*
@@ -3605,7 +3606,8 @@ ostree_repo_list_objects (OstreeRepo *self,
* ostree_repo_list_commit_objects_starting_with:
* @self: Repo
* @start: List commits starting with this checksum
* @out_commits: Array of GVariants
* @out_commits: (out) (transfer container) (element-type GVariant GVariant):
* Map of serialized commit name to variant data
* @cancellable: Cancellable
* @error: Error
*
+21
View File
@@ -970,6 +970,27 @@ gboolean ostree_repo_prune (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
struct _OstreeRepoPruneOptions {
OstreeRepoPruneFlags flags;
GHashTable *reachable; /* Set<GVariant> (object names) */
gboolean unused_bools[6];
int unused_ints[6];
gpointer unused_ptrs[7];
};
typedef struct _OstreeRepoPruneOptions OstreeRepoPruneOptions;
_OSTREE_PUBLIC
gboolean ostree_repo_prune_from_reachable (OstreeRepo *self,
OstreeRepoPruneOptions *options,
gint *out_objects_total,
gint *out_objects_pruned,
guint64 *out_pruned_object_size_total,
GCancellable *cancellable,
GError **error);
/**
* OstreeRepoPullFlags:
* @OSTREE_REPO_PULL_FLAGS_NONE: No special options for pull
+14 -2
View File
@@ -24,6 +24,8 @@ struct _OstreeTlsCertInteraction
{
GTlsInteraction parent_instance;
char *cert_path;
char *key_path;
GTlsCertificate *cert;
};
@@ -44,6 +46,14 @@ request_certificate (GTlsInteraction *interaction,
GError **error)
{
OstreeTlsCertInteraction *self = (OstreeTlsCertInteraction*)interaction;
if (!self->cert)
{
self->cert = g_tls_certificate_new_from_files (self->cert_path, self->key_path, error);
if (!self->cert)
return G_TLS_INTERACTION_FAILED;
}
g_tls_connection_set_certificate (connection, self->cert);
return G_TLS_INTERACTION_HANDLED;
}
@@ -61,9 +71,11 @@ _ostree_tls_cert_interaction_class_init (OstreeTlsCertInteractionClass *klass)
}
OstreeTlsCertInteraction *
_ostree_tls_cert_interaction_new (GTlsCertificate *cert)
_ostree_tls_cert_interaction_new (const char *cert_path,
const char *key_path)
{
OstreeTlsCertInteraction *self = g_object_new (OSTREE_TYPE_TLS_CERT_INTERACTION, NULL);
self->cert = g_object_ref (cert);
self->cert_path = g_strdup (cert_path);
self->key_path = g_strdup (key_path);
return self;
}
+2 -1
View File
@@ -34,6 +34,7 @@ typedef struct _OstreeTlsCertInteractionClass OstreeTlsCertInteractionClass;
GType _ostree_tls_cert_interaction_get_type (void) G_GNUC_CONST;
OstreeTlsCertInteraction * _ostree_tls_cert_interaction_new (GTlsCertificate *cert);
OstreeTlsCertInteraction * _ostree_tls_cert_interaction_new (const char *cert_path,
const char *key_path);
G_END_DECLS