New upstream version 2017.7

This commit is contained in:
Simon McVittie committed 2017-06-21 09:51:58 +01:00
commit 19f82ee114
127 files changed
+3512 -2635

No files matched your search

-31
View File
@@ -1,31 +0,0 @@
/*
* 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;
@@ -1,4 +1,6 @@
/***
/* Released symbol file: DO NOT EDIT except in release commits!
Edit libostree-devel.sym instead.
Copyright (C) 2016 Colin Walters <walters@verbum.org>
This library is free software; you can redistribute it and/or
@@ -17,6 +19,9 @@
Boston, MA 02111-1307, USA.
***/
/* DO NOT EDIT this file - use libostree-devel.sym instead. Release
* commits will move symbols from libostree-devel.sym to libostree-released.sym.
*/
/*
Retroactively make all of these symbols 2016.3, which is
@@ -397,24 +402,12 @@ global:
ostree_async_progress_set_variant;
} LIBOSTREE_2017.4;
/* NOTE NOTE NOTE
* Versions above here are released. Only add symbols below this line.
* NOTE NOTE NOTE
*/
/*
LIBOSTREE_2017.$NEWVERSION {
LIBOSTREE_2017.7 {
global:
someostree_symbol_deleteme;
ostree_sysroot_repo;
ostree_sysroot_query_deployments_for;
} LIBOSTREE_2017.6;
*/
/* 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;
*/
/* NOTE: Only add more content here in release commits! See the
* comments at the top of this file.
*/
+3 -7
View File
@@ -1763,16 +1763,12 @@ validate_variant (GVariant *variant,
{
if (!g_variant_is_normal_form (variant))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Not normal form");
return FALSE;
return glnx_throw (error, "%s", "Not normal form");
}
if (!g_variant_is_of_type (variant, variant_type))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Doesn't match variant type '%s'",
(char*)variant_type);
return FALSE;
return glnx_throw (error, "Doesn't match variant type '%s'",
(char *)variant_type);
}
return TRUE;
}
-7
View File
@@ -44,13 +44,6 @@ G_BEGIN_DECLS
*/
#define OSTREE_MAX_METADATA_WARN_SIZE (7 * 1024 * 1024)
/**
* OSTREE_MAX_RECURSION:
*
* Maximum depth of metadata.
*/
#define OSTREE_MAX_RECURSION (256)
/**
* OSTREE_SHA256_DIGEST_LEN:
*
+15 -21
View File
@@ -99,8 +99,7 @@ struct FetcherRequest {
OstreeFetcherRequestFlags flags;
gboolean is_membuf;
GError *caught_write_error;
char *out_tmpfile;
int out_tmpfile_fd;
OtTmpfile tmpf;
GString *output_buf;
CURL *easy;
@@ -269,12 +268,11 @@ request_get_uri (FetcherRequest *req, guint idx)
static gboolean
ensure_tmpfile (FetcherRequest *req, GError **error)
{
if (req->out_tmpfile_fd == -1)
if (!req->tmpf.initialized)
{
if (!glnx_open_tmpfile_linkable_at (req->fetcher->tmpdir_dfd, ".",
O_WRONLY | O_CLOEXEC, &req->out_tmpfile_fd,
&req->out_tmpfile,
error))
if (!ot_open_tmpfile_linkable_at (req->fetcher->tmpdir_dfd, ".",
O_WRONLY | O_CLOEXEC, &req->tmpf,
error))
return FALSE;
}
return TRUE;
@@ -387,18 +385,14 @@ check_multi_info (OstreeFetcher *fetcher)
{
g_task_return_error (task, g_steal_pointer (&local_error));
}
else if (fchmod (req->out_tmpfile_fd, 0644) < 0)
else if (fchmod (req->tmpf.fd, 0644) < 0)
{
glnx_set_error_from_errno (error);
g_task_return_error (task, g_steal_pointer (&local_error));
}
else if (!glnx_link_tmpfile_at (fetcher->tmpdir_dfd,
GLNX_LINK_TMPFILE_REPLACE,
req->out_tmpfile_fd,
req->out_tmpfile,
fetcher->tmpdir_dfd,
tmpfile_path,
error))
else if (!ot_link_tmpfile_at (&req->tmpf, GLNX_LINK_TMPFILE_REPLACE,
fetcher->tmpdir_dfd, tmpfile_path,
error))
g_task_return_error (task, g_steal_pointer (&local_error));
else
{
@@ -586,8 +580,8 @@ write_cb (void *ptr, size_t size, size_t nmemb, void *data)
{
if (!ensure_tmpfile (req, &req->caught_write_error))
return -1;
g_assert (req->out_tmpfile_fd >= 0);
if (glnx_loop_write (req->out_tmpfile_fd, ptr, realsize) < 0)
g_assert (req->tmpf.fd >= 0);
if (glnx_loop_write (req->tmpf.fd, ptr, realsize) < 0)
{
glnx_set_error_from_errno (&req->caught_write_error);
return -1;
@@ -622,9 +616,7 @@ request_unref (FetcherRequest *req)
g_ptr_array_unref (req->mirrorlist);
g_free (req->filename);
g_clear_error (&req->caught_write_error);
if (req->out_tmpfile_fd != -1)
(void) close (req->out_tmpfile_fd);
g_free (req->out_tmpfile);
ot_tmpfile_clear (&req->tmpf);
if (req->output_buf)
g_string_free (req->output_buf, TRUE);
curl_easy_cleanup (req->easy);
@@ -770,6 +762,9 @@ initiate_next_curl_request (FetcherRequest *req,
curl_easy_setopt (req->easy, CURLOPT_SSLKEY, self->tls_client_key_path);
}
if ((self->config_flags & OSTREE_FETCHER_FLAGS_TRANSFER_GZIP) > 0)
curl_easy_setopt (req->easy, CURLOPT_ACCEPT_ENCODING, "");
/* We should only speak HTTP; TODO: only enable file if specified */
curl_easy_setopt (req->easy, CURLOPT_PROTOCOLS, (long)(CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FILE));
/* Picked the current version in F25 as of 20170127, since
@@ -847,7 +842,6 @@ _ostree_fetcher_request_async (OstreeFetcher *self,
/* We'll allocate the tmpfile on demand, so we handle
* file I/O errors just in the write func.
*/
req->out_tmpfile_fd = -1;
if (req->is_membuf)
req->output_buf = g_string_new ("");
+5
View File
@@ -63,6 +63,7 @@ typedef struct {
GVariant *extra_headers;
int max_outstanding;
gboolean transfer_gzip;
/* Our active HTTP requests */
GHashTable *outstanding;
@@ -553,6 +554,9 @@ ostree_fetcher_session_thread (gpointer data)
SOUP_SESSION_IDLE_TIMEOUT, 60,
NULL);
if (closure->transfer_gzip)
soup_session_add_feature_by_type (closure->session, SOUP_TYPE_CONTENT_DECODER);
/* XXX: Now that we have mirrorlist support, we could make this even smarter
* by spreading requests across mirrors. */
g_object_get (closure->session, "max-conns-per-host", &max_conns, NULL);
@@ -663,6 +667,7 @@ _ostree_fetcher_constructed (GObject *object)
self->thread_closure->ref_count = 1;
self->thread_closure->main_context = g_main_context_ref (main_context);
self->thread_closure->running = 1;
self->thread_closure->transfer_gzip = (self->config_flags & OSTREE_FETCHER_FLAGS_TRANSFER_GZIP) != 0;
self->thread_closure->tmpdir_dfd = -1;
self->thread_closure->tmpdir_lock = empty_lockfile;
+4 -1
View File
@@ -46,9 +46,12 @@ struct OstreeFetcherClass
GObjectClass parent_class;
};
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeFetcher, g_object_unref)
typedef enum {
OSTREE_FETCHER_FLAGS_NONE = 0,
OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE = (1 << 0)
OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE = (1 << 0),
OSTREE_FETCHER_FLAGS_TRANSFER_GZIP = (1 << 1)
} OstreeFetcherConfigFlags;
void
+2 -3
View File
@@ -665,9 +665,8 @@ ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result,
if (ostree_gpg_verify_result_count_valid (result) == 0)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"GPG signatures found, but none are in trusted keyring");
return FALSE;
return glnx_throw (error, "%s",
"GPG signatures found, but none are in trusted keyring");
}
return TRUE;
+11 -57
View File
@@ -27,6 +27,8 @@
#include <sys/ioctl.h>
#include <ext2fs/ext2_fs.h>
#include "otutil.h"
/**
* _ostree_linuxfs_fd_alter_immutable_flag:
* @fd: A file descriptor
@@ -47,29 +49,21 @@ _ostree_linuxfs_fd_alter_immutable_flag (int fd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
unsigned long flags;
int r;
static gint no_alter_immutable = 0;
if (g_atomic_int_get (&no_alter_immutable))
return TRUE;
r = ioctl (fd, EXT2_IOC_GETFLAGS, &flags);
unsigned long flags;
int r = ioctl (fd, EXT2_IOC_GETFLAGS, &flags);
if (r == -1)
{
int errsv = errno;
if (errsv == EPERM)
if (errno == EPERM)
g_atomic_int_set (&no_alter_immutable, 1);
else if (errsv == EOPNOTSUPP || errsv == ENOTTY)
else if (errno == EOPNOTSUPP || errno == ENOTTY)
;
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"ioctl(EXT2_IOC_GETFLAGS): %s",
g_strerror (errsv));
goto out;
}
return glnx_throw_errno_prefix (error, "ioctl(EXT2_IOC_GETFLAGS)");
}
else
{
@@ -80,54 +74,14 @@ _ostree_linuxfs_fd_alter_immutable_flag (int fd,
r = ioctl (fd, EXT2_IOC_SETFLAGS, &flags);
if (r == -1)
{
int errsv = errno;
if (errsv == EPERM)
if (errno == EPERM)
g_atomic_int_set (&no_alter_immutable, 1);
else if (errsv == EOPNOTSUPP || errsv == ENOTTY)
else if (errno == EOPNOTSUPP || errno == ENOTTY)
;
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"ioctl(EXT2_IOC_GETFLAGS): %s",
g_strerror (errsv));
goto out;
}
return glnx_throw_errno_prefix (error, "ioctl(EXT2_IOC_SETFLAGS)");
}
}
ret = TRUE;
out:
return ret;
}
gboolean
_ostree_linuxfs_alter_immutable_flag (GFile *path,
gboolean new_immutable_state,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
glnx_fd_close int fd = -1;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
fd = open (gs_file_get_path_cached (path), O_RDONLY|O_NONBLOCK|O_LARGEFILE);
if (fd == -1)
{
int errsv = errno;
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"open(%s): %s",
gs_file_get_path_cached (path),
g_strerror (errsv));
goto out;
}
if (!_ostree_linuxfs_fd_alter_immutable_flag (fd, new_immutable_state,
cancellable, error))
goto out;
ret = TRUE;
out:
return ret;
return TRUE;
}
-6
View File
@@ -30,10 +30,4 @@ _ostree_linuxfs_fd_alter_immutable_flag (int fd,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_linuxfs_alter_immutable_flag (GFile *path,
gboolean new_immutable_state,
GCancellable *cancellable,
GError **error);
G_END_DECLS
+4 -4
View File
@@ -38,15 +38,15 @@ G_BEGIN_DECLS
struct OstreeRemote {
volatile int ref_count;
char *name;
char *group; /* group name in options */
char *keyring; /* keyring name (NAME.trustedkeys.gpg) */
char *name; /* (not nullable) */
char *group; /* group name in options (not nullable) */
char *keyring; /* keyring name (NAME.trustedkeys.gpg) (not nullable) */
GFile *file; /* NULL if remote defined in repo/config */
GKeyFile *options;
};
G_GNUC_INTERNAL
OstreeRemote *ostree_remote_new (void);
OstreeRemote *ostree_remote_new (const gchar *name);
G_GNUC_INTERNAL
OstreeRemote *ostree_remote_new_from_keyfile (GKeyFile *keyfile,
+29 -5
View File
@@ -53,12 +53,17 @@
*/
OstreeRemote *
ostree_remote_new (void)
ostree_remote_new (const gchar *name)
{
OstreeRemote *remote;
g_return_val_if_fail (name != NULL && *name != '\0', NULL);
remote = g_slice_new0 (OstreeRemote);
remote->ref_count = 1;
remote->name = g_strdup (name);
remote->group = g_strdup_printf ("remote \"%s\"", name);
remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", name);
remote->options = g_key_file_new ();
return remote;
@@ -70,6 +75,7 @@ ostree_remote_new_from_keyfile (GKeyFile *keyfile,
{
g_autoptr(GMatchInfo) match = NULL;
OstreeRemote *remote;
g_autofree gchar *name = NULL;
static gsize regex_initialized;
static GRegex *regex;
@@ -88,10 +94,8 @@ ostree_remote_new_from_keyfile (GKeyFile *keyfile,
if (!g_regex_match (regex, group, 0, &match))
return NULL;
remote = ostree_remote_new ();
remote->name = g_match_info_fetch (match, 1);
remote->group = g_strdup (group);
remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", remote->name);
name = g_match_info_fetch (match, 1);
remote = ostree_remote_new (name);
ot_keyfile_copy_group (keyfile, remote->options, group);
@@ -148,3 +152,23 @@ G_DEFINE_BOXED_TYPE(OstreeRemote, ostree_remote,
ostree_remote_ref,
ostree_remote_unref);
#endif
/**
* ostree_remote_get_name:
* @remote: an #OstreeRemote
*
* Get the human-readable name of the remote. This is what the user configured,
* if the remote was explicitly configured; and will otherwise be a stable,
* arbitrary, string.
*
* Returns: remote’s name
* Since: 2017.7
*/
const gchar *
ostree_remote_get_name (OstreeRemote *remote)
{
g_return_val_if_fail (remote != NULL, NULL);
g_return_val_if_fail (remote->ref_count > 0, NULL);
return remote->name;
}
+4 -4
View File
@@ -48,16 +48,16 @@ G_BEGIN_DECLS
typedef struct OstreeRemote OstreeRemote;
#endif
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
#ifndef __GI_SCANNER__
_OSTREE_PUBLIC
GType ostree_remote_get_type (void) G_GNUC_CONST;
#else
#ifndef __GI_SCANNER__
_OSTREE_PUBLIC
OstreeRemote *ostree_remote_ref (OstreeRemote *remote);
_OSTREE_PUBLIC
void ostree_remote_unref (OstreeRemote *remote);
#endif /* GI_SCANNER */
#endif
_OSTREE_PUBLIC
const gchar *ostree_remote_get_name (OstreeRemote *remote);
G_END_DECLS
+49 -45
View File
@@ -60,13 +60,11 @@ checkout_object_for_uncompressed_cache (OstreeRepo *self,
guint32 file_mode = g_file_info_get_attribute_uint32 (src_info, "unix::mode");
file_mode &= ~(S_ISUID|S_ISGID);
glnx_fd_close int fd = -1;
g_autofree char *temp_filename = NULL;
if (!glnx_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_WRONLY | O_CLOEXEC,
&fd, &temp_filename,
error))
g_auto(OtTmpfile) tmpf = { 0, };
if (!ot_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_WRONLY | O_CLOEXEC,
&tmpf, error))
return FALSE;
g_autoptr(GOutputStream) temp_out = g_unix_output_stream_new (fd, FALSE);
g_autoptr(GOutputStream) temp_out = g_unix_output_stream_new (tmpf.fd, FALSE);
if (g_output_stream_splice (temp_out, content, 0, cancellable, error) < 0)
return FALSE;
@@ -76,14 +74,14 @@ checkout_object_for_uncompressed_cache (OstreeRepo *self,
if (!self->disable_fsync)
{
if (TEMP_FAILURE_RETRY (fsync (fd)) < 0)
if (TEMP_FAILURE_RETRY (fsync (tmpf.fd)) < 0)
return glnx_throw_errno (error);
}
if (!g_output_stream_close (temp_out, cancellable, error))
return FALSE;
if (fchmod (fd, file_mode) < 0)
if (fchmod (tmpf.fd, file_mode) < 0)
return glnx_throw_errno (error);
if (!_ostree_repo_ensure_loose_objdir_at (self->uncompressed_objects_dir_fd,
@@ -91,10 +89,9 @@ checkout_object_for_uncompressed_cache (OstreeRepo *self,
cancellable, error))
return FALSE;
if (!glnx_link_tmpfile_at (self->tmp_dir_fd, GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST,
fd, temp_filename,
self->uncompressed_objects_dir_fd, loose_path,
error))
if (!ot_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST,
self->uncompressed_objects_dir_fd, loose_path,
error))
return FALSE;
return TRUE;
@@ -143,10 +140,7 @@ write_regular_file_content (OstreeRepo *self,
{
if (TEMP_FAILURE_RETRY (fchown (outfd, g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
g_file_info_get_attribute_uint32 (file_info, "unix::gid"))) < 0)
return glnx_throw_errno (error);
if (TEMP_FAILURE_RETRY (fchmod (outfd, g_file_info_get_attribute_uint32 (file_info, "unix::mode"))) < 0)
return glnx_throw_errno (error);
return glnx_throw_errno_prefix (error, "fchown");
if (xattrs)
{
@@ -155,10 +149,19 @@ write_regular_file_content (OstreeRepo *self,
}
}
guint32 file_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
/* Don't make setuid files on checkout when we're doing --user */
if (mode == OSTREE_REPO_CHECKOUT_MODE_USER)
file_mode &= ~(S_ISUID|S_ISGID);
if (TEMP_FAILURE_RETRY (fchmod (outfd, file_mode)) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
if (fsync_is_enabled (self, options))
{
if (fsync (outfd) == -1)
return glnx_throw_errno (error);
return glnx_throw_errno_prefix (error, "fsync");
}
if (outstream)
@@ -185,7 +188,6 @@ create_file_copy_from_input_at (OstreeRepo *repo,
GCancellable *cancellable,
GError **error)
{
g_autofree char *temp_filename = NULL;
const gboolean union_mode = options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
const gboolean add_mode = options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES;
const gboolean sepolicy_enabled = options->sepolicy && !repo->disable_xattrs;
@@ -252,33 +254,26 @@ create_file_copy_from_input_at (OstreeRepo *repo,
}
else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
{
glnx_fd_close int temp_fd = -1;
guint32 file_mode;
g_auto(OtTmpfile) tmpf = { 0, };
GLnxLinkTmpfileReplaceMode replace_mode;
file_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
/* Don't make setuid files on checkout when we're doing --user */
if (options->mode == OSTREE_REPO_CHECKOUT_MODE_USER)
file_mode &= ~(S_ISUID|S_ISGID);
if (!glnx_open_tmpfile_linkable_at (destination_dfd, ".", O_WRONLY | O_CLOEXEC,
&temp_fd, &temp_filename,
error))
if (!ot_open_tmpfile_linkable_at (destination_dfd, ".", O_WRONLY | O_CLOEXEC,
&tmpf, error))
return FALSE;
if (sepolicy_enabled)
if (sepolicy_enabled && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER)
{
g_autofree char *label = NULL;
if (!ostree_sepolicy_get_label (options->sepolicy,
state->selabel_path_buf->str,
if (!ostree_sepolicy_get_label (options->sepolicy, state->selabel_path_buf->str,
g_file_info_get_attribute_uint32 (file_info, "unix::mode"),
&label, cancellable, error))
return FALSE;
if (fsetxattr (temp_fd, "security.selinux", label, strlen (label), 0) < 0)
if (fsetxattr (tmpf.fd, "security.selinux", label, strlen (label), 0) < 0)
return glnx_throw_errno_prefix (error, "Setting security.selinux");
}
if (!write_regular_file_content (repo, options, temp_fd, file_info, xattrs, input,
if (!write_regular_file_content (repo, options, tmpf.fd, file_info, xattrs, input,
cancellable, error))
return FALSE;
@@ -290,10 +285,9 @@ create_file_copy_from_input_at (OstreeRepo *repo,
else
replace_mode = GLNX_LINK_TMPFILE_NOREPLACE;
if (!glnx_link_tmpfile_at (destination_dfd, replace_mode,
temp_fd, temp_filename, destination_dfd,
destination_name,
error))
if (!ot_link_tmpfile_at (&tmpf, replace_mode,
destination_dfd, destination_name,
error))
return FALSE;
}
else
@@ -699,9 +693,9 @@ checkout_tree_at_recurse (OstreeRepo *self,
g_autoptr(GVariant) contents_csum_v = NULL;
while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v))
{
const size_t namelen = strlen (fname);
const size_t origlen = selabel_path_buf ? selabel_path_buf->len : 0;
if (selabel_path_buf)
g_string_append_len (selabel_path_buf, fname, namelen);
g_string_append (selabel_path_buf, fname);
char tmp_checksum[OSTREE_SHA256_STRING_LEN+1];
_ostree_checksum_inplace_from_bytes_v (contents_csum_v, tmp_checksum);
@@ -713,7 +707,7 @@ checkout_tree_at_recurse (OstreeRepo *self,
return FALSE;
if (selabel_path_buf)
g_string_truncate (selabel_path_buf, selabel_path_buf->len - namelen);
g_string_truncate (selabel_path_buf, origlen);
}
contents_csum_v = NULL; /* iter_loop freed it */
}
@@ -728,10 +722,10 @@ checkout_tree_at_recurse (OstreeRepo *self,
while (g_variant_iter_loop (&viter, "(&s@ay@ay)", &dname,
&subdirtree_csum_v, &subdirmeta_csum_v))
{
const size_t namelen = strlen (dname);
const size_t origlen = selabel_path_buf ? selabel_path_buf->len : 0;
if (selabel_path_buf)
{
g_string_append_len (selabel_path_buf, dname, namelen);
g_string_append (selabel_path_buf, dname);
g_string_append_c (selabel_path_buf, '/');
}
@@ -746,7 +740,7 @@ checkout_tree_at_recurse (OstreeRepo *self,
return FALSE;
if (selabel_path_buf)
g_string_truncate (selabel_path_buf, selabel_path_buf->len - namelen);
g_string_truncate (selabel_path_buf, origlen);
}
}
@@ -755,8 +749,18 @@ checkout_tree_at_recurse (OstreeRepo *self,
*/
if (!did_exist)
{
if (TEMP_FAILURE_RETRY (fchmod (destination_dfd, mode)) < 0)
return glnx_throw_errno (error);
guint32 canonical_mode;
/* Silently ignore world-writable directories (plus sticky, suid bits,
* etc.) when doing a checkout for bare-user-only repos, or if requested explicitly.
* This is related to the logic in ostree-repo-commit.c for files.
* See also: https://github.com/ostreedev/ostree/pull/909 i.e. 0c4b3a2b6da950fd78e63f9afec602f6188f1ab0
*/
if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY || options->bareuseronly_dirs)
canonical_mode = (mode & 0775) | S_IFDIR;
else
canonical_mode = mode;
if (TEMP_FAILURE_RETRY (fchmod (destination_dfd, canonical_mode)) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
}
if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER)
File diff suppressed because it is too large. Load diff
+56 -79
View File
@@ -148,7 +148,6 @@ _ostree_repo_file_new_for_commit (OstreeRepo *repo,
const char *commit,
GError **error)
{
OstreeRepoFile *ret = NULL;
g_autoptr(GVariant) commit_v = NULL;
g_autoptr(GVariant) tree_contents_csum_v = NULL;
g_autoptr(GVariant) tree_metadata_csum_v = NULL;
@@ -161,7 +160,7 @@ _ostree_repo_file_new_for_commit (OstreeRepo *repo,
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
commit, &commit_v, error))
goto out;
return NULL;
/* PARSE OSTREE_OBJECT_TYPE_COMMIT */
g_variant_get_child (commit_v, 6, "@ay", &tree_contents_csum_v);
@@ -172,17 +171,13 @@ _ostree_repo_file_new_for_commit (OstreeRepo *repo,
ostree_checksum_inplace_from_bytes (g_variant_get_data (tree_metadata_csum_v),
tree_metadata_csum);
ret = _ostree_repo_file_new_root (repo, tree_contents_csum, tree_metadata_csum);
out:
return ret;
return _ostree_repo_file_new_root (repo, tree_contents_csum, tree_metadata_csum);
}
static gboolean
do_resolve (OstreeRepoFile *self,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GVariant) root_contents = NULL;
g_autoptr(GVariant) root_metadata = NULL;
@@ -190,27 +185,24 @@ do_resolve (OstreeRepoFile *self,
if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_TREE,
self->tree_contents_checksum, &root_contents, error))
goto out;
return FALSE;
if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_META,
self->tree_metadata_checksum, &root_metadata, error))
goto out;
return FALSE;
self->tree_metadata = root_metadata;
root_metadata = NULL;
self->tree_contents = root_contents;
root_contents = NULL;
ret = TRUE;
out:
return ret;
return TRUE;
}
static gboolean
do_resolve_nonroot (OstreeRepoFile *self,
GError **error)
{
gboolean ret = FALSE;
gboolean is_dir;
int i;
g_autoptr(GVariant) container = NULL;
@@ -221,13 +213,13 @@ do_resolve_nonroot (OstreeRepoFile *self,
g_autofree char *tmp_checksum = NULL;
if (!ostree_repo_file_ensure_resolved (self->parent, error))
goto out;
return FALSE;
if (!self->parent->tree_contents)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
"Not a directory");
goto out;
return FALSE;
}
i = ostree_repo_file_tree_find_child (self->parent, self->name, &is_dir, &container);
@@ -235,7 +227,7 @@ do_resolve_nonroot (OstreeRepoFile *self,
if (i < 0)
{
set_error_noent ((GFile*)self, error);
goto out;
return FALSE;
}
if (is_dir)
@@ -255,14 +247,14 @@ do_resolve_nonroot (OstreeRepoFile *self,
if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_TREE,
tmp_checksum, &tree_contents,
error))
goto out;
return FALSE;
g_free (tmp_checksum);
tmp_checksum = ostree_checksum_from_bytes_v (metadata_csum_v);
if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_META,
tmp_checksum, &tree_metadata,
error))
goto out;
return FALSE;
self->tree_contents = tree_contents;
tree_contents = NULL;
@@ -274,35 +266,29 @@ do_resolve_nonroot (OstreeRepoFile *self,
else
self->index = i;
ret = TRUE;
out:
return ret;
return TRUE;
}
gboolean
ostree_repo_file_ensure_resolved (OstreeRepoFile *self,
GError **error)
{
gboolean ret = FALSE;
if (self->parent == NULL)
{
if (self->tree_contents == NULL)
if (!do_resolve (self, error))
goto out;
return FALSE;
}
else
{
if (self->index == -1)
{
if (!do_resolve_nonroot (self, error))
goto out;
return FALSE;
}
}
ret = TRUE;
out:
return ret;
return TRUE;
}
gboolean
@@ -311,25 +297,21 @@ ostree_repo_file_get_xattrs (OstreeRepoFile *self,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GVariant) ret_xattrs = NULL;
if (!ostree_repo_file_ensure_resolved (self, error))
goto out;
return FALSE;
g_autoptr(GVariant) ret_xattrs = NULL;
if (self->tree_metadata)
ret_xattrs = g_variant_get_child_value (self->tree_metadata, 3);
else
else
{
if (!ostree_repo_load_file (self->repo, ostree_repo_file_get_checksum (self),
NULL, NULL, &ret_xattrs, cancellable, error))
goto out;
return FALSE;
}
ret = TRUE;
ot_transfer_out_value(out_xattrs, &ret_xattrs);
out:
return ret;
return TRUE;
}
GVariant *
@@ -721,28 +703,24 @@ query_child_info_dir (OstreeRepo *repo,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GFileInfo) ret_info = NULL;
g_autoptr(GVariant) metadata = NULL;
ret_info = g_file_info_new ();
g_autoptr(GFileInfo) ret_info = g_file_info_new ();
g_file_info_set_attribute_uint32 (ret_info, "standard::type",
G_FILE_TYPE_DIRECTORY);
if (g_file_attribute_matcher_matches (matcher, "unix::mode"))
{
g_autoptr(GVariant) metadata = NULL;
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_DIR_META,
metadata_checksum, &metadata, error))
goto out;
return FALSE;
set_info_from_dirmeta (ret_info, metadata);
}
ret = TRUE;
ot_transfer_out_value(out_info, &ret_info);
out:
return ret;
return TRUE;
}
int
@@ -890,12 +868,11 @@ ostree_repo_file_query_info (GFile *file,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
OstreeRepoFile *self = OSTREE_REPO_FILE (file);
g_autoptr(GFileInfo) info = NULL;
if (!ostree_repo_file_ensure_resolved (self, error))
goto out;
return NULL;
if (!self->parent)
{
@@ -904,20 +881,14 @@ ostree_repo_file_query_info (GFile *file,
}
else
{
if (!ostree_repo_file_tree_query_child (self->parent, self->index,
attributes, flags,
if (!ostree_repo_file_tree_query_child (self->parent, self->index,
attributes, flags,
&info, cancellable, error))
goto out;
return NULL;
g_assert (info != NULL);
}
ret = TRUE;
out:
if (!ret)
g_clear_object (&info);
else
g_object_ref (info);
return info;
return g_steal_pointer (&info);
}
static GFileAttributeInfoList *
@@ -938,38 +909,44 @@ ostree_repo_file_query_writable_namespaces (GFile *file,
static GFileInputStream *
ostree_repo_file_read (GFile *file,
GCancellable *cancellable,
GError **error)
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
OstreeRepoFile *self = OSTREE_REPO_FILE (file);
const char *checksum;
g_autoptr(GInputStream) ret_stream = NULL;
if (!ostree_repo_file_ensure_resolved (self, error))
goto out;
return FALSE;
if (self->tree_contents)
{
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_IS_DIRECTORY,
"Can't open directory");
goto out;
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
"Can't open directory");
return NULL;
}
checksum = ostree_repo_file_get_checksum (self);
if (!ostree_repo_load_file (self->repo, checksum, &ret_stream,
NULL, NULL, cancellable, error))
goto out;
ret = TRUE;
out:
if (!ret)
g_clear_object (&ret_stream);
g_autoptr(GFileInfo) finfo = NULL;
if (!ostree_repo_load_file (self->repo, checksum, NULL,
&finfo, NULL, cancellable, error))
return NULL;
if (g_file_info_get_file_type (finfo) == G_FILE_TYPE_REGULAR)
{
if (!ostree_repo_load_file (self->repo, checksum, &ret_stream,
NULL, NULL, cancellable, error))
return NULL;
}
else
g_object_ref (ret_stream);
return (GFileInputStream*)ret_stream;
{
g_autoptr(GFile) parent = g_file_get_parent (file);
const char *target = g_file_info_get_symlink_target (finfo);
g_autoptr(GFile) dest = g_file_resolve_relative_path (parent, target);
return g_file_read (dest, cancellable, error);
}
return g_steal_pointer (&ret_stream);
}
static void
+2 -3
View File
@@ -640,9 +640,8 @@ aic_handle_entry (OstreeRepoArchiveImportContext *ctx,
return TRUE;
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Unsupported file type for path \"%s\"", path);
return FALSE;
return glnx_throw (error, "Unsupported file type for path \"%s\"",
path);
}
}
}
+6 -23
View File
@@ -106,6 +106,7 @@ struct OstreeRepo {
gboolean inited;
gboolean writable;
gboolean is_system; /* Was this repo created via ostree_sysroot_get_repo() ? */
GError *writable_error;
gboolean in_transaction;
gboolean disable_fsync;
@@ -115,6 +116,7 @@ struct OstreeRepo {
GHashTable *updated_uncompressed_dirs;
GHashTable *object_sizes;
uid_t owner_uid;
uid_t target_owner_uid;
gid_t target_owner_gid;
@@ -318,28 +320,6 @@ _ostree_repo_commit_trusted_content_bare (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_repo_open_untrusted_content_bare (OstreeRepo *self,
const char *expected_checksum,
guint64 content_len,
OstreeRepoContentBareCommit *out_state,
GOutputStream **out_stream,
gboolean *out_have_object,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_repo_commit_untrusted_content_bare (OstreeRepo *self,
const char *expected_checksum,
OstreeRepoContentBareCommit *state,
guint32 uid,
guint32 gid,
guint32 mode,
GVariant *xattrs,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_repo_read_bare_fd (OstreeRepo *self,
const char *checksum,
@@ -351,9 +331,12 @@ gboolean
_ostree_repo_update_mtime (OstreeRepo *self,
GError **error);
void
gboolean
_ostree_repo_add_remote (OstreeRepo *self,
OstreeRemote *remote);
gboolean
_ostree_repo_remove_remote (OstreeRepo *self,
OstreeRemote *remote);
OstreeRemote *
_ostree_repo_get_remote (OstreeRepo *self,
const char *name,
+174 -51
View File
@@ -80,6 +80,7 @@ typedef struct {
GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */
GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */
GHashTable *scanned_metadata; /* Maps object name to itself */
GHashTable *fetched_detached_metadata; /* Set<checksum> */
GHashTable *requested_metadata; /* Maps object name to itself */
GHashTable *requested_content; /* Maps checksum to itself */
GHashTable *requested_fallback_content; /* Maps checksum to itself */
@@ -110,6 +111,7 @@ typedef struct {
gboolean is_mirror;
gboolean is_commit_only;
gboolean is_untrusted;
gboolean is_bareuseronly_files;
GPtrArray *dirs;
@@ -151,7 +153,7 @@ typedef struct {
guchar csum[OSTREE_SHA256_DIGEST_LEN];
char *path;
OstreeObjectType objtype;
guint recursion_depth;
guint recursion_depth; /* NB: not used anymore, though might be nice to print */
} ScanObjectQueueData;
static void start_fetch (OtPullData *pull_data, FetchObjectData *fetch);
@@ -555,6 +557,94 @@ pull_matches_subdir (OtPullData *pull_data,
return FALSE;
}
/* This bit mirrors similar code in commit_loose_content_object() for the
* bare-user-only mode. It's opt-in though for all pulls.
*/
static gboolean
validate_bareuseronly_mode (OtPullData *pull_data,
const char *checksum,
guint32 content_mode,
GError **error)
{
if (!pull_data->is_bareuseronly_files)
return TRUE;
if (S_ISREG (content_mode))
{
const guint32 invalid_modebits = ((content_mode & ~S_IFMT) & ~0775);
if (invalid_modebits > 0)
return glnx_throw (error, "object %s.file: invalid mode 0%04o with bits 0%04o",
checksum, content_mode, invalid_modebits);
}
else if (S_ISLNK (content_mode))
; /* Nothing */
else
g_assert_not_reached ();
return TRUE;
}
/* Import a single content object in the case where
* we have pull_data->remote_repo_local.
*
* 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,
const char *checksum,
GCancellable *cancellable,
GError **error)
{
g_assert (pull_data->remote_repo_local);
const gboolean trusted = !pull_data->is_untrusted;
if (trusted && !pull_data->is_bareuseronly_files)
{
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, pull_data->remote_repo_local,
OSTREE_OBJECT_TYPE_FILE, checksum,
trusted,
cancellable, error))
return FALSE;
}
else
{
/* In this case we either need to validate the checksum
* or the file mode.
*/
g_autoptr(GInputStream) content_input = NULL;
g_autoptr(GFileInfo) content_finfo = NULL;
g_autoptr(GVariant) content_xattrs = NULL;
if (!ostree_repo_load_file (pull_data->remote_repo_local, checksum,
&content_input, &content_finfo, &content_xattrs,
cancellable, error))
return FALSE;
if (!validate_bareuseronly_mode (pull_data, checksum,
g_file_info_get_attribute_uint32 (content_finfo, "unix::mode"),
error))
return FALSE;
/* Now that we've potentially validated it, convert to object stream */
guint64 length;
g_autoptr(GInputStream) object_stream = NULL;
if (!ostree_raw_file_to_content_stream (content_input, content_finfo,
content_xattrs, &object_stream,
&length, cancellable, error))
return FALSE;
g_autofree guchar *real_csum = NULL;
if (!ostree_repo_write_content (pull_data->repo, checksum,
object_stream, length,
&real_csum,
cancellable, error))
return FALSE;
}
return TRUE;
}
static gboolean
scan_dirtree_object (OtPullData *pull_data,
const char *checksum,
@@ -563,9 +653,6 @@ scan_dirtree_object (OtPullData *pull_data,
GCancellable *cancellable,
GError **error)
{
if (recursion_depth > OSTREE_MAX_RECURSION)
return glnx_throw (error, "Exceeded maximum recursion");
g_autoptr(GVariant) tree = NULL;
if (!ostree_repo_load_variant (pull_data->repo, OSTREE_OBJECT_TYPE_DIR_TREE, checksum,
&tree, error))
@@ -597,15 +684,19 @@ scan_dirtree_object (OtPullData *pull_data,
&file_is_stored, cancellable, error))
return FALSE;
if (!file_is_stored && pull_data->remote_repo_local)
/* If we already have this object, move on to the next */
if (file_is_stored)
continue;
/* Is this a local repo? */
if (pull_data->remote_repo_local)
{
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, pull_data->remote_repo_local,
OSTREE_OBJECT_TYPE_FILE, file_checksum, !pull_data->is_untrusted,
cancellable, error))
if (!import_one_local_content_object (pull_data, file_checksum, cancellable, error))
return FALSE;
}
else if (!file_is_stored && !g_hash_table_lookup (pull_data->requested_content, file_checksum))
else if (!g_hash_table_lookup (pull_data->requested_content, file_checksum))
{
/* In this case we're doing HTTP pulls */
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);
file_checksum = NULL; /* Transfer ownership */
@@ -780,7 +871,12 @@ content_fetch_on_complete (GObject *object,
checksum_obj = ostree_object_to_string (checksum, objtype);
g_debug ("fetch of %s complete", checksum_obj);
if (pull_data->is_mirror && pull_data->repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
/* If we're mirroring and writing into an archive repo, we can directly copy
* the content rather than paying the cost of exploding it, checksumming, and
* re-gzip.
*/
if (pull_data->is_mirror && pull_data->repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2
&& !pull_data->is_bareuseronly_files)
{
gboolean have_object;
if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, checksum,
@@ -812,16 +908,22 @@ content_fetch_on_complete (GObject *object,
}
/* Also, delete it now that we've opened it, we'll hold
* a reference to the fd. If we fail to write later, then
* a reference to the fd. If we fail to validate or write, then
* the temp space will be cleaned up.
*/
(void) unlinkat (_ostree_fetcher_get_dfd (fetcher), temp_path, 0);
if (!validate_bareuseronly_mode (pull_data,
checksum,
g_file_info_get_attribute_uint32 (file_info, "unix::mode"),
error))
goto out;
if (!ostree_raw_file_to_content_stream (file_in, file_info, xattrs,
&object_input, &length,
cancellable, error))
goto out;
pull_data->n_outstanding_content_write_requests++;
ostree_repo_write_content_async (pull_data->repo, checksum,
object_input, length,
@@ -912,8 +1014,15 @@ meta_fetch_on_complete (GObject *object,
{
/* There isn't any detached metadata, just fetch the commit */
g_clear_error (&local_error);
/* Now that we've at least tried to fetch it, we can proceed to
* scan/fetch the commit 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);
else
queue_scan_one_metadata_object (pull_data, checksum, objtype, fetch_data->path, 0);
}
/* When traversing parents, do not fail on a missing commit.
@@ -960,8 +1069,12 @@ meta_fetch_on_complete (GObject *object,
pull_data->cancellable, error))
goto out;
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);
else
queue_scan_one_metadata_object (pull_data, checksum, objtype, fetch_data->path, 0);
}
else
{
@@ -977,7 +1090,7 @@ meta_fetch_on_complete (GObject *object,
if (!write_commitpartial_for (pull_data, checksum, error))
goto out;
}
ostree_repo_write_metadata_async (pull_data->repo, objtype, checksum, metadata,
pull_data->cancellable,
on_metadata_written, fetch_data);
@@ -1176,13 +1289,6 @@ scan_commit_object (OtPullData *pull_data,
gint depth;
gboolean is_partial;
if (recursion_depth > OSTREE_MAX_RECURSION)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Exceeded maximum recursion");
goto out;
}
if (g_hash_table_lookup_extended (pull_data->commit_to_depth, checksum,
NULL, &depthp))
{
@@ -1377,15 +1483,20 @@ scan_one_metadata_object_c (OtPullData *pull_data,
}
else if (is_stored && objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
/* For commits, always refetch detached metadata. */
enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, TRUE, TRUE);
/* Even though we already have the commit, we always try to (re)fetch the
* 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);
else
{
if (!scan_commit_object (pull_data, tmp_checksum, recursion_depth,
pull_data->cancellable, error))
goto out;
if (!scan_commit_object (pull_data, tmp_checksum, recursion_depth,
pull_data->cancellable, error))
goto out;
g_hash_table_add (pull_data->scanned_metadata, g_variant_ref (object));
pull_data->n_scanned_metadata++;
g_hash_table_add (pull_data->scanned_metadata, g_variant_ref (object));
pull_data->n_scanned_metadata++;
}
}
else if (is_stored && objtype == OSTREE_OBJECT_TYPE_DIR_TREE)
{
@@ -2144,6 +2255,7 @@ _ostree_repo_cache_summary (OstreeRepo *self,
static OstreeFetcher *
_ostree_repo_remote_new_fetcher (OstreeRepo *self,
const char *remote_name,
gboolean gzip,
GError **error)
{
OstreeFetcher *fetcher = NULL;
@@ -2162,6 +2274,9 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self,
if (tls_permissive)
fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE;
if (gzip)
fetcher_flags |= OSTREE_FETCHER_FLAGS_TRANSFER_GZIP;
fetcher = _ostree_fetcher_new (self->tmp_dir_fd, remote_name, fetcher_flags);
{
@@ -2419,7 +2534,7 @@ repo_remote_fetch_summary (OstreeRepo *self,
mainctx = g_main_context_new ();
g_main_context_push_thread_default (mainctx);
fetcher = _ostree_repo_remote_new_fetcher (self, name, error);
fetcher = _ostree_repo_remote_new_fetcher (self, name, TRUE, error);
if (fetcher == NULL)
goto out;
@@ -2527,7 +2642,7 @@ static gboolean
reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **error)
{
g_clear_object (&pull_data->fetcher);
pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, error);
pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, FALSE, error);
if (pull_data->fetcher == NULL)
return FALSE;
@@ -2679,7 +2794,7 @@ initiate_request (OtPullData *pull_data,
* * override-commit-ids (as): Array of specific commit IDs to fetch for refs
* * dry-run (b): Only print information on what will be downloaded (requires static deltas)
* * override-url (s): Fetch objects from this URL if remote specifies no metalink in options
* * inherit-transaction (b): Don't initiate, finish or abort a transaction, usefult to do multiple pulls in one transaction.
* * inherit-transaction (b): Don't initiate, finish or abort a transaction, useful to do multiple pulls in one transaction.
* * http-headers (a(ss)): Additional headers to add to all HTTP requests
* * update-frequency (u): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid
*/
@@ -2764,6 +2879,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
pull_data->is_mirror = (flags & OSTREE_REPO_PULL_FLAGS_MIRROR) > 0;
pull_data->is_commit_only = (flags & OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY) > 0;
pull_data->is_untrusted = (flags & OSTREE_REPO_PULL_FLAGS_UNTRUSTED) > 0;
pull_data->is_bareuseronly_files = (flags & OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES) > 0;
pull_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
if (error)
@@ -2787,6 +2903,8 @@ ostree_repo_pull_with_options (OstreeRepo *self,
(GDestroyNotify)g_free);
pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
(GDestroyNotify)g_variant_unref, NULL);
pull_data->fetched_detached_metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL);
pull_data->requested_content = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL);
pull_data->requested_fallback_content = g_hash_table_new_full (g_str_hash, g_str_equal,
@@ -3029,11 +3147,15 @@ ostree_repo_pull_with_options (OstreeRepo *self,
}
}
/* For local pulls, default to disabling static deltas so that the
* exact object files are copied.
*/
if (pull_data->remote_repo_local && !pull_data->require_static_deltas)
pull_data->disable_static_deltas = TRUE;
if (pull_data->remote_repo_local)
{
/* For local pulls, default to disabling static deltas so that the
* exact object files are copied.
*/
if (!pull_data->require_static_deltas)
pull_data->disable_static_deltas = TRUE;
}
/* We can't use static deltas if pulling into an archive-z2 repo. */
if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
@@ -3161,8 +3283,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
if (pull_data->summary)
{
refs = g_variant_get_child_value (pull_data->summary, 0);
n = g_variant_n_children (refs);
for (i = 0; i < n; i++)
for (i = 0, n = g_variant_n_children (refs); i < n; i++)
{
const char *refname;
g_autoptr(GVariant) ref = g_variant_get_child_value (refs, i);
@@ -3229,7 +3350,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
char *commitid = commitid_strviter ? g_strdup (*commitid_strviter) : NULL;
g_hash_table_insert (requested_refs_to_fetch, g_strdup (branch), commitid);
}
strviter++;
if (commitid_strviter)
commitid_strviter++;
@@ -3365,7 +3486,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
ret = TRUE;
goto out;
}
g_assert_cmpint (pull_data->n_outstanding_metadata_fetches, ==, 0);
g_assert_cmpint (pull_data->n_outstanding_metadata_write_requests, ==, 0);
g_assert_cmpint (pull_data->n_outstanding_content_fetches, ==, 0);
@@ -3378,9 +3499,9 @@ ostree_repo_pull_with_options (OstreeRepo *self,
const char *checksum = value;
g_autofree char *remote_ref = NULL;
g_autofree char *original_rev = NULL;
if (pull_data->remote_name)
remote_ref = g_strdup_printf ("%s/%s", pull_data->remote_name, ref);
remote_ref = g_strdup_printf ("%s:%s", pull_data->remote_name, ref);
else
remote_ref = g_strdup (ref);
@@ -3397,7 +3518,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
}
}
if (pull_data->is_mirror && pull_data->summary_data)
if (pull_data->is_mirror && pull_data->summary_data && !refs_to_fetch && !configured_branches)
{
GLnxFileReplaceFlags replaceflag =
pull_data->repo->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : 0;
@@ -3467,15 +3588,16 @@ ostree_repo_pull_with_options (OstreeRepo *self,
if (!ot_ensure_unlinked_at (pull_data->repo->repo_dir_fd, commitpartial_path, 0))
goto out;
}
g_hash_table_iter_init (&hash_iter, commits_to_fetch);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *commit = value;
g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (commit);
if (!ot_ensure_unlinked_at (pull_data->repo->repo_dir_fd, commitpartial_path, 0))
goto out;
}
g_hash_table_iter_init (&hash_iter, commits_to_fetch);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *commit = value;
g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (commit);
if (!ot_ensure_unlinked_at (pull_data->repo->repo_dir_fd, commitpartial_path, 0))
goto out;
}
}
ret = TRUE;
@@ -3509,6 +3631,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_clear_pointer (&pull_data->commit_to_depth, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->expected_commit_sizes, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->scanned_metadata, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->fetched_detached_metadata, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->summary_deltas_checksums, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->requested_fallback_content, (GDestroyNotify) g_hash_table_unref);
@@ -45,9 +45,8 @@ _ostree_static_delta_parse_checksum_array (GVariant *array,
if (G_UNLIKELY(n > (G_MAXUINT32/OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN) ||
(n_checksums * OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN) != n))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid checksum array length %" G_GSIZE_FORMAT, n);
return FALSE;
return glnx_throw (error,
"Invalid checksum array length %" G_GSIZE_FORMAT, n);
}
*out_checksums_array = (gpointer)g_variant_get_data (array);
@@ -115,9 +115,7 @@ read_varuint64 (StaticDeltaExecutionState *state,
gsize bytes_read;
if (!_ostree_read_varuint64 (state->opdata, state->oplen, out_value, &bytes_read))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Unexpected EOF reading varint");
return FALSE;
return glnx_throw (error, "%s", "Unexpected EOF reading varint");
}
state->opdata += bytes_read;
state->oplen -= bytes_read;
@@ -692,7 +690,8 @@ dispatch_open (OstreeRepo *repo,
if (!state->stats_only)
{
g_assert (repo->mode == OSTREE_REPO_MODE_BARE ||
repo->mode == OSTREE_REPO_MODE_BARE_USER);
repo->mode == OSTREE_REPO_MODE_BARE_USER ||
repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY);
}
if (!open_output_target (state, cancellable, error))
+243 -149
View File
@@ -150,24 +150,28 @@ _ostree_repo_get_remote_inherited (OstreeRepo *self,
return g_steal_pointer (&remote);
}
void
gboolean
_ostree_repo_add_remote (OstreeRepo *self,
OstreeRemote *remote)
{
g_return_if_fail (self != NULL);
g_return_if_fail (remote != NULL);
g_return_if_fail (remote->name != NULL);
gboolean already_existed;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (remote != NULL, FALSE);
g_return_val_if_fail (remote->name != NULL, FALSE);
g_mutex_lock (&self->remotes_lock);
g_hash_table_replace (self->remotes, remote->name, ostree_remote_ref (remote));
already_existed = g_hash_table_replace (self->remotes, remote->name, ostree_remote_ref (remote));
g_mutex_unlock (&self->remotes_lock);
return already_existed;
}
static gboolean
ost_repo_remove_remote (OstreeRepo *self,
OstreeRemote *remote)
gboolean
_ostree_repo_remove_remote (OstreeRepo *self,
OstreeRemote *remote)
{
gboolean removed;
@@ -706,6 +710,12 @@ ostree_repo_is_system (OstreeRepo *repo)
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)
return TRUE;
default_repo_path = get_default_repo_path (repo->sysroot_dir);
return g_file_equal (repo->repodir, default_repo_path);
@@ -882,10 +892,7 @@ impl_repo_remote_add (OstreeRepo *self,
name, remote->file ? gs_file_get_path_cached (remote->file) : "(in config)");
}
remote = ostree_remote_new ();
remote->name = g_strdup (name);
remote->group = g_strdup_printf ("remote \"%s\"", name);
remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", name);
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
@@ -1039,7 +1046,7 @@ impl_repo_remote_delete (OstreeRepo *self,
if (!ot_ensure_unlinked_at (self->repo_dir_fd, remote->keyring, error))
return FALSE;
ost_repo_remove_remote (self, remote);
_ostree_repo_remove_remote (self, remote);
return TRUE;
}
@@ -1322,7 +1329,6 @@ ostree_repo_remote_gpg_import (OstreeRepo *self,
struct stat stbuf;
gpgme_error_t gpg_error;
gboolean ret = FALSE;
const GLnxFileCopyFlags copyflags = self->disable_xattrs ? GLNX_FILE_COPY_NOXATTRS : 0;
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
@@ -1446,7 +1452,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self,
{
if (!glnx_file_copy_at (self->repo_dir_fd, remote->keyring,
&stbuf, target_temp_fd, "pubring.gpg",
copyflags, cancellable, error))
GLNX_FILE_COPY_NOXATTRS, cancellable, error))
{
g_prefix_error (error, "Unable to copy remote's keyring: ");
goto out;
@@ -1530,7 +1536,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self,
* updated keyring in the target context's temporary directory. */
if (!glnx_file_copy_at (target_temp_fd, "pubring.gpg", NULL,
self->repo_dir_fd, remote->keyring,
copyflags | GLNX_FILE_COPY_OVERWRITE,
GLNX_FILE_COPY_NOXATTRS | GLNX_FILE_COPY_OVERWRITE,
cancellable, error))
goto out;
@@ -2086,6 +2092,7 @@ ostree_repo_open (OstreeRepo *self,
if (fstat (self->objects_dir_fd, &stbuf) != 0)
return glnx_throw_errno (error);
self->owner_uid = stbuf.st_uid;
if (stbuf.st_uid != getuid () || stbuf.st_gid != getgid ())
{
@@ -2495,19 +2502,33 @@ load_metadata_internal (OstreeRepo *self,
return TRUE;
}
/* Basically fstatat(), but also looks in both the committed and staging
* directories, and returns *out_dfd for where we found the object.
*/
static gboolean
query_info_for_bare_content_object (OstreeRepo *self,
const char *loose_path_buf,
GFileInfo **out_info,
GCancellable *cancellable,
GError **error)
stat_bare_content_object (OstreeRepo *self,
const char *loose_path_buf,
int *out_dfd,
GFileInfo **out_info,
GCancellable *cancellable,
GError **error)
{
struct stat stbuf;
int res;
int dirfd;
if (TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0)
dirfd = self->objects_dir_fd;
res = TEMP_FAILURE_RETRY (fstatat (dirfd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW));
if (res < 0 && errno == ENOENT && self->commit_stagedir_fd != -1)
{
dirfd = self->commit_stagedir_fd;
res = TEMP_FAILURE_RETRY (fstatat (dirfd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW));
}
if (res < 0)
{
if (errno == ENOENT)
{
*out_dfd = -1;
*out_info = NULL;
return TRUE;
}
@@ -2522,13 +2543,14 @@ query_info_for_bare_content_object (OstreeRepo *self,
}
else if (S_ISLNK (stbuf.st_mode))
{
if (!ot_readlinkat_gfile_info (self->objects_dir_fd, loose_path_buf,
if (!ot_readlinkat_gfile_info (dirfd, loose_path_buf,
ret_info, cancellable, error))
return FALSE;
}
else
return glnx_throw (error, "Not a regular file or symlink: %s", loose_path_buf);
*out_dfd = dirfd;
ot_transfer_out_value (out_info, &ret_info);
return TRUE;
}
@@ -2569,6 +2591,12 @@ _ostree_repo_read_bare_fd (OstreeRepo *self,
if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, out_fd, error))
return FALSE;
if (*out_fd == -1 && self->commit_stagedir_fd != -1)
{
if (!ot_openat_ignore_enoent (self->commit_stagedir_fd, loose_path_buf, out_fd, error))
return FALSE;
}
if (*out_fd == -1)
{
if (self->parent_repo)
@@ -2590,9 +2618,9 @@ _ostree_repo_read_bare_fd (OstreeRepo *self,
* ostree_repo_load_file:
* @self: Repo
* @checksum: ASCII SHA256 checksum
* @out_input: (out) (allow-none): File content
* @out_file_info: (out) (allow-none): File information
* @out_xattrs: (out) (allow-none): Extended attributes
* @out_input: (out) (optional) (nullable): File content
* @out_file_info: (out) (optional) (nullable): File information
* @out_xattrs: (out) (optional) (nullable): Extended attributes
* @cancellable: Cancellable
* @error: Error
*
@@ -2655,9 +2683,11 @@ ostree_repo_load_file (OstreeRepo *self,
}
else
{
if (!query_info_for_bare_content_object (self, loose_path_buf,
&ret_file_info,
cancellable, error))
int objdir_fd; /* referenced */
if (!stat_bare_content_object (self, loose_path_buf,
&objdir_fd,
&ret_file_info,
cancellable, error))
return FALSE;
if (ret_file_info)
@@ -2675,7 +2705,7 @@ ostree_repo_load_file (OstreeRepo *self,
* always do an open, then query the user.ostreemeta xattr for
* more information.
*/
fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
fd = openat (objdir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return glnx_throw_errno (error);
@@ -2729,7 +2759,7 @@ ostree_repo_load_file (OstreeRepo *self,
if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR &&
out_input)
{
fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
fd = openat (objdir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return glnx_throw_errno (error);
@@ -2753,7 +2783,7 @@ ostree_repo_load_file (OstreeRepo *self,
{
glnx_fd_close int fd = -1;
fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
fd = openat (objdir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return glnx_throw_errno (error);
@@ -2777,7 +2807,7 @@ ostree_repo_load_file (OstreeRepo *self,
{
if (self->disable_xattrs)
ret_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0));
else if (!glnx_dfd_name_get_all_xattrs (self->objects_dir_fd, loose_path_buf,
else if (!glnx_dfd_name_get_all_xattrs (objdir_fd, loose_path_buf,
&ret_xattrs,
cancellable, error))
return FALSE;
@@ -3043,75 +3073,18 @@ copy_detached_metadata (OstreeRepo *self,
return TRUE;
}
/* Special case between bare-user and bare-user-only,
* mostly for https://github.com/flatpak/flatpak/issues/845
* see below for any more comments.
*/
static gboolean
import_one_object_copy (OstreeRepo *self,
OstreeRepo *source,
const char *checksum,
OstreeObjectType objtype,
gboolean trusted,
GCancellable *cancellable,
GError **error)
import_is_bareuser_only_conversion (OstreeRepo *src_repo,
OstreeRepo *dest_repo,
OstreeObjectType objtype)
{
guint64 length;
g_autoptr(GInputStream) object_stream = NULL;
if (!ostree_repo_load_object_stream (source, objtype, checksum,
&object_stream, &length,
cancellable, error))
return FALSE;
if (objtype == OSTREE_OBJECT_TYPE_FILE)
{
if (trusted)
{
if (!ostree_repo_write_content_trusted (self, checksum,
object_stream, length,
cancellable, error))
return FALSE;
}
else
{
g_autofree guchar *real_csum = NULL;
if (!ostree_repo_write_content (self, checksum,
object_stream, length,
&real_csum,
cancellable, error))
return FALSE;
}
}
else
{
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
if (!copy_detached_metadata (self, source, checksum, cancellable, error))
return FALSE;
}
if (trusted)
{
if (!ostree_repo_write_metadata_stream_trusted (self, objtype,
checksum, object_stream, length,
cancellable, error))
return FALSE;
}
else
{
g_autofree guchar *real_csum = NULL;
g_autoptr(GVariant) variant = NULL;
if (!ostree_repo_load_variant (source, objtype, checksum,
&variant, error))
return FALSE;
if (!ostree_repo_write_metadata (self, objtype,
checksum, variant,
&real_csum,
cancellable, error))
return FALSE;
}
}
return TRUE;
return src_repo->mode == OSTREE_REPO_MODE_BARE_USER
&& dest_repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY
&& objtype == OSTREE_OBJECT_TYPE_FILE;
}
static gboolean
@@ -3126,6 +3099,33 @@ import_one_object_link (OstreeRepo *self,
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (loose_path_buf, checksum, objtype, self->mode);
/* Hardlinking between bare-user → bare-user-only is only possible for regular
* files, *not* symlinks, which in bare-user are stored as regular files. At
* this point we need to parse the file to see the difference.
*/
if (import_is_bareuser_only_conversion (source, self, objtype))
{
g_autoptr(GFileInfo) finfo = NULL;
if (!ostree_repo_load_file (source, checksum, NULL, &finfo, NULL,
cancellable, error))
return FALSE;
switch (g_file_info_get_file_type (finfo))
{
case G_FILE_TYPE_REGULAR:
/* This is OK, we'll drop through and try a hardlink */
break;
case G_FILE_TYPE_SYMBOLIC_LINK:
/* NOTE early return */
*out_was_supported = FALSE;
return TRUE;
default:
g_assert_not_reached ();
break;
}
}
if (!_ostree_repo_ensure_loose_objdir_at (self->objects_dir_fd, loose_path_buf, cancellable, error))
return FALSE;
@@ -3184,6 +3184,28 @@ ostree_repo_import_object_from (OstreeRepo *self,
checksum, TRUE, cancellable, error);
}
static gboolean
import_via_hardlink_is_possible (OstreeRepo *src_repo,
OstreeRepo *dest_repo,
OstreeObjectType objtype)
{
/* We need the ability to make hardlinks */
if (src_repo->owner_uid != dest_repo->owner_uid)
return FALSE;
/* Equal modes are always compatible */
if (src_repo->mode == dest_repo->mode)
return TRUE;
/* Metadata is identical between all modes */
if (OSTREE_OBJECT_TYPE_IS_META (objtype))
return TRUE;
/* And now a special case between bare-user and bare-user-only,
* mostly for https://github.com/flatpak/flatpak/issues/845
*/
if (import_is_bareuser_only_conversion (src_repo, dest_repo, objtype))
return TRUE;
return FALSE;
}
/**
* ostree_repo_import_object_from_with_trust:
* @self: Destination repo
@@ -3210,29 +3232,95 @@ ostree_repo_import_object_from_with_trust (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
gboolean hardlink_was_supported = FALSE;
if (trusted && /* Don't hardlink into untrusted remotes */
self->mode == source->mode)
/* We try to import via hardlink. If the remote is explicitly not trusted
* (i.e.) their checksums may be incorrect, we skip that. Also, we require the
* repository modes to match, as well as the owner uid (since we need to be
* able to make hardlinks).
*/
if (trusted && import_via_hardlink_is_possible (source, self, objtype))
{
gboolean hardlink_was_supported = FALSE;
if (!import_one_object_link (self, source, checksum, objtype,
&hardlink_was_supported,
cancellable, error))
return FALSE;
/* If we hardlinked, we're done! */
if (hardlink_was_supported)
return TRUE;
}
if (!hardlink_was_supported)
{
gboolean has_object;
/* The copy path */
if (!ostree_repo_has_object (self, objtype, checksum, &has_object,
cancellable, error))
/* First, do we have the object already? */
gboolean has_object;
if (!ostree_repo_has_object (self, objtype, checksum, &has_object,
cancellable, error))
return FALSE;
/* If we have it, we're done */
if (has_object)
return TRUE;
if (OSTREE_OBJECT_TYPE_IS_META (objtype))
{
/* Metadata object */
g_autoptr(GVariant) variant = NULL;
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
/* FIXME - cleanup detached metadata if copy below fails */
if (!copy_detached_metadata (self, source, checksum, cancellable, error))
return FALSE;
}
if (!ostree_repo_load_variant (source, objtype, checksum,
&variant, error))
return FALSE;
if (!has_object)
if (trusted)
{
if (!import_one_object_copy (self, source, checksum, objtype, trusted,
cancellable, error))
if (!ostree_repo_write_metadata_trusted (self, objtype,
checksum, variant,
cancellable, error))
return FALSE;
}
else
{
g_autofree guchar *real_csum = NULL;
if (!ostree_repo_write_metadata (self, objtype,
checksum, variant,
&real_csum,
cancellable, error))
return FALSE;
}
}
else
{
/* Content object */
guint64 length;
g_autoptr(GInputStream) object_stream = NULL;
if (!ostree_repo_load_object_stream (source, objtype, checksum,
&object_stream, &length,
cancellable, error))
return FALSE;
if (trusted)
{
if (!ostree_repo_write_content_trusted (self, checksum,
object_stream, length,
cancellable, error))
return FALSE;
}
else
{
g_autofree guchar *real_csum = NULL;
if (!ostree_repo_write_content (self, checksum,
object_stream, length,
&real_csum,
cancellable, error))
return FALSE;
}
}
@@ -3263,9 +3351,14 @@ ostree_repo_query_object_storage_size (OstreeRepo *self,
{
char loose_path[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (loose_path, sha256, objtype, self->mode);
int res;
struct stat stbuf;
if (TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0)
res = TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW));
if (res < 0 && errno == ENOENT && self->commit_stagedir_fd != -1)
res = TEMP_FAILURE_RETRY (fstatat (self->commit_stagedir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW));
if (res < 0)
return glnx_throw_errno_prefix (error, "Querying object %s.%s", sha256, ostree_object_type_to_string (objtype));
*out_size = stbuf.st_size;
@@ -4470,54 +4563,55 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GHashTable) refs = NULL;
if (!ostree_repo_list_refs (self, NULL, &refs, cancellable, error))
return FALSE;
g_auto(GVariantDict) additional_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER;
g_variant_dict_init (&additional_metadata_builder, additional_metadata);
g_autoptr(GVariantBuilder) refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(s(taya{sv}))"));
g_autoptr(GList) ordered_keys = g_hash_table_get_keys (refs);
ordered_keys = g_list_sort (ordered_keys, (GCompareFunc)strcmp);
{
g_autoptr(GHashTable) refs = NULL;
if (!ostree_repo_list_refs (self, NULL, &refs, cancellable, error))
return FALSE;
for (GList *iter = ordered_keys; iter; iter = iter->next)
{
const char *ref = iter->data;
const char *commit = g_hash_table_lookup (refs, ref);
g_auto(GVariantDict) commit_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER;
g_autoptr(GList) ordered_keys = g_hash_table_get_keys (refs);
ordered_keys = g_list_sort (ordered_keys, (GCompareFunc)strcmp);
g_assert (commit);
for (GList *iter = ordered_keys; iter; iter = iter->next)
{
const char *ref = iter->data;
const char *commit = g_hash_table_lookup (refs, ref);
g_auto(GVariantDict) commit_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER;
g_autofree char *remotename = NULL;
if (!ostree_parse_refspec (ref, &remotename, NULL, NULL))
g_assert_not_reached ();
g_assert (commit);
/* Don't put remote refs in the summary */
if (remotename != NULL)
continue;
g_autofree char *remotename = NULL;
if (!ostree_parse_refspec (ref, &remotename, NULL, NULL))
g_assert_not_reached ();
g_autoptr(GVariant) commit_obj = NULL;
if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, commit, &commit_obj, error))
return FALSE;
/* Don't put remote refs in the summary */
if (remotename != NULL)
continue;
g_variant_dict_init (&commit_metadata_builder, NULL);
g_autoptr(GVariant) commit_obj = NULL;
if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, commit, &commit_obj, error))
return FALSE;
/* Forward the commit’s timestamp if it’s valid. */
guint64 commit_timestamp = ostree_commit_get_timestamp (commit_obj);
g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (commit_timestamp);
g_variant_dict_init (&commit_metadata_builder, NULL);
if (dt != NULL)
g_variant_dict_insert_value (&commit_metadata_builder, OSTREE_COMMIT_TIMESTAMP,
g_variant_new_uint64 (GUINT64_TO_BE (commit_timestamp)));
/* Forward the commit’s timestamp if it’s valid. */
guint64 commit_timestamp = ostree_commit_get_timestamp (commit_obj);
g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (commit_timestamp);
g_variant_builder_add_value (refs_builder,
g_variant_new ("(s(t@ay@a{sv}))", ref,
(guint64) g_variant_get_size (commit_obj),
ostree_checksum_to_bytes_v (commit),
g_variant_dict_end (&commit_metadata_builder)));
}
if (dt != NULL)
g_variant_dict_insert_value (&commit_metadata_builder, OSTREE_COMMIT_TIMESTAMP,
g_variant_new_uint64 (GUINT64_TO_BE (commit_timestamp)));
g_variant_builder_add_value (refs_builder,
g_variant_new ("(s(t@ay@a{sv}))", ref,
(guint64) g_variant_get_size (commit_obj),
ostree_checksum_to_bytes_v (commit),
g_variant_dict_end (&commit_metadata_builder)));
}
}
{
g_autoptr(GPtrArray) delta_names = NULL;
@@ -4542,7 +4636,6 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
g_autoptr(GInputStream) in_stream = g_unix_input_stream_new (superblock_file_fd, FALSE);
if (!in_stream)
return FALSE;
superblock_file_fd = -1; /* Transfer ownership */
g_autofree guchar *csum = NULL;
if (!ot_gio_checksum_stream (in_stream,
@@ -4554,7 +4647,8 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
g_variant_dict_insert_value (&deltas_builder, delta_names->pdata[i], ot_gvariant_new_bytearray (csum, 32));
}
g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_STATIC_DELTAS, g_variant_dict_end (&deltas_builder));
if (delta_names->len > 0)
g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_STATIC_DELTAS, g_variant_dict_end (&deltas_builder));
}
{
+5 -2
View File
@@ -768,7 +768,8 @@ typedef struct {
gboolean process_whiteouts;
gboolean no_copy_fallback;
gboolean force_copy; /* Since: 2017.6 */
gboolean unused_bools[6];
gboolean bareuseronly_dirs; /* Since: 2017.7 */
gboolean unused_bools[5];
const char *subpath;
@@ -1015,12 +1016,14 @@ gboolean ostree_repo_prune_from_reachable (OstreeRepo *self,
* @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors
* @OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY: Fetch only the commit metadata
* @OSTREE_REPO_PULL_FLAGS_UNTRUSTED: Don't trust local remote
* @OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES: Since 2017.7. Reject writes of content objects with modes outside of 0775.
*/
typedef enum {
OSTREE_REPO_PULL_FLAGS_NONE,
OSTREE_REPO_PULL_FLAGS_MIRROR = (1 << 0),
OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY = (1 << 1),
OSTREE_REPO_PULL_FLAGS_UNTRUSTED = (1 << 2)
OSTREE_REPO_PULL_FLAGS_UNTRUSTED = (1 << 2),
OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES = (1 << 3)
} OstreeRepoPullFlags;
_OSTREE_PUBLIC
+5 -9
View File
@@ -501,31 +501,27 @@ _ostree_sysroot_cleanup_internal (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
glnx_unref_object OstreeRepo *repo = NULL;
g_return_val_if_fail (OSTREE_IS_SYSROOT (self), FALSE);
g_return_val_if_fail (self->loaded, FALSE);
if (!cleanup_other_bootversions (self, cancellable, error))
return FALSE;
return glnx_prefix_error (error, "Cleaning bootversions");
if (!cleanup_old_deployments (self, cancellable, error))
return FALSE;
if (!ostree_sysroot_get_repo (self, &repo, cancellable, error))
return FALSE;
return glnx_prefix_error (error, "Cleaning deployments");
OstreeRepo *repo = ostree_sysroot_repo (self);
if (!generate_deployment_refs (self, repo,
self->bootversion,
self->subbootversion,
self->deployments,
cancellable, error))
return FALSE;
return glnx_prefix_error (error, "Generating deployment refs");
if (do_prune_repo)
{
if (!prune_repo (repo, cancellable, error))
return FALSE;
return glnx_prefix_error (error, "Pruning repo");
}
return TRUE;
+80 -89
View File
@@ -423,11 +423,18 @@ copy_modified_config_file (int orig_etc_fd,
return ret;
}
/**
* merge_etc_changes:
/*
* merge_configuration_from:
* @sysroot: Sysroot
* @merge_deployment: Source of configuration differences
* @merge_deployment_dfd: Directory fd, may be -1
* @new_deployment: Target for merge of configuration
* @new_deployment_dfd: Directory fd for @new_deployment (may *not* be -1)
* @cancellable: Cancellable
* @error: Error
*
* Compute the difference between @orig_etc and @modified_etc,
* and apply that to @new_etc.
* Compute the difference between @merge_deployment's `/usr/etc` and `/etc`, and
* apply that to @new_deployment's `/etc`.
*
* The algorithm for computing the difference is pretty simple; it's
* approximately equivalent to "diff -unR orig_etc modified_etc",
@@ -435,26 +442,37 @@ copy_modified_config_file (int orig_etc_fd,
* changed in @new_etc, the modified version always wins.
*/
static gboolean
merge_etc_changes (GFile *orig_etc,
GFile *modified_etc,
GFile *new_etc,
OstreeSysrootDebugFlags flags,
GCancellable *cancellable,
GError **error)
merge_configuration_from (OstreeSysroot *sysroot,
OstreeDeployment *merge_deployment,
int merge_deployment_dfd,
OstreeDeployment *new_deployment,
int new_deployment_dfd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GPtrArray) modified = NULL;
g_autoptr(GPtrArray) removed = NULL;
g_autoptr(GPtrArray) added = NULL;
guint i;
glnx_fd_close int orig_etc_fd = -1;
glnx_fd_close int modified_etc_fd = -1;
glnx_fd_close int new_etc_fd = -1;
glnx_fd_close int owned_merge_deployment_dfd = -1;
const OstreeSysrootDebugFlags flags = sysroot->debug_flags;
modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref);
removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
g_assert (merge_deployment != NULL && new_deployment != NULL);
g_assert (new_deployment_dfd != -1);
/* Allow the caller to pass -1 for the merge, for convenience */
if (merge_deployment_dfd == -1)
{
g_autofree char *merge_deployment_path = ostree_sysroot_get_deployment_dirpath (sysroot, merge_deployment);
if (!glnx_opendirat (sysroot->sysroot_fd, merge_deployment_path, FALSE,
&owned_merge_deployment_dfd, error))
return FALSE;
merge_deployment_dfd = owned_merge_deployment_dfd;
}
/* TODO: get rid of GFile usage here */
g_autoptr(GFile) orig_etc = ot_fdrel_to_gfile (merge_deployment_dfd, "usr/etc");
g_autoptr(GFile) modified_etc = ot_fdrel_to_gfile (merge_deployment_dfd, "etc");
/* Return values for below */
g_autoptr(GPtrArray) modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref);
g_autoptr(GPtrArray) removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
g_autoptr(GPtrArray) added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
/* For now, ignore changes to xattrs; the problem is that
* security.selinux will be different between the /usr/etc labels
* and the ones in the real /etc, so they all show up as different.
@@ -466,42 +484,37 @@ merge_etc_changes (GFile *orig_etc,
if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_IGNORE_XATTRS,
orig_etc, modified_etc, modified, removed, added,
cancellable, error))
{
g_prefix_error (error, "While computing configuration diff: ");
goto out;
}
return glnx_prefix_error (error, "While computing configuration diff");
ot_log_structured_print_id_v (OSTREE_CONFIGMERGE_ID,
"Copying /etc changes: %u modified, %u removed, %u added",
"Copying /etc changes: %u modified, %u removed, %u added",
modified->len,
removed->len,
added->len);
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (orig_etc), TRUE,
&orig_etc_fd, error))
goto out;
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (modified_etc), TRUE,
&modified_etc_fd, error))
goto out;
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (new_etc), TRUE,
&new_etc_fd, error))
goto out;
glnx_fd_close int orig_etc_fd = -1;
if (!glnx_opendirat (merge_deployment_dfd, "usr/etc", TRUE, &orig_etc_fd, error))
return FALSE;
glnx_fd_close int modified_etc_fd = -1;
if (!glnx_opendirat (merge_deployment_dfd, "etc", TRUE, &modified_etc_fd, error))
return FALSE;
glnx_fd_close int new_etc_fd = -1;
if (!glnx_opendirat (new_deployment_dfd, "etc", TRUE, &new_etc_fd, error))
return FALSE;
for (i = 0; i < removed->len; i++)
for (guint i = 0; i < removed->len; i++)
{
GFile *file = removed->pdata[i];
g_autoptr(GFile) target_file = NULL;
g_autofree char *path = NULL;
path = g_file_get_relative_path (orig_etc, file);
g_assert (path);
target_file = g_file_resolve_relative_path (new_etc, path);
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (target_file), cancellable, error))
goto out;
if (!glnx_shutil_rm_rf_at (new_etc_fd, path, cancellable, error))
return FALSE;
}
for (i = 0; i < modified->len; i++)
for (guint i = 0; i < modified->len; i++)
{
OstreeDiffItem *diff = modified->pdata[i];
g_autofree char *path = g_file_get_relative_path (modified_etc, diff->target);
@@ -510,9 +523,9 @@ merge_etc_changes (GFile *orig_etc,
if (!copy_modified_config_file (orig_etc_fd, modified_etc_fd, new_etc_fd, path,
flags, cancellable, error))
goto out;
return FALSE;
}
for (i = 0; i < added->len; i++)
for (guint i = 0; i < added->len; i++)
{
GFile *file = added->pdata[i];
g_autofree char *path = g_file_get_relative_path (modified_etc, file);
@@ -521,12 +534,10 @@ merge_etc_changes (GFile *orig_etc,
if (!copy_modified_config_file (orig_etc_fd, modified_etc_fd, new_etc_fd, path,
flags, cancellable, error))
goto out;
return FALSE;
}
ret = TRUE;
out:
return ret;
return TRUE;
}
/**
@@ -775,16 +786,7 @@ merge_configuration (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autofree char *deployment_abspath = glnx_fdrel_abspath (deployment_dfd, ".");
g_autoptr(GFile) deployment_path = g_file_new_for_path (deployment_abspath);
g_autoptr(GFile) source_etc_path = NULL;
g_autoptr(GFile) source_etc_pristine_path = NULL;
g_autoptr(GFile) deployment_usretc_path = NULL;
g_autoptr(GFile) deployment_etc_path = NULL;
glnx_unref_object OstreeSePolicy *sepolicy = NULL;
gboolean etc_exists;
gboolean usretc_exists;
if (previous_deployment)
{
@@ -792,8 +794,6 @@ merge_configuration (OstreeSysroot *sysroot,
OstreeBootconfigParser *previous_bootconfig;
previous_path = ostree_sysroot_get_deployment_directory (sysroot, previous_deployment);
source_etc_path = g_file_resolve_relative_path (previous_path, "etc");
source_etc_pristine_path = g_file_resolve_relative_path (previous_path, "usr/etc");
previous_bootconfig = ostree_deployment_get_bootconfig (previous_deployment);
if (previous_bootconfig)
@@ -807,26 +807,20 @@ merge_configuration (OstreeSysroot *sysroot,
}
}
deployment_etc_path = g_file_get_child (deployment_path, "etc");
deployment_usretc_path = g_file_resolve_relative_path (deployment_path, "usr/etc");
etc_exists = g_file_query_exists (deployment_etc_path, NULL);
usretc_exists = g_file_query_exists (deployment_usretc_path, NULL);
gboolean etc_exists = FALSE;
if (!ot_query_exists_at (deployment_dfd, "etc", &etc_exists, error))
return FALSE;
gboolean usretc_exists = FALSE;
if (!ot_query_exists_at (deployment_dfd, "usr/etc", &usretc_exists, error))
return FALSE;
if (etc_exists && usretc_exists)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Tree contains both /etc and /usr/etc");
goto out;
}
return glnx_throw (error, "Tree contains both /etc and /usr/etc");
else if (etc_exists)
{
/* Compatibility hack */
if (renameat (deployment_dfd, "etc", deployment_dfd, "usr/etc") < 0)
{
glnx_set_error_from_errno (error);
goto out;
}
return glnx_throw_errno_prefix (error, "renameat");
usretc_exists = TRUE;
etc_exists = FALSE;
}
@@ -843,9 +837,9 @@ merge_configuration (OstreeSysroot *sysroot,
/* Here, we initialize SELinux policy from the /usr/etc inside
* the root - this is before we've finalized the configuration
* merge into /etc. */
sepolicy = ostree_sepolicy_new (deployment_path, cancellable, error);
sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error);
if (!sepolicy)
goto out;
return FALSE;
if (ostree_sepolicy_get_name (sepolicy) != NULL)
etc_co_opts.sepolicy = sepolicy;
@@ -854,21 +848,21 @@ merge_configuration (OstreeSysroot *sysroot,
deployment_dfd, "etc",
ostree_deployment_get_csum (deployment),
cancellable, error))
goto out;
return FALSE;
}
if (source_etc_path)
if (previous_deployment)
{
if (!merge_etc_changes (source_etc_pristine_path, source_etc_path, deployment_etc_path,
sysroot->debug_flags, cancellable, error))
goto out;
if (!merge_configuration_from (sysroot, previous_deployment, -1,
deployment, deployment_dfd,
cancellable, error))
return FALSE;
}
ret = TRUE;
if (out_sepolicy)
*out_sepolicy = g_steal_pointer (&sepolicy);
out:
return ret;
return TRUE;
}
static gboolean
@@ -1034,9 +1028,9 @@ checksum_from_kernel_src (const char *name,
const char *last_dash = strrchr (name, '-');
if (!last_dash)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Malformed kernel/initramfs name '%s', missing '-'", name);
return FALSE;
return glnx_throw (error,
"Malformed kernel/initramfs name '%s', missing '-'",
name);
}
*out_checksum = g_strdup (last_dash + 1);
return TRUE;
@@ -1962,10 +1956,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
if (!glnx_opendirat (self->sysroot_fd, osdeploypath, TRUE, &os_deploy_dfd, error))
return FALSE;
glnx_unref_object OstreeRepo *repo = NULL;
if (!ostree_sysroot_get_repo (self, &repo, cancellable, error))
return FALSE;
OstreeRepo *repo = ostree_sysroot_repo (self);
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
if (provided_merge_deployment != NULL)
merge_deployment = g_object_ref (provided_merge_deployment);
+1
View File
@@ -57,6 +57,7 @@ struct OstreeSysroot {
/* Only access through ostree_sysroot_get_repo() */
OstreeRepo *repo;
gboolean repo_opened;
OstreeSysrootDebugFlags debug_flags;
};
+46
View File
@@ -512,6 +512,10 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
char *refs_to_fetch[] = { NULL, NULL };
const char *from_revision = NULL;
g_autofree char *origin_refspec = NULL;
g_autofree char *new_revision = NULL;
g_autoptr(GVariant) new_variant = NULL;
g_autoptr(GVariant) new_metadata = NULL;
g_autoptr(GVariant) rebase = NULL;
if (self->override_csum != NULL)
refs_to_fetch[0] = self->override_csum;
@@ -541,6 +545,48 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
ostree_async_progress_finish (progress);
}
/* Check to see if the commit marks the ref as EOL, redirecting to
* another. */
if (!ostree_repo_resolve_rev (repo, origin_refspec, FALSE,
&new_revision, error))
return FALSE;
if (!ostree_repo_load_variant (repo,
OSTREE_OBJECT_TYPE_COMMIT,
new_revision,
&new_variant,
error))
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);
if (rebase)
{
const char *new_ref = g_variant_get_string (rebase, 0);
/* Pull the new ref */
if (self->origin_remote &&
(upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC) == 0)
{
refs_to_fetch[0] = (char *) new_ref;
if (!ostree_repo_pull_one_dir (repo, self->origin_remote, dir_to_pull, refs_to_fetch,
flags, progress, cancellable, error))
return FALSE;
}
/* Use the new ref for the rest of the update process */
g_free (self->origin_ref);
self->origin_ref = g_strdup(new_ref);
g_free (origin_refspec);
if (self->origin_remote)
origin_refspec = g_strconcat (self->origin_remote, ":", new_ref, NULL);
else
origin_refspec = g_strdup (new_ref);
g_key_file_set_string (self->origin, "origin", "refspec", origin_refspec);
}
if (self->override_csum != NULL)
{
if (!ostree_repo_set_ref_immediate (repo,
+105 -15
View File
@@ -26,6 +26,7 @@
#include <sys/wait.h>
#include "ostree-core-private.h"
#include "ostree-repo-private.h"
#include "ostree-sepolicy-private.h"
#include "ostree-sysroot-private.h"
#include "ostree-deployment-private.h"
@@ -133,6 +134,7 @@ 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;
G_OBJECT_CLASS (ostree_sysroot_parent_class)->constructed (object);
}
@@ -727,6 +729,18 @@ ostree_sysroot_load (OstreeSysroot *self,
return ostree_sysroot_load_if_changed (self, NULL, cancellable, error);
}
static gboolean
ensure_repo_opened (OstreeSysroot *self,
GError **error)
{
if (self->repo_opened)
return TRUE;
if (!ostree_repo_open (self->repo, NULL, error))
return FALSE;
self->repo_opened = TRUE;
return TRUE;
}
gboolean
ostree_sysroot_load_if_changed (OstreeSysroot *self,
gboolean *out_changed,
@@ -736,6 +750,13 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
if (!ensure_sysroot_fd (self, error))
return FALSE;
/* Here we also lazily initialize the repository. We didn't do this
* previous to v2017.6, but we do now to support the error-free
* ostree_sysroot_repo() API.
*/
if (!ensure_repo_opened (self, error))
return FALSE;
int bootversion = 0;
if (!read_current_bootversion (self, &bootversion, cancellable, error))
return FALSE;
@@ -916,8 +937,7 @@ ostree_sysroot_get_repo (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
/* ostree_repo_open() is idempotent. */
if (!ostree_repo_open (self->repo, cancellable, error))
if (!ensure_repo_opened (self, error))
return FALSE;
if (out_repo != NULL)
@@ -925,6 +945,24 @@ ostree_sysroot_get_repo (OstreeSysroot *self,
return TRUE;
}
/**
* ostree_sysroot_repo:
* @self: Sysroot
*
* This function is a variant of ostree_sysroot_get_repo() that cannot fail, and
* returns a cached repository. Can only be called after ostree_sysroot_load()
* has been invoked successfully.
*
* Returns: (transfer none): The OSTree repository in sysroot @self.
*/
OstreeRepo *
ostree_sysroot_repo (OstreeSysroot *self)
{
g_return_val_if_fail (self->loaded, NULL);
g_assert (self->repo);
return self->repo;
}
/**
* ostree_sysroot_query_bootloader:
* @sysroot: Sysroot
@@ -1069,6 +1107,63 @@ find_booted_deployment (OstreeSysroot *self,
return TRUE;
}
/**
* ostree_sysroot_query_deployments_for:
* @self: Sysroot
* @osname: (allow-none): "stateroot" name
* @out_pending: (out) (allow-none) (transfer full): The pending deployment
* @out_rollback: (out) (allow-none) (transfer full): The rollback deployment
*
* Find the pending and rollback deployments for @osname. Pass %NULL for @osname
* to use the booted deployment's osname. By default, pending deployment is the
* first deployment in the order that matches @osname, and @rollback will be the
* next one after the booted deployment, or the deployment after the pending if
* we're not looking at the booted deployment.
*
* Since: 2017.7
*/
void
ostree_sysroot_query_deployments_for (OstreeSysroot *self,
const char *osname,
OstreeDeployment **out_pending,
OstreeDeployment **out_rollback)
{
g_return_if_fail (osname != NULL || self->booted_deployment != NULL);
g_autoptr(OstreeDeployment) ret_pending = NULL;
g_autoptr(OstreeDeployment) ret_rollback = NULL;
if (osname == NULL)
osname = ostree_deployment_get_osname (self->booted_deployment);
gboolean found_booted = FALSE;
for (guint i = 0; i < self->deployments->len; i++)
{
OstreeDeployment *deployment = self->deployments->pdata[i];
/* Is this deployment booted? If so, note we're past the booted */
if (self->booted_deployment != NULL &&
ostree_deployment_equal (deployment, self->booted_deployment))
{
found_booted = TRUE;
continue;
}
/* Ignore deployments not for this osname */
if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
continue;
if (!found_booted && !ret_pending)
ret_pending = g_object_ref (deployment);
else if (found_booted && !ret_rollback)
ret_rollback = g_object_ref (deployment);
}
if (out_pending)
*out_pending = g_steal_pointer (&ret_pending);
if (out_rollback)
*out_rollback = g_steal_pointer (&ret_rollback);
}
/**
* ostree_sysroot_get_merge_deployment:
* @self: Sysroot
@@ -1094,23 +1189,13 @@ ostree_sysroot_get_merge_deployment (OstreeSysroot *self,
*/
if (self->booted_deployment &&
g_strcmp0 (ostree_deployment_get_osname (self->booted_deployment), osname) == 0)
{
return g_object_ref (self->booted_deployment);
}
else
{
guint i;
for (i = 0; i < self->deployments->len; i++)
{
OstreeDeployment *deployment = self->deployments->pdata[i];
if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
continue;
return g_object_ref (deployment);
}
g_autoptr(OstreeDeployment) pending = NULL;
ostree_sysroot_query_deployments_for (self, osname, &pending, NULL);
return g_steal_pointer (&pending);
}
return NULL;
}
/**
@@ -1352,6 +1437,11 @@ ostree_sysroot_init_osname (OstreeSysroot *self,
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT is
* specified, then instead of prepending, the new deployment will be
* added right after the booted or merge deployment, instead of first.
*
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN is
* specified, then no cleanup will be performed after adding the
* deployment. Make sure to call ostree_sysroot_cleanup() sometime
* later, instead.
*/
gboolean
ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
+9
View File
@@ -126,6 +126,9 @@ gboolean ostree_sysroot_write_origin_file (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
OstreeRepo * ostree_sysroot_repo (OstreeSysroot *self);
_OSTREE_PUBLIC
gboolean ostree_sysroot_get_repo (OstreeSysroot *self,
OstreeRepo **out_repo,
@@ -184,6 +187,12 @@ gboolean ostree_sysroot_deployment_unlock (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_sysroot_query_deployments_for (OstreeSysroot *self,
const char *osname,
OstreeDeployment **out_pending,
OstreeDeployment **out_rollback);
_OSTREE_PUBLIC
OstreeDeployment *ostree_sysroot_get_merge_deployment (OstreeSysroot *self,
const char *osname);
+15 -3
View File
@@ -32,6 +32,8 @@
* OSTREE_YEAR_VERSION:
*
* ostree year version component (e.g. 2017 if %OSTREE_VERSION is 2017.2)
*
* Since: 2017.4
*/
#define OSTREE_YEAR_VERSION (2017)
@@ -39,23 +41,29 @@
* OSTREE_RELEASE_VERSION:
*
* ostree release version component (e.g. 2 if %OSTREE_VERSION is 2017.2)
*
* Since: 2017.4
*/
#define OSTREE_RELEASE_VERSION (6)
#define OSTREE_RELEASE_VERSION (7)
/**
* OSTREE_VERSION
*
* ostree version.
*
* Since: 2017.4
*/
#define OSTREE_VERSION (2017.6)
#define OSTREE_VERSION (2017.7)
/**
* OSTREE_VERSION_S:
*
* ostree version, encoded as a string, useful for printing and
* concatenation.
*
* Since: 2017.4
*/
#define OSTREE_VERSION_S "2017.6"
#define OSTREE_VERSION_S "2017.7"
#define OSTREE_ENCODE_VERSION(year,release) \
((year) << 16 | (release))
@@ -65,6 +73,8 @@
*
* ostree version, encoded as an hexadecimal number, useful for
* integer comparisons.
*
* Since: 2017.4
*/
#define OSTREE_VERSION_HEX \
(OSTREE_ENCODE_VERSION (OSTREE_YEAR_VERSION, OSTREE_RELEASE_VERSION))
@@ -76,6 +86,8 @@
*
* Compile-time version checking. Evaluates to %TRUE if the version
* of ostree is equal or greater than the required one.
*
* Since: 2017.4
*/
#define OSTREE_CHECK_VERSION(year,release) \
(OSTREE_YEAR_VERSION > (year) || \
+12
View File
@@ -32,6 +32,8 @@
* OSTREE_YEAR_VERSION:
*
* ostree year version component (e.g. 2017 if %OSTREE_VERSION is 2017.2)
*
* Since: 2017.4
*/
#define OSTREE_YEAR_VERSION (@YEAR_VERSION@)
@@ -39,6 +41,8 @@
* OSTREE_RELEASE_VERSION:
*
* ostree release version component (e.g. 2 if %OSTREE_VERSION is 2017.2)
*
* Since: 2017.4
*/
#define OSTREE_RELEASE_VERSION (@RELEASE_VERSION@)
@@ -46,6 +50,8 @@
* OSTREE_VERSION
*
* ostree version.
*
* Since: 2017.4
*/
#define OSTREE_VERSION (@VERSION@)
@@ -54,6 +60,8 @@
*
* ostree version, encoded as a string, useful for printing and
* concatenation.
*
* Since: 2017.4
*/
#define OSTREE_VERSION_S "@VERSION@"
@@ -65,6 +73,8 @@
*
* ostree version, encoded as an hexadecimal number, useful for
* integer comparisons.
*
* Since: 2017.4
*/
#define OSTREE_VERSION_HEX \
(OSTREE_ENCODE_VERSION (OSTREE_YEAR_VERSION, OSTREE_RELEASE_VERSION))
@@ -76,6 +86,8 @@
*
* Compile-time version checking. Evaluates to %TRUE if the version
* of ostree is equal or greater than the required one.
*
* Since: 2017.4
*/
#define OSTREE_CHECK_VERSION(year,release) \
(OSTREE_YEAR_VERSION > (year) || \
+67 -47
View File
@@ -25,6 +25,61 @@
#include <sys/xattr.h>
#include <gio/gunixinputstream.h>
/* Before https://github.com/GNOME/libglnx/commit/9929adc, the libglnx
* tmpfile API made it hard to clean up tmpfiles in failure cases.
* it's API breaking. Carry the fix here until we're ready to fully port.
*/
void
ot_tmpfile_clear (OtTmpfile *tmpf)
{
if (!tmpf->initialized)
return;
if (tmpf->fd == -1)
return;
(void) close (tmpf->fd);
/* If ->path is set, we're likely aborting due to an error. Clean it up */
if (tmpf->path)
{
(void) unlinkat (tmpf->src_dfd, tmpf->path, 0);
g_free (tmpf->path);
}
}
gboolean
ot_open_tmpfile_linkable_at (int dfd,
const char *subpath,
int flags,
OtTmpfile *out_tmpf,
GError **error)
{
if (!glnx_open_tmpfile_linkable_at (dfd, subpath, flags, &out_tmpf->fd, &out_tmpf->path, error))
return FALSE;
out_tmpf->initialized = TRUE;
out_tmpf->src_dfd = dfd;
return TRUE;
}
gboolean
ot_link_tmpfile_at (OtTmpfile *tmpf,
GLnxLinkTmpfileReplaceMode mode,
int target_dfd,
const char *target,
GError **error)
{
g_return_val_if_fail (tmpf->initialized, FALSE);
glnx_fd_close int fd = glnx_steal_fd (&tmpf->fd);
if (!glnx_link_tmpfile_at (tmpf->src_dfd, mode, fd, tmpf->path,
target_dfd, target, error))
{
if (tmpf->path)
(void) unlinkat (tmpf->src_dfd, tmpf->path, 0);
tmpf->initialized = FALSE;
return FALSE;
}
tmpf->initialized = FALSE;
return TRUE;
}
/* Convert a fd-relative path to a GFile* - use
* for legacy code.
*/
@@ -42,24 +97,15 @@ ot_readlinkat_gfile_info (int dfd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
char targetbuf[PATH_MAX+1];
ssize_t len;
do
len = readlinkat (dfd, path, targetbuf, sizeof (targetbuf) - 1);
while (G_UNLIKELY (len == -1 && errno == EINTR));
if (len == -1)
{
glnx_set_error_from_errno (error);
goto out;
}
if (TEMP_FAILURE_RETRY (len = readlinkat (dfd, path, targetbuf, sizeof (targetbuf) - 1)) < 0)
return glnx_throw_errno_prefix (error, "readlinkat");
targetbuf[len] = '\0';
g_file_info_set_symlink_target (target_info, targetbuf);
ret = TRUE;
out:
return ret;
return TRUE;
}
@@ -85,26 +131,17 @@ ot_openat_read_stream (int dfd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
int fd = -1;
int flags = O_RDONLY | O_NOCTTY | O_CLOEXEC;
if (!follow)
flags |= O_NOFOLLOW;
do
fd = openat (dfd, path, flags, 0);
while (G_UNLIKELY (fd == -1 && errno == EINTR));
if (fd == -1)
{
glnx_set_error_from_errno (error);
goto out;
}
if (TEMP_FAILURE_RETRY (fd = openat (dfd, path, flags, 0)) < 0)
return glnx_throw_errno_prefix (error, "openat(%s)", path);
*out_istream = g_unix_input_stream_new (fd, TRUE);
ret = TRUE;
out:
return ret;
return TRUE;
}
gboolean
@@ -115,10 +152,7 @@ ot_ensure_unlinked_at (int dfd,
if (unlinkat (dfd, path, 0) != 0)
{
if (G_UNLIKELY (errno != ENOENT))
{
glnx_set_error_from_errno (error);
return FALSE;
}
return glnx_throw_errno_prefix (error, "unlink(%s)", path);
}
return TRUE;
}
@@ -134,10 +168,7 @@ ot_query_exists_at (int dfd, const char *path,
if (fstatat (dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
{
if (errno != ENOENT)
{
glnx_set_error_from_errno (error);
return FALSE;
}
return glnx_throw_errno_prefix (error, "fstatat(%s)", path);
ret_exists = FALSE;
}
else
@@ -153,23 +184,15 @@ ot_openat_ignore_enoent (int dfd,
int *out_fd,
GError **error)
{
gboolean ret = FALSE;
int target_fd = -1;
target_fd = openat (dfd, path, O_CLOEXEC | O_RDONLY);
int target_fd = openat (dfd, path, O_CLOEXEC | O_RDONLY);
if (target_fd < 0)
{
if (errno != ENOENT)
{
glnx_set_error_from_errno (error);
goto out;
}
return glnx_throw_errno_prefix (error, "openat(%s)", path);
}
ret = TRUE;
*out_fd = target_fd;
out:
return ret;
return TRUE;
}
/* Like glnx_dirfd_iterator_init_at(), but if %ENOENT, then set
@@ -206,10 +229,7 @@ ot_file_mapat_bytes (int dfd,
g_autoptr(GMappedFile) mfile = NULL;
if (fd < 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
return glnx_null_throw_errno_prefix (error, "openat(%s)", path);
mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
if (!mfile)
+24
View File
@@ -25,6 +25,30 @@
G_BEGIN_DECLS
/* This is a copy of https://github.com/GNOME/libglnx/pull/46 until we
* can do a full port; see https://github.com/ostreedev/ostree/pull/861 */
typedef struct {
gboolean initialized;
int src_dfd;
int fd;
char *path;
} OtTmpfile;
void ot_tmpfile_clear (OtTmpfile *tmpf);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OtTmpfile, ot_tmpfile_clear);
gboolean
ot_open_tmpfile_linkable_at (int dfd,
const char *subpath,
int flags,
OtTmpfile *out_tmpf,
GError **error);
gboolean
ot_link_tmpfile_at (OtTmpfile *tmpf,
GLnxLinkTmpfileReplaceMode flags,
int target_dfd,
const char *target,
GError **error);
GFile * ot_fdrel_to_gfile (int dfd, const char *path);
gboolean ot_readlinkat_gfile_info (int dfd,
+1 -4
View File
@@ -100,10 +100,7 @@ ot_gfile_ensure_unlinked (GFile *path,
if (unlink (gs_file_get_path_cached (path)) != 0)
{
if (errno != ENOENT)
{
glnx_set_error_from_errno (error);
return FALSE;
}
return glnx_throw_errno_prefix (error, "unlink(%s)", gs_file_get_path_cached (path));
}
return TRUE;
}
+2 -6
View File
@@ -40,9 +40,7 @@ ot_parse_boolean (const char *value,
*out_parsed = FALSE;
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid boolean argument '%s'", value);
return FALSE;
return glnx_throw (error, "Invalid boolean argument '%s'", value);
}
return TRUE;
@@ -57,9 +55,7 @@ ot_parse_keyvalue (const char *keyvalue,
const char *eq = strchr (keyvalue, '=');
if (!eq)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Missing '=' in KEY=VALUE for --set");
return FALSE;
return glnx_throw (error, "Missing '=' in KEY=VALUE for --set");
}
*out_key = g_strndup (keyvalue, eq - keyvalue);
*out_value = g_strdup (eq + 1);
+3 -9
View File
@@ -41,21 +41,15 @@ ot_util_filename_validate (const char *name,
{
if (strcmp (name, ".") == 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid self-referential filename '.'");
return FALSE;
return glnx_throw (error, "Invalid self-referential filename '.'");
}
if (strcmp (name, "..") == 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid path uplink filename '..'");
return FALSE;
return glnx_throw (error, "Invalid path uplink filename '..'");
}
if (strchr (name, '/') != NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid / in filename %s", name);
return FALSE;
return glnx_throw (error, "Invalid / in filename %s", name);
}
return TRUE;
}
+1 -3
View File
@@ -56,7 +56,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro
const char *refspec;
g_autoptr(GOptionContext) context = NULL;
glnx_unref_object OstreeSysroot *sysroot = NULL;
GKeyFile *origin = NULL;
g_autoptr(GKeyFile) origin = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
glnx_unref_object OstreeDeployment *new_deployment = NULL;
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
@@ -171,7 +171,5 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro
ret = TRUE;
out:
if (origin)
g_key_file_unref (origin);
return ret;
}
+14 -2
View File
@@ -88,6 +88,8 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
gboolean ret = FALSE;
glnx_unref_object OstreeRepo *repo = NULL;
OstreeDeployment *booted_deployment = NULL;
g_autoptr(OstreeDeployment) pending_deployment = NULL;
g_autoptr(OstreeDeployment) rollback_deployment = NULL;
g_autoptr(GPtrArray) deployments = NULL;
const int is_tty = isatty (1);
const char *red_bold_prefix = is_tty ? "\x1b[31m\x1b[1m" : "";
@@ -110,6 +112,10 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
deployments = ostree_sysroot_get_deployments (sysroot);
booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
if (booted_deployment)
ostree_sysroot_query_deployments_for (sysroot, NULL, &pending_deployment,
&rollback_deployment);
if (deployments->len == 0)
{
g_print ("No deployments.\n");
@@ -129,11 +135,17 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
origin = ostree_deployment_get_origin (deployment);
g_print ("%c %s %s.%d\n",
const char *deployment_status = "";
if (deployment == pending_deployment)
deployment_status = " (pending)";
else if (deployment == rollback_deployment)
deployment_status = " (rollback)";
g_print ("%c %s %s.%d%s\n",
deployment == booted_deployment ? '*' : ' ',
ostree_deployment_get_osname (deployment),
ostree_deployment_get_csum (deployment),
ostree_deployment_get_deployserial (deployment));
ostree_deployment_get_deployserial (deployment),
deployment_status);
if (version)
g_print (" Version: %s\n", version);
switch (unlocked)
+1 -3
View File
@@ -58,7 +58,7 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro
glnx_unref_object OstreeAsyncProgress *progress = NULL;
gboolean changed;
GKeyFile *old_origin;
GKeyFile *new_origin = NULL;
g_autoptr(GKeyFile) new_origin = NULL;
context = g_option_context_new ("REF - Construct new tree from REF and deploy it");
@@ -166,7 +166,5 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro
ret = TRUE;
out:
if (new_origin)
g_key_file_unref (new_origin);
return ret;
}
+19 -38
View File
@@ -39,64 +39,45 @@ cat_one_file (GFile *f,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GInputStream) in = NULL;
in = (GInputStream*)g_file_read (f, cancellable, error);
g_autoptr(GInputStream) in = (GInputStream*)g_file_read (f, cancellable, error);
if (!in)
goto out;
return FALSE;
{
gssize n_bytes_written = g_output_stream_splice (stdout_stream, in, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
cancellable, error);
if (n_bytes_written < 0)
goto out;
}
if (g_output_stream_splice (stdout_stream, in, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
cancellable, error) < 0)
return FALSE;
ret = TRUE;
out:
return ret;
return TRUE;
}
gboolean
ostree_builtin_cat (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
gboolean ret = FALSE;
int i;
const char *rev;
g_autoptr(GOutputStream) stdout_stream = NULL;
g_autoptr(GFile) root = NULL;
g_autoptr(GFile) f = NULL;
context = g_option_context_new ("COMMIT PATH... - Concatenate contents of files");
g_autoptr(GOptionContext) context = g_option_context_new ("COMMIT PATH... - Concatenate contents of files");
g_autoptr(OstreeRepo) repo = NULL;
if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
goto out;
return FALSE;
if (argc <= 2)
{
ot_util_usage_error (context, "A COMMIT and at least one PATH argument are required", error);
goto out;
return FALSE;
}
rev = argv[1];
const char *rev = argv[1];
g_autoptr(GFile) root = NULL;
if (!ostree_repo_read_commit (repo, rev, &root, NULL, NULL, error))
goto out;
return FALSE;
stdout_stream = g_unix_output_stream_new (1, FALSE);
g_autoptr(GOutputStream) stdout_stream = g_unix_output_stream_new (1, FALSE);
for (i = 2; i < argc; i++)
for (int i = 2; i < argc; i++)
{
g_clear_object (&f);
f = g_file_resolve_relative_path (root, argv[i]);
g_autoptr(GFile) f = g_file_resolve_relative_path (root, argv[i]);
if (!cat_one_file (f, stdout_stream, cancellable, error))
goto out;
return FALSE;
}
ret = TRUE;
out:
return ret;
return TRUE;
}
+5 -1
View File
@@ -43,6 +43,7 @@ static char *opt_from_file;
static gboolean opt_disable_fsync;
static gboolean opt_require_hardlinks;
static gboolean opt_force_copy;
static gboolean opt_bareuseronly_dirs;
static gboolean
parse_fsync_cb (const char *option_name,
@@ -73,6 +74,7 @@ static GOptionEntry options[] = {
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
{ "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL },
{ "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL },
{ "bareuseronly-dirs", 'M', 0, G_OPTION_ARG_NONE, &opt_bareuseronly_dirs, "Suppress mode bits outside of 0775 for directories (suid, world writable, etc.)", NULL },
{ NULL }
};
@@ -91,7 +93,8 @@ process_one_checkout (OstreeRepo *repo,
* `ostree_repo_checkout_at` until such time as we have a more
* convenient infrastructure for testing C APIs with data.
*/
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add || opt_force_copy)
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks ||
opt_union_add || opt_force_copy || opt_bareuseronly_dirs)
{
OstreeRepoCheckoutAtOptions options = { 0, };
@@ -119,6 +122,7 @@ process_one_checkout (OstreeRepo *repo,
options.subpath = subpath;
options.no_copy_fallback = opt_require_hardlinks;
options.force_copy = opt_force_copy;
options.bareuseronly_dirs = opt_bareuseronly_dirs;
if (!ostree_repo_checkout_at (repo, &options,
AT_FDCWD, destination,
+1 -3
View File
@@ -147,9 +147,7 @@ handle_statoverride_line (const char *line,
spc = strchr (line, ' ');
if (spc == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Malformed statoverride file (no space found)");
return FALSE;
return glnx_throw (error, "Malformed statoverride file (no space found)");
}
mode_add = (guint32)(gint32)g_ascii_strtod (line, NULL);
+2 -3
View File
@@ -41,9 +41,8 @@ split_key_string (const char *k,
if (!dot)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Key must be of the form \"sectionname.keyname\"");
return FALSE;
return glnx_throw (error,
"Key must be of the form \"sectionname.keyname\"");
}
*out_section = g_strndup (k, dot - k);
+4
View File
@@ -33,6 +33,7 @@
static char *opt_remote;
static gboolean opt_disable_fsync;
static gboolean opt_untrusted;
static gboolean opt_bareuseronly_files;
static gboolean opt_require_static_deltas;
static gboolean opt_gpg_verify;
static gboolean opt_gpg_verify_summary;
@@ -42,6 +43,7 @@ static GOptionEntry options[] = {
{ "remote", 0, 0, G_OPTION_ARG_STRING, &opt_remote, "Add REMOTE to refspec", "REMOTE" },
{ "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust source", NULL },
{ "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL },
{ "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL },
{ "gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify, "GPG verify commits (must specify --remote)", NULL },
{ "gpg-verify-summary", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify_summary, "GPG verify summary (must specify --remote)", NULL },
@@ -92,6 +94,8 @@ ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GEr
if (opt_untrusted)
pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED;
if (opt_bareuseronly_files)
pullflags |= OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES;
if (opt_disable_fsync)
ostree_repo_set_disable_fsync (repo, TRUE);
+4
View File
@@ -34,6 +34,7 @@ static gboolean opt_dry_run;
static gboolean opt_disable_static_deltas;
static gboolean opt_require_static_deltas;
static gboolean opt_untrusted;
static gboolean opt_bareuseronly_files;
static char** opt_subpaths;
static char** opt_http_headers;
static char* opt_cache_dir;
@@ -50,6 +51,7 @@ static GOptionEntry options[] = {
{ "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror", NULL },
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL },
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL },
{ "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL },
{ "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL },
{ "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" },
{ "url", 0, 0, G_OPTION_ARG_STRING, &opt_url, "Pull objects from this URL instead of the one from the remote config", NULL },
@@ -167,6 +169,8 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError **
if (opt_untrusted)
pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED;
if (opt_bareuseronly_files)
pullflags |= OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES;
if (opt_dry_run && !opt_require_static_deltas)
{
+30 -14
View File
@@ -71,6 +71,18 @@ format_timestamp (guint64 timestamp,
return str;
}
static gchar *
uint64_secs_to_iso8601 (guint64 secs)
{
g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (secs);
g_autoptr(GDateTime) local = (dt != NULL) ? g_date_time_to_local (dt) : NULL;
if (local != NULL)
return g_date_time_format (local, "%FT%T%:::z");
else
return g_strdup ("invalid");
}
static void
dump_indented_lines (const gchar *data)
{
@@ -196,23 +208,27 @@ dump_summary_ref (const char *ref_name,
while (g_variant_iter_loop (metadata, "{sv}", &key, &value))
{
g_autofree char *string = g_variant_print (value, FALSE);
g_print (" %s: %s\n", key, string);
g_autofree gchar *value_str = NULL;
const gchar *pretty_key = NULL;
if (g_strcmp0 (key, OSTREE_COMMIT_TIMESTAMP) == 0)
{
pretty_key = "Timestamp";
value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value)));
}
else
{
value_str = g_variant_print (value, FALSE);
}
/* Print out. */
if (pretty_key != NULL)
g_print (" %s (%s): %s\n", pretty_key, key, value_str);
else
g_print (" %s: %s\n", key, value_str);
}
}
static gchar *
uint64_secs_to_iso8601 (guint64 secs)
{
g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (secs);
g_autoptr(GDateTime) local = (dt != NULL) ? g_date_time_to_local (dt) : NULL;
if (local != NULL)
return g_date_time_format (local, "%FT%T%:::z");
else
return g_strdup ("invalid");
}
void
ot_dump_summary_bytes (GBytes *summary_bytes,
OstreeDumpFlags flags)
+9 -27
View File
@@ -202,8 +202,7 @@ ot_delete_cookie_at (int dfd, const char *jar_path,
{
gboolean found = FALSE;
#ifdef HAVE_LIBCURL
glnx_fd_close int tempfile_fd = -1;
g_autofree char *tempfile_path = NULL;
g_auto(OtTmpfile) tmpf = { 0, };
g_autofree char *dnbuf = NULL;
const char *dn = NULL;
g_autoptr(OtCookieParser) parser = NULL;
@@ -213,9 +212,8 @@ ot_delete_cookie_at (int dfd, const char *jar_path,
dnbuf = g_strdup (jar_path);
dn = dirname (dnbuf);
if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, dn, O_WRONLY | O_CLOEXEC,
&tempfile_fd, &tempfile_path,
error))
if (!ot_open_tmpfile_linkable_at (AT_FDCWD, dn, O_WRONLY | O_CLOEXEC,
&tmpf, error))
return FALSE;
while (ot_parse_cookies_next (parser))
@@ -229,19 +227,14 @@ ot_delete_cookie_at (int dfd, const char *jar_path,
continue;
}
if (glnx_loop_write (tempfile_fd, parser->line, strlen (parser->line)) < 0 ||
glnx_loop_write (tempfile_fd, "\n", 1) < 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
if (glnx_loop_write (tmpf.fd, parser->line, strlen (parser->line)) < 0 ||
glnx_loop_write (tmpf.fd, "\n", 1) < 0)
return glnx_throw_errno_prefix (error, "write");
}
if (!glnx_link_tmpfile_at (AT_FDCWD, GLNX_LINK_TMPFILE_REPLACE,
tempfile_fd,
tempfile_path,
AT_FDCWD, jar_path,
error))
if (!ot_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE,
AT_FDCWD, jar_path,
error))
return FALSE;
#else
GSList *cookies;
@@ -279,22 +272,11 @@ gboolean
ot_list_cookies_at (int dfd, const char *jar_path, GError **error)
{
#ifdef HAVE_LIBCURL
glnx_fd_close int tempfile_fd = -1;
g_autofree char *tempfile_path = NULL;
g_autofree char *dnbuf = NULL;
const char *dn = NULL;
g_autoptr(OtCookieParser) parser = NULL;
if (!ot_parse_cookies_at (AT_FDCWD, jar_path, &parser, NULL, error))
return FALSE;
dnbuf = dirname (g_strdup (jar_path));
dn = dnbuf;
if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, dn, O_WRONLY | O_CLOEXEC,
&tempfile_fd, &tempfile_path,
error))
return FALSE;
while (ot_parse_cookies_next (parser))
{
g_autoptr(GDateTime) expires = g_date_time_new_from_unix_utc (parser->expiration);