New upstream version 2017.9
This commit is contained in:
commit
e5ac0cef85
134 files changed
+3986
-5324
No files matched your search
@@ -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;
|
||||
*/
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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 ***/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user