New upstream version 2017.9

This commit is contained in:
Simon McVittie committed 2017-07-28 08:57:43 +01:00
commit e5ac0cef85
134 files changed
+3986 -5324

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
/* DEVEL symbol file - add new symbols here
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.
***/
/* Add new symbols here. Release commits should copy this section into -released.sym. */
LIBOSTREE_2017.10 {
};
/* 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
* source. Replace $LASTSTABLE with the last stable version, and $NEWVERSION
* with whatever the next version with new symbols will be.
LIBOSTREE_2017.$NEWVERSION {
global:
someostree_symbol_deleteme;
} LIBOSTREE_2017.$LASTSTABLE;
*/
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* 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.
*
* Authors:
* - Philip Withnall <withnall@endlessm.com>
*/
/* Symbols in this file are added to the build if OSTree is configured with
* --enable-experimental-api. They are not stable or officially supported, and
* might disappear or change in future releases. */
LIBOSTREE_2017.6_EXPERIMENTAL {
global:
ostree_remote_ref;
ostree_remote_unref;
} LIBOSTREE_2017.6;
LIBOSTREE_2017.7_EXPERIMENTAL {
global:
ostree_remote_get_name;
} LIBOSTREE_2017.6_EXPERIMENTAL;
LIBOSTREE_2017.8_EXPERIMENTAL {
global:
ostree_collection_ref_dup;
ostree_collection_ref_dupv;
ostree_collection_ref_equal;
ostree_collection_ref_free;
ostree_collection_ref_freev;
ostree_collection_ref_get_type;
ostree_collection_ref_hash;
ostree_collection_ref_new;
ostree_repo_find_remotes_async;
ostree_repo_find_remotes_finish;
ostree_repo_finder_avahi_get_type;
ostree_repo_finder_avahi_new;
ostree_repo_finder_avahi_start;
ostree_repo_finder_avahi_stop;
ostree_repo_finder_config_get_type;
ostree_repo_finder_config_new;
ostree_repo_finder_get_type;
ostree_repo_finder_mount_get_type;
ostree_repo_finder_mount_new;
ostree_repo_finder_resolve_async;
ostree_repo_finder_resolve_all_async;
ostree_repo_finder_resolve_all_finish;
ostree_repo_finder_resolve_finish;
ostree_repo_finder_result_compare;
ostree_repo_finder_result_dup;
ostree_repo_finder_result_free;
ostree_repo_finder_result_freev;
ostree_repo_finder_result_get_type;
ostree_repo_finder_result_new;
ostree_repo_get_collection_id;
ostree_repo_list_collection_refs;
ostree_repo_pull_from_remotes_async;
ostree_repo_pull_from_remotes_finish;
ostree_repo_resolve_keyring_for_collection;
ostree_repo_set_collection_id;
ostree_repo_set_collection_ref_immediate;
ostree_repo_transaction_set_collection_ref;
ostree_validate_collection_id;
} LIBOSTREE_2017.7_EXPERIMENTAL;
+3
View File
@@ -413,6 +413,9 @@ global:
ostree_validate_remote_name;
} LIBOSTREE_2017.7;
LIBOSTREE_2017.9 {
};
/* NOTE: Only add more content here in release commits! See the
* comments at the top of this file.
*/
+5 -7
View File
@@ -420,15 +420,13 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
}
/* Now let's fdatasync() for the new file */
{ glnx_fd_close int new_config_fd = open (gs_file_get_path_cached (new_config_path), O_RDONLY | O_CLOEXEC);
if (new_config_fd < 0)
{
glnx_set_prefix_error_from_errno (error, "Opening %s", gs_file_get_path_cached (new_config_path));
goto out;
}
{ glnx_fd_close int new_config_fd = -1;
if (!glnx_openat_rdonly (AT_FDCWD, gs_file_get_path_cached (new_config_path), TRUE, &new_config_fd, error))
goto out;
if (fdatasync (new_config_fd) < 0)
{
glnx_set_error_from_errno (error);
(void)glnx_throw_errno_prefix (error, "fdatasync");
goto out;
}
}
+49 -5
View File
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <gio/gfiledescriptorbased.h>
#include <gio/gunixinputstream.h>
#include "libglnx.h"
#include "ostree.h"
#include "ostree-core-private.h"
@@ -35,6 +36,40 @@
#define ALIGN_VALUE(this, boundary) \
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
/* Return a copy of @input suitable for addition to
* a GError message; newlines are quashed, the value
* is forced to be UTF-8, is truncated to @maxlen (if maxlen != -1).
*/
static char *
quash_string_for_error_message (const char *input,
ssize_t len,
ssize_t maxlen)
{
if (len == -1)
len = strlen (input);
if (maxlen != -1 && maxlen < len)
len = maxlen;
#if GLIB_CHECK_VERSION(2, 52, 0)
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
char *buf = g_utf8_make_valid (input, len);
G_GNUC_END_IGNORE_DEPRECATIONS
#else
char *buf = g_strndup (input, len);
#endif
for (char *iter = buf; iter && *iter; iter++)
{
char c = *iter;
if (c == '\n')
*iter = ' ';
#if !GLIB_CHECK_VERSION(2, 52, 0)
/* No g_utf8_make_valid()? OK, let's just brute force this. */
if (!g_ascii_isprint (c))
*iter = ' ';
#endif
}
return buf;
}
static gboolean
file_header_parse (GVariant *metadata,
GFileInfo **out_file_info,
@@ -740,15 +775,16 @@ ostree_content_file_parse_at (gboolean compressed,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GInputStream) file_input = NULL;
if (!ot_openat_read_stream (parent_dfd, path, TRUE, &file_input,
cancellable, error))
glnx_fd_close int fd = -1;
if (!glnx_openat_rdonly (parent_dfd, path, TRUE, &fd, error))
return FALSE;
struct stat stbuf;
if (!glnx_stream_fstat ((GFileDescriptorBased*)file_input, &stbuf, error))
if (!glnx_fstat (fd, &stbuf, error))
return FALSE;
g_autoptr(GInputStream) file_input = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE);
g_autoptr(GFileInfo) ret_file_info = NULL;
g_autoptr(GVariant) ret_xattrs = NULL;
g_autoptr(GInputStream) ret_input = NULL;
@@ -1823,7 +1859,15 @@ ostree_validate_structureof_checksum_string (const char *checksum,
size_t len = strlen (checksum);
if (len != OSTREE_SHA256_STRING_LEN)
return glnx_throw (error, "Invalid rev '%s'", checksum);
{
/* If we happen to get e.g. an Apache directory listing HTML, don't
* dump it all to the error.
* https://github.com/projectatomic/rpm-ostree/issues/885
*/
g_autofree char *sanitized = quash_string_for_error_message (checksum, len,
OSTREE_SHA256_STRING_LEN);
return glnx_throw (error, "Invalid rev %s", sanitized);
}
for (i = 0; i < len; i++)
{
+59
View File
@@ -195,6 +195,65 @@ typedef enum {
OSTREE_REPO_MODE_BARE_USER_ONLY,
} OstreeRepoMode;
/**
* OSTREE_COMMIT_META_KEY_VERSION:
*
* GVariant type `s`. This metadata key is used for version numbers. A freeform
* string; the intention is that systems using ostree do not interpret this
* semantically as traditional package managers do.
*
* This is the only ostree-defined metadata key that does not start with `ostree.`.
* Since: 2014.9
*/
#define OSTREE_COMMIT_META_KEY_VERSION "version"
/**
* OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE:
*
* GVariant type `s`. Should contain a refspec defining a new target branch;
* `ostree admin upgrade` and `OstreeSysrootUpgrader` will automatically initiate
* a rebase upon encountering this metadata key.
*
* Since: 2017.7
*/
#define OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE "ostree.endoflife-rebase"
/**
* OSTREE_COMMIT_META_KEY_ENDOFLIFE:
*
* GVariant type `s`. This metadata key is used to display vendor's message
* when an update stream for a particular branch ends. It usually provides
* update instructions for the users.
*
* Since: 2017.7
*/
#define OSTREE_COMMIT_META_KEY_ENDOFLIFE "ostree.endoflife"
/**
* OSTREE_COMMIT_META_KEY_REF_BINDING:
*
* GVariant type `as`; each element is a branch name. If this is added to a
* commit, `ostree_repo_pull()` will enforce that the commit was retrieved from
* one of the branch names in this array. This prevents "sidegrade" attacks.
* The rationale for having this support multiple branch names is that it helps
* support a "promotion" model of taking a commit and moving it between development
* and production branches.
*
* Since: 2017.9
*/
#define OSTREE_COMMIT_META_KEY_REF_BINDING "ostree.ref-binding"
/**
* OSTREE_COMMIT_META_KEY_COLLECTION_BINDING:
*
* GVariant type `s`. If this is added to a commit, `ostree_repo_pull()`
* will enforce that the commit was retrieved from a repository which has
* the same collection ID. See `ostree_repo_set_collection_id()`.
* This is most useful in concert with `OSTREE_COMMIT_META_KEY_REF_BINDING`,
* as it more strongly binds the commit to the repository and branch.
*
* Since: 2017.9
*/
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
#define OSTREE_COMMIT_META_KEY_COLLECTION_BINDING "ostree.collection-binding"
#endif
_OSTREE_PUBLIC
const GVariantType *ostree_metadata_variant_type (OstreeObjectType objtype);
@@ -23,6 +23,8 @@
#endif
#include <string.h>
#include "ostree-enumtypes.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
+5 -2
View File
@@ -353,7 +353,9 @@ check_multi_info (OstreeFetcher *fetcher)
g_autofree char *msg = g_strdup_printf ("Server returned HTTP %lu", response);
g_task_return_new_error (task, G_IO_ERROR, giocode,
"%s", msg);
if (req->fetcher->remote_name)
if (req->fetcher->remote_name &&
!((req->flags & OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT) > 0 &&
giocode == G_IO_ERROR_NOT_FOUND))
_ostree_fetcher_journal_failure (req->fetcher->remote_name,
eff_url, msg);
@@ -859,13 +861,14 @@ void
_ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
OstreeFetcherRequestFlags flags,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
_ostree_fetcher_request_async (self, mirrorlist, filename, 0, FALSE,
_ostree_fetcher_request_async (self, mirrorlist, filename, flags, FALSE,
max_size, priority, cancellable,
callback, user_data);
}
+8 -3
View File
@@ -1128,7 +1128,9 @@ on_request_sent (GObject *object,
g_prefix_error (&local_error,
"All %u mirrors failed. Last error was: ",
pending->mirrorlist->len);
if (pending->thread_closure->remote_name)
if (pending->thread_closure->remote_name &&
!((pending->flags & OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT) > 0 &&
code == G_IO_ERROR_NOT_FOUND))
_ostree_fetcher_journal_failure (pending->thread_closure->remote_name,
uristring, local_error->message);
@@ -1238,13 +1240,14 @@ void
_ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
OstreeFetcherRequestFlags flags,
guint64 max_size,
int priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
_ostree_fetcher_request_async (self, mirrorlist, filename, 0, FALSE,
_ostree_fetcher_request_async (self, mirrorlist, filename, flags, FALSE,
max_size, priority, cancellable,
callback, user_data);
}
@@ -1334,8 +1337,10 @@ _ostree_fetcher_bytes_transferred (OstreeFetcher *self)
{
if (G_IS_FILE_DESCRIPTOR_BASED (stream))
{
int fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)stream);
struct stat stbuf;
if (glnx_stream_fstat ((GFileDescriptorBased*)stream, &stbuf, NULL))
if (glnx_fstat (fd, &stbuf, NULL))
ret += stbuf.st_size;
}
}
+5 -8
View File
@@ -55,8 +55,7 @@ gboolean
_ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
GPtrArray *mirrorlist,
const char *filename,
gboolean add_nul,
gboolean allow_noent,
OstreeFetcherRequestFlags flags,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
@@ -79,7 +78,7 @@ _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
data.error = error;
_ostree_fetcher_request_to_membuf (fetcher, mirrorlist, filename,
add_nul ? OSTREE_FETCHER_REQUEST_NUL_TERMINATION : 0,
flags,
max_size, OSTREE_FETCHER_DEFAULT_PRIORITY,
cancellable, fetch_uri_sync_on_complete, &data);
while (!data.done)
@@ -87,7 +86,7 @@ _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
if (!data.result_buf)
{
if (allow_noent)
if (flags & OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT)
{
if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
@@ -112,8 +111,7 @@ _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
gboolean
_ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher,
OstreeFetcherURI *uri,
gboolean add_nul,
gboolean allow_noent,
OstreeFetcherRequestFlags flags,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
@@ -121,8 +119,7 @@ _ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher,
{
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,
return _ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist, NULL, flags,
out_contents, max_size,
cancellable, error);
}
+2 -4
View File
@@ -29,8 +29,7 @@ G_BEGIN_DECLS
gboolean _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
GPtrArray *mirrorlist,
const char *filename,
gboolean add_nul,
gboolean allow_noent,
OstreeFetcherRequestFlags flags,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
@@ -38,8 +37,7 @@ gboolean _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
gboolean _ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher,
OstreeFetcherURI *uri,
gboolean add_nul,
gboolean allow_noent,
OstreeFetcherRequestFlags flags,
GBytes **out_contents,
guint64 max_size,
GCancellable *cancellable,
+6 -4
View File
@@ -54,6 +54,11 @@ typedef enum {
OSTREE_FETCHER_FLAGS_TRANSFER_GZIP = (1 << 1)
} OstreeFetcherConfigFlags;
typedef enum {
OSTREE_FETCHER_REQUEST_NUL_TERMINATION = (1 << 0),
OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT = (1 << 1)
} OstreeFetcherRequestFlags;
void
_ostree_fetcher_uri_free (OstreeFetcherURI *uri);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeFetcherURI, _ostree_fetcher_uri_free)
@@ -111,6 +116,7 @@ guint64 _ostree_fetcher_bytes_transferred (OstreeFetcher *self);
void _ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
GPtrArray *mirrorlist,
const char *filename,
OstreeFetcherRequestFlags flags,
guint64 max_size,
int priority,
GCancellable *cancellable,
@@ -122,10 +128,6 @@ gboolean _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
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,
+3 -8
View File
@@ -93,6 +93,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR("GPG", error);
gpgme_error_t gpg_error = 0;
ot_auto_gpgme_data gpgme_data_t data_buffer = NULL;
ot_auto_gpgme_data gpgme_data_t signature_buffer = NULL;
@@ -166,12 +167,8 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
glnx_fd_close int fd = -1;
ot_auto_gpgme_data gpgme_data_t kdata = NULL;
fd = openat (AT_FDCWD, path, O_RDONLY | O_CLOEXEC) ;
if (fd < 0)
{
glnx_set_prefix_error_from_errno (error, "Opening %s", path);
goto out;
}
if (!glnx_openat_rdonly (AT_FDCWD, path, TRUE, &fd, error))
goto out;
gpg_error = gpgme_data_new_from_fd (&kdata, fd);
if (gpg_error != GPG_ERR_NO_ERROR)
@@ -253,8 +250,6 @@ out:
(void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_dir, NULL, NULL);
}
g_prefix_error (error, "GPG: ");
return result;
}
+2 -2
View File
@@ -203,8 +203,8 @@ _ostree_impl_system_generator (const char *ostree_cmdline,
return FALSE;
g_clear_object (&outstream);
/* It should be readable */
if (fchmod (tmpf.fd, 0644) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
if (!glnx_fchmod (tmpf.fd, 0644, error))
return FALSE;
/* Error out if somehow it already exists, that'll help us debug conflicts */
if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_NOREPLACE,
normal_dir_dfd, "var.mount", error))
+4 -12
View File
@@ -431,10 +431,7 @@ try_one_url (OstreeMetalinkRequest *self,
gssize n_bytes;
if (!_ostree_fetcher_request_uri_to_membuf (self->metalink->fetcher,
uri,
FALSE,
FALSE,
&bytes,
uri, 0, &bytes,
self->metalink->max_size,
self->cancellable,
error))
@@ -614,14 +611,9 @@ _ostree_metalink_request_sync (OstreeMetalink *self,
request.urls = g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free);
request.parser = g_markup_parse_context_new (&metalink_parser, G_MARKUP_PREFIX_ERROR_POSITION, &request, NULL);
if (!_ostree_fetcher_request_uri_to_membuf (self->fetcher,
self->uri,
FALSE,
FALSE,
&contents,
self->max_size,
cancellable,
error))
if (!_ostree_fetcher_request_uri_to_membuf (self->fetcher, self->uri, 0,
&contents, self->max_size,
cancellable, error))
goto out;
data = g_bytes_get_data (contents, &len);
+6 -4
View File
@@ -81,8 +81,8 @@ checkout_object_for_uncompressed_cache (OstreeRepo *self,
if (!g_output_stream_close (temp_out, cancellable, error))
return FALSE;
if (fchmod (tmpf.fd, file_mode) < 0)
return glnx_throw_errno (error);
if (!glnx_fchmod (tmpf.fd, file_mode, error))
return FALSE;
if (!_ostree_repo_ensure_loose_objdir_at (self->uncompressed_objects_dir_fd,
loose_path,
@@ -770,9 +770,11 @@ checkout_tree_at_recurse (OstreeRepo *self,
}
/* Set directory mtime to OSTREE_TIMESTAMP, so that it is constant for all checkouts.
* Must be done after setting permissions and creating all children.
* Must be done after setting permissions and creating all children. Note we skip doing
* this for directories that already exist (under the theory we possibly don't own them),
* and we also skip it if doing copying checkouts, which is mostly for /etc.
*/
if (!did_exist)
if (!did_exist && !options->force_copy)
{
const struct timespec times[2] = { { OSTREE_TIMESTAMP, UTIME_OMIT }, { OSTREE_TIMESTAMP, 0} };
if (TEMP_FAILURE_RETRY (futimens (destination_dfd, times)) < 0)
+37 -38
View File
@@ -253,8 +253,8 @@ commit_loose_regfile_object (OstreeRepo *self,
if (S_ISREG (mode))
{
const mode_t content_mode = (mode & (S_IFREG | 0775)) | S_IRUSR;
if (fchmod (tmpf->fd, content_mode) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
if (!glnx_fchmod (tmpf->fd, content_mode, error))
return FALSE;
}
else
g_assert (S_ISLNK (mode));
@@ -266,8 +266,8 @@ commit_loose_regfile_object (OstreeRepo *self,
return glnx_throw (error, "Invalid mode 0%04o with bits 0%04o in bare-user-only repository",
mode, invalid_modebits);
if (fchmod (tmpf->fd, mode) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
if (!glnx_fchmod (tmpf->fd, mode, error))
return FALSE;
}
if (_ostree_repo_mode_is_bare (self->mode))
@@ -299,13 +299,13 @@ commit_loose_regfile_object (OstreeRepo *self,
typedef struct
{
gsize unpacked;
gsize archived;
goffset unpacked;
goffset archived;
} OstreeContentSizeCacheEntry;
static OstreeContentSizeCacheEntry *
content_size_cache_entry_new (gsize unpacked,
gsize archived)
content_size_cache_entry_new (goffset unpacked,
goffset archived)
{
OstreeContentSizeCacheEntry *entry = g_slice_new0 (OstreeContentSizeCacheEntry);
@@ -325,8 +325,8 @@ content_size_cache_entry_free (gpointer entry)
static void
repo_store_size_entry (OstreeRepo *self,
const gchar *checksum,
gsize unpacked,
gsize archived)
goffset unpacked,
goffset archived)
{
if (G_UNLIKELY (self->object_sizes == NULL))
self->object_sizes = g_hash_table_new_full (g_str_hash, g_str_equal,
@@ -495,8 +495,8 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
}
}
if (fchmod (tmpf.fd, 0644) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
if (!glnx_fchmod (tmpf.fd, 0644, error))
return FALSE;
*out_tmpf = tmpf; tmpf.initialized = FALSE;
return TRUE;
@@ -594,7 +594,7 @@ write_content_object (OstreeRepo *self,
*/
g_auto(OtCleanupUnlinkat) tmp_unlinker = { self->tmp_dir_fd, NULL };
g_auto(GLnxTmpfile) tmpf = { 0, };
gssize unpacked_size = 0;
goffset unpacked_size = 0;
gboolean indexable = FALSE;
/* Is it a symlink physically? */
if (phys_object_is_symlink)
@@ -643,17 +643,18 @@ write_content_object (OstreeRepo *self,
/* Don't close the base; we'll do that later */
g_filter_output_stream_set_close_base_stream ((GFilterOutputStream*)compressed_out_stream, FALSE);
unpacked_size = g_output_stream_splice (compressed_out_stream, file_input,
0, cancellable, error);
if (unpacked_size < 0)
if (g_output_stream_splice (compressed_out_stream, file_input,
0, cancellable, error) < 0)
return FALSE;
unpacked_size = g_file_info_get_size (file_info);
}
if (!g_output_stream_flush (temp_out, cancellable, error))
return FALSE;
if (fchmod (tmpf.fd, 0644) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
if (!glnx_fchmod (tmpf.fd, 0644, error))
return FALSE;
}
const char *actual_checksum = NULL;
@@ -733,6 +734,17 @@ write_content_object (OstreeRepo *self,
}
else
{
/* Update size metadata if configured */
if (indexable && object_file_type == G_FILE_TYPE_REGULAR)
{
struct stat stbuf;
if (!glnx_fstat (tmpf.fd, &stbuf, error))
return FALSE;
repo_store_size_entry (self, actual_checksum, unpacked_size, stbuf.st_size);
}
/* This path is for regular files */
if (!commit_loose_regfile_object (self, actual_checksum, &tmpf,
uid, gid, mode,
@@ -742,17 +754,6 @@ write_content_object (OstreeRepo *self,
ostree_object_type_to_string (OSTREE_OBJECT_TYPE_FILE));
}
/* Update size metadata if configured */
if (indexable && object_file_type == G_FILE_TYPE_REGULAR)
{
struct stat stbuf;
if (!glnx_fstat (tmpf.fd, &stbuf, error))
return FALSE;
repo_store_size_entry (self, actual_checksum, unpacked_size, stbuf.st_size);
}
/* Update statistics */
g_mutex_lock (&self->txn_stats_lock);
self->txn_stats.content_objects_written++;
@@ -851,8 +852,8 @@ write_metadata_object (OstreeRepo *self,
return FALSE;
if (glnx_loop_write (tmpf.fd, bufp, len) < 0)
return glnx_throw_errno_prefix (error, "write()");
if (fchmod (tmpf.fd, 0644) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
if (!glnx_fchmod (tmpf.fd, 0644, error))
return FALSE;
/* And commit it into place */
if (!_ostree_repo_commit_tmpf_final (self, actual_checksum, objtype,
@@ -2823,18 +2824,16 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
while (TRUE)
{
struct dirent *dent;
struct stat stbuf;
g_autoptr(GFileInfo) child_info = NULL;
const char *loose_checksum;
if (!glnx_dirfd_iterator_next_dent (src_dfd_iter, &dent, cancellable, error))
return FALSE;
if (dent == NULL)
break;
if (fstatat (src_dfd_iter->fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
return glnx_throw_errno (error);
struct stat stbuf;
if (!glnx_fstatat (src_dfd_iter->fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, error))
return FALSE;
loose_checksum = devino_cache_lookup (self, modifier, stbuf.st_dev, stbuf.st_ino);
const char *loose_checksum = devino_cache_lookup (self, modifier, stbuf.st_dev, stbuf.st_ino);
if (loose_checksum)
{
if (!ostree_mutable_tree_replace_file (mtree, dent->d_name, loose_checksum,
@@ -2844,7 +2843,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
continue;
}
child_info = _ostree_stbuf_to_gfileinfo (&stbuf);
g_autoptr(GFileInfo) child_info = _ostree_stbuf_to_gfileinfo (&stbuf);
g_file_info_set_name (child_info, dent->d_name);
if (S_ISREG (stbuf.st_mode))
+9 -1
View File
@@ -76,6 +76,13 @@ struct OstreeRepoCommitModifier {
GHashTable *devino_cache;
};
typedef enum {
OSTREE_REPO_SYSROOT_KIND_UNKNOWN,
OSTREE_REPO_SYSROOT_KIND_NO, /* Not a system repo */
OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT, /* Constructed via ostree_sysroot_get_repo() */
OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE, /* We match /ostree/repo */
} OstreeRepoSysrootKind;
/**
* OstreeRepo:
*
@@ -97,6 +104,7 @@ struct OstreeRepo {
int objects_dir_fd;
int uncompressed_objects_dir_fd;
GFile *sysroot_dir;
GWeakRef sysroot; /* Weak to avoid a circular ref; see also `is_system` */
char *remotes_config_dir;
GHashTable *txn_refs; /* (element-type utf8 utf8) */
@@ -114,7 +122,7 @@ struct OstreeRepo {
gboolean inited;
gboolean writable;
gboolean is_system; /* Was this repo created via ostree_sysroot_get_repo() ? */
OstreeRepoSysrootKind sysroot_kind;
GError *writable_error;
gboolean in_transaction;
gboolean disable_fsync;
+383 -139
View File
@@ -155,6 +155,8 @@ typedef struct {
* whether to fetch the primary object after fetching its
* detached metadata (no need if it's already stored). */
gboolean object_is_stored;
OstreeCollectionRef *requested_ref; /* (nullable) */
} FetchObjectData;
typedef struct {
@@ -172,31 +174,35 @@ typedef struct {
char *path;
OstreeObjectType objtype;
guint recursion_depth; /* NB: not used anymore, though might be nice to print */
OstreeCollectionRef *requested_ref; /* (nullable) */
} ScanObjectQueueData;
static void start_fetch (OtPullData *pull_data, FetchObjectData *fetch);
static void start_fetch_deltapart (OtPullData *pull_data,
FetchStaticDeltaData *fetch);
static gboolean fetcher_queue_is_full (OtPullData *pull_data);
static void queue_scan_one_metadata_object (OtPullData *pull_data,
const char *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth);
static void queue_scan_one_metadata_object (OtPullData *pull_data,
const char *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
const OstreeCollectionRef *ref);
static void queue_scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth);
static void queue_scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
const OstreeCollectionRef *ref);
static gboolean scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
GCancellable *cancellable,
GError **error);
static gboolean scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
const OstreeCollectionRef *ref,
GCancellable *cancellable,
GError **error);
static gboolean
update_progress (gpointer user_data)
@@ -422,11 +428,14 @@ idle_worker (gpointer user_data)
scan_data->objtype,
scan_data->path,
scan_data->recursion_depth,
scan_data->requested_ref,
pull_data->cancellable,
&error);
check_outstanding_requests_handle_error (pull_data, &error);
g_free (scan_data->path);
if (scan_data->requested_ref != NULL)
ostree_collection_ref_free (scan_data->requested_ref);
g_free (scan_data);
return G_SOURCE_CONTINUE;
}
@@ -461,7 +470,7 @@ fetch_mirrored_uri_contents_utf8_sync (OstreeFetcher *fetcher,
{
g_autoptr(GBytes) bytes = NULL;
if (!_ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist,
filename, TRUE, FALSE,
filename, OSTREE_FETCHER_REQUEST_NUL_TERMINATION,
&bytes,
OSTREE_MAX_METADATA_SIZE,
cancellable, error))
@@ -507,12 +516,13 @@ write_commitpartial_for (OtPullData *pull_data,
}
static void
enqueue_one_object_request (OtPullData *pull_data,
const char *checksum,
OstreeObjectType objtype,
const char *path,
gboolean is_detached_meta,
gboolean object_is_stored);
enqueue_one_object_request (OtPullData *pull_data,
const char *checksum,
OstreeObjectType objtype,
const char *path,
gboolean is_detached_meta,
gboolean object_is_stored,
const OstreeCollectionRef *ref);
static gboolean
matches_pull_dir (const char *current_file,
@@ -604,18 +614,19 @@ validate_bareuseronly_mode (OtPullData *pull_data,
return TRUE;
}
/* Import a single content object in the case where
* we have pull_data->remote_repo_local.
/* Synchronously import a single content object; this is used async for content,
* or synchronously for metadata. @src_repo is either
* pull_data->remote_repo_local or one of pull_data->localcache_repos.
*
* One important special case here is handling the
* OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES flag.
*/
static gboolean
import_one_local_content_object (OtPullData *pull_data,
OstreeRepo *src_repo,
const char *checksum,
GCancellable *cancellable,
GError **error)
import_one_local_content_object_sync (OtPullData *pull_data,
OstreeRepo *src_repo,
const char *checksum,
GCancellable *cancellable,
GError **error)
{
const gboolean trusted = !pull_data->is_untrusted;
if (trusted && !pull_data->is_bareuseronly_files)
@@ -664,6 +675,83 @@ import_one_local_content_object (OtPullData *pull_data,
return TRUE;
}
typedef struct {
OtPullData *pull_data;
OstreeRepo *src_repo;
char checksum[OSTREE_SHA256_STRING_LEN+1];
} ImportLocalAsyncData;
static void
async_import_in_thread (GTask *task,
gpointer source,
gpointer task_data,
GCancellable *cancellable)
{
ImportLocalAsyncData *iataskdata = task_data;
g_autoptr(GError) local_error = NULL;
if (!import_one_local_content_object_sync (iataskdata->pull_data,
iataskdata->src_repo,
iataskdata->checksum,
cancellable,
&local_error))
g_task_return_error (task, g_steal_pointer (&local_error));
else
g_task_return_boolean (task, TRUE);
}
/* Start an async import of a single object; currently used for content objects.
* @src_repo is from pull_data->remote_repo_local or
* pull_data->localcache_repos.
*
* One important special case here is handling the
* OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES flag.
*/
static void
async_import_one_local_content_object (OtPullData *pull_data,
OstreeRepo *src_repo,
const char *checksum,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
ImportLocalAsyncData *iataskdata = g_new0 (ImportLocalAsyncData, 1);
iataskdata->pull_data = pull_data;
iataskdata->src_repo = src_repo;
memcpy (iataskdata->checksum, checksum, OSTREE_SHA256_STRING_LEN);
g_autoptr(GTask) task = g_task_new (pull_data->repo, cancellable, callback, user_data);
g_task_set_source_tag (task, async_import_one_local_content_object);
g_task_set_task_data (task, iataskdata, g_free);
pull_data->n_outstanding_content_write_requests++;
g_task_run_in_thread (task, async_import_in_thread);
}
static gboolean
async_import_one_local_content_object_finish (OtPullData *pull_data,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, pull_data->repo), FALSE);
return g_task_propagate_boolean ((GTask*)result, error);
}
static void
on_local_object_imported (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
OtPullData *pull_data = user_data;
g_autoptr(GError) local_error = NULL;
GError **error = &local_error;
if (!async_import_one_local_content_object_finish (pull_data, result, error))
goto out;
out:
g_assert_cmpint (pull_data->n_outstanding_content_write_requests, >, 0);
pull_data->n_outstanding_content_write_requests--;
check_outstanding_requests_handle_error (pull_data, &local_error);
}
static gboolean
scan_dirtree_object (OtPullData *pull_data,
const char *checksum,
@@ -714,10 +802,11 @@ scan_dirtree_object (OtPullData *pull_data,
/* Is this a local repo? */
if (pull_data->remote_repo_local)
{
if (!import_one_local_content_object (pull_data, pull_data->remote_repo_local,
file_checksum, cancellable, error))
return FALSE;
async_import_one_local_content_object (pull_data, pull_data->remote_repo_local,
file_checksum, cancellable,
on_local_object_imported,
pull_data);
g_hash_table_add (pull_data->requested_content, g_steal_pointer (&file_checksum));
/* Note early loop continue */
continue;
}
@@ -736,9 +825,9 @@ scan_dirtree_object (OtPullData *pull_data,
return FALSE;
if (!localcache_repo_has_obj)
continue;
if (!import_one_local_content_object (pull_data, localcache_repo, file_checksum,
cancellable, error))
return FALSE;
async_import_one_local_content_object (pull_data, localcache_repo, file_checksum, cancellable,
on_local_object_imported, pull_data);
g_hash_table_add (pull_data->requested_content, g_steal_pointer (&file_checksum));
did_import_from_cache_repo = TRUE;
pull_data->n_fetched_localcache_content++;
break;
@@ -749,7 +838,7 @@ scan_dirtree_object (OtPullData *pull_data,
/* Not available locally, queue a HTTP request */
g_hash_table_add (pull_data->requested_content, file_checksum);
enqueue_one_object_request (pull_data, file_checksum, OSTREE_OBJECT_TYPE_FILE, path, FALSE, FALSE);
enqueue_one_object_request (pull_data, file_checksum, OSTREE_OBJECT_TYPE_FILE, path, FALSE, FALSE, NULL);
file_checksum = NULL; /* Transfer ownership */
}
@@ -779,14 +868,15 @@ scan_dirtree_object (OtPullData *pull_data,
g_autofree char *subpath = g_strconcat (path, dirname, "/", NULL);
queue_scan_one_metadata_object_c (pull_data, tree_csum_bytes,
OSTREE_OBJECT_TYPE_DIR_TREE, subpath, recursion_depth + 1);
OSTREE_OBJECT_TYPE_DIR_TREE, subpath, recursion_depth + 1, NULL);
queue_scan_one_metadata_object_c (pull_data, meta_csum_bytes,
OSTREE_OBJECT_TYPE_DIR_META, subpath, recursion_depth + 1);
OSTREE_OBJECT_TYPE_DIR_META, subpath, recursion_depth + 1, NULL);
}
return TRUE;
}
/* Given a @ref, fetch its contents (should be a SHA256 ASCII string) */
static gboolean
fetch_ref_contents (OtPullData *pull_data,
const char *main_collection_id,
@@ -812,7 +902,7 @@ fetch_ref_contents (OtPullData *pull_data,
g_strchomp (ret_contents);
if (!ostree_validate_checksum_string (ret_contents, error))
return FALSE;
return glnx_prefix_error (error, "Fetching %s", filename);
ot_transfer_out_value (out_contents, &ret_contents);
return TRUE;
@@ -883,6 +973,8 @@ fetch_object_data_free (FetchObjectData *fetch_data)
{
g_variant_unref (fetch_data->object);
g_free (fetch_data->path);
if (fetch_data->requested_ref)
ostree_collection_ref_free (fetch_data->requested_ref);
g_free (fetch_data);
}
@@ -1062,7 +1154,7 @@ on_metadata_written (GObject *object,
goto out;
}
queue_scan_one_metadata_object_c (pull_data, csum, objtype, fetch_data->path, 0);
queue_scan_one_metadata_object_c (pull_data, csum, objtype, fetch_data->path, 0, fetch_data->requested_ref);
out:
pull_data->n_outstanding_metadata_write_requests--;
@@ -1108,9 +1200,9 @@ meta_fetch_on_complete (GObject *object,
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (checksum));
if (!fetch_data->object_is_stored)
enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE);
enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE, fetch_data->requested_ref);
else
queue_scan_one_metadata_object (pull_data, checksum, objtype, fetch_data->path, 0);
queue_scan_one_metadata_object (pull_data, checksum, objtype, fetch_data->path, 0, fetch_data->requested_ref);
}
/* When traversing parents, do not fail on a missing commit.
@@ -1125,7 +1217,7 @@ meta_fetch_on_complete (GObject *object,
if (pull_data->has_tombstone_commits)
{
enqueue_one_object_request (pull_data, checksum, OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT,
fetch_data->path, FALSE, FALSE);
fetch_data->path, FALSE, FALSE, NULL);
}
}
}
@@ -1137,12 +1229,8 @@ meta_fetch_on_complete (GObject *object,
if (objtype == OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT)
goto out;
fd = openat (_ostree_fetcher_get_dfd (fetcher), tmp_unlinker.path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
{
glnx_set_error_from_errno (error);
goto out;
}
if (!glnx_openat_rdonly (_ostree_fetcher_get_dfd (fetcher), tmp_unlinker.path, TRUE, &fd, error))
goto out;
/* Now delete it, keeping the fd open as the last reference; see comment in
* corresponding content fetch path.
@@ -1162,9 +1250,9 @@ meta_fetch_on_complete (GObject *object,
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (checksum));
if (!fetch_data->object_is_stored)
enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE);
enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE, fetch_data->requested_ref);
else
queue_scan_one_metadata_object (pull_data, checksum, objtype, fetch_data->path, 0);
queue_scan_one_metadata_object (pull_data, checksum, objtype, fetch_data->path, 0, fetch_data->requested_ref);
}
else
{
@@ -1250,12 +1338,8 @@ static_deltapart_fetch_on_complete (GObject *object,
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);
if (fd == -1)
{
glnx_set_error_from_errno (error);
goto out;
}
if (!glnx_openat_rdonly (_ostree_fetcher_get_dfd (fetcher), temp_path, TRUE, &fd, error))
goto out;
/* From here on, if we fail to apply the delta, we'll re-fetch it */
if (unlinkat (_ostree_fetcher_get_dfd (fetcher), temp_path, 0) < 0)
@@ -1295,11 +1379,10 @@ process_verify_result (OtPullData *pull_data,
OstreeGpgVerifyResult *result,
GError **error)
{
const char *error_prefix = glnx_strjoina ("Commit ", checksum);
GLNX_AUTO_PREFIX_ERROR(error_prefix, error);
if (result == NULL)
{
g_prefix_error (error, "Commit %s: ", checksum);
return FALSE;
}
return FALSE;
/* Allow callers to output the results immediately. */
g_signal_emit_by_name (pull_data->repo,
@@ -1307,10 +1390,8 @@ process_verify_result (OtPullData *pull_data,
checksum, result);
if (!ostree_gpg_verify_result_require_valid_signature (result, error))
{
g_prefix_error (error, "Commit %s: ", checksum);
return FALSE;
}
return FALSE;
return TRUE;
}
@@ -1357,12 +1438,151 @@ commitstate_is_partial (OtPullData *pull_data,
|| (commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) > 0;
}
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
/* Reads the collection-id of a given remote from the repo
* configuration.
*/
static char *
get_real_remote_repo_collection_id (OstreeRepo *repo,
const gchar *remote_name)
{
g_autofree gchar *remote_collection_id = NULL;
if (!ostree_repo_get_remote_option (repo, remote_name, "collection-id", NULL,
&remote_collection_id, NULL) ||
(remote_collection_id == NULL) ||
(remote_collection_id[0] == '\0'))
return NULL;
return g_steal_pointer (&remote_collection_id);
}
/* Reads the collection-id of the remote repo. Where it will be read
* from depends on whether we pull from the "local" remote repo (the
* "file://" URL) or "remote" remote repo (likely the "http(s)://"
* URL).
*/
static char *
get_remote_repo_collection_id (OtPullData *pull_data)
{
if (pull_data->remote_repo_local != NULL)
{
const char *remote_collection_id =
ostree_repo_get_collection_id (pull_data->remote_repo_local);
if ((remote_collection_id == NULL) ||
(remote_collection_id[0] == '\0'))
return NULL;
return g_strdup (remote_collection_id);
}
return get_real_remote_repo_collection_id (pull_data->repo,
pull_data->remote_name);
}
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
/* Verify the ref and collection bindings.
*
* The ref binding is verified only if it exists. But if we have the
* collection ID specified in the remote configuration then the ref
* binding must exist, otherwise the verification will fail. Parts of
* the verification can be skipped by passing NULL to the requested_ref
* parameter (in case we requested a checksum directly, without looking it up
* from a ref).
*
* The collection binding is verified only when we have collection ID
* specified in the remote configuration. If it is specified, then the
* binding must exist and must be equal to the remote repository
* collection ID.
*/
static gboolean
scan_commit_object (OtPullData *pull_data,
const char *checksum,
guint recursion_depth,
GCancellable *cancellable,
GError **error)
verify_bindings (OtPullData *pull_data,
GVariant *commit,
const OstreeCollectionRef *requested_ref,
GError **error)
{
g_autofree char *remote_collection_id = NULL;
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
remote_collection_id = get_remote_repo_collection_id (pull_data);
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
g_autoptr(GVariant) metadata = g_variant_get_child_value (commit, 0);
g_autofree const char **refs = NULL;
if (!g_variant_lookup (metadata,
OSTREE_COMMIT_META_KEY_REF_BINDING,
"^a&s",
&refs))
{
/* Early return here - if the remote collection ID is NULL, then
* we certainly will not verify the collection binding in the
* commit.
*/
if (remote_collection_id == NULL)
return TRUE;
return glnx_throw (error,
"expected commit metadata to have ref "
"binding information, found none");
}
if (requested_ref != NULL)
{
if (!g_strv_contains ((const char *const *) refs, requested_ref->ref_name))
{
g_autoptr(GString) refs_dump = g_string_new (NULL);
const char *refs_str;
if (refs != NULL && (*refs) != NULL)
{
for (const char **iter = refs; *iter != NULL; ++iter)
{
const char *ref = *iter;
if (refs_dump->len > 0)
g_string_append (refs_dump, ", ");
g_string_append_printf (refs_dump, "‘%s’", ref);
}
refs_str = refs_dump->str;
}
else
{
refs_str = "no refs";
}
return glnx_throw (error, "commit has no requested ref ‘%s’ "
"in ref binding metadata (%s)",
requested_ref->ref_name, refs_str);
}
}
if (remote_collection_id != NULL)
{
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
const char *collection_id;
if (!g_variant_lookup (metadata,
OSTREE_COMMIT_META_KEY_COLLECTION_BINDING,
"&s",
&collection_id))
return glnx_throw (error,
"expected commit metadata to have collection ID "
"binding information, found none");
if (!g_str_equal (collection_id, remote_collection_id))
return glnx_throw (error,
"commit has collection ID ‘%s’ in collection binding "
"metadata, while the remote it came from has "
"collection ID ‘%s’",
collection_id, remote_collection_id);
#endif
}
return TRUE;
}
static gboolean
scan_commit_object (OtPullData *pull_data,
const char *checksum,
guint recursion_depth,
const OstreeCollectionRef *ref,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
/* If we found a legacy transaction flag, assume we have to scan.
@@ -1405,6 +1625,15 @@ scan_commit_object (OtPullData *pull_data,
if (!ostree_repo_load_commit (pull_data->repo, checksum, &commit, &commitstate, error))
goto out;
/* If ref is non-NULL then the commit we fetched was requested through the
* branch, otherwise we requested a commit checksum without specifying a branch.
*/
if (!verify_bindings (pull_data, commit, ref, error))
{
g_prefix_error (error, "Commit %s: ", checksum);
goto out;
}
/* If we found a legacy transaction flag, assume all commits are partial */
is_partial = commitstate_is_partial (pull_data, commitstate);
@@ -1421,7 +1650,7 @@ scan_commit_object (OtPullData *pull_data,
{
queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes,
OSTREE_OBJECT_TYPE_COMMIT, NULL,
recursion_depth + 1);
recursion_depth + 1, NULL);
}
else if (parent_csum_bytes != NULL && depth > 0)
{
@@ -1448,7 +1677,8 @@ scan_commit_object (OtPullData *pull_data,
queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes,
OSTREE_OBJECT_TYPE_COMMIT,
NULL,
recursion_depth + 1);
recursion_depth + 1,
NULL);
}
}
@@ -1475,10 +1705,10 @@ scan_commit_object (OtPullData *pull_data,
goto out;
queue_scan_one_metadata_object_c (pull_data, tree_contents_csum_bytes,
OSTREE_OBJECT_TYPE_DIR_TREE, "/", recursion_depth + 1);
OSTREE_OBJECT_TYPE_DIR_TREE, "/", recursion_depth + 1, NULL);
queue_scan_one_metadata_object_c (pull_data, tree_meta_csum_bytes,
OSTREE_OBJECT_TYPE_DIR_META, NULL, recursion_depth + 1);
OSTREE_OBJECT_TYPE_DIR_META, NULL, recursion_depth + 1, NULL);
}
ret = TRUE;
@@ -1487,23 +1717,25 @@ scan_commit_object (OtPullData *pull_data,
}
static void
queue_scan_one_metadata_object (OtPullData *pull_data,
const char *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth)
queue_scan_one_metadata_object (OtPullData *pull_data,
const char *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
const OstreeCollectionRef *ref)
{
guchar buf[OSTREE_SHA256_DIGEST_LEN];
ostree_checksum_inplace_to_bytes (csum, buf);
queue_scan_one_metadata_object_c (pull_data, buf, objtype, path, recursion_depth);
queue_scan_one_metadata_object_c (pull_data, buf, objtype, path, recursion_depth, ref);
}
static void
queue_scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth)
queue_scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
const OstreeCollectionRef *ref)
{
ScanObjectQueueData *scan_data = g_new0 (ScanObjectQueueData, 1);
@@ -1511,19 +1743,21 @@ queue_scan_one_metadata_object_c (OtPullData *pull_data,
scan_data->objtype = objtype;
scan_data->path = g_strdup (path);
scan_data->recursion_depth = recursion_depth;
scan_data->requested_ref = (ref != NULL) ? ostree_collection_ref_dup (ref) : NULL;
g_queue_push_tail (&pull_data->scan_object_queue, scan_data);
ensure_idle_queued (pull_data);
}
static gboolean
scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
GCancellable *cancellable,
GError **error)
scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
const OstreeCollectionRef *ref,
GCancellable *cancellable,
GError **error)
{
g_autofree char *tmp_checksum = ostree_checksum_from_bytes (csum);
g_autoptr(GVariant) object = ostree_object_name_serialize (tmp_checksum, objtype);
@@ -1594,7 +1828,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
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);
enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, do_fetch_detached, FALSE, ref);
}
else if (is_stored && objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
@@ -1602,10 +1836,10 @@ scan_one_metadata_object_c (OtPullData *pull_data,
* detached metadata before scanning it, in case new signatures appear.
* https://github.com/projectatomic/rpm-ostree/issues/630 */
if (!g_hash_table_contains (pull_data->fetched_detached_metadata, tmp_checksum))
enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, TRUE, TRUE);
enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, TRUE, TRUE, ref);
else
{
if (!scan_commit_object (pull_data, tmp_checksum, recursion_depth,
if (!scan_commit_object (pull_data, tmp_checksum, recursion_depth, ref,
pull_data->cancellable, error))
return FALSE;
@@ -1627,12 +1861,13 @@ scan_one_metadata_object_c (OtPullData *pull_data,
}
static void
enqueue_one_object_request (OtPullData *pull_data,
const char *checksum,
OstreeObjectType objtype,
const char *path,
gboolean is_detached_meta,
gboolean object_is_stored)
enqueue_one_object_request (OtPullData *pull_data,
const char *checksum,
OstreeObjectType objtype,
const char *path,
gboolean is_detached_meta,
gboolean object_is_stored,
const OstreeCollectionRef *ref)
{
gboolean is_meta;
FetchObjectData *fetch_data;
@@ -1645,6 +1880,7 @@ enqueue_one_object_request (OtPullData *pull_data,
fetch_data->path = g_strdup (path);
fetch_data->is_detached_meta = is_detached_meta;
fetch_data->object_is_stored = object_is_stored;
fetch_data->requested_ref = (ref != NULL) ? ostree_collection_ref_dup (ref) : NULL;
if (is_meta)
pull_data->n_requested_metadata++;
@@ -1699,6 +1935,7 @@ start_fetch (OtPullData *pull_data,
else
pull_data->n_outstanding_content_fetches++;
OstreeFetcherRequestFlags flags = 0;
/* Override the path if we're trying to fetch the .commitmeta file first */
if (fetch->is_detached_meta)
{
@@ -1706,6 +1943,7 @@ start_fetch (OtPullData *pull_data,
_ostree_loose_path (buf, expected_checksum, OSTREE_OBJECT_TYPE_COMMIT_META, pull_data->remote_mode);
obj_subpath = g_build_filename ("objects", buf, NULL);
mirrorlist = pull_data->meta_mirrorlist;
flags |= OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT;
}
else
{
@@ -1725,7 +1963,7 @@ start_fetch (OtPullData *pull_data,
expected_max_size = 0;
_ostree_fetcher_request_to_tmpfile (pull_data->fetcher, mirrorlist,
obj_subpath, expected_max_size,
obj_subpath, flags, expected_max_size,
is_meta ? OSTREE_REPO_PULL_METADATA_PRIORITY
: OSTREE_REPO_PULL_CONTENT_PRIORITY,
pull_data->cancellable,
@@ -1749,7 +1987,7 @@ load_remote_repo_config (OtPullData *pull_data,
g_autoptr(GKeyFile) ret_keyfile = g_key_file_new ();
if (!g_key_file_load_from_data (ret_keyfile, contents, strlen (contents),
0, error))
return FALSE;
return glnx_prefix_error (error, "Parsing config");
ot_transfer_out_value (out_keyfile, &ret_keyfile);
return TRUE;
@@ -1812,7 +2050,7 @@ process_one_static_delta_fallback (OtPullData *pull_data,
* for it as logically part of the delta fetch.
*/
g_hash_table_add (pull_data->requested_fallback_content, g_strdup (checksum));
enqueue_one_object_request (pull_data, checksum, OSTREE_OBJECT_TYPE_FILE, NULL, FALSE, FALSE);
enqueue_one_object_request (pull_data, checksum, OSTREE_OBJECT_TYPE_FILE, NULL, FALSE, FALSE, NULL);
checksum = NULL; /* We transferred ownership to the requested_content hash */
}
}
@@ -1830,7 +2068,7 @@ start_fetch_deltapart (OtPullData *pull_data,
g_assert_cmpint (pull_data->n_outstanding_deltapart_fetches, <=, _OSTREE_MAX_OUTSTANDING_DELTAPART_REQUESTS);
_ostree_fetcher_request_to_tmpfile (pull_data->fetcher,
pull_data->content_mirrorlist,
deltapart_path, fetch->size,
deltapart_path, 0, fetch->size,
OSTREE_FETCHER_DEFAULT_PRIORITY,
pull_data->cancellable,
static_deltapart_fetch_on_complete,
@@ -1838,12 +2076,13 @@ start_fetch_deltapart (OtPullData *pull_data,
}
static gboolean
process_one_static_delta (OtPullData *pull_data,
const char *from_revision,
const char *to_revision,
GVariant *delta_superblock,
GCancellable *cancellable,
GError **error)
process_one_static_delta (OtPullData *pull_data,
const char *from_revision,
const char *to_revision,
GVariant *delta_superblock,
const OstreeCollectionRef *ref,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
gboolean delta_byteswap;
@@ -1918,6 +2157,7 @@ process_one_static_delta (OtPullData *pull_data,
fetch_data->object = ostree_object_name_serialize (to_checksum, OSTREE_OBJECT_TYPE_COMMIT);
fetch_data->is_detached_meta = FALSE;
fetch_data->object_is_stored = FALSE;
fetch_data->requested_ref = (ref != NULL) ? ostree_collection_ref_dup (ref) : NULL;
ostree_repo_write_metadata_async (pull_data->repo, OSTREE_OBJECT_TYPE_COMMIT, to_checksum,
to_commit,
@@ -2142,6 +2382,7 @@ typedef struct {
OtPullData *pull_data;
char *from_revision;
char *to_revision;
OstreeCollectionRef *requested_ref; /* (nullable) */
} FetchDeltaSuperData;
static void
@@ -2183,7 +2424,7 @@ on_superblock_fetched (GObject *src,
goto out;
}
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, fdata->requested_ref);
}
else
{
@@ -2224,7 +2465,7 @@ on_superblock_fetched (GObject *src,
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,
if (!process_one_static_delta (pull_data, from_revision, to_revision, delta_superblock, fdata->requested_ref,
pull_data->cancellable, error))
goto out;
}
@@ -2232,6 +2473,8 @@ on_superblock_fetched (GObject *src,
out:
g_free (fdata->from_revision);
g_free (fdata->to_revision);
if (fdata->requested_ref)
ostree_collection_ref_free (fdata->requested_ref);
g_free (fdata);
g_assert (pull_data->n_outstanding_metadata_fetches > 0);
pull_data->n_outstanding_metadata_fetches--;
@@ -2446,16 +2689,16 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self,
}
{
g_autofree char *jar_path = NULL;
g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt",
remote_name);
g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name);
/* TODO; port away from this; a bit hard since both libsoup and libcurl
* expect a file. Doing ot_fdrel_to_gfile() works for now though.
*/
GFile*repo_path = ostree_repo_get_path (self);
g_autofree char *jar_path =
g_build_filename (gs_file_get_path_cached (repo_path), cookie_file, NULL);
jar_path = g_build_filename (gs_file_get_path_cached (self->repodir), cookie_file,
NULL);
if (g_file_test(jar_path, G_FILE_TEST_IS_REGULAR))
if (g_file_test (jar_path, G_FILE_TEST_IS_REGULAR))
_ostree_fetcher_set_cookie_jar (fetcher, jar_path);
}
success = TRUE;
@@ -2507,7 +2750,8 @@ _ostree_preload_metadata_file (OstreeRepo *self,
else
{
ret = _ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist,
filename, FALSE, TRUE,
filename,
OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT,
out_bytes,
OSTREE_MAX_METADATA_SIZE,
cancellable, error);
@@ -2774,7 +3018,8 @@ reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **e
static void
initiate_delta_request (OtPullData *pull_data,
const char *from_revision,
const char *to_revision)
const char *to_revision,
const OstreeCollectionRef *ref)
{
g_autofree char *delta_name =
_ostree_get_relative_static_delta_superblock_path (from_revision, to_revision);
@@ -2782,6 +3027,7 @@ initiate_delta_request (OtPullData *pull_data,
fdata->pull_data = pull_data;
fdata->from_revision = g_strdup (from_revision);
fdata->to_revision = g_strdup (to_revision);
fdata->requested_ref = (ref != NULL) ? ostree_collection_ref_dup (ref) : NULL;
_ostree_fetcher_request_to_membuf (pull_data->fetcher,
pull_data->content_mirrorlist,
@@ -2815,7 +3061,7 @@ initiate_request (OtPullData *pull_data,
/* Are deltas disabled? OK, just start an object fetch and be done */
if (pull_data->disable_static_deltas)
{
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref);
return TRUE;
}
@@ -2831,16 +3077,16 @@ initiate_request (OtPullData *pull_data,
return FALSE;
if (delta_from_revision) /* Did we find a delta FROM commit? */
initiate_delta_request (pull_data, delta_from_revision, to_revision);
initiate_delta_request (pull_data, delta_from_revision, to_revision, ref);
else if (have_scratch_delta) /* No delta FROM, do we have a scratch? */
initiate_delta_request (pull_data, NULL, to_revision);
initiate_delta_request (pull_data, NULL, to_revision, ref);
else if (pull_data->require_static_deltas) /* No deltas found; are they required? */
{
set_required_deltas_error (error, (ref != NULL) ? ref->ref_name : "", to_revision);
return FALSE;
}
else /* No deltas, fall back to object fetches. */
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref);
}
else if (ref != NULL)
{
@@ -2874,14 +3120,14 @@ initiate_request (OtPullData *pull_data,
/* This is similar to the below, except we *might* use the previous
* commit, or we might do a scratch delta first.
*/
initiate_delta_request (pull_data, delta_from_revision ?: NULL, to_revision);
initiate_delta_request (pull_data, delta_from_revision ?: NULL, to_revision, ref);
}
else
{
/* Legacy path without a summary file - let's try a scratch delta, if that
* doesn't work, it'll drop down to object requests.
*/
initiate_delta_request (pull_data, NULL, to_revision);
initiate_delta_request (pull_data, NULL, to_revision, NULL);
}
return TRUE;
@@ -3342,7 +3588,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
{
if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher,
pull_data->meta_mirrorlist,
"summary.sig", FALSE, TRUE,
"summary.sig", OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT,
&bytes_sig,
OSTREE_MAX_METADATA_SIZE,
cancellable, error))
@@ -3366,7 +3612,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
{
if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher,
pull_data->meta_mirrorlist,
"summary", FALSE, TRUE,
"summary", OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT,
&bytes_summary,
OSTREE_MAX_METADATA_SIZE,
cancellable, error))
@@ -4604,8 +4850,7 @@ find_remotes_cb (GObject *obj,
if (!_ostree_fetcher_mirrored_request_to_membuf (fetcher,
mirrorlist,
commit_filename,
FALSE, /* don’t add trailing nul */
TRUE, /* return NULL on ENOENT */
OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT,
&commit_bytes,
0, /* no maximum size */
cancellable,
@@ -5097,9 +5342,8 @@ check_remote_matches_collection_id (OstreeRepo *repo,
{
g_autofree gchar *remote_collection_id = NULL;
if (!ostree_repo_get_remote_option (repo, remote_name, "collection-id", NULL,
&remote_collection_id, NULL) ||
remote_collection_id == NULL)
remote_collection_id = get_real_remote_repo_collection_id (repo, remote_name);
if (remote_collection_id == NULL)
return FALSE;
return g_str_equal (remote_collection_id, collection_id);
@@ -50,7 +50,7 @@ typedef struct {
GVariant *mode_dict;
GVariant *xattr_dict;
gboolean object_start;
gboolean caught_error;
GError **async_error;
@@ -68,12 +68,12 @@ typedef struct {
guint32 gid;
guint32 mode;
GVariant *xattrs;
const guint8 *output_target;
const guint8 *input_target_csum;
const guint8 *payload_data;
guint64 payload_size;
guint64 payload_size;
} StaticDeltaExecutionState;
typedef struct {
@@ -127,26 +127,21 @@ open_output_target (StaticDeltaExecutionState *state,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
guint8 *objcsum;
g_assert (state->checksums != NULL);
g_assert (state->output_target == NULL);
g_assert (state->checksum_index < state->n_checksums);
objcsum = (guint8*)state->checksums + (state->checksum_index * OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN);
guint8 *objcsum = (guint8*)state->checksums + (state->checksum_index * OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN);
if (G_UNLIKELY(!ostree_validate_structureof_objtype (*objcsum, error)))
goto out;
return FALSE;
state->output_objtype = (OstreeObjectType) *objcsum;
state->output_target = objcsum + 1;
ostree_checksum_inplace_from_bytes (state->output_target, state->checksum);
ret = TRUE;
out:
return ret;
return TRUE;
}
static guint
@@ -353,7 +348,7 @@ _ostree_static_delta_part_execute_async (OstreeRepo *repo,
gboolean
_ostree_static_delta_part_execute_finish (OstreeRepo *repo,
GAsyncResult *result,
GError **error)
GError **error)
{
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
@@ -386,7 +381,7 @@ content_out_write (OstreeRepo *repo,
StaticDeltaExecutionState *state,
const guint8* buf,
gsize len,
GCancellable *cancellable,
GCancellable *cancellable,
GError **error)
{
gsize bytes_written;
@@ -407,21 +402,19 @@ content_out_write (OstreeRepo *repo,
static gboolean
do_content_open_generic (OstreeRepo *repo,
StaticDeltaExecutionState *state,
GCancellable *cancellable,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GVariant) modev = NULL;
guint64 mode_offset;
guint64 xattr_offset;
guint32 uid, gid, mode;
if (!read_varuint64 (state, &mode_offset, error))
goto out;
return FALSE;
if (!read_varuint64 (state, &xattr_offset, error))
goto out;
return FALSE;
modev = g_variant_get_child_value (state->mode_dict, mode_offset);
g_autoptr(GVariant) modev = g_variant_get_child_value (state->mode_dict, mode_offset);
guint32 uid, gid, mode;
g_variant_get (modev, "(uuu)", &uid, &gid, &mode);
state->uid = GUINT32_FROM_BE (uid);
state->gid = GUINT32_FROM_BE (gid);
@@ -429,9 +422,7 @@ do_content_open_generic (OstreeRepo *repo,
state->xattrs = g_variant_get_child_value (state->xattr_dict, xattr_offset);
ret = TRUE;
out:
return ret;
return TRUE;
}
struct bzpatch_opaque_s
@@ -460,35 +451,29 @@ dispatch_bspatch (OstreeRepo *repo,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
guint64 offset, length;
g_autoptr(GMappedFile) input_mfile = NULL;
g_autofree guchar *buf = NULL;
struct bspatch_stream stream;
struct bzpatch_opaque_s opaque;
if (!read_varuint64 (state, &offset, error))
goto out;
return FALSE;
if (!read_varuint64 (state, &length, error))
goto out;
return FALSE;
if (state->stats_only)
{
ret = TRUE;
goto out;
}
return TRUE; /* Early return */
if (!state->have_obj)
{
input_mfile = g_mapped_file_new_from_fd (state->read_source_fd, FALSE, error);
g_autoptr(GMappedFile) input_mfile = g_mapped_file_new_from_fd (state->read_source_fd, FALSE, error);
if (!input_mfile)
goto out;
return FALSE;
buf = g_malloc0 (state->content_size);
g_autofree guchar *buf = g_malloc0 (state->content_size);
struct bzpatch_opaque_s opaque;
opaque.state = state;
opaque.offset = offset;
opaque.length = length;
struct bspatch_stream stream;
stream.read = bspatch_read;
stream.opaque = &opaque;
if (bspatch ((const guint8*)g_mapped_file_get_contents (input_mfile),
@@ -496,16 +481,14 @@ dispatch_bspatch (OstreeRepo *repo,
buf,
state->content_size,
&stream) < 0)
goto out;
return FALSE;
if (!content_out_write (repo, state, buf, state->content_size,
cancellable, error))
goto out;
return FALSE;
}
ret = TRUE;
out:
return ret;
return TRUE;
}
/* Before, we had a distinction between "trusted" and "untrusted" deltas
@@ -534,7 +517,7 @@ handle_untrusted_content_checksum (OstreeRepo *repo,
static gboolean
dispatch_open_splice_and_close (OstreeRepo *repo,
StaticDeltaExecutionState *state,
GCancellable *cancellable,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
@@ -560,7 +543,7 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
ret = TRUE;
goto out;
}
metadata = g_variant_new_from_data (ostree_metadata_variant_type (state->output_objtype),
state->payload_data + offset, length, TRUE, NULL, NULL);
@@ -581,7 +564,7 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
guint64 objlen;
g_autoptr(GInputStream) object_input = NULL;
g_autoptr(GInputStream) memin = NULL;
if (!do_content_open_generic (repo, state, cancellable, error))
goto out;
@@ -591,7 +574,7 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
goto out;
if (!validate_ofs (state, content_offset, state->content_size, error))
goto out;
if (state->stats_only)
{
ret = TRUE;
@@ -599,7 +582,7 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
}
/* Fast path for regular files to bare repositories */
if (S_ISREG (state->mode) &&
if (S_ISREG (state->mode) &&
(repo->mode == OSTREE_REPO_MODE_BARE ||
repo->mode == OSTREE_REPO_MODE_BARE_USER))
{
@@ -676,10 +659,10 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
static gboolean
dispatch_open (OstreeRepo *repo,
StaticDeltaExecutionState *state,
GCancellable *cancellable,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GLNX_AUTO_PREFIX_ERROR("opcode open", error);
g_assert (state->output_target == NULL);
/* FIXME - lift this restriction */
@@ -689,71 +672,58 @@ dispatch_open (OstreeRepo *repo,
repo->mode == OSTREE_REPO_MODE_BARE_USER ||
repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY);
}
if (!open_output_target (state, cancellable, error))
goto out;
return FALSE;
if (!do_content_open_generic (repo, state, cancellable, error))
goto out;
return FALSE;
if (!read_varuint64 (state, &state->content_size, error))
goto out;
return FALSE;
if (state->stats_only)
{
ret = TRUE;
goto out;
}
return TRUE; /* Early return */
if (!_ostree_repo_open_content_bare (repo, state->checksum,
state->content_size,
&state->tmpf,
&state->have_obj,
cancellable, error))
goto out;
return FALSE;
if (!state->have_obj)
state->content_out = g_unix_output_stream_new (state->tmpf.fd, FALSE);
if (!handle_untrusted_content_checksum (repo, state, cancellable, error))
goto out;
return FALSE;
ret = TRUE;
out:
if (!ret)
g_prefix_error (error, "opcode open: ");
return ret;
return TRUE;
}
static gboolean
dispatch_write (OstreeRepo *repo,
StaticDeltaExecutionState *state,
GCancellable *cancellable,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GLNX_AUTO_PREFIX_ERROR("opcode open-splice-and-close", error);
guint64 content_size;
guint64 content_offset;
if (!read_varuint64 (state, &content_size, error))
goto out;
return FALSE;
if (!read_varuint64 (state, &content_offset, error))
goto out;
return FALSE;
if (state->stats_only)
{
ret = TRUE;
goto out;
}
return TRUE; /* Early return */
if (!state->have_obj)
{
if (state->read_source_fd != -1)
{
if (lseek (state->read_source_fd, content_offset, SEEK_SET) == -1)
{
glnx_set_error_from_errno (error);
goto out;
}
return glnx_throw_errno_prefix (error, "lseek");
while (content_size > 0)
{
char buf[4096];
@@ -763,49 +733,38 @@ dispatch_write (OstreeRepo *repo,
bytes_read = read (state->read_source_fd, buf, MIN(sizeof(buf), content_size));
while (G_UNLIKELY (bytes_read == -1 && errno == EINTR));
if (bytes_read == -1)
{
glnx_set_error_from_errno (error);
goto out;
}
return glnx_throw_errno_prefix (error, "read");
if (G_UNLIKELY (bytes_read == 0))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Unexpected EOF reading object %s", state->read_source_object);
goto out;
}
return glnx_throw (error, "Unexpected EOF reading object %s", state->read_source_object);
if (!content_out_write (repo, state, (guint8*)buf, bytes_read,
cancellable, error))
goto out;
return FALSE;
content_size -= bytes_read;
}
}
else
{
if (!validate_ofs (state, content_offset, content_size, error))
goto out;
return FALSE;
if (!content_out_write (repo, state, state->payload_data + content_offset, content_size,
cancellable, error))
goto out;
return FALSE;
}
}
ret = TRUE;
out:
if (!ret)
g_prefix_error (error, "opcode open-splice-and-close: ");
return ret;
return TRUE;
}
static gboolean
dispatch_set_read_source (OstreeRepo *repo,
StaticDeltaExecutionState *state,
GCancellable *cancellable,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GLNX_AUTO_PREFIX_ERROR("opcode set-read-source", error);
guint64 source_offset;
if (state->read_source_fd != -1)
@@ -815,15 +774,12 @@ dispatch_set_read_source (OstreeRepo *repo,
}
if (!read_varuint64 (state, &source_offset, error))
goto out;
return FALSE;
if (!validate_ofs (state, source_offset, 32, error))
goto out;
return FALSE;
if (state->stats_only)
{
ret = TRUE;
goto out;
}
return TRUE; /* Early return */
g_free (state->read_source_object);
state->read_source_object = ostree_checksum_from_bytes (state->payload_data + source_offset);
@@ -832,28 +788,21 @@ dispatch_set_read_source (OstreeRepo *repo,
&state->read_source_fd,
NULL, NULL, NULL,
cancellable, error))
goto out;
return FALSE;
ret = TRUE;
out:
if (!ret)
g_prefix_error (error, "opcode set-read-source: ");
return ret;
return TRUE;
}
static gboolean
dispatch_unset_read_source (OstreeRepo *repo,
StaticDeltaExecutionState *state,
GCancellable *cancellable,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GLNX_AUTO_PREFIX_ERROR("opcode unset-read-source", error);
if (state->stats_only)
{
ret = TRUE;
goto out;
}
return TRUE; /* Early return */
if (state->read_source_fd != -1)
{
@@ -862,60 +811,48 @@ dispatch_unset_read_source (OstreeRepo *repo,
}
g_clear_pointer (&state->read_source_object, g_free);
ret = TRUE;
out:
if (!ret)
g_prefix_error (error, "opcode unset-read-source: ");
return ret;
return TRUE;
}
static gboolean
dispatch_close (OstreeRepo *repo,
StaticDeltaExecutionState *state,
GCancellable *cancellable,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GLNX_AUTO_PREFIX_ERROR("opcode open-splice-and-close", error);
if (state->content_out)
{
if (!g_output_stream_flush (state->content_out, cancellable, error))
goto out;
return FALSE;
if (state->content_checksum)
{
const char *actual_checksum = g_checksum_get_string (state->content_checksum);
if (strcmp (actual_checksum, state->checksum) != 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted object %s (actual checksum is %s)",
state->checksum, actual_checksum);
goto out;
}
return glnx_throw (error, "Corrupted object %s (actual checksum is %s)",
state->checksum, actual_checksum);
}
if (!_ostree_repo_commit_trusted_content_bare (repo, state->checksum, &state->tmpf,
state->uid, state->gid, state->mode,
state->xattrs,
cancellable, error))
goto out;
return FALSE;
g_clear_object (&state->content_out);
}
if (!dispatch_unset_read_source (repo, state, cancellable, error))
goto out;
return FALSE;
g_clear_pointer (&state->xattrs, g_variant_unref);
g_clear_pointer (&state->content_checksum, g_checksum_free);
state->checksum_index++;
state->output_target = NULL;
ret = TRUE;
out:
if (!ret)
g_prefix_error (error, "opcode open-splice-and-close: ");
return ret;
return TRUE;
}
+106 -35
View File
@@ -32,6 +32,7 @@
#include <glnx-console.h>
#include "ostree-core-private.h"
#include "ostree-sysroot-private.h"
#include "ostree-remote-private.h"
#include "ostree-repo-private.h"
#include "ostree-repo-file.h"
@@ -125,6 +126,10 @@ G_DEFINE_TYPE (OstreeRepo, ostree_repo, G_TYPE_OBJECT)
#define SYSCONF_REMOTES SHORTENED_SYSCONFDIR "/ostree/remotes.d"
static GFile *
get_remotes_d_dir (OstreeRepo *self,
GFile *sysroot);
OstreeRemote *
_ostree_repo_get_remote (OstreeRepo *self,
const char *name,
@@ -467,6 +472,7 @@ ostree_repo_finalize (GObject *object)
if (self->uncompressed_objects_dir_fd != -1)
(void) close (self->uncompressed_objects_dir_fd);
g_clear_object (&self->sysroot_dir);
g_weak_ref_clear (&self->sysroot);
g_free (self->remotes_config_dir);
if (self->loose_object_devino_hash)
@@ -547,10 +553,6 @@ ostree_repo_constructed (GObject *object)
g_assert (self->repodir != NULL);
/* Ensure the "sysroot-path" property is set. */
if (self->sysroot_dir == NULL)
self->sysroot_dir = g_object_ref (_ostree_get_default_sysroot_path ());
G_OBJECT_CLASS (ostree_repo_parent_class)->constructed (object);
}
@@ -645,6 +647,7 @@ ostree_repo_init (OstreeRepo *self)
self->objects_dir_fd = -1;
self->uncompressed_objects_dir_fd = -1;
self->commit_stagedir_lock = empty_lockfile;
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_UNKNOWN;
}
/**
@@ -728,18 +731,20 @@ ostree_repo_new_default (void)
gboolean
ostree_repo_is_system (OstreeRepo *repo)
{
g_autoptr(GFile) default_repo_path = NULL;
g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
/* If we were created via ostree_sysroot_get_repo(), we know the answer is yes
* without having to compare file paths.
*/
if (repo->is_system)
if (repo->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT ||
repo->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE)
return TRUE;
default_repo_path = get_default_repo_path (repo->sysroot_dir);
/* No sysroot_dir set? Not a system repo then. */
if (!repo->sysroot_dir)
return FALSE;
g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir);
return g_file_equal (repo->repodir, default_repo_path);
}
@@ -916,24 +921,11 @@ impl_repo_remote_add (OstreeRepo *self,
remote = ostree_remote_new (name);
/* The OstreeRepo maintains its own internal system root path,
* so we need to not only check if a "sysroot" argument was given
* but also whether it's actually different from OstreeRepo's.
*
* XXX Having API regret about the "sysroot" argument now.
*/
gboolean different_sysroot = FALSE;
if (sysroot != NULL)
different_sysroot = !g_file_equal (sysroot, self->sysroot_dir);
if (different_sysroot || ostree_repo_is_system (self))
g_autoptr(GFile) etc_ostree_remotes_d = get_remotes_d_dir (self, sysroot);
if (etc_ostree_remotes_d)
{
g_autoptr(GError) local_error = NULL;
if (sysroot == NULL)
sysroot = self->sysroot_dir;
g_autoptr(GFile) etc_ostree_remotes_d = g_file_resolve_relative_path (sysroot, SYSCONF_REMOTES);
if (!g_file_make_directory_with_parents (etc_ostree_remotes_d,
cancellable, &local_error))
{
@@ -1761,8 +1753,6 @@ ostree_repo_create (OstreeRepo *self,
if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_RDWR|O_CLOEXEC, &tmpf, error))
return FALSE;
if (fchmod (tmpf.fd, 0600) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
if (!_ostree_write_bareuser_metadata (tmpf.fd, 0, 0, 644, NULL, error))
return FALSE;
}
@@ -1874,14 +1864,55 @@ append_one_remote_config (OstreeRepo *self,
}
static GFile *
get_remotes_d_dir (OstreeRepo *self)
get_remotes_d_dir (OstreeRepo *self,
GFile *sysroot)
{
if (self->remotes_config_dir != NULL)
/* Support explicit override */
if (self->sysroot_dir != NULL && self->remotes_config_dir != NULL)
return g_file_resolve_relative_path (self->sysroot_dir, self->remotes_config_dir);
else if (ostree_repo_is_system (self))
return g_file_resolve_relative_path (self->sysroot_dir, SYSCONF_REMOTES);
return NULL;
g_autoptr(GFile) sysroot_owned = NULL;
/* Very complicated sysroot logic; this bit breaks the otherwise mostly clean
* layering between OstreeRepo and OstreeSysroot. First, If a sysroot was
* provided, use it. Otherwise, check to see whether we reference
* /ostree/repo, or if not that, see if we have a ref to a sysroot (and it's
* physical).
*/
g_autoptr(OstreeSysroot) sysroot_ref = NULL;
if (sysroot == NULL)
{
/* No explicit sysroot? Let's see if we have a kind */
switch (self->sysroot_kind)
{
case OSTREE_REPO_SYSROOT_KIND_UNKNOWN:
g_assert_not_reached ();
break;
case OSTREE_REPO_SYSROOT_KIND_NO:
break;
case OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE:
sysroot = sysroot_owned = g_file_new_for_path ("/");
break;
case OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT:
sysroot_ref = (OstreeSysroot*)g_weak_ref_get (&self->sysroot);
/* Only write to /etc/ostree/remotes.d if we are pointed at a deployment */
if (sysroot_ref != NULL && !sysroot_ref->is_physical)
sysroot = ostree_sysroot_get_path (sysroot_ref);
break;
}
}
/* For backwards compat, also fall back to the sysroot-path variable, which we
* don't set anymore internally, and I hope no one else uses.
*/
if (sysroot == NULL && sysroot_ref == NULL)
sysroot = self->sysroot_dir;
/* Did we find a sysroot? If not, NULL means use the repo config, otherwise
* return the path in /etc.
*/
if (sysroot == NULL)
return NULL;
else
return g_file_resolve_relative_path (sysroot, SYSCONF_REMOTES);
}
static gboolean
@@ -2036,7 +2067,7 @@ reload_remote_config (OstreeRepo *self,
if (!add_remotes_from_keyfile (self, self->config, NULL, error))
return FALSE;
g_autoptr(GFile) remotes_d = get_remotes_d_dir (self);
g_autoptr(GFile) remotes_d = get_remotes_d_dir (self, NULL);
if (remotes_d == NULL)
return TRUE;
@@ -2101,6 +2132,7 @@ ostree_repo_open (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
struct stat self_stbuf;
struct stat stbuf;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -2137,6 +2169,9 @@ ostree_repo_open (OstreeRepo *self,
return FALSE;
}
if (!glnx_fstat (self->repo_dir_fd, &self_stbuf, error))
return FALSE;
if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE,
&self->objects_dir_fd, error))
{
@@ -2166,6 +2201,20 @@ ostree_repo_open (OstreeRepo *self,
self->target_owner_uid = self->target_owner_gid = -1;
}
if (self->writable)
{
/* Always try to recreate the tmpdir to be nice to people
* who are looking to free up space.
*
* https://github.com/ostreedev/ostree/issues/1018
*/
if (mkdirat (self->repo_dir_fd, "tmp", 0755) == -1)
{
if (G_UNLIKELY (errno != EEXIST))
return glnx_throw_errno_prefix (error, "mkdir(tmp)");
}
}
if (!glnx_opendirat (self->repo_dir_fd, "tmp", TRUE, &self->tmp_dir_fd, error))
return FALSE;
@@ -2178,6 +2227,27 @@ ostree_repo_open (OstreeRepo *self,
return FALSE;
}
/* If we weren't created via ostree_sysroot_get_repo(), for backwards
* compatibility we need to figure out now whether or not we refer to the
* system repo. See also ostree-sysroot.c.
*/
if (self->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_UNKNOWN)
{
struct stat system_stbuf;
/* Ignore any errors if we can't access /ostree/repo */
if (fstatat (AT_FDCWD, "/ostree/repo", &system_stbuf, 0) == 0)
{
/* Are we the same as /ostree/repo? */
if (self_stbuf.st_dev == system_stbuf.st_dev &&
self_stbuf.st_ino == system_stbuf.st_ino)
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE;
else
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO;
}
else
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO;
}
if (!ostree_repo_reload_config (self, cancellable, error))
return FALSE;
@@ -4144,7 +4214,7 @@ find_keyring (OstreeRepo *self,
return g_steal_pointer (&file);
}
g_autoptr(GFile) remotes_d = get_remotes_d_dir (self);
g_autoptr(GFile) remotes_d = get_remotes_d_dir (self, NULL);
if (remotes_d)
{
g_autoptr(GFile) file2 = g_file_get_child (remotes_d, remote->keyring);
@@ -4648,9 +4718,10 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
return FALSE;
g_autofree char *superblock = _ostree_get_relative_static_delta_superblock_path ((from && from[0]) ? from : NULL, to);
glnx_fd_close int superblock_file_fd = openat (self->repo_dir_fd, superblock, O_RDONLY | O_CLOEXEC);
if (superblock_file_fd == -1)
return glnx_throw_errno (error);
glnx_fd_close int superblock_file_fd = -1;
if (!glnx_openat_rdonly (self->repo_dir_fd, superblock, TRUE, &superblock_file_fd, error))
return FALSE;
g_autoptr(GInputStream) in_stream = g_unix_input_stream_new (superblock_file_fd, FALSE);
if (!in_stream)
+26
View File
@@ -1244,6 +1244,32 @@ gboolean ostree_repo_regenerate_summary (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
/**
* OSTREE_REPO_METADATA_REF:
*
* The name of a ref which is used to store metadata for the entire repository,
* such as its expected update time (`ostree.summary.expires`), name, or new
* GPG keys. Metadata is stored on contentless commits in the ref, and hence is
* signed with the commits.
*
* This supersedes the additional metadata dictionary in the `summary` file
* (see ostree_repo_regenerate_summary()), as the use of a ref means that the
* metadata for multiple upstream repositories can be included in a single mirror
* repository, disambiguating the refs using collection IDs. In order to support
* peer to peer redistribution of repository metadata, repositories must set a
* collection ID (ostree_repo_set_collection_id()).
*
* Users of OSTree may place arbitrary metadata in commits on this ref, but the
* keys must be namespaced by product or developer. For example,
* `exampleos.end-of-life`. The `ostree.` prefix is reserved.
*
* Since: 2017.8
*/
#define OSTREE_REPO_METADATA_REF "ostree-metadata"
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
G_END_DECLS
+67 -130
View File
@@ -52,34 +52,24 @@ symlink_at_replace (const char *oldpath,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
int res;
/* Possibly in the future generate a temporary random name here,
* would need to move "generate a temporary name" code into
* libglnx or glib?
*/
g_autofree char *temppath = g_strconcat (newpath, ".tmp", NULL);
/* Clean up any stale temporary links */
/* Clean up any stale temporary links */
(void) unlinkat (parent_dfd, temppath, 0);
/* Create the temp link */
do
res = symlinkat (oldpath, parent_dfd, temppath);
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1)
{
glnx_set_error_from_errno (error);
goto out;
}
/* Create the temp link */
if (TEMP_FAILURE_RETRY (symlinkat (oldpath, parent_dfd, temppath)) < 0)
return glnx_throw_errno_prefix (error, "symlinkat");
/* Rename it into place */
if (!glnx_renameat (parent_dfd, temppath, parent_dfd, newpath, error))
goto out;
return FALSE;
ret = TRUE;
out:
return ret;
return TRUE;
}
static GLnxFileCopyFlags
@@ -104,26 +94,17 @@ hardlink_or_copy_at (int src_dfd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
if (linkat (src_dfd, src_subpath, dest_dfd, dest_subpath, 0) != 0)
{
if (errno == EMLINK || errno == EXDEV)
{
return glnx_file_copy_at (src_dfd, src_subpath, NULL, dest_dfd, dest_subpath,
sysroot_flags_to_copy_flags (0, flags),
cancellable, error);
}
if (G_IN_SET (errno, EMLINK, EXDEV))
return glnx_file_copy_at (src_dfd, src_subpath, NULL, dest_dfd, dest_subpath,
sysroot_flags_to_copy_flags (0, flags),
cancellable, error);
else
{
glnx_set_error_from_errno (error);
goto out;
}
return glnx_throw_errno_prefix (error, "linkat");
}
ret = TRUE;
out:
return ret;
return TRUE;
}
static gboolean
@@ -135,8 +116,6 @@ dirfd_copy_attributes_and_xattrs (int src_parent_dfd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
struct stat src_stbuf;
g_autoptr(GVariant) xattrs = NULL;
/* Clone all xattrs first, so we get the SELinux security context
@@ -147,31 +126,21 @@ dirfd_copy_attributes_and_xattrs (int src_parent_dfd,
{
if (!glnx_dfd_name_get_all_xattrs (src_parent_dfd, src_name,
&xattrs, cancellable, error))
goto out;
return FALSE;
if (!glnx_fd_set_all_xattrs (dest_dfd, xattrs,
cancellable, error))
goto out;
return FALSE;
}
if (fstat (src_dfd, &src_stbuf) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
struct stat src_stbuf;
if (!glnx_fstat (src_dfd, &src_stbuf, error))
return FALSE;
if (fchown (dest_dfd, src_stbuf.st_uid, src_stbuf.st_gid) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
return glnx_throw_errno_prefix (error, "fchown");
if (fchmod (dest_dfd, src_stbuf.st_mode) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
return glnx_throw_errno_prefix (error, "fchmod");
ret = TRUE;
out:
return ret;
return TRUE;
}
static gboolean
@@ -199,7 +168,7 @@ copy_dir_recurse (int src_parent_dfd,
if (!dirfd_copy_attributes_and_xattrs (src_parent_dfd, name, src_dfd_iter.fd, dest_dfd,
flags, cancellable, error))
return FALSE;
while (TRUE)
{
struct stat child_stbuf;
@@ -209,9 +178,9 @@ copy_dir_recurse (int src_parent_dfd,
if (dent == NULL)
break;
if (fstatat (src_dfd_iter.fd, dent->d_name, &child_stbuf,
AT_SYMLINK_NOFOLLOW) != 0)
return glnx_throw_errno (error);
if (!glnx_fstatat (src_dfd_iter.fd, dent->d_name, &child_stbuf,
AT_SYMLINK_NOFOLLOW, error))
return FALSE;
if (S_ISDIR (child_stbuf.st_mode))
{
@@ -242,7 +211,6 @@ ensure_directory_from_template (int orig_etc_fd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
glnx_fd_close int src_dfd = -1;
glnx_fd_close int target_dfd = -1;
@@ -250,7 +218,7 @@ ensure_directory_from_template (int orig_etc_fd,
g_assert (*path != '/' && *path != '\0');
if (!glnx_opendirat (modified_etc_fd, path, TRUE, &src_dfd, error))
goto out;
return FALSE;
/* Create with mode 0700, we'll fchmod/fchown later */
again:
@@ -268,7 +236,7 @@ ensure_directory_from_template (int orig_etc_fd,
{
if (!ensure_directory_from_template (orig_etc_fd, modified_etc_fd, new_etc_fd,
parent_path, NULL, flags, cancellable, error))
goto out;
return FALSE;
/* Loop */
goto again;
@@ -280,29 +248,19 @@ ensure_directory_from_template (int orig_etc_fd,
}
}
else
{
glnx_set_error_from_errno (error);
g_prefix_error (error, "mkdirat: ");
goto out;
}
return glnx_throw_errno_prefix (error, "mkdirat");
}
if (!glnx_opendirat (new_etc_fd, path, TRUE, &target_dfd, error))
goto out;
return FALSE;
if (!dirfd_copy_attributes_and_xattrs (modified_etc_fd, path, src_dfd, target_dfd,
flags, cancellable, error))
goto out;
return FALSE;
ret = TRUE;
if (out_dfd)
{
g_assert (target_dfd != -1);
*out_dfd = target_dfd;
target_dfd = -1;
}
out:
return ret;
*out_dfd = glnx_steal_fd (&target_dfd);
return TRUE;
}
/**
@@ -321,100 +279,79 @@ copy_modified_config_file (int orig_etc_fd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
struct stat modified_stbuf;
struct stat new_stbuf;
if (!glnx_fstatat (modified_etc_fd, path, &modified_stbuf, AT_SYMLINK_NOFOLLOW, error))
return glnx_prefix_error (error, "Reading modified config file");
glnx_fd_close int dest_parent_dfd = -1;
if (fstatat (modified_etc_fd, path, &modified_stbuf, AT_SYMLINK_NOFOLLOW) < 0)
{
glnx_set_error_from_errno (error);
g_prefix_error (error, "Failed to read modified config file '%s': ", path);
goto out;
}
if (strchr (path, '/') != NULL)
{
g_autofree char *parent = g_path_get_dirname (path);
if (!ensure_directory_from_template (orig_etc_fd, modified_etc_fd, new_etc_fd,
parent, &dest_parent_dfd, flags, cancellable, error))
goto out;
return FALSE;
}
else
{
dest_parent_dfd = dup (new_etc_fd);
if (dest_parent_dfd == -1)
{
glnx_set_error_from_errno (error);
goto out;
}
return glnx_throw_errno_prefix (error, "dup");
}
g_assert (dest_parent_dfd != -1);
if (fstatat (new_etc_fd, path, &new_stbuf, AT_SYMLINK_NOFOLLOW) < 0)
{
if (errno == ENOENT)
;
else
{
glnx_set_error_from_errno (error);
goto out;
}
if (errno != ENOENT)
return glnx_throw_errno_prefix (error, "fstatat");
}
else if (S_ISDIR(new_stbuf.st_mode))
{
if (!S_ISDIR(modified_stbuf.st_mode))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Modified config file newly defaults to directory '%s', cannot merge",
path);
goto out;
return g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Modified config file newly defaults to directory '%s', cannot merge",
path), FALSE;
}
else
{
/* Do nothing here - we assume that we've already
* recursively copied the parent directory.
*/
ret = TRUE;
goto out;
return TRUE;
}
}
else
{
if (unlinkat (new_etc_fd, path, 0) < 0)
{
glnx_set_error_from_errno (error);
goto out;
}
if (!glnx_unlinkat (new_etc_fd, path, 0, error))
return FALSE;
}
if (S_ISDIR (modified_stbuf.st_mode))
{
if (!copy_dir_recurse (modified_etc_fd, new_etc_fd, path, flags,
cancellable, error))
goto out;
return FALSE;
}
else if (S_ISLNK (modified_stbuf.st_mode) || S_ISREG (modified_stbuf.st_mode))
{
if (!glnx_file_copy_at (modified_etc_fd, path, &modified_stbuf,
if (!glnx_file_copy_at (modified_etc_fd, path, &modified_stbuf,
new_etc_fd, path,
sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags),
cancellable, error))
goto out;
return FALSE;
}
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Unsupported non-regular/non-symlink file in /etc '%s'",
path);
goto out;
return glnx_throw (error,
"Unsupported non-regular/non-symlink file in /etc '%s'",
path);
}
ret = TRUE;
out:
return ret;
return TRUE;
}
/*
@@ -575,7 +512,7 @@ checkout_deployment_tree (OstreeSysroot *sysroot,
if (!glnx_opendirat (osdeploy_dfd, checkout_target_name, TRUE, &ret_fd, error))
goto out;
ret = TRUE;
*out_deployment_dfd = ret_fd;
out:
@@ -652,7 +589,7 @@ relabel_recursively (OstreeSysroot *sysroot,
cancellable, error);
if (!direnum)
goto out;
while (TRUE)
{
GFileInfo *file_info;
@@ -706,7 +643,7 @@ selinux_relabel_dir (OstreeSysroot *sysroot,
cancellable, error);
if (!root_info)
goto out;
g_ptr_array_add (path_parts, (char*)prefix);
if (!relabel_recursively (sysroot, sepolicy, dir, root_info, path_parts,
cancellable, error))
@@ -959,7 +896,7 @@ get_kernel_from_tree (int deployment_dfd,
if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error))
goto out;
if (dent == NULL)
break;
@@ -983,7 +920,7 @@ get_kernel_from_tree (int deployment_dfd,
ret_initramfs_name = g_strdup (dent->d_name);
}
}
if (ret_kernel_name != NULL && ret_initramfs_name != NULL)
break;
}
@@ -1328,7 +1265,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
&variant, NULL))
{
metadata = g_variant_get_child_value (variant, 0);
g_variant_lookup (metadata, "version", "s", &deployment_version);
g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_VERSION, "s", &deployment_version);
}
}
@@ -1355,7 +1292,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
ostree_bootconfig_parser_set (bootconfig, "title", title_key->str);
g_autofree char *version_key = g_strdup_printf ("%d", n_deployments - ostree_deployment_get_index (deployment));
ostree_bootconfig_parser_set (bootconfig, "version", version_key);
ostree_bootconfig_parser_set (bootconfig, OSTREE_COMMIT_META_KEY_VERSION, version_key);
g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", dest_kernel_name, NULL);
ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath);
@@ -1451,7 +1388,7 @@ static GHashTable *
assign_bootserials (GPtrArray *deployments)
{
guint i;
GHashTable *ret =
GHashTable *ret =
g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
for (i = 0; i < deployments->len; i++)
@@ -1488,7 +1425,7 @@ deployment_bootconfigs_equal (OstreeDeployment *a,
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *b_kargs = NULL;
g_autofree char *a_boot_options_without_ostree = NULL;
g_autofree char *b_boot_options_without_ostree = NULL;
/* We checksum the kernel arguments *except* ostree= */
a_kargs = _ostree_kernel_args_from_string (a_boot_options);
_ostree_kernel_args_replace (a_kargs, "ostree");
@@ -1662,10 +1599,10 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
{
OstreeDeployment *deployment = new_deployments->pdata[i];
g_autoptr(GFile) deployment_root = NULL;
if (deployment == self->booted_deployment)
found_booted_deployment = TRUE;
deployment_root = ostree_sysroot_get_deployment_directory (self, deployment);
if (!g_file_query_exists (deployment_root, NULL))
{
@@ -1693,7 +1630,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
g_prefix_error (error, "Creating new current bootlinks: ");
goto out;
}
if (!full_system_sync (self, cancellable, error))
{
g_prefix_error (error, "Full sync: ");
@@ -1707,7 +1644,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
g_prefix_error (error, "Swapping current bootlinks: ");
goto out;
}
bootloader_is_atomic = TRUE;
}
else
@@ -1741,7 +1678,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, new_loader_entries_dir, 0755,
cancellable, error))
goto out;
/* Need the repo to try and extract the versions for deployments.
* But this is a "nice-to-have" for the bootloader UI, so failure
* here is not fatal to the whole operation. We just gracefully
@@ -1819,7 +1756,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
g_prefix_error (error, "Full sync: ");
goto out;
}
if (!swap_bootloader (self, self->bootversion, new_bootversion,
cancellable, error))
{
+2 -1
View File
@@ -48,7 +48,8 @@ struct OstreeSysroot {
GLnxLockFile lock;
gboolean loaded;
gboolean is_physical; /* TRUE if we're pointed at physical storage root and not a deployment */
GPtrArray *deployments;
int bootversion;
int subbootversion;
+1 -1
View File
@@ -559,7 +559,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
return FALSE;
g_variant_get_child (new_variant, 0, "@a{sv}", &new_metadata);
rebase = g_variant_lookup_value (new_metadata, "ostree.endoflife-rebase", G_VARIANT_TYPE_STRING);
rebase = g_variant_lookup_value (new_metadata, OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE, G_VARIANT_TYPE_STRING);
if (rebase)
{
const char *new_ref = g_variant_get_string (rebase, 0);
+23 -1
View File
@@ -134,7 +134,9 @@ ostree_sysroot_constructed (GObject *object)
repo_path = g_file_resolve_relative_path (self->path, "ostree/repo");
self->repo = ostree_repo_new_for_sysroot_path (repo_path, self->path);
self->repo->is_system = TRUE;
self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT;
/* Hold a weak ref for the remote-add handling */
g_weak_ref_init (&self->repo->sysroot, object);
G_OBJECT_CLASS (ostree_sysroot_parent_class)->constructed (object);
}
@@ -813,6 +815,26 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
cancellable, error))
return FALSE;
/* Determine whether we're "physical" or not, the first time we initialize */
if (!self->loaded)
{
/* If we have a booted deployment, the sysroot is / and we're definitely
* not physical.
*/
if (self->booted_deployment)
self->is_physical = FALSE; /* (the default, but explicit for clarity) */
/* Otherwise - check for /sysroot which should only exist in a deployment,
* not in ${sysroot} (a metavariable for the real physical root).
*/
else if (fstatat (self->sysroot_fd, "sysroot", &stbuf, 0) < 0)
{
if (errno != ENOENT)
return glnx_throw_errno_prefix (error, "fstatat");
self->is_physical = TRUE;
}
/* Otherwise, the default is FALSE */
}
self->bootversion = bootversion;
self->subbootversion = subbootversion;
self->deployments = deployments;
+3 -3
View File
@@ -44,7 +44,7 @@
*
* Since: 2017.4
*/
#define OSTREE_RELEASE_VERSION (8)
#define OSTREE_RELEASE_VERSION (9)
/**
* OSTREE_VERSION
@@ -53,7 +53,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION (2017.8)
#define OSTREE_VERSION (2017.9)
/**
* OSTREE_VERSION_S:
@@ -63,7 +63,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION_S "2017.8"
#define OSTREE_VERSION_S "2017.9"
#define OSTREE_ENCODE_VERSION(year,release) \
((year) << 16 | (release))
+1 -1
View File
@@ -57,7 +57,7 @@ ot_admin_checksum_version (GVariant *checksum)
metadata = g_variant_get_child_value (checksum, 0);
if (!g_variant_lookup (metadata, "version", "&s", &ret))
if (!g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_VERSION, "&s", &ret))
return NULL;
return g_strdup (ret);
+72
View File
@@ -29,6 +29,7 @@
#include "otutil.h"
#include "ot-tool-util.h"
#include "parse-datetime.h"
#include "ostree-repo-private.h"
static char *opt_subject;
static char *opt_body;
@@ -36,6 +37,7 @@ static char *opt_body_file;
static gboolean opt_editor;
static char *opt_parent;
static gboolean opt_orphan;
static char **opt_bind_refs;
static char *opt_branch;
static char *opt_statoverride_file;
static char *opt_skiplist_file;
@@ -78,6 +80,7 @@ static GOptionEntry options[] = {
{ "editor", 'e', 0, G_OPTION_ARG_NONE, &opt_editor, "Use an editor to write the commit message", NULL },
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &opt_branch, "Branch", "BRANCH" },
{ "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL },
{ "bind-ref", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_bind_refs, "Add a ref to ref binding commit metadata", "BRANCH" },
{ "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" },
{ "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Add a key/value pair to metadata", "KEY=VALUE" },
{ "add-detached-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_detached_metadata_strings, "Add a key/value pair to detached metadata", "KEY=VALUE" },
@@ -303,6 +306,71 @@ parse_keyvalue_strings (char **strings,
return TRUE;
}
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
static void
add_collection_binding (OstreeRepo *repo,
GVariantBuilder *metadata_builder)
{
const char *collection_id = ostree_repo_get_collection_id (repo);
if (collection_id == NULL)
return;
g_variant_builder_add (metadata_builder, "{s@v}", OSTREE_COMMIT_META_KEY_COLLECTION_BINDING,
g_variant_new_variant (g_variant_new_string (collection_id)));
}
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
static int
compare_strings (gconstpointer a, gconstpointer b)
{
const char **sa = (const char **)a;
const char **sb = (const char **)b;
return strcmp (*sa, *sb);
}
static void
add_ref_binding (GVariantBuilder *metadata_builder)
{
if (opt_orphan)
return;
g_assert_nonnull (opt_branch);
g_autoptr(GPtrArray) refs = g_ptr_array_new ();
g_ptr_array_add (refs, opt_branch);
for (char **iter = opt_bind_refs; iter != NULL && *iter != NULL; ++iter)
g_ptr_array_add (refs, *iter);
g_ptr_array_sort (refs, compare_strings);
g_autoptr(GVariant) refs_v = g_variant_new_strv ((const char *const *)refs->pdata,
refs->len);
g_variant_builder_add (metadata_builder, "{s@v}", OSTREE_COMMIT_META_KEY_REF_BINDING,
g_variant_new_variant (g_steal_pointer (&refs_v)));
}
/* Note if you're using the API, you currently need to do this yourself */
static void
fill_bindings (OstreeRepo *repo,
GVariant *metadata,
GVariant **out_metadata)
{
g_autoptr(GVariantBuilder) metadata_builder =
ot_util_variant_builder_from_variant (metadata, G_VARIANT_TYPE_VARDICT);
add_ref_binding (metadata_builder);
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
/* Allow the collection ID to be overridden using
* --add-metadata-string=ostree.collection-binding=blah */
if (metadata == NULL ||
!g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, "*", NULL))
add_collection_binding (repo, metadata_builder);
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
*out_metadata = g_variant_ref_sink (g_variant_builder_end (metadata_builder));
}
gboolean
ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError **error)
{
@@ -559,6 +627,10 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
{
gboolean update_summary;
guint64 timestamp;
g_autoptr(GVariant) old_metadata = g_steal_pointer (&metadata);
fill_bindings (repo, old_metadata, &metadata);
if (!opt_timestamp)
{
GDateTime *now = g_date_time_new_now_utc ();
+88 -34
View File
@@ -207,6 +207,88 @@ ostree_run (int argc,
return 0;
}
/* Process a --repo arg; used below, and for the remote builtins */
static OstreeRepo *
parse_repo_option (GOptionContext *context,
const char *repo_path,
gboolean skip_repo_open,
GCancellable *cancellable,
GError **error)
{
g_autoptr(OstreeRepo) repo = NULL;
if (repo_path == NULL)
{
g_autoptr(GError) local_error = NULL;
repo = ostree_repo_new_default ();
if (!ostree_repo_open (repo, cancellable, &local_error))
{
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_autofree char *help = NULL;
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Command requires a --repo argument");
help = g_option_context_get_help (context, FALSE, NULL);
g_printerr ("%s", help);
}
else
{
g_propagate_error (error, g_steal_pointer (&local_error));
}
return NULL;
}
}
else
{
g_autoptr(GFile) repo_file = g_file_new_for_path (repo_path);
repo = ostree_repo_new (repo_file);
if (!skip_repo_open)
{
if (!ostree_repo_open (repo, cancellable, error))
return NULL;
}
}
return g_steal_pointer (&repo);
}
/* Used by the remote builtins which are special in taking --sysroot or --repo */
gboolean
ostree_parse_sysroot_or_repo_option (GOptionContext *context,
const char *sysroot_path,
const char *repo_path,
OstreeSysroot **out_sysroot,
OstreeRepo **out_repo,
GCancellable *cancellable,
GError **error)
{
g_autoptr(OstreeSysroot) sysroot = NULL;
g_autoptr(OstreeRepo) repo = NULL;
if (sysroot_path)
{
g_autoptr(GFile) sysroot_file = g_file_new_for_path (sysroot_path);
sysroot = ostree_sysroot_new (sysroot_file);
if (!ostree_sysroot_load (sysroot, cancellable, error))
return FALSE;
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
return FALSE;
}
else
{
repo = parse_repo_option (context, repo_path, FALSE, cancellable, error);
if (!repo)
return FALSE;
}
ot_transfer_out_value (out_sysroot, &sysroot);
ot_transfer_out_value (out_repo, &repo);
return TRUE;
}
gboolean
ostree_option_context_parse (GOptionContext *context,
const GOptionEntry *main_entries,
@@ -217,7 +299,7 @@ ostree_option_context_parse (GOptionContext *context,
GCancellable *cancellable,
GError **error)
{
glnx_unref_object OstreeRepo *repo = NULL;
g_autoptr(OstreeRepo) repo = NULL;
/* Entries are listed in --help output in the order added. We add the
* main entries ourselves so that we can add the --repo entry first. */
@@ -254,40 +336,12 @@ ostree_option_context_parse (GOptionContext *context,
if (opt_verbose)
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, message_handler, NULL);
if (opt_repo == NULL && !(flags & OSTREE_BUILTIN_FLAG_NO_REPO))
if (!(flags & OSTREE_BUILTIN_FLAG_NO_REPO))
{
g_autoptr(GError) local_error = NULL;
repo = ostree_repo_new_default ();
if (!ostree_repo_open (repo, cancellable, &local_error))
{
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_autofree char *help = NULL;
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Command requires a --repo argument");
help = g_option_context_get_help (context, FALSE, NULL);
g_printerr ("%s", help);
}
else
{
g_propagate_error (error, g_steal_pointer (&local_error));
}
return FALSE;
}
}
else if (opt_repo != NULL)
{
g_autoptr(GFile) repo_file = g_file_new_for_path (opt_repo);
repo = ostree_repo_new (repo_file);
if (!(flags & OSTREE_BUILTIN_FLAG_NO_CHECK))
{
if (!ostree_repo_open (repo, cancellable, error))
return FALSE;
}
repo = parse_repo_option (context, opt_repo, (flags & OSTREE_BUILTIN_FLAG_NO_CHECK) > 0,
cancellable, error);
if (!repo)
return FALSE;
}
if (out_repo)
+8
View File
@@ -46,6 +46,14 @@ int ostree_run (int argc, char **argv, OstreeCommand *commands, GError **error);
int ostree_usage (OstreeCommand *commands, gboolean is_error);
gboolean ostree_parse_sysroot_or_repo_option (GOptionContext *context,
const char *sysroot_path,
const char *repo_path,
OstreeSysroot **out_sysroot,
OstreeRepo **out_repo,
GCancellable *cancellable,
GError **error);
gboolean ostree_option_context_parse (GOptionContext *context,
const GOptionEntry *main_entries,
int *argc, char ***argv,
+8 -21
View File
@@ -36,18 +36,8 @@ static GOptionEntry option_entries[] = {
gboolean
ot_remote_builtin_add_cookie (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(GOptionContext) context = g_option_context_new ("NAME DOMAIN PATH COOKIE_NAME VALUE - Add a cookie to remote");
g_autoptr(OstreeRepo) repo = NULL;
const char *remote_name;
const char *domain;
const char *path;
const char *cookie_name;
const char *value;
g_autofree char *jar_path = NULL;
g_autofree char *cookie_file = NULL;
context = g_option_context_new ("NAME DOMAIN PATH COOKIE_NAME VALUE - Add a cookie to remote");
if (!ostree_option_context_parse (context, option_entries, &argc, &argv,
OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
return FALSE;
@@ -58,16 +48,13 @@ ot_remote_builtin_add_cookie (int argc, char **argv, GCancellable *cancellable,
return FALSE;
}
remote_name = argv[1];
domain = argv[2];
path = argv[3];
cookie_name = argv[4];
value = argv[5];
cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name);
jar_path = g_build_filename (gs_file_get_path_cached (repo->repodir), cookie_file, NULL);
if (!ot_add_cookie_at (AT_FDCWD, jar_path, domain, path, cookie_name, value, error))
const char *remote_name = argv[1];
const char *domain = argv[2];
const char *path = argv[3];
const char *cookie_name = argv[4];
const char *value = argv[5];
g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name);
if (!ot_add_cookie_at (ostree_repo_get_dfd (repo), cookie_file, domain, path, cookie_name, value, error))
return FALSE;
return TRUE;
+11 -1
View File
@@ -34,6 +34,8 @@ static char *opt_contenturl;
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
static char *opt_collection_id;
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
static char *opt_sysroot;
static char *opt_repo;
static GOptionEntry option_entries[] = {
{ "set", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" },
@@ -45,6 +47,8 @@ static GOptionEntry option_entries[] = {
{ "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id,
"Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" },
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
{ "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Use sysroot at PATH (overrides --repo)", "PATH" },
{ NULL }
};
@@ -52,6 +56,7 @@ gboolean
ot_remote_builtin_add (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(OstreeSysroot) sysroot = NULL;
g_autoptr(OstreeRepo) repo = NULL;
const char *remote_name;
const char *remote_url;
@@ -63,7 +68,12 @@ ot_remote_builtin_add (int argc, char **argv, GCancellable *cancellable, GError
context = g_option_context_new ("NAME [metalink=|mirrorlist=]URL [BRANCH...] - Add a remote repository");
if (!ostree_option_context_parse (context, option_entries, &argc, &argv,
OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error))
goto out;
if (!ostree_parse_sysroot_or_repo_option (context, opt_sysroot, opt_repo,
&sysroot, &repo,
cancellable, error))
goto out;
if (argc < 3)
+7 -18
View File
@@ -36,16 +36,8 @@ static GOptionEntry option_entries[] = {
gboolean
ot_remote_builtin_delete_cookie (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(OstreeRepo) repo = NULL;
const char *remote_name;
const char *domain;
const char *path;
const char *cookie_name;
g_autofree char *jar_path = NULL;
g_autofree char *cookie_file = NULL;
context = g_option_context_new ("NAME DOMAIN PATH COOKIE_NAME- Remote one cookie from remote");
g_autoptr(GOptionContext) context = g_option_context_new ("NAME DOMAIN PATH COOKIE_NAME- Remote one cookie from remote");
if (!ostree_option_context_parse (context, option_entries, &argc, &argv,
OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
@@ -57,15 +49,12 @@ ot_remote_builtin_delete_cookie (int argc, char **argv, GCancellable *cancellabl
return FALSE;
}
remote_name = argv[1];
domain = argv[2];
path = argv[3];
cookie_name = argv[4];
cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name);
jar_path = g_build_filename (gs_file_get_path_cached (repo->repodir), cookie_file, NULL);
if (!ot_delete_cookie_at (AT_FDCWD, jar_path, domain, path, cookie_name, error))
const char *remote_name = argv[1];
const char *domain = argv[2];
const char *path = argv[3];
const char *cookie_name = argv[4];
g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name);
if (!ot_delete_cookie_at (ostree_repo_get_dfd (repo), cookie_file, domain, path, cookie_name, error))
return FALSE;
return TRUE;
+20 -15
View File
@@ -25,43 +25,48 @@
#include "ot-main.h"
#include "ot-remote-builtins.h"
gboolean opt_if_exists = FALSE;
static gboolean opt_if_exists = FALSE;
static char *opt_sysroot;
static char *opt_repo;
static GOptionEntry option_entries[] = {
{ "if-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_exists, "Do nothing if the provided remote does not exist", NULL },
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
{ "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Use sysroot at PATH (overrides --repo)", "PATH" },
{ NULL }
};
gboolean
ot_remote_builtin_delete (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(OstreeRepo) repo = NULL;
const char *remote_name;
gboolean ret = FALSE;
context = g_option_context_new ("NAME - Delete a remote repository");
g_autoptr(GOptionContext) context = g_option_context_new ("NAME - Delete a remote repository");
if (!ostree_option_context_parse (context, option_entries, &argc, &argv,
OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
goto out;
OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error))
return FALSE;
g_autoptr(OstreeSysroot) sysroot = NULL;
g_autoptr(OstreeRepo) repo = NULL;
if (!ostree_parse_sysroot_or_repo_option (context, opt_sysroot, opt_repo,
&sysroot, &repo,
cancellable, error))
return FALSE;
if (argc < 2)
{
ot_util_usage_error (context, "NAME must be specified", error);
goto out;
return FALSE;
}
remote_name = argv[1];
const char *remote_name = argv[1];
if (!ostree_repo_remote_change (repo, NULL,
opt_if_exists ? OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS :
opt_if_exists ? OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS :
OSTREE_REPO_REMOTE_CHANGE_DELETE,
remote_name, NULL, NULL,
cancellable, error))
goto out;
return FALSE;
ret = TRUE;
out:
return ret;
return TRUE;
}
+4 -12
View File
@@ -35,13 +35,8 @@ static GOptionEntry option_entries[] = {
gboolean
ot_remote_builtin_list_cookies (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(OstreeRepo) repo = NULL;
const char *remote_name;
g_autofree char *jar_path = NULL;
g_autofree char *cookie_file = NULL;
context = g_option_context_new ("NAME - Show remote repository cookies");
g_autoptr(GOptionContext) context = g_option_context_new ("NAME - Show remote repository cookies");
if (!ostree_option_context_parse (context, option_entries, &argc, &argv,
OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
@@ -53,12 +48,9 @@ ot_remote_builtin_list_cookies (int argc, char **argv, GCancellable *cancellable
return FALSE;
}
remote_name = argv[1];
cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name);
jar_path = g_build_filename (g_file_get_path (repo->repodir), cookie_file, NULL);
if (!ot_list_cookies_at (AT_FDCWD, jar_path, error))
const char *remote_name = argv[1];
g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name);
if (!ot_list_cookies_at (ostree_repo_get_dfd (repo), cookie_file, error))
return FALSE;
return TRUE;
+16 -94
View File
@@ -23,10 +23,6 @@
#include "ot-remote-cookie-util.h"
#ifndef HAVE_LIBCURL
#include <libsoup/soup.h>
#endif
#include "otutil.h"
#include "ot-main.h"
#include "ot-remote-builtins.h"
@@ -148,49 +144,24 @@ ot_add_cookie_at (int dfd, const char *jar_path,
const char *name, const char *value,
GError **error)
{
#ifdef HAVE_LIBCURL
glnx_fd_close int fd = openat (AT_FDCWD, jar_path, O_WRONLY | O_APPEND | O_CREAT, 0644);
g_autofree char *buf = NULL;
g_autoptr(GDateTime) now = NULL;
g_autoptr(GDateTime) expires = NULL;
glnx_fd_close int fd = openat (dfd, jar_path, O_WRONLY | O_APPEND | O_CREAT, 0644);
if (fd < 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
return glnx_throw_errno_prefix (error, "open(%s)", jar_path);
now = g_date_time_new_now_utc ();
expires = g_date_time_add_years (now, 25);
g_autoptr(GDateTime) now = g_date_time_new_now_utc ();
g_autoptr(GDateTime) expires = g_date_time_add_years (now, 25);
/* Adapted from soup-cookie-jar-text.c:write_cookie() */
buf = g_strdup_printf ("%s\t%s\t%s\t%s\t%llu\t%s\t%s\n",
domain,
*domain == '.' ? "TRUE" : "FALSE",
path,
"FALSE",
(long long unsigned)g_date_time_to_unix (expires),
name,
value);
g_autofree char *buf = g_strdup_printf ("%s\t%s\t%s\t%s\t%llu\t%s\t%s\n",
domain,
*domain == '.' ? "TRUE" : "FALSE",
path,
"FALSE",
(long long unsigned)g_date_time_to_unix (expires),
name,
value);
if (glnx_loop_write (fd, buf, strlen (buf)) < 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
#else
glnx_unref_object SoupCookieJar *jar = NULL;
SoupCookie *cookie;
jar = soup_cookie_jar_text_new (jar_path, FALSE);
/* Pick a silly long expire time, we're just storing the cookies in the
* jar and on pull the jar is read-only so expiry has little actual value */
cookie = soup_cookie_new (name, value, domain, path,
SOUP_COOKIE_MAX_AGE_ONE_YEAR * 25);
/* jar takes ownership of cookie */
soup_cookie_jar_add_cookie (jar, cookie);
#endif
return glnx_throw_errno_prefix (error, "write");
return TRUE;
}
@@ -201,18 +172,14 @@ ot_delete_cookie_at (int dfd, const char *jar_path,
GError **error)
{
gboolean found = FALSE;
#ifdef HAVE_LIBCURL
g_auto(GLnxTmpfile) tmpf = { 0, };
g_autofree char *dnbuf = NULL;
const char *dn = NULL;
g_autoptr(OtCookieParser) parser = NULL;
if (!ot_parse_cookies_at (dfd, jar_path, &parser, NULL, error))
return FALSE;
dnbuf = g_strdup (jar_path);
dn = dirname (dnbuf);
if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, dn, O_WRONLY | O_CLOEXEC,
g_assert (!strchr (jar_path, '/'));
if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_WRONLY | O_CLOEXEC,
&tmpf, error))
return FALSE;
@@ -233,33 +200,9 @@ ot_delete_cookie_at (int dfd, const char *jar_path,
}
if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE,
AT_FDCWD, jar_path,
dfd, jar_path,
error))
return FALSE;
#else
GSList *cookies;
glnx_unref_object SoupCookieJar *jar = NULL;
jar = soup_cookie_jar_text_new (jar_path, FALSE);
cookies = soup_cookie_jar_all_cookies (jar);
while (cookies != NULL)
{
SoupCookie *cookie = cookies->data;
if (!strcmp (domain, soup_cookie_get_domain (cookie)) &&
!strcmp (path, soup_cookie_get_path (cookie)) &&
!strcmp (name, soup_cookie_get_name (cookie)))
{
soup_cookie_jar_delete_cookie (jar, cookie);
found = TRUE;
}
soup_cookie_free (cookie);
cookies = g_slist_delete_link (cookies, cookies);
}
#endif
if (!found)
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cookie not found in jar");
@@ -271,7 +214,6 @@ ot_delete_cookie_at (int dfd, const char *jar_path,
gboolean
ot_list_cookies_at (int dfd, const char *jar_path, GError **error)
{
#ifdef HAVE_LIBCURL
g_autoptr(OtCookieParser) parser = NULL;
if (!ot_parse_cookies_at (AT_FDCWD, jar_path, &parser, NULL, error))
@@ -294,26 +236,6 @@ ot_list_cookies_at (int dfd, const char *jar_path, GError **error)
g_print ("Expires: %s\n", expires_str);
g_print ("Value: %s\n", parser->value);
}
#else
glnx_unref_object SoupCookieJar *jar = soup_cookie_jar_text_new (jar_path, TRUE);
GSList *cookies = soup_cookie_jar_all_cookies (jar);
while (cookies != NULL)
{
SoupCookie *cookie = cookies->data;
SoupDate *expiry = soup_cookie_get_expires (cookie);
g_print ("--\n");
g_print ("Domain: %s\n", soup_cookie_get_domain (cookie));
g_print ("Path: %s\n", soup_cookie_get_path (cookie));
g_print ("Name: %s\n", soup_cookie_get_name (cookie));
g_print ("Secure: %s\n", soup_cookie_get_secure (cookie) ? "yes" : "no");
g_print ("Expires: %s\n", soup_date_to_string (expiry, SOUP_DATE_COOKIE));
g_print ("Value: %s\n", soup_cookie_get_value (cookie));
soup_cookie_free (cookie);
cookies = g_slist_delete_link (cookies, cookies);
}
#endif
return TRUE;
}