New upstream version 2017.12

This commit is contained in:
Simon McVittie committed 2017-10-03 18:51:37 +01:00
commit d5964d6850
283 files changed
+4566 -2286

No files matched your search

+2 -3
View File
@@ -18,9 +18,8 @@
***/
/* Add new symbols here. Release commits should copy this section into -released.sym. */
LIBOSTREE_2017.12 {
} LIBOSTREE_2017.11;
LIBOSTREE_2017.13 {
} LIBOSTREE_2017.12;
/* 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
+5
View File
@@ -77,3 +77,8 @@ global:
ostree_repo_transaction_set_collection_ref;
ostree_validate_collection_id;
} LIBOSTREE_2017.7_EXPERIMENTAL;
LIBOSTREE_2017.12_EXPERIMENTAL {
global:
ostree_repo_resolve_collection_ref;
} LIBOSTREE_2017.8_EXPERIMENTAL;
+6
View File
@@ -430,6 +430,12 @@ LIBOSTREE_2017.10 {
LIBOSTREE_2017.11 {
} LIBOSTREE_2017.10;
LIBOSTREE_2017.12 {
global:
ostree_repo_equal;
ostree_repo_hash;
} LIBOSTREE_2017.11;
/* NOTE: Only add more content here in release commits! See the
* comments at the top of this file.
*/
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2016 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+6 -7
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -247,7 +246,7 @@ ostree_bloom_set_bit (OstreeBloom *bloom,
{
g_assert (bloom->is_mutable);
g_assert (idx / 8 < bloom->n_bytes);
bloom->mutable_bytes[idx / 8] |= (1 << (idx % 8));
bloom->mutable_bytes[idx / 8] |= (guint8) (1 << (idx % 8));
}
/**
@@ -274,11 +273,11 @@ ostree_bloom_maybe_contains (OstreeBloom *bloom,
for (i = 0; i < bloom->k; i++)
{
gsize idx;
guint64 idx;
idx = bloom->hash_func (element, i);
if (!ostree_bloom_get_bit (bloom, idx % (bloom->n_bytes * 8)))
if (!ostree_bloom_get_bit (bloom, (gsize) (idx % (bloom->n_bytes * 8))))
return FALSE; /* definitely not in the set */
}
@@ -338,8 +337,8 @@ ostree_bloom_add_element (OstreeBloom *bloom,
for (i = 0; i < bloom->k; i++)
{
gsize idx = bloom->hash_func (element, i);
ostree_bloom_set_bit (bloom, idx % (bloom->n_bytes * 8));
guint64 idx = bloom->hash_func (element, i);
ostree_bloom_set_bit (bloom, (gsize) (idx % (bloom->n_bytes * 8)));
}
}
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Collabora Ltd
*
* Based on ot-bootloader-syslinux.c by Colin Walters <walters@verbum.org>
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Collabora Ltd
*
* Based on ot-bootloader-syslinux.h by Colin Walters <walters@verbum.org>
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+15 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -90,6 +89,7 @@ _ostree_make_temporary_symlink_at (int tmp_dirfd,
GError **error);
GFileInfo * _ostree_stbuf_to_gfileinfo (const struct stat *stbuf);
gboolean _ostree_gfileinfo_equal (GFileInfo *a, GFileInfo *b);
GFileInfo * _ostree_mode_uidgid_to_gfileinfo (mode_t mode, uid_t uid, gid_t gid);
static inline void
@@ -134,6 +134,19 @@ static inline char * _ostree_get_commitpartial_path (const char *checksum)
return g_strconcat ("state/", checksum, ".commitpartial", NULL);
}
gboolean
_ostree_validate_bareuseronly_mode (guint32 mode,
const char *checksum,
GError **error);
static inline gboolean
_ostree_validate_bareuseronly_mode_finfo (GFileInfo *finfo,
const char *checksum,
GError **error)
{
const guint32 content_mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
return _ostree_validate_bareuseronly_mode (content_mode, checksum, error);
}
gboolean
_ostree_parse_delta_name (const char *delta_name,
char **out_from,
+72 -3
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -33,6 +32,13 @@
#include "ostree-chain-input-stream.h"
#include "otutil.h"
/* Generic ABI checks */
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE == 0);
G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE_Z2 == 1);
G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE == OSTREE_REPO_MODE_ARCHIVE_Z2);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER == 2);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER_ONLY == 3);
#define ALIGN_VALUE(this, boundary) \
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
@@ -1525,7 +1531,7 @@ _ostree_loose_path (char *buf,
buf++;
snprintf (buf, _OSTREE_LOOSE_PATH_MAX - 2, "/%s.%s%s",
checksum + 2, ostree_object_type_to_string (objtype),
(!OSTREE_OBJECT_TYPE_IS_META (objtype) && mode == OSTREE_REPO_MODE_ARCHIVE_Z2) ? "z" : "");
(!OSTREE_OBJECT_TYPE_IS_META (objtype) && mode == OSTREE_REPO_MODE_ARCHIVE) ? "z" : "");
}
/**
@@ -1562,12 +1568,52 @@ _ostree_stbuf_to_gfileinfo (const struct stat *stbuf)
g_file_info_set_attribute_uint32 (ret, "unix::uid", stbuf->st_uid);
g_file_info_set_attribute_uint32 (ret, "unix::gid", stbuf->st_gid);
g_file_info_set_attribute_uint32 (ret, "unix::mode", mode);
/* those aren't stored by ostree, but used by the devino cache */
g_file_info_set_attribute_uint32 (ret, "unix::device", stbuf->st_dev);
g_file_info_set_attribute_uint64 (ret, "unix::inode", stbuf->st_ino);
if (S_ISREG (mode))
g_file_info_set_attribute_uint64 (ret, "standard::size", stbuf->st_size);
return ret;
}
/**
* _ostree_gfileinfo_equal:
* @a: First file info
* @b: Second file info
*
* OSTree only cares about a subset of file attributes. This function
* checks whether two #GFileInfo objects are equal as far as OSTree is
* concerned.
*
* Returns: TRUE if the #GFileInfo objects are OSTree-equivalent.
*/
gboolean
_ostree_gfileinfo_equal (GFileInfo *a, GFileInfo *b)
{
/* trivial case */
if (a == b)
return TRUE;
#define CHECK_ONE_ATTR(type, attr, a, b) \
do { if (g_file_info_get_attribute_##type(a, attr) != \
g_file_info_get_attribute_##type(b, attr)) \
return FALSE; \
} while (0)
CHECK_ONE_ATTR (uint32, "unix::uid", a, b);
CHECK_ONE_ATTR (uint32, "unix::gid", a, b);
CHECK_ONE_ATTR (uint32, "unix::mode", a, b);
CHECK_ONE_ATTR (uint32, "standard::type", a, b);
CHECK_ONE_ATTR (uint64, "standard::size", a, b);
#undef CHECK_ONE_ATTR
return TRUE;
}
GFileInfo *
_ostree_mode_uidgid_to_gfileinfo (mode_t mode, uid_t uid, gid_t gid)
{
@@ -1998,6 +2044,29 @@ ostree_validate_structureof_dirtree (GVariant *dirtree,
return TRUE;
}
/* This bit mirrors similar code in commit_loose_regfile_object() for the
* bare-user-only mode. It's opt-in though for all pulls.
*/
gboolean
_ostree_validate_bareuseronly_mode (guint32 content_mode,
const char *checksum,
GError **error)
{
if (S_ISREG (content_mode))
{
const guint32 invalid_modebits = ((content_mode & ~S_IFMT) & ~0775);
if (invalid_modebits > 0)
return glnx_throw (error, "Content object %s: 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;
}
static gboolean
validate_stat_mode_perms (guint32 mode,
GError **error)
+5 -4
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -181,7 +180,8 @@ typedef enum {
/**
* OstreeRepoMode:
* @OSTREE_REPO_MODE_BARE: Files are stored as themselves; checkouts are hardlinks; can only be written as root
* @OSTREE_REPO_MODE_ARCHIVE_Z2: Files are compressed, should be owned by non-root. Can be served via HTTP
* @OSTREE_REPO_MODE_ARCHIVE: Files are compressed, should be owned by non-root. Can be served via HTTP. Since: 2017.12
* @OSTREE_REPO_MODE_ARCHIVE_Z2: Legacy alias for `OSTREE_REPO_MODE_ARCHIVE`
* @OSTREE_REPO_MODE_BARE_USER: Files are stored as themselves, except ownership; can be written by user. Hardlinks work only in user checkouts.
* @OSTREE_REPO_MODE_BARE_USER_ONLY: Same as BARE_USER, but all metadata is not stored, so it can only be used for user checkouts. Does not need xattrs.
*
@@ -190,7 +190,8 @@ typedef enum {
*/
typedef enum {
OSTREE_REPO_MODE_BARE,
OSTREE_REPO_MODE_ARCHIVE_Z2,
OSTREE_REPO_MODE_ARCHIVE,
OSTREE_REPO_MODE_ARCHIVE_Z2 = OSTREE_REPO_MODE_ARCHIVE,
OSTREE_REPO_MODE_BARE_USER,
OSTREE_REPO_MODE_BARE_USER_ONLY,
} OstreeRepoMode;
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2015 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+11 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -27,6 +26,16 @@
#include "ostree-repo-private.h"
#include "otutil.h"
/* See ostree-repo.c for a bit more info about these ABI checks */
#if __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 8 && __SIZEOF_INT__ == 4
G_STATIC_ASSERT(sizeof(OstreeDiffDirsOptions) ==
sizeof(int) * 2 +
sizeof(gpointer) +
sizeof(int) * (7+6) +
sizeof(int) + /* hole */
sizeof(gpointer) * 7);
#endif
static gboolean
get_file_checksum (OstreeDiffFlags flags,
GFile *f,
+2 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -86,6 +85,7 @@ typedef struct {
gboolean unused_bools[7];
int unused_ints[6];
/* 4 byte hole on 64 bit */
gpointer unused_ptrs[7];
} OstreeDiffDirsOptions;
+21 -5
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2016 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -379,14 +378,13 @@ check_multi_info (OstreeFetcher *fetcher)
g_autoptr(GError) local_error = NULL;
GError **error = &local_error;
/* TODO - share file naming with soup, and fix it */
g_autofree char *tmpfile_path =
g_compute_checksum_for_string (G_CHECKSUM_SHA256,
eff_url, strlen (eff_url));
ostree_fetcher_generate_url_tmpname (eff_url);
if (!ensure_tmpfile (req, error))
{
g_task_return_error (task, g_steal_pointer (&local_error));
}
/* This should match the libsoup chmod */
else if (fchmod (req->tmpf.fd, 0644) < 0)
{
glnx_set_error_from_errno (error);
@@ -748,6 +746,24 @@ initiate_next_curl_request (FetcherRequest *req,
if (self->tls_client_cert_path)
{
/* Support for pkcs11:
* https://github.com/ostreedev/ostree/pull/1183
* This will be used by https://github.com/advancedtelematic/aktualizr
* at least to fetch certificates. No test coverage at the moment
* though. See https://gitlab.com/gnutls/gnutls/tree/master/tests/pkcs11
* and https://github.com/opendnssec/SoftHSMv2 and
* https://github.com/p11-glue/p11-kit/tree/master/p11-kit for
* possible ideas there.
*/
if (g_str_has_prefix (self->tls_client_key_path, "pkcs11:"))
{
curl_easy_setopt (req->easy, CURLOPT_SSLENGINE, "pkcs11");
curl_easy_setopt (req->easy, CURLOPT_SSLENGINE_DEFAULT, 1L);
curl_easy_setopt (req->easy, CURLOPT_SSLKEYTYPE, "ENG");
}
if (g_str_has_prefix (self->tls_client_cert_path, "pkcs11:"))
curl_easy_setopt (req->easy, CURLOPT_SSLCERTTYPE, "ENG");
curl_easy_setopt (req->easy, CURLOPT_SSLCERT, self->tls_client_cert_path);
curl_easy_setopt (req->easy, CURLOPT_SSLKEY, self->tls_client_key_path);
}
+53 -134
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -55,10 +54,7 @@ typedef struct {
volatile gint running;
GError *initialization_error; /* Any failure to load the db */
int tmpdir_dfd;
char *remote_name;
char *tmpdir_name;
GLnxLockFile tmpdir_lock;
int base_tmpdir_dfd;
GVariant *extra_headers;
@@ -94,7 +90,7 @@ typedef struct {
gboolean is_membuf;
OstreeFetcherRequestFlags flags;
GInputStream *request_body;
char *out_tmpfile;
GLnxTmpfile tmpf;
GOutputStream *out_stream;
guint64 max_size;
@@ -155,17 +151,6 @@ thread_closure_unref (ThreadClosure *thread_closure)
g_clear_pointer (&thread_closure->extra_headers, (GDestroyNotify)g_variant_unref);
if (thread_closure->tmpdir_dfd != -1)
close (thread_closure->tmpdir_dfd);
/* Note: We don't remove the tmpdir here, because that would cause
us to not reuse it on resume. This happens because we use two
fetchers for each pull, so finalizing the first one would remove
all the files to be resumed from the previous second one */
g_free (thread_closure->tmpdir_name);
glnx_release_lock_file (&thread_closure->tmpdir_lock);
g_clear_pointer (&thread_closure->output_stream_set, g_hash_table_unref);
g_mutex_clear (&thread_closure->output_stream_set_lock);
@@ -210,7 +195,7 @@ pending_uri_unref (OstreeFetcherPendingURI *pending)
g_free (pending->filename);
g_clear_object (&pending->request);
g_clear_object (&pending->request_body);
g_free (pending->out_tmpfile);
glnx_tmpfile_clear (&pending->tmpf);
g_clear_object (&pending->out_stream);
g_free (pending);
}
@@ -477,59 +462,7 @@ session_thread_request_uri (ThreadClosure *thread_closure,
}
else
{
g_autofree char *uristring
= soup_uri_to_string (soup_request_get_uri (pending->request), FALSE);
g_autofree char *tmpfile = NULL;
struct stat stbuf;
gboolean exists;
/* The tmp directory is lazily created for each fetcher instance,
* since it may require superuser permissions and some instances
* only need _ostree_fetcher_request_uri_to_membuf() which keeps
* everything in memory buffers. */
if (thread_closure->tmpdir_name == NULL)
{
if (!_ostree_repo_allocate_tmpdir (thread_closure->base_tmpdir_dfd,
OSTREE_REPO_TMPDIR_FETCHER,
&thread_closure->tmpdir_name,
&thread_closure->tmpdir_dfd,
&thread_closure->tmpdir_lock,
NULL,
cancellable,
&local_error))
{
g_task_return_error (task, local_error);
return;
}
}
tmpfile = g_compute_checksum_for_string (G_CHECKSUM_SHA256, uristring, strlen (uristring));
if (fstatat (thread_closure->tmpdir_dfd, tmpfile, &stbuf, AT_SYMLINK_NOFOLLOW) == 0)
exists = TRUE;
else
{
if (errno == ENOENT)
exists = FALSE;
else
{
glnx_set_error_from_errno (&local_error);
g_task_return_error (task, local_error);
return;
}
}
if (SOUP_IS_REQUEST_HTTP (pending->request))
{
glnx_unref_object SoupMessage *msg = NULL;
msg = soup_request_http_get_message ((SoupRequestHTTP*) pending->request);
if (exists && stbuf.st_size > 0)
soup_message_headers_set_range (msg->request_headers, stbuf.st_size, -1);
}
pending->out_tmpfile = tmpfile;
tmpfile = NULL; /* Transfer ownership */
start_pending_request (thread_closure, task);
start_pending_request (thread_closure, task);
}
}
@@ -658,7 +591,6 @@ _ostree_fetcher_constructed (GObject *object)
{
OstreeFetcher *self = OSTREE_FETCHER (object);
g_autoptr(GMainContext) main_context = NULL;
GLnxLockFile empty_lockfile = GLNX_LOCK_FILE_INIT;
const char *http_proxy;
main_context = g_main_context_new ();
@@ -668,8 +600,6 @@ _ostree_fetcher_constructed (GObject *object)
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;
self->thread_closure->outstanding = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)pending_uri_unref);
self->thread_closure->output_stream_set = g_hash_table_new_full (NULL, NULL,
@@ -749,7 +679,7 @@ _ostree_fetcher_new (int tmpdir_dfd,
int
_ostree_fetcher_get_dfd (OstreeFetcher *fetcher)
{
return fetcher->thread_closure->tmpdir_dfd;
return fetcher->thread_closure->base_tmpdir_dfd;
}
void
@@ -874,13 +804,8 @@ finish_stream (OstreeFetcherPendingURI *pending,
if (!pending->is_membuf)
{
if (fstatat (pending->thread_closure->tmpdir_dfd,
pending->out_tmpfile,
&stbuf, AT_SYMLINK_NOFOLLOW) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
if (!glnx_fstat (pending->tmpf.fd, &stbuf, error))
goto out;
}
pending->state = OSTREE_FETCHER_STATE_COMPLETE;
@@ -973,11 +898,39 @@ on_stream_read (GObject *object,
pending = g_task_get_task_data (task);
cancellable = g_task_get_cancellable (task);
/* Only open the output stream on demand to ensure we use as
* few file descriptors as possible.
*/
if (!pending->out_stream)
{
if (!pending->is_membuf)
{
if (!glnx_open_tmpfile_linkable_at (pending->thread_closure->base_tmpdir_dfd, ".",
O_WRONLY | O_CLOEXEC, &pending->tmpf, &local_error))
goto out;
/* This should match the libcurl chmod */
if (!glnx_fchmod (pending->tmpf.fd, 0644, &local_error))
goto out;
pending->out_stream = g_unix_output_stream_new (pending->tmpf.fd, FALSE);
}
else
{
pending->out_stream = g_memory_output_stream_new_resizable ();
}
g_mutex_lock (&pending->thread_closure->output_stream_set_lock);
g_hash_table_add (pending->thread_closure->output_stream_set,
g_object_ref (pending->out_stream));
g_mutex_unlock (&pending->thread_closure->output_stream_set_lock);
}
/* Get a GBytes buffer */
bytes = g_input_stream_read_bytes_finish ((GInputStream*)object, result, &local_error);
if (!bytes)
goto out;
bytes_read = g_bytes_get_size (bytes);
/* Was this the end of the stream? */
if (bytes_read == 0)
{
if (!finish_stream (pending, cancellable, &local_error))
@@ -990,14 +943,24 @@ on_stream_read (GObject *object,
}
else
{
g_task_return_pointer (task,
g_strdup (pending->out_tmpfile),
(GDestroyNotify) g_free);
g_autofree char *uristring =
soup_uri_to_string (soup_request_get_uri (pending->request), FALSE);
g_autofree char *tmpfile_path =
ostree_fetcher_generate_url_tmpname (uristring);
if (!glnx_link_tmpfile_at (&pending->tmpf, GLNX_LINK_TMPFILE_REPLACE,
pending->thread_closure->base_tmpdir_dfd, tmpfile_path,
&local_error))
g_task_return_error (task, g_steal_pointer (&local_error));
else
g_task_return_pointer (task,
g_steal_pointer (&tmpfile_path),
(GDestroyNotify) g_free);
}
remove_pending (pending);
}
else
{
/* Verify max size */
if (pending->max_size > 0)
{
if (bytes_read > pending->max_size ||
@@ -1011,7 +974,7 @@ on_stream_read (GObject *object,
goto out;
}
}
pending->current_size += bytes_read;
/* We do this instead of _write_bytes_async() as that's not
@@ -1063,19 +1026,7 @@ on_request_sent (GObject *object,
if (SOUP_IS_REQUEST_HTTP (object))
{
msg = soup_request_http_get_message ((SoupRequestHTTP*) object);
if (!pending->is_membuf &&
msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE)
{
// We already have the whole file, so just use it.
pending->state = OSTREE_FETCHER_STATE_COMPLETE;
(void) g_input_stream_close (pending->request_body, NULL, NULL);
g_task_return_pointer (task,
g_strdup (pending->out_tmpfile),
(GDestroyNotify) g_free);
remove_pending (pending);
goto out;
}
else if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
{
/* is there another mirror we can try? */
if (pending->mirrorlist_idx + 1 < pending->mirrorlist->len)
@@ -1091,8 +1042,8 @@ on_request_sent (GObject *object,
}
else
{
g_autofree char *uristring
= soup_uri_to_string (soup_request_get_uri (pending->request), FALSE);
g_autofree char *uristring =
soup_uri_to_string (soup_request_get_uri (pending->request), FALSE);
GIOErrorEnum code;
switch (msg->status_code)
@@ -1143,38 +1094,6 @@ on_request_sent (GObject *object,
pending->content_length = soup_request_get_content_length (pending->request);
if (!pending->is_membuf)
{
int oflags = O_CREAT | O_WRONLY | O_CLOEXEC;
int fd;
/* If we got partial content, we can append; if the server
* ignored our range request, we need to truncate.
*/
if (msg && msg->status_code == SOUP_STATUS_PARTIAL_CONTENT)
oflags |= O_APPEND;
else
oflags |= O_TRUNC;
fd = openat (pending->thread_closure->tmpdir_dfd,
pending->out_tmpfile, oflags, 0666);
if (fd == -1)
{
glnx_set_error_from_errno (&local_error);
goto out;
}
pending->out_stream = g_unix_output_stream_new (fd, TRUE);
}
else
{
pending->out_stream = g_memory_output_stream_new_resizable ();
}
g_mutex_lock (&pending->thread_closure->output_stream_set_lock);
g_hash_table_add (pending->thread_closure->output_stream_set,
g_object_ref (pending->out_stream));
g_mutex_unlock (&pending->thread_closure->output_stream_set_lock);
g_input_stream_read_bytes_async (pending->request_body,
8192, G_PRIORITY_DEFAULT,
cancellable,
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011,2017 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+11 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2016 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -26,6 +25,16 @@
G_BEGIN_DECLS
/* FIXME - delete this and replace by having fetchers simply
* return O_TMPFILE fds, not file paths.
*/
static inline char *
ostree_fetcher_generate_url_tmpname (const char *url)
{
return g_compute_checksum_for_string (G_CHECKSUM_SHA256,
url, strlen (url));
}
gboolean _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,
GPtrArray *mirrorlist,
const char *filename,
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2012 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
* Copyright (C) 2013 Sjoerd Simons <sjoerd.simons@collabora.co.uk>
*
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
* Copyright (C) 2013 Sjoerd Simons <sjoerd.simons@collabora.co.uk>
*
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013,2014 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013,2014 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2016 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@redhat.com>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@redhat.com>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+9 -3
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2011 Colin Walters <walters@verbum.org>
* Copyright © 2015 Red Hat, Inc.
* Copyright © 2017 Endless Mobile, Inc.
@@ -36,17 +35,24 @@
G_BEGIN_DECLS
/* @refspec_name is set if this is a dynamic remote. It’s the name of the static
* remote which this one inherits from, and is what should be used in refspecs
* for pulls from this remote. If it’s %NULL, @name should be used instead. */
struct OstreeRemote {
volatile int ref_count;
char *name; /* (not nullable) */
char *refspec_name; /* (nullable) */
char *group; /* group name in options (not nullable) */
char *keyring; /* keyring name (NAME.trustedkeys.gpg) (not nullable) */
char *keyring; /* keyring name ($refspec_name.trustedkeys.gpg) (not nullable) */
GFile *file; /* NULL if remote defined in repo/config */
GKeyFile *options;
};
G_GNUC_INTERNAL
OstreeRemote *ostree_remote_new (const gchar *name);
G_GNUC_INTERNAL
OstreeRemote *ostree_remote_new_dynamic (const gchar *name,
const gchar *refspec_name);
G_GNUC_INTERNAL
OstreeRemote *ostree_remote_new_from_keyfile (GKeyFile *keyfile,
+12 -4
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2011 Colin Walters <walters@verbum.org>
* Copyright © 2015 Red Hat, Inc.
* Copyright © 2017 Endless Mobile, Inc.
@@ -54,16 +53,25 @@
OstreeRemote *
ostree_remote_new (const gchar *name)
{
return ostree_remote_new_dynamic (name, NULL);
}
OstreeRemote *
ostree_remote_new_dynamic (const gchar *name,
const gchar *refspec_name)
{
OstreeRemote *remote;
g_return_val_if_fail (name != NULL && *name != '\0', NULL);
g_return_val_if_fail (refspec_name == NULL || *refspec_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->refspec_name = g_strdup (refspec_name);
remote->group = g_strdup_printf ("remote \"%s\"", (refspec_name != NULL) ? refspec_name : name);
remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", (refspec_name != NULL) ? refspec_name : name);
remote->options = g_key_file_new ();
return remote;
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2011 Colin Walters <walters@verbum.org>
* Copyright © 2015 Red Hat, Inc.
* Copyright © 2017 Endless Mobile, Inc.
+64 -23
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011,2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -303,11 +302,11 @@ create_file_copy_from_input_at (OstreeRepo *repo,
return FALSE;
/* The add/union/none behaviors map directly to GLnxLinkTmpfileReplaceMode */
GLnxLinkTmpfileReplaceMode replace_mode;
GLnxLinkTmpfileReplaceMode replace_mode = GLNX_LINK_TMPFILE_NOREPLACE;
switch (options->overwrite_mode)
{
case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE:
replace_mode = GLNX_LINK_TMPFILE_NOREPLACE;
/* Handled above */
break;
case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES:
replace_mode = GLNX_LINK_TMPFILE_REPLACE;
@@ -338,6 +337,41 @@ typedef enum {
HARDLINK_RESULT_LINKED
} HardlinkResult;
/* Used for OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES. In
* order to atomically replace a target, we add a new link
* in self->tmp_dir_fd, with a name placed into the mutable
* buffer @tmpname.
*/
static gboolean
hardlink_add_tmp_name (OstreeRepo *self,
int srcfd,
const char *loose_path,
char *tmpname,
GCancellable *cancellable,
GError **error)
{
const int max_attempts = 128;
guint i;
for (i = 0; i < max_attempts; i++)
{
glnx_gen_temp_name (tmpname);
if (linkat (srcfd, loose_path, self->tmp_dir_fd, tmpname, 0) < 0)
{
if (errno == EEXIST)
continue;
else
return glnx_throw_errno_prefix (error, "linkat");
}
else
break;
}
if (i == max_attempts)
return glnx_throw (error, "Exhausted attempts to make temporary hardlink");
return TRUE;
}
static gboolean
checkout_file_hardlink (OstreeRepo *self,
OstreeRepoCheckoutAtOptions *options,
@@ -353,7 +387,6 @@ checkout_file_hardlink (OstreeRepo *self,
int srcfd = _ostree_repo_mode_is_bare (self->mode) ?
self->objects_dir_fd : self->uncompressed_objects_dir_fd;
again:
if (linkat (srcfd, loose_path, destination_dfd, destination_name, 0) == 0)
ret_result = HARDLINK_RESULT_LINKED;
else if (!options->no_copy_fallback && (errno == EMLINK || errno == EXDEV || errno == EPERM))
@@ -380,27 +413,20 @@ checkout_file_hardlink (OstreeRepo *self,
ret_result = HARDLINK_RESULT_SKIP_EXISTED;
break;
case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES:
{
/* Idiocy, from man rename(2)
*
* "If oldpath and newpath are existing hard links referring to
* the same file, then rename() does nothing, and returns a
* success status."
*
* So we can't make this atomic.
*/
(void) unlinkat (destination_dfd, destination_name, 0);
goto again;
}
case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL:
{
/* In this mode, we error out on EEXIST *unless* the files are already
* hardlinked, which is what rpm-ostree wants for package layering.
* https://github.com/projectatomic/rpm-ostree/issues/982
/* In both union-files and union-identical, see if the src/target are
* already hardlinked. If they are, we're done.
*
* If not, for union-identical we error out, which is what
* rpm-ostree wants for package layering.
* https://github.com/projectatomic/rpm-ostree/issues/982
* This should be similar to the librpm version:
* https://github.com/rpm-software-management/rpm/blob/e3cd2bc85e0578f158d14e6f9624eb955c32543b/lib/rpmfi.c#L921
* in rpmfilesCompare().
*
* For union-files, we make a temporary link, then rename() it
* into place.
*/
struct stat src_stbuf;
if (!glnx_fstatat (srcfd, loose_path, &src_stbuf,
@@ -413,10 +439,25 @@ checkout_file_hardlink (OstreeRepo *self,
const gboolean is_identical =
(src_stbuf.st_dev == dest_stbuf.st_dev &&
src_stbuf.st_ino == dest_stbuf.st_ino);
if (is_identical)
ret_result = HARDLINK_RESULT_SKIP_EXISTED;
else if (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
{
char *tmpname = strdupa ("checkout-union-XXXXXX");
/* Make a link with a temp name */
if (!hardlink_add_tmp_name (self, srcfd, loose_path, tmpname, cancellable, error))
return FALSE;
/* Rename it into place */
if (!glnx_renameat (self->tmp_dir_fd, tmpname, destination_dfd, destination_name, error))
return FALSE;
ret_result = HARDLINK_RESULT_LINKED;
}
else
return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name);
{
g_assert_cmpint (options->overwrite_mode, ==, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL);
return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name);
}
break;
}
}
@@ -495,7 +536,7 @@ checkout_one_file_at (OstreeRepo *repo,
(repo_is_usermode && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER);
gboolean current_can_cache = (options->enable_uncompressed_cache
&& current_repo->enable_uncompressed_cache);
gboolean is_archive_z2_with_cache = (current_repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2
gboolean is_archive_z2_with_cache = (current_repo->mode == OSTREE_REPO_MODE_ARCHIVE
&& options->mode == OSTREE_REPO_CHECKOUT_MODE_USER
&& current_can_cache);
@@ -567,7 +608,7 @@ checkout_one_file_at (OstreeRepo *repo,
&& !is_whiteout
&& !is_symlink
&& need_copy
&& repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2
&& repo->mode == OSTREE_REPO_MODE_ARCHIVE
&& options->mode == OSTREE_REPO_CHECKOUT_MODE_USER)
{
HardlinkResult hardlink_res = HARDLINK_RESULT_NOT_SUPPORTED;
File diff suppressed because it is too large. Load diff
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2016 Kinvolk GmbH
* Copyright © 2017 Endless Mobile, Inc.
*
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+21 -19
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2016 Kinvolk GmbH
* Copyright © 2017 Endless Mobile, Inc.
*
@@ -166,28 +165,28 @@ ostree_avahi_browser_event_to_string (AvahiBrowserEvent event)
typedef struct
{
gchar *uri;
gchar *keyring;
OstreeRemote *keyring_remote; /* (owned) */
} UriAndKeyring;
static void
uri_and_keyring_free (UriAndKeyring *data)
{
g_free (data->uri);
g_free (data->keyring);
ostree_remote_unref (data->keyring_remote);
g_free (data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (UriAndKeyring, uri_and_keyring_free)
static UriAndKeyring *
uri_and_keyring_new (const gchar *uri,
const gchar *keyring)
uri_and_keyring_new (const gchar *uri,
OstreeRemote *keyring_remote)
{
g_autoptr(UriAndKeyring) data = NULL;
data = g_new0 (UriAndKeyring, 1);
data->uri = g_strdup (uri);
data->keyring = g_strdup (keyring);
data->keyring_remote = ostree_remote_ref (keyring_remote);
return g_steal_pointer (&data);
}
@@ -197,7 +196,7 @@ uri_and_keyring_hash (gconstpointer key)
{
const UriAndKeyring *_key = key;
return g_str_hash (_key->uri) ^ g_str_hash (_key->keyring);
return g_str_hash (_key->uri) ^ g_str_hash (_key->keyring_remote->keyring);
}
static gboolean
@@ -206,7 +205,8 @@ uri_and_keyring_equal (gconstpointer a,
{
const UriAndKeyring *_a = a, *_b = b;
return g_str_equal (_a->uri, _b->uri) && g_str_equal (_a->keyring, _b->keyring);
return (g_str_equal (_a->uri, _b->uri) &&
g_str_equal (_a->keyring_remote->keyring, _b->keyring_remote->keyring));
}
/* This must return a valid remote name (suitable for use in a refspec). */
@@ -214,7 +214,7 @@ static gchar *
uri_and_keyring_to_name (UriAndKeyring *data)
{
g_autofree gchar *escaped_uri = g_uri_escape_string (data->uri, NULL, FALSE);
g_autofree gchar *escaped_keyring = g_uri_escape_string (data->keyring, NULL, FALSE);
g_autofree gchar *escaped_keyring = g_uri_escape_string (data->keyring_remote->keyring, NULL, FALSE);
/* FIXME: Need a better separator than `_`, since it’s not escaped in the input. */
g_autofree gchar *out = g_strdup_printf ("%s_%s", escaped_uri, escaped_keyring);
@@ -771,14 +771,15 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService
for (i = 0; i < possible_refs->len; i++)
{
const OstreeCollectionRef *ref = g_ptr_array_index (possible_refs, i);
g_autofree gchar *keyring = NULL;
g_autoptr(UriAndKeyring) resolved_repo = NULL;
g_autoptr(OstreeRemote) keyring_remote = NULL;
/* Look up the GPG keyring for this ref. */
keyring = ostree_repo_resolve_keyring_for_collection (parent_repo, ref->collection_id,
cancellable, &error);
keyring_remote = ostree_repo_resolve_keyring_for_collection (parent_repo,
ref->collection_id,
cancellable, &error);
if (keyring == NULL)
if (keyring_remote == NULL)
{
g_debug ("Ignoring ref (%s, %s) on host ‘%s’ due to missing keyring: %s",
ref->collection_id, refs[i]->ref_name, service->address,
@@ -789,10 +790,11 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService
/* Add this repo to the results, keyed by the canonicalised repository URI
* to deduplicate the results. */
g_debug ("Resolved ref (%s, %s) to repo URI ‘%s’ with keyring ‘%s’.",
ref->collection_id, ref->ref_name, uri, keyring);
g_debug ("Resolved ref (%s, %s) to repo URI ‘%s’ with keyring ‘%s’ from remote ‘%s’.",
ref->collection_id, ref->ref_name, uri, keyring_remote->keyring,
keyring_remote->name);
resolved_repo = uri_and_keyring_new (uri, keyring);
resolved_repo = uri_and_keyring_new (uri, keyring_remote);
supported_ref_to_checksum = g_hash_table_lookup (repo_to_refs, resolved_repo);
@@ -819,10 +821,10 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService
/* Build an #OstreeRemote. Use the escaped URI, since remote->name
* is used in file paths, so needs to not contain special characters. */
g_autofree gchar *name = uri_and_keyring_to_name (repo);
remote = ostree_remote_new (name);
remote = ostree_remote_new_dynamic (name, repo->keyring_remote->name);
g_clear_pointer (&remote->keyring, g_free);
remote->keyring = g_strdup (repo->keyring);
remote->keyring = g_strdup (repo->keyring_remote->keyring);
/* gpg-verify-summary is false since we use the unsigned summary file support. */
g_key_file_set_string (remote->options, remote->group, "url", repo->uri);
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+273 -144
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -46,19 +45,21 @@
* #OstreeRepoFinderMount is an implementation of #OstreeRepoFinder which looks
* refs up in well-known locations on any mounted removable volumes.
*
* For an #OstreeCollectionRef, (`C`, `R`), it checks whether `.ostree/repos/C/R`
* exists and is an OSTree repository on each mounted removable volume. Collection
* IDs and ref names are not escaped when building the path, so if either
* contains `/` in its name, the repository will be checked for in a
* subdirectory of `.ostree/repos`. Non-removable volumes are ignored.
* For each mounted removable volume, the directory `.ostree/repos.d` will be
* enumerated, and all OSTree repositories below it will be searched, in lexical
* order, for the requested #OstreeCollectionRefs. The names of the directories
* below `.ostree/repos.d` are irrelevant, apart from their lexical ordering.
* The directories `.ostree/repo`, `ostree/repo` and `var/lib/flatpak`
* will be searched after the others, if they exist.
* Non-removable volumes are ignored.
*
* For each repository which is found, a result will be returned for the
* intersection of the refs being searched for, and the refs in `refs/heads` and
* `refs/mirrors` in the repository on the removable volume.
*
* Symlinks are followed when resolving the refs, so a volume might contain a
* single OSTree at some arbitrary path, with a number of refs linking to it
* from `.ostree/repos`. Any symlink which points outside the volume’s file
* Symlinks are followed when listing the repositories, so a volume might
* contain a single OSTree at some arbitrary path, with a symlink from
* `.ostree/repos.d`. Any symlink which points outside the volume’s file
* system will be ignored. Repositories are deduplicated in the results.
*
* The volume monitor used to find mounted volumes can be overridden by setting
@@ -92,28 +93,28 @@ G_DEFINE_TYPE_WITH_CODE (OstreeRepoFinderMount, ostree_repo_finder_mount, G_TYPE
typedef struct
{
gchar *uri;
gchar *keyring;
OstreeRemote *keyring_remote; /* (owned) */
} UriAndKeyring;
static void
uri_and_keyring_free (UriAndKeyring *data)
{
g_free (data->uri);
g_free (data->keyring);
ostree_remote_unref (data->keyring_remote);
g_free (data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (UriAndKeyring, uri_and_keyring_free)
static UriAndKeyring *
uri_and_keyring_new (const gchar *uri,
const gchar *keyring)
uri_and_keyring_new (const gchar *uri,
OstreeRemote *keyring_remote)
{
g_autoptr(UriAndKeyring) data = NULL;
data = g_new0 (UriAndKeyring, 1);
data->uri = g_strdup (uri);
data->keyring = g_strdup (keyring);
data->keyring_remote = ostree_remote_ref (keyring_remote);
return g_steal_pointer (&data);
}
@@ -123,7 +124,7 @@ uri_and_keyring_hash (gconstpointer key)
{
const UriAndKeyring *_key = key;
return g_str_hash (_key->uri) ^ g_str_hash (_key->keyring);
return g_str_hash (_key->uri) ^ g_str_hash (_key->keyring_remote->keyring);
}
static gboolean
@@ -132,7 +133,8 @@ uri_and_keyring_equal (gconstpointer a,
{
const UriAndKeyring *_a = a, *_b = b;
return g_str_equal (_a->uri, _b->uri) && g_str_equal (_a->keyring, _b->keyring);
return (g_str_equal (_a->uri, _b->uri) &&
g_str_equal (_a->keyring_remote->keyring, _b->keyring_remote->keyring));
}
/* This must return a valid remote name (suitable for use in a refspec). */
@@ -140,7 +142,7 @@ static gchar *
uri_and_keyring_to_name (UriAndKeyring *data)
{
g_autofree gchar *escaped_uri = g_uri_escape_string (data->uri, NULL, FALSE);
g_autofree gchar *escaped_keyring = g_uri_escape_string (data->keyring, NULL, FALSE);
g_autofree gchar *escaped_keyring = g_uri_escape_string (data->keyring_remote->keyring, NULL, FALSE);
/* FIXME: Need a better separator than `_`, since it’s not escaped in the input. */
g_autofree gchar *out = g_strdup_printf ("%s_%s", escaped_uri, escaped_keyring);
@@ -166,6 +168,137 @@ results_compare_cb (gconstpointer a,
return ostree_repo_finder_result_compare (result_a, result_b);
}
typedef struct
{
char *ordering_name; /* (owned) */
OstreeRepo *repo; /* (owned) */
GHashTable *refs; /* (owned) (element-type OstreeCollectionRef utf8) */
} RepoAndRefs;
static void
repo_and_refs_clear (RepoAndRefs *data)
{
g_hash_table_unref (data->refs);
g_object_unref (data->repo);
g_free (data->ordering_name);
}
static gint
repo_and_refs_compare (gconstpointer a,
gconstpointer b)
{
const RepoAndRefs *_a = a;
const RepoAndRefs *_b = b;
return strcmp (_a->ordering_name, _b->ordering_name);
}
/* Check whether the repo at @dfd/@path is within the given mount, is not equal
* to the @parent_repo, and can be opened. If so, return it as @out_repo and
* all its collection–refs as @out_refs, to be added into the results. */
static gboolean
scan_repo (int dfd,
const char *path,
const char *mount_name,
const struct stat *mount_root_stbuf,
OstreeRepo *parent_repo,
OstreeRepo **out_repo,
GHashTable **out_refs,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GError) local_error = NULL;
g_autoptr(OstreeRepo) repo = ostree_repo_open_at (dfd, path, cancellable, &local_error);
if (repo == NULL)
{
g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as it could not be opened: %s",
path, mount_name, local_error->message);
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
int repo_dfd = ostree_repo_get_dfd (repo);
struct stat stbuf;
if (!glnx_fstat (repo_dfd, &stbuf, &local_error))
{
g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as querying its info failed: %s",
path, mount_name, local_error->message);
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
/* Check the resolved repository path is below the mount point. Do not
* allow ref symlinks to point somewhere outside of the mounted volume. */
if (stbuf.st_dev != mount_root_stbuf->st_dev)
{
g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as it’s on a different file system from the mount",
path, mount_name);
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
/* Exclude repositories which resolve to @parent_repo. */
if (stbuf.st_dev == parent_repo->device &&
stbuf.st_ino == parent_repo->inode)
{
g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as it is the same as the one we are resolving",
path, mount_name);
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
/* List the repo’s refs and return them. */
g_autoptr(GHashTable) repo_refs = NULL; /* (element-type OstreeCollectionRef utf8) */
if (!ostree_repo_list_collection_refs (repo, NULL, &repo_refs,
OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES,
cancellable, &local_error))
{
g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as its refs could not be listed: %s",
path, mount_name, local_error->message);
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
if (out_repo != NULL)
*out_repo = g_steal_pointer (&repo);
if (out_refs != NULL)
*out_refs = g_steal_pointer (&repo_refs);
return TRUE;
}
static void
scan_and_add_repo (int dfd,
const char *path,
gboolean sortable,
const char *mount_name,
const struct stat *mount_root_stbuf,
OstreeRepo *parent_repo,
GArray *inout_repos_refs,
GCancellable *cancellable)
{
g_autoptr(GHashTable) repo_refs = NULL;
g_autoptr(OstreeRepo) repo = NULL;
if (scan_repo (dfd, path,
mount_name, mount_root_stbuf,
parent_repo, &repo, &repo_refs, cancellable, NULL))
{
RepoAndRefs val = {
sortable ? g_strdup (path) : NULL,
g_steal_pointer (&repo),
g_steal_pointer (&repo_refs)
};
g_array_append_val (inout_repos_refs, val);
g_debug ("%s: Adding repo ‘%s’ (%ssortable)",
G_STRFUNC, path, sortable ? "" : "not ");
}
}
static void
ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finder,
const OstreeCollectionRef * const *refs,
@@ -214,7 +347,6 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
continue;
}
/* Check if it contains a .ostree/repos directory. */
mount_root = g_mount_get_root (mount);
mount_root_path = g_file_get_path (mount_root);
@@ -225,18 +357,6 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
continue;
}
if (!glnx_opendirat (mount_root_dfd, ".ostree/repos", TRUE, &repos_dfd, &local_error))
{
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
g_debug ("Ignoring mount ‘%s’ as ‘%s/.ostree/repos’ directory doesn’t exist.",
mount_name, mount_root_path);
else
g_debug ("Ignoring mount ‘%s’ as ‘%s/.ostree/repos’ directory can’t be opened: %s",
mount_name, mount_root_path, local_error->message);
continue;
}
/* stat() the mount root so we can later check whether the resolved
* repositories for individual refs are on the same device (to avoid the
* symlinks for them pointing outside the mount root). */
@@ -247,6 +367,68 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
continue;
}
/* Check if it contains a .ostree/repos.d directory. If not, move on and
* try the other well-known subdirectories. */
if (!glnx_opendirat (mount_root_dfd, ".ostree/repos.d", TRUE, &repos_dfd, NULL))
repos_dfd = -1;
/* List all the repositories in the repos.d directory. */
/* (element-type GHashTable (element-type OstreeCollectionRef utf8)) */
g_autoptr(GArray) repos_refs = g_array_new (FALSE, TRUE, sizeof (RepoAndRefs));
g_array_set_clear_func (repos_refs, (GDestroyNotify) repo_and_refs_clear);
GLnxDirFdIterator repos_iter;
if (repos_dfd >= 0 &&
!glnx_dirfd_iterator_init_at (repos_dfd, ".", TRUE, &repos_iter, &local_error))
{
g_debug ("Error iterating over ‘%s/.ostree/repos.d’ directory in mount ‘%s’: %s",
mount_root_path, mount_name, local_error->message);
g_clear_error (&local_error);
/* don’t skip this mount as there’s still the ostree/repo directory to try */
}
else if (repos_dfd >= 0)
{
while (TRUE)
{
struct dirent *repo_dent;
if (!glnx_dirfd_iterator_next_dent (&repos_iter, &repo_dent, cancellable, &local_error))
{
g_debug ("Error iterating over ‘%s/.ostree/repos.d’ directory in mount ‘%s’: %s",
mount_root_path, mount_name, local_error->message);
g_clear_error (&local_error);
/* don’t skip this mount as there’s still the ostree/repo directory to try */
break;
}
if (repo_dent == NULL)
break;
/* Grab the set of collection–refs from the repo if we can open it. */
scan_and_add_repo (repos_dfd, repo_dent->d_name, TRUE,
mount_name, &mount_root_stbuf,
parent_repo, repos_refs, cancellable);
}
}
/* Sort the repos lexically. */
g_array_sort (repos_refs, repo_and_refs_compare);
/* Also check the well-known special-case directories in the mount.
* Add them after sorting, so they’re always last. */
const gchar * const well_known_repos[] =
{
".ostree/repo",
"ostree/repo",
"var/lib/flatpak",
};
for (i = 0; i < G_N_ELEMENTS (well_known_repos); i++)
scan_and_add_repo (mount_root_dfd, well_known_repos[i], FALSE,
mount_name, &mount_root_stbuf,
parent_repo, repos_refs, cancellable);
/* Check whether a subdirectory exists for any of the @refs we’re looking
* for. If so, and it’s a symbolic link, dereference it so multiple links
* to the same repository (containing multiple refs) are coalesced.
@@ -256,122 +438,69 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
for (i = 0; refs[i] != NULL; i++)
{
struct stat stbuf;
g_autofree gchar *collection_and_ref = NULL;
const OstreeCollectionRef *ref = refs[i];
g_autofree gchar *resolved_repo_uri = NULL;
g_autofree gchar *keyring = NULL;
g_autoptr(UriAndKeyring) resolved_repo = NULL;
collection_and_ref = g_build_filename (refs[i]->collection_id, refs[i]->ref_name, NULL);
if (!glnx_fstatat (repos_dfd, collection_and_ref, &stbuf, AT_NO_AUTOMOUNT, &local_error))
for (gsize j = 0; j < repos_refs->len; j++)
{
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as querying info of ‘%s’ failed: %s",
refs[i]->collection_id, refs[i]->ref_name, mount_name, collection_and_ref, local_error->message);
g_clear_error (&local_error);
continue;
const RepoAndRefs *repo_and_refs = &g_array_index (repos_refs, RepoAndRefs, j);
OstreeRepo *repo = repo_and_refs->repo;
GHashTable *repo_refs = repo_and_refs->refs;
g_autofree char *repo_path = g_file_get_path (ostree_repo_get_path (repo));
g_autoptr(OstreeRemote) keyring_remote = NULL;
const gchar *checksum = g_hash_table_lookup (repo_refs, ref);
if (checksum == NULL)
{
g_debug ("Ignoring repository ‘%s’ when looking for ref (%s, %s) on mount ‘%s’ as it doesn’t contain the ref.",
repo_path, ref->collection_id, ref->ref_name, mount_name);
g_clear_error (&local_error);
continue;
}
/* Finally, look up the GPG keyring for this ref. */
keyring_remote = ostree_repo_resolve_keyring_for_collection (parent_repo,
ref->collection_id,
cancellable, &local_error);
if (keyring_remote == NULL)
{
g_debug ("Ignoring repository ‘%s’ when looking for ref (%s, %s) on mount ‘%s’ due to missing keyring: %s",
repo_path, ref->collection_id, ref->ref_name, mount_name, local_error->message);
g_clear_error (&local_error);
continue;
}
/* There is a valid repo at (or pointed to by)
* $mount_root/.ostree/repos.d/$something.
* Add it to the results, keyed by the canonicalised repository URI
* to deduplicate the results. */
g_autofree char *canonical_repo_path = realpath (repo_path, NULL);
resolved_repo_uri = g_strconcat ("file://", canonical_repo_path, NULL);
g_debug ("Resolved ref (%s, %s) on mount ‘%s’ to repo URI ‘%s’ with keyring ‘%s’ from remote ‘%s’.",
ref->collection_id, ref->ref_name, mount_name, resolved_repo_uri,
keyring_remote->keyring, keyring_remote->name);
resolved_repo = uri_and_keyring_new (resolved_repo_uri, keyring_remote);
supported_ref_to_checksum = g_hash_table_lookup (repo_to_refs, resolved_repo);
if (supported_ref_to_checksum == NULL)
{
supported_ref_to_checksum = g_hash_table_new_full (ostree_collection_ref_hash,
ostree_collection_ref_equal,
NULL, g_free);
g_hash_table_insert (repo_to_refs, g_steal_pointer (&resolved_repo), supported_ref_to_checksum /* transfer */);
}
g_hash_table_insert (supported_ref_to_checksum, (gpointer) ref, g_strdup (checksum));
/* We’ve found a result for this collection–ref. No point in checking
* the other repos on the mount, since pulling in parallel from them won’t help. */
break;
}
if ((stbuf.st_mode & S_IFMT) != S_IFDIR)
{
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as ‘%s’ is of type %u, not a directory.",
refs[i]->collection_id, refs[i]->ref_name, mount_name, collection_and_ref, (stbuf.st_mode & S_IFMT));
g_clear_error (&local_error);
continue;
}
/* Check the resolved repository path is below the mount point. Do not
* allow ref symlinks to point somewhere outside of the mounted
* volume. */
if (stbuf.st_dev != mount_root_stbuf.st_dev)
{
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as it’s on a different file system from the mount.",
refs[i]->collection_id, refs[i]->ref_name, mount_name);
g_clear_error (&local_error);
continue;
}
/* Exclude repositories which resolve to @parent_repo. */
if (stbuf.st_dev == parent_repo->device &&
stbuf.st_ino == parent_repo->inode)
{
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as it is the same as the one we are resolving",
refs[i]->collection_id, refs[i]->ref_name, mount_name);
g_clear_error (&local_error);
continue;
}
/* Grab the given ref and a checksum for it from the repo, if it appears to be a valid repo */
g_autoptr(OstreeRepo) repo = ostree_repo_open_at (repos_dfd, collection_and_ref,
cancellable, &local_error);
if (!repo)
{
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository could not be opened: %s",
refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message);
g_clear_error (&local_error);
continue;
}
g_autoptr(GHashTable) repo_refs = NULL; /* (element-type OstreeCollectionRef utf8) */
if (!ostree_repo_list_collection_refs (repo, refs[i]->collection_id, &repo_refs,
OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES,
cancellable, &local_error))
{
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its refs could not be listed: %s",
refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message);
g_clear_error (&local_error);
continue;
}
const gchar *checksum = g_hash_table_lookup (repo_refs, refs[i]);
if (checksum == NULL)
{
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository doesn’t contain the ref.",
refs[i]->collection_id, refs[i]->ref_name, mount_name);
g_clear_error (&local_error);
continue;
}
/* Finally, look up the GPG keyring for this ref. */
keyring = ostree_repo_resolve_keyring_for_collection (parent_repo, refs[i]->collection_id,
cancellable, &local_error);
if (keyring == NULL)
{
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ due to missing keyring: %s",
refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message);
g_clear_error (&local_error);
continue;
}
/* There is a valid repo at (or pointed to by)
* $mount_root/.ostree/repos/$refs[i]->collection_id/$refs[i]->ref_name.
* Add it to the results, keyed by the canonicalised repository URI
* to deduplicate the results. */
g_autofree char *repo_abspath = g_build_filename (mount_root_path, ".ostree/repos",
collection_and_ref, NULL);
/* FIXME - why are we using realpath here? */
g_autofree char *canonical_repo_dir_path = realpath (repo_abspath, NULL);
resolved_repo_uri = g_strconcat ("file://", canonical_repo_dir_path, NULL);
g_debug ("Resolved ref (%s, %s) on mount ‘%s’ to repo URI ‘%s’ with keyring ‘%s’.",
refs[i]->collection_id, refs[i]->ref_name, mount_name, resolved_repo_uri, keyring);
resolved_repo = uri_and_keyring_new (resolved_repo_uri, keyring);
supported_ref_to_checksum = g_hash_table_lookup (repo_to_refs, resolved_repo);
if (supported_ref_to_checksum == NULL)
{
supported_ref_to_checksum = g_hash_table_new_full (ostree_collection_ref_hash,
ostree_collection_ref_equal,
NULL, g_free);
g_hash_table_insert (repo_to_refs, g_steal_pointer (&resolved_repo), supported_ref_to_checksum /* transfer */);
}
g_hash_table_insert (supported_ref_to_checksum, (gpointer) refs[i], g_strdup (checksum));
}
/* Aggregate the results. */
@@ -384,10 +513,10 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
/* Build an #OstreeRemote. Use the escaped URI, since remote->name
* is used in file paths, so needs to not contain special characters. */
g_autofree gchar *name = uri_and_keyring_to_name (repo);
remote = ostree_remote_new (name);
remote = ostree_remote_new_dynamic (name, repo->keyring_remote->name);
g_clear_pointer (&remote->keyring, g_free);
remote->keyring = g_strdup (repo->keyring);
remote->keyring = g_strdup (repo->keyring_remote->keyring);
/* gpg-verify-summary is false since we use the unsigned summary file support. */
g_key_file_set_string (remote->options, remote->group, "url", repo->uri);
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
+9 -6
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011,2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -872,10 +871,14 @@ ostree_repo_import_archive_to_mtree (OstreeRepo *self,
if (opts->autocreate_parents &&
ostree_mutable_tree_get_metadata_checksum (mtree) == NULL)
{
glnx_unref_object GFileInfo *fi = g_file_info_new ();
g_file_info_set_attribute_uint32 (fi, "unix::uid", 0);
g_file_info_set_attribute_uint32 (fi, "unix::gid", 0);
g_file_info_set_attribute_uint32 (fi, "unix::mode", DEFAULT_DIRMODE);
/* _ostree_stbuf_to_gfileinfo() only looks at these fields,
* but we use it to ensure it sets all of the relevant GFileInfo
* properties.
*/
struct stat stbuf = { .st_mode = DEFAULT_DIRMODE,
.st_uid = 0,
.st_gid = 0 };
g_autoptr(GFileInfo) fi = _ostree_stbuf_to_gfileinfo (&stbuf);
g_autoptr(GFileInfo) mfi = NULL;
(void)_ostree_repo_commit_modifier_apply (self, modifier, "/",
+18 -7
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011,2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -92,8 +91,7 @@ struct OstreeRepo {
GObject parent;
char *stagedir_prefix;
int commit_stagedir_fd;
char *commit_stagedir_name;
GLnxTmpDir commit_stagedir;
GLnxLockFile commit_stagedir_lock;
/* A cached fd-relative version, distinct from the case where we may have a
@@ -205,13 +203,11 @@ _ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoMemoryCacheRef, _ostree_repo_memory_cache_ref_destroy)
#define OSTREE_REPO_TMPDIR_STAGING "staging-"
#define OSTREE_REPO_TMPDIR_FETCHER "fetcher-"
gboolean
_ostree_repo_allocate_tmpdir (int tmpdir_dfd,
const char *tmpdir_prefix,
char **tmpdir_name_out,
int *tmpdir_fd_out,
GLnxTmpDir *tmpdir_out,
GLnxLockFile *file_lock_out,
gboolean * reusing_dir_out,
GCancellable *cancellable,
@@ -346,6 +342,21 @@ _ostree_repo_verify_commit_internal (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
typedef enum {
_OSTREE_REPO_IMPORT_FLAGS_NONE,
_OSTREE_REPO_IMPORT_FLAGS_TRUSTED,
_OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY,
} OstreeRepoImportFlags;
gboolean
_ostree_repo_import_object (OstreeRepo *self,
OstreeRepo *source,
OstreeObjectType objtype,
const char *checksum,
OstreeRepoImportFlags flags,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_repo_commit_tmpf_final (OstreeRepo *self,
const char *checksum,
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011,2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+207 -194
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011,2012,2013 Colin Walters <walters@verbum.org>
* Copyright © 2017 Endless Mobile, Inc.
*
@@ -69,7 +68,8 @@ typedef struct {
OstreeRepo *repo;
int tmpdir_dfd;
OstreeRepoPullFlags flags;
char *remote_name;
char *remote_name;
char *remote_refspec_name;
OstreeRepoMode remote_mode;
OstreeFetcher *fetcher;
OstreeFetcherSecurityState fetcher_security_state;
@@ -133,9 +133,9 @@ typedef struct {
guint n_fetched_deltapart_fallbacks;
guint n_fetched_metadata;
guint n_fetched_content;
/* Objects from pull --localcache-repo */
guint n_fetched_localcache_metadata;
guint n_fetched_localcache_content;
/* Objects imported via hardlink/reflink/copying or --localcache-repo*/
guint n_imported_metadata;
guint n_imported_content;
gboolean timestamp_check; /* Verify commit timestamps */
int maxdepth;
@@ -143,8 +143,7 @@ typedef struct {
gboolean is_mirror;
gboolean is_commit_only;
gboolean is_untrusted;
gboolean is_bareuseronly_files;
OstreeRepoImportFlags importflags;
GPtrArray *dirs;
@@ -218,6 +217,7 @@ static gboolean scan_one_metadata_object_c (OtPullData *pull_dat
const OstreeCollectionRef *ref,
GCancellable *cancellable,
GError **error);
static void scan_object_queue_data_free (ScanObjectQueueData *scan_data);
static gboolean
update_progress (gpointer user_data)
@@ -258,11 +258,15 @@ update_progress (gpointer user_data)
"fetched", "u", fetched,
"requested", "u", requested,
"scanning", "u", g_queue_is_empty (&pull_data->scan_object_queue) ? 0 : 1,
"caught-error", "b", pull_data->caught_error,
"scanned-metadata", "u", n_scanned_metadata,
"bytes-transferred", "t", bytes_transferred,
"start-time", "t", start_time,
"metadata-fetched-localcache", "u", pull_data->n_fetched_localcache_metadata,
"content-fetched-localcache", "u", pull_data->n_fetched_localcache_content,
/* We use these status keys even though we now also
* use these values for filesystem-local pulls.
*/
"metadata-fetched-localcache", "u", pull_data->n_imported_metadata,
"content-fetched-localcache", "u", pull_data->n_imported_content,
/* Deltas */
"fetched-delta-parts",
"u", pull_data->n_fetched_deltaparts,
@@ -309,9 +313,6 @@ pull_termination_condition (OtPullData *pull_data)
/* we only enter the main loop when we're fetching objects */
g_assert (pull_data->phase == OSTREE_PULL_PHASE_FETCHING_OBJECTS);
if (pull_data->caught_error)
return TRUE;
if (pull_data->dry_run)
return pull_data->dry_run_emitted_progress;
@@ -321,6 +322,10 @@ pull_termination_condition (OtPullData *pull_data)
return current_idle;
}
/* Most async operations finish by calling this function; it will consume
* @errorp if set, update statistics, and initiate processing of any further
* requests as appropriate.
*/
static void
check_outstanding_requests_handle_error (OtPullData *pull_data,
GError **errorp)
@@ -340,6 +345,18 @@ check_outstanding_requests_handle_error (OtPullData *pull_data,
g_clear_error (errorp);
}
}
/* If we're in error state, we wait for any pending operations to complete,
* but ensure that all no further operations are queued.
*/
if (pull_data->caught_error)
{
g_queue_foreach (&pull_data->scan_object_queue, (GFunc) scan_object_queue_data_free, NULL);
g_queue_clear (&pull_data->scan_object_queue);
g_hash_table_remove_all (pull_data->pending_fetch_metadata);
g_hash_table_remove_all (pull_data->pending_fetch_deltaparts);
g_hash_table_remove_all (pull_data->pending_fetch_content);
}
else
{
GHashTableIter hiter;
@@ -424,6 +441,15 @@ fetcher_queue_is_full (OtPullData *pull_data)
return fetch_full || deltas_full || writes_full;
}
static void
scan_object_queue_data_free (ScanObjectQueueData *scan_data)
{
g_free (scan_data->path);
if (scan_data->requested_ref != NULL)
ostree_collection_ref_free (scan_data->requested_ref);
g_free (scan_data);
}
static gboolean
idle_worker (gpointer user_data)
{
@@ -447,11 +473,8 @@ idle_worker (gpointer user_data)
pull_data->cancellable,
&error);
check_outstanding_requests_handle_error (pull_data, &error);
scan_object_queue_data_free (scan_data);
g_free (scan_data->path);
if (scan_data->requested_ref != NULL)
ostree_collection_ref_free (scan_data->requested_ref);
g_free (scan_data);
return G_SOURCE_CONTINUE;
}
@@ -602,100 +625,15 @@ 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;
}
/* Synchronously import a single content object; this is used async for content,
* or synchronously for metadata. @src_repo is either
* pull_data->remote_repo_local or one of pull_data->localcache_repos.
*
* One important special case here is handling the
* OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES flag.
*/
static gboolean
import_one_local_content_object_sync (OtPullData *pull_data,
OstreeRepo *src_repo,
const char *checksum,
GCancellable *cancellable,
GError **error)
{
const gboolean trusted = !pull_data->is_untrusted;
if (trusted && !pull_data->is_bareuseronly_files)
{
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, src_repo,
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 (src_repo, 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;
}
typedef struct {
OtPullData *pull_data;
OstreeRepo *src_repo;
char checksum[OSTREE_SHA256_STRING_LEN+1];
} ImportLocalAsyncData;
/* Asynchronously import a single content object. @src_repo is either
* pull_data->remote_repo_local or one of pull_data->localcache_repos.
*/
static void
async_import_in_thread (GTask *task,
gpointer source,
@@ -703,12 +641,12 @@ async_import_in_thread (GTask *task,
GCancellable *cancellable)
{
ImportLocalAsyncData *iataskdata = task_data;
OtPullData *pull_data = iataskdata->pull_data;
g_autoptr(GError) local_error = NULL;
if (!import_one_local_content_object_sync (iataskdata->pull_data,
iataskdata->src_repo,
iataskdata->checksum,
cancellable,
&local_error))
/* pull_data->importflags was set up in the pull option processing */
if (!_ostree_repo_import_object (pull_data->repo, iataskdata->src_repo,
OSTREE_OBJECT_TYPE_FILE, iataskdata->checksum,
pull_data->importflags, cancellable, &local_error))
g_task_return_error (task, g_steal_pointer (&local_error));
else
g_task_return_boolean (task, TRUE);
@@ -762,6 +700,7 @@ on_local_object_imported (GObject *object,
goto out;
out:
pull_data->n_imported_content++;
g_assert_cmpint (pull_data->n_outstanding_content_write_requests, >, 0);
pull_data->n_outstanding_content_write_requests--;
check_outstanding_requests_handle_error (pull_data, &local_error);
@@ -844,7 +783,6 @@ scan_dirtree_object (OtPullData *pull_data,
on_local_object_imported, pull_data);
g_hash_table_add (pull_data->requested_content, g_steal_pointer (&file_checksum));
did_import_from_cache_repo = TRUE;
pull_data->n_fetched_localcache_content++;
break;
}
}
@@ -900,24 +838,53 @@ fetch_ref_contents (OtPullData *pull_data,
GCancellable *cancellable,
GError **error)
{
g_autofree char *filename = NULL;
if (ref->collection_id == NULL || g_strcmp0 (ref->collection_id, main_collection_id) == 0)
filename = g_build_filename ("refs", "heads", ref->ref_name, NULL);
else
filename = g_build_filename ("refs", "mirrors", ref->collection_id, ref->ref_name, NULL);
g_autofree char *ret_contents = NULL;
if (!fetch_mirrored_uri_contents_utf8_sync (pull_data->fetcher,
pull_data->meta_mirrorlist,
filename, &ret_contents,
cancellable, error))
return FALSE;
g_strchomp (ret_contents);
if (pull_data->remote_repo_local != NULL && ref->collection_id != NULL)
{
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
if (!ostree_repo_resolve_collection_ref (pull_data->remote_repo_local,
ref, TRUE /* ignore enoent */,
OSTREE_REPO_RESOLVE_REV_EXT_NONE,
&ret_contents, cancellable, error))
return FALSE;
#else /* if !OSTREE_ENABLE_EXPERIMENTAL_API */
g_assert_not_reached ();
#endif /* !OSTREE_ENABLE_EXPERIMENTAL_API */
}
else if (pull_data->remote_repo_local != NULL)
{
if (!ostree_repo_resolve_rev_ext (pull_data->remote_repo_local,
ref->ref_name, TRUE /* ignore enoent */,
OSTREE_REPO_RESOLVE_REV_EXT_NONE,
&ret_contents, error))
return FALSE;
}
else
{
g_autofree char *filename = NULL;
if (!ostree_validate_checksum_string (ret_contents, error))
return glnx_prefix_error (error, "Fetching %s", filename);
if (ref->collection_id == NULL || g_strcmp0 (ref->collection_id, main_collection_id) == 0)
filename = g_build_filename ("refs", "heads", ref->ref_name, NULL);
else
filename = g_build_filename ("refs", "mirrors", ref->collection_id, ref->ref_name, NULL);
if (!fetch_mirrored_uri_contents_utf8_sync (pull_data->fetcher,
pull_data->meta_mirrorlist,
filename, &ret_contents,
cancellable, error))
return FALSE;
}
/* Validate and return. */
if (ret_contents != NULL)
g_strchomp (ret_contents);
if (ret_contents == NULL ||
!ostree_validate_checksum_string (ret_contents, error))
return glnx_prefix_error (error, "Fetching checksum for ref (%s, %s)",
ref->collection_id ? ref->collection_id : "(empty)",
ref->ref_name);
ot_transfer_out_value (out_contents, &ret_contents);
return TRUE;
@@ -1069,12 +1036,18 @@ content_fetch_on_complete (GObject *object,
checksum_obj = ostree_object_to_string (checksum, objtype);
g_debug ("fetch of %s complete", checksum_obj);
/* 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.
const gboolean verifying_bareuseronly =
(pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY) > 0;
/* If we're mirroring and writing into an archive repo, and both checksum and
* bareuseronly are turned off, 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)
const gboolean mirroring_into_archive =
pull_data->is_mirror && pull_data->repo->mode == OSTREE_REPO_MODE_ARCHIVE;
const gboolean import_trusted = !verifying_bareuseronly &&
(pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_TRUSTED) > 0;
if (mirroring_into_archive && import_trusted)
{
gboolean have_object;
if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, checksum,
@@ -1108,11 +1081,11 @@ content_fetch_on_complete (GObject *object,
*/
ot_cleanup_unlinkat (&tmp_unlinker);
if (!validate_bareuseronly_mode (pull_data,
checksum,
g_file_info_get_attribute_uint32 (file_info, "unix::mode"),
error))
goto out;
if (verifying_bareuseronly)
{
if (!_ostree_validate_bareuseronly_mode_finfo (file_info, checksum, error))
goto out;
}
if (!ostree_raw_file_to_content_stream (file_in, file_info, xattrs,
&object_input, &length,
@@ -1793,35 +1766,38 @@ scan_one_metadata_object_c (OtPullData *pull_data,
g_autofree char *tmp_checksum = ostree_checksum_from_bytes (csum);
g_autoptr(GVariant) object = ostree_object_name_serialize (tmp_checksum, objtype);
/* It may happen that we've already looked at this object (think shared
* dirtree subtrees), if that's the case, we're done */
if (g_hash_table_lookup (pull_data->scanned_metadata, object))
return TRUE;
gboolean is_requested = g_hash_table_lookup (pull_data->requested_metadata, object) != NULL;
/* Determine if we already have the object */
gboolean is_stored;
if (!ostree_repo_has_object (pull_data->repo, objtype, tmp_checksum, &is_stored,
cancellable, error))
return FALSE;
if (pull_data->remote_repo_local)
/* Are we pulling an object we don't have from a local repo? */
if (!is_stored && pull_data->remote_repo_local)
{
if (!is_stored)
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
/* mark as partial to ensure we scan the commit below */
if (!write_commitpartial_for (pull_data, tmp_checksum, error))
return FALSE;
}
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, pull_data->remote_repo_local,
objtype, tmp_checksum, !pull_data->is_untrusted,
cancellable, error))
/* mark as partial to ensure we scan the commit below */
if (!write_commitpartial_for (pull_data, tmp_checksum, error))
return FALSE;
/* The import API will fetch both the commit and detached metadata, so
* add it to the hash to avoid re-fetching it below.
*/
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (tmp_checksum));
}
if (!_ostree_repo_import_object (pull_data->repo, pull_data->remote_repo_local,
objtype, tmp_checksum, pull_data->importflags,
cancellable, error))
return FALSE;
/* The import API will fetch both the commit and detached metadata, so
* add it to the hash to avoid re-fetching it below.
*/
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (tmp_checksum));
pull_data->n_imported_metadata++;
is_stored = TRUE;
is_requested = TRUE;
}
@@ -1844,17 +1820,16 @@ scan_one_metadata_object_c (OtPullData *pull_data,
if (!write_commitpartial_for (pull_data, tmp_checksum, error))
return FALSE;
}
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, refd_repo,
objtype, tmp_checksum,
!pull_data->is_untrusted,
cancellable, error))
if (!_ostree_repo_import_object (pull_data->repo, refd_repo,
objtype, tmp_checksum, pull_data->importflags,
cancellable, error))
return FALSE;
/* See comment above */
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (tmp_checksum));
is_stored = TRUE;
is_requested = TRUE;
pull_data->n_fetched_localcache_metadata++;
pull_data->n_imported_metadata++;
break;
}
}
@@ -3142,10 +3117,14 @@ initiate_request (OtPullData *pull_data,
g_clear_pointer (&delta_from_revision, g_free);
}
/* This is similar to the below, except we *might* use the previous
* commit, or we might do a scratch delta first.
/* If the current ref is the same, we don't do a delta request, just a
* scan. Otherise, use the previous commit if available, or a scratch
* delta.
*/
initiate_delta_request (pull_data, delta_from_revision ?: NULL, to_revision, ref);
if (delta_from_revision && g_str_equal (delta_from_revision, to_revision))
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref);
else
initiate_delta_request (pull_data, delta_from_revision ?: NULL, to_revision, ref);
}
else
{
@@ -3252,7 +3231,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
flags = flags_i;
(void) g_variant_lookup (options, "subdir", "&s", &dir_to_pull);
(void) g_variant_lookup (options, "subdirs", "^a&s", &dirs_to_pull);
(void) g_variant_lookup (options, "override-remote-name", "s", &pull_data->remote_name);
(void) g_variant_lookup (options, "override-remote-name", "s", &pull_data->remote_refspec_name);
opt_gpg_verify_set =
g_variant_lookup (options, "gpg-verify", "b", &pull_data->gpg_verify);
opt_gpg_verify_summary_set =
@@ -3268,6 +3247,9 @@ ostree_repo_pull_with_options (OstreeRepo *self,
(void) g_variant_lookup (options, "update-frequency", "u", &update_frequency);
(void) g_variant_lookup (options, "localcache-repos", "^a&s", &opt_localcache_repos);
(void) g_variant_lookup (options, "timestamp-check", "b", &pull_data->timestamp_check);
if (pull_data->remote_refspec_name != NULL)
pull_data->remote_name = g_strdup (pull_data->remote_refspec_name);
}
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
@@ -3293,8 +3275,9 @@ 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;
/* See our processing of OSTREE_REPO_PULL_FLAGS_UNTRUSTED below */
if ((flags & OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES) > 0)
pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY;
pull_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
if (error)
@@ -3385,6 +3368,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
{
g_autofree char *unconfigured_state = NULL;
g_free (pull_data->remote_name);
pull_data->remote_name = g_strdup (remote_name_or_baseurl);
/* Fetch GPG verification settings from remote if it wasn't already
@@ -3573,7 +3557,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
&pull_data->has_tombstone_commits, error))
goto out;
if (pull_data->remote_mode != OSTREE_REPO_MODE_ARCHIVE_Z2)
if (pull_data->remote_mode != OSTREE_REPO_MODE_ARCHIVE)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Can't pull from archives with mode \"%s\"",
@@ -3583,6 +3567,9 @@ ostree_repo_pull_with_options (OstreeRepo *self,
}
}
/* Change some option defaults if we're actually pulling from a local
* (filesystem accessible) repo.
*/
if (pull_data->remote_repo_local)
{
/* For local pulls, default to disabling static deltas so that the
@@ -3591,10 +3578,25 @@ ostree_repo_pull_with_options (OstreeRepo *self,
if (!pull_data->require_static_deltas)
pull_data->disable_static_deltas = TRUE;
/* Note the inversion here; PULL_FLAGS_UNTRUSTED is converted to
* IMPORT_FLAGS_TRUSTED only if it's unset (and just for local repos).
*/
if ((flags & OSTREE_REPO_PULL_FLAGS_UNTRUSTED) == 0)
pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_TRUSTED;
}
else
{
/* For non-local repos, we require the TRUSTED_HTTP pull flag to map to
* the TRUSTED object import flag. In practice we don't do object imports
* for HTTP, but it's easiest to use one set of flags between HTTP and
* local imports.
*/
if (flags & OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP)
pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_TRUSTED;
}
/* We can't use static deltas if pulling into an archive repo. */
if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
if (self->mode == OSTREE_REPO_MODE_ARCHIVE)
{
if (pull_data->require_static_deltas)
{
@@ -4055,7 +4057,8 @@ ostree_repo_pull_with_options (OstreeRepo *self,
ostree_repo_transaction_set_collection_ref (pull_data->repo,
ref, checksum);
else
ostree_repo_transaction_set_ref (pull_data->repo, pull_data->remote_name,
ostree_repo_transaction_set_ref (pull_data->repo,
(pull_data->remote_refspec_name != NULL) ? pull_data->remote_refspec_name : pull_data->remote_name,
ref->ref_name, checksum);
}
}
@@ -4089,36 +4092,42 @@ ostree_repo_pull_with_options (OstreeRepo *self,
end_time = g_get_monotonic_time ();
bytes_transferred = _ostree_fetcher_bytes_transferred (pull_data->fetcher);
if (bytes_transferred > 0 && pull_data->progress)
if (pull_data->progress)
{
guint shift;
g_autoptr(GString) buf = g_string_new ("");
/* Ensure the rest of the progress keys are set appropriately. */
update_progress (pull_data);
if (bytes_transferred < 1024)
shift = 1;
else
shift = 1024;
if (pull_data->n_fetched_deltaparts > 0)
/* See if we did a local-only import */
if (pull_data->remote_repo_local)
g_string_append_printf (buf, "%u metadata, %u content objects imported",
pull_data->n_imported_metadata, pull_data->n_imported_content);
else if (pull_data->n_fetched_deltaparts > 0)
g_string_append_printf (buf, "%u delta parts, %u loose fetched",
pull_data->n_fetched_deltaparts,
pull_data->n_fetched_metadata + pull_data->n_fetched_content);
else
g_string_append_printf (buf, "%u metadata, %u content objects fetched",
pull_data->n_fetched_metadata, pull_data->n_fetched_content);
if (pull_data->n_fetched_localcache_metadata ||
pull_data->n_fetched_localcache_content)
if (!pull_data->remote_repo_local &&
(pull_data->n_imported_metadata || pull_data->n_imported_content))
g_string_append_printf (buf, " (%u meta, %u content local)",
pull_data->n_fetched_localcache_metadata,
pull_data->n_fetched_localcache_content);
pull_data->n_imported_metadata,
pull_data->n_imported_content);
g_string_append_printf (buf, "; %" G_GUINT64_FORMAT " %s transferred in %u seconds",
(guint64)(bytes_transferred / shift),
shift == 1 ? "B" : "KiB",
(guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC));
if (bytes_transferred > 0)
{
guint shift;
if (bytes_transferred < 1024)
shift = 1;
else
shift = 1024;
g_string_append_printf (buf, "; %" G_GUINT64_FORMAT " %s transferred in %u seconds",
(guint64)(bytes_transferred / shift),
shift == 1 ? "B" : "KiB",
(guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC));
}
ostree_async_progress_set_status (pull_data->progress, buf->str);
}
@@ -4245,6 +4254,8 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_clear_pointer (&pull_data->pending_fetch_content, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->pending_fetch_metadata, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->pending_fetch_deltaparts, (GDestroyNotify) g_hash_table_unref);
g_queue_foreach (&pull_data->scan_object_queue, (GFunc) scan_object_queue_data_free, NULL);
g_queue_clear (&pull_data->scan_object_queue);
g_clear_pointer (&pull_data->idle_src, (GDestroyNotify) g_source_destroy);
g_clear_pointer (&pull_data->dirs, (GDestroyNotify) g_ptr_array_unref);
g_clear_pointer (&remote_config, (GDestroyNotify) g_key_file_unref);
@@ -4521,7 +4532,7 @@ static void find_remotes_cb (GObject *obj,
* will typically be all available finders using their default options (but
* this is not guaranteed).
*
* GPG verification of the summary and all commits will be used unconditionally.
* GPG verification of commits will be used unconditionally.
*
* This will use the thread-default #GMainContext, but will not iterate it.
*
@@ -4820,7 +4831,7 @@ find_remotes_cb (GObject *obj,
for (i = 0; i < results->len; i++)
{
OstreeRepoFinderResult *result = g_ptr_array_index (results, i);
g_autoptr(GBytes) summary_bytes = NULL, summary_sig_bytes = NULL;
g_autoptr(GBytes) summary_bytes = NULL;
g_autoptr(GVariant) summary_v = NULL;
guint64 summary_last_modified;
g_autoptr(GVariant) summary_refs = NULL;
@@ -4837,13 +4848,12 @@ find_remotes_cb (GObject *obj,
g_debug ("%s: Fetching summary for remote ‘%s’ with keyring ‘%s’.",
G_STRFUNC, result->remote->name, result->remote->keyring);
/* Download the summary and signature, and validate the signature. This
* will load from the cache if possible. */
/* Download the summary. This will load from the cache if possible. */
ostree_repo_remote_fetch_summary_with_options (self,
result->remote->name,
NULL, /* no options */
&summary_bytes,
&summary_sig_bytes,
NULL,
cancellable,
&error);
@@ -4937,7 +4947,7 @@ find_remotes_cb (GObject *obj,
if (commit_metadata->timestamp != 0)
continue;
_ostree_loose_path (buf, commit_metadata->checksum, OSTREE_OBJECT_TYPE_COMMIT, OSTREE_REPO_MODE_ARCHIVE_Z2);
_ostree_loose_path (buf, commit_metadata->checksum, OSTREE_OBJECT_TYPE_COMMIT, OSTREE_REPO_MODE_ARCHIVE);
commit_filename = g_build_filename ("objects", buf, NULL);
/* For each of the remotes whose summary files contain this ref, try
@@ -5251,7 +5261,7 @@ copy_option (GVariantDict *master_options,
* immediately. The results of any successfully completed downloads at that
* point will remain cached in the local repository.
*
* GPG verification of the summary and all commits will be used unconditionally.
* GPG verification of commits will be used unconditionally.
*
* The following @options are currently defined:
*
@@ -5369,6 +5379,8 @@ ostree_repo_pull_from_remotes_async (OstreeRepo *self,
g_variant_dict_insert (&local_options_dict, "gpg-verify", "b", TRUE);
g_variant_dict_insert (&local_options_dict, "gpg-verify-summary", "b", FALSE);
g_variant_dict_insert (&local_options_dict, "inherit-transaction", "b", TRUE);
if (result->remote->refspec_name != NULL)
g_variant_dict_insert (&local_options_dict, "override-remote-name", "s", result->remote->refspec_name);
copy_option (&options_dict, &local_options_dict, "depth", G_VARIANT_TYPE ("i"));
copy_option (&options_dict, &local_options_dict, "disable-static-deltas", G_VARIANT_TYPE ("b"));
copy_option (&options_dict, &local_options_dict, "http-headers", G_VARIANT_TYPE ("a(ss)"));
@@ -5497,7 +5509,7 @@ check_remote_matches_collection_id (OstreeRepo *repo,
* Find the GPG keyring for the given @collection_id, using the local
* configuration from the given #OstreeRepo. This will search the configured
* remotes for ones whose `collection-id` key matches @collection_id, and will
* return the GPG keyring from the first matching remote.
* return the first matching remote.
*
* If multiple remotes match and have different keyrings, a debug message will
* be emitted, and the first result will be returned. It is expected that the
@@ -5505,10 +5517,11 @@ check_remote_matches_collection_id (OstreeRepo *repo,
*
* If no match can be found, a %G_IO_ERROR_NOT_FOUND error will be returned.
*
* Returns: (transfer full): filename of the GPG keyring for @collection_id
* Returns: (transfer full): #OstreeRemote containing the GPG keyring for
* @collection_id
* Since: 2017.8
*/
gchar *
OstreeRemote *
ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
const gchar *collection_id,
GCancellable *cancellable,
@@ -5516,7 +5529,7 @@ ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
{
gsize i;
g_auto(GStrv) remotes = NULL;
const OstreeRemote *keyring_remote = NULL;
OstreeRemote *keyring_remote = NULL;
g_return_val_if_fail (OSTREE_IS_REPO (self), NULL);
g_return_val_if_fail (ostree_validate_collection_id (collection_id, NULL), NULL);
@@ -5566,7 +5579,7 @@ ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
}
if (keyring_remote != NULL)
return g_strdup (keyring_remote->keyring);
return ostree_remote_ref (keyring_remote);
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+68 -11
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011,2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -469,6 +468,69 @@ ostree_repo_resolve_rev_ext (OstreeRepo *self,
return _ostree_repo_resolve_rev_internal (self, refspec, allow_noent, FALSE, out_rev, error);
}
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
/**
* ostree_repo_resolve_collection_ref:
* @self: an #OstreeRepo
* @ref: a collection–ref to resolve
* @allow_noent: %TRUE to not throw an error if @ref doesn’t exist
* @flags: options controlling behaviour
* @out_rev: (out) (transfer full) (optional) (nullable): return location for
* the checksum corresponding to @ref, or %NULL if @allow_noent is %TRUE and
* the @ref could not be found
* @cancellable: (nullable): a #GCancellable, or %NULL
* @error: return location for a #GError, or %NULL
*
* Look up the checksum for the given collection–ref, returning it in @out_rev.
* This will search through the mirrors and remote refs.
*
* If @allow_noent is %TRUE and the given @ref cannot be found, %TRUE will be
* returned and @out_rev will be set to %NULL. If @allow_noent is %FALSE and
* the given @ref cannot be found, a %G_IO_ERROR_NOT_FOUND error will be
* returned.
*
* There are currently no @flags which affect the behaviour of this function.
*
* Returns: %TRUE on success, %FALSE on failure
* Since: 2017.12
*/
gboolean
ostree_repo_resolve_collection_ref (OstreeRepo *self,
const OstreeCollectionRef *ref,
gboolean allow_noent,
OstreeRepoResolveRevExtFlags flags,
char **out_rev,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
g_return_val_if_fail (ref != NULL, FALSE);
g_return_val_if_fail (ref->collection_id != NULL && ref->ref_name != NULL, FALSE);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
g_autoptr(GHashTable) refs = NULL; /* (element-type OstreeCollectionRef utf8) */
if (!ostree_repo_list_collection_refs (self, ref->collection_id, &refs,
OSTREE_REPO_LIST_REFS_EXT_NONE,
cancellable, error))
return FALSE;
const char *ret_contents = g_hash_table_lookup (refs, ref);
if (ret_contents == NULL && !allow_noent)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Collection–ref (%s, %s) not found",
ref->collection_id, ref->ref_name);
return FALSE;
}
if (out_rev != NULL)
*out_rev = g_strdup (ret_contents);
return TRUE;
}
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
static gboolean
enumerate_refs_recurse (OstreeRepo *repo,
const char *remote,
@@ -545,12 +607,10 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GHashTable) ret_all_refs = NULL;
g_autofree char *remote = NULL;
g_autofree char *ref_prefix = NULL;
ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
g_autoptr(GHashTable) ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
if (refspec_prefix)
{
struct stat stbuf;
@@ -571,12 +631,9 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
path = glnx_strjoina (prefix_path, ref_prefix);
}
if (fstatat (self->repo_dir_fd, path, &stbuf, 0) < 0)
{
if (errno != ENOENT)
return glnx_throw_errno (error);
}
else
if (!glnx_fstatat_allow_noent (self->repo_dir_fd, path, &stbuf, 0, error))
return FALSE;
if (errno == 0)
{
if (S_ISDIR (stbuf.st_mode))
{
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2015 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013,2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2013,2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+158 -364
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
* Copyright (C) 2015 Red Hat, Inc.
*
@@ -49,6 +48,10 @@
/* ABI Size checks for ostree-repo.h, only for LP64 systems;
* https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models
*
* To generate this data, I used `pahole` from gdb. More concretely, `gdb --args
* /usr/bin/ostree`, then `start`, (to ensure debuginfo was loaded), then e.g.
* `$ pahole OstreeRepoTransactionStats`.
*/
#if __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 8 && __SIZEOF_INT__ == 4
G_STATIC_ASSERT(sizeof(OstreeRepoTransactionStats) == sizeof(int) * 4 + 8 * 5);
@@ -487,9 +490,7 @@ ostree_repo_finalize (GObject *object)
g_clear_object (&self->repodir);
if (self->repo_dir_fd != -1)
(void) close (self->repo_dir_fd);
if (self->commit_stagedir_fd != -1)
(void) close (self->commit_stagedir_fd);
g_free (self->commit_stagedir_name);
glnx_tmpdir_unset (&self->commit_stagedir);
glnx_release_lock_file (&self->commit_stagedir_lock);
if (self->tmp_dir_fd != -1)
(void) close (self->tmp_dir_fd);
@@ -661,7 +662,6 @@ static void
ostree_repo_init (OstreeRepo *self)
{
static gsize gpgme_initialized;
GLnxLockFile empty_lockfile = GLNX_LOCK_FILE_INIT;
const GDebugKey test_error_keys[] = {
{ "pre-commit", OSTREE_REPO_TEST_ERROR_PRE_COMMIT },
};
@@ -687,10 +687,8 @@ ostree_repo_init (OstreeRepo *self)
self->repo_dir_fd = -1;
self->cache_dir_fd = -1;
self->tmp_dir_fd = -1;
self->commit_stagedir_fd = -1;
self->objects_dir_fd = -1;
self->uncompressed_objects_dir_fd = -1;
self->commit_stagedir_lock = empty_lockfile;
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_UNKNOWN;
}
@@ -1753,7 +1751,8 @@ ostree_repo_mode_to_string (OstreeRepoMode mode,
case OSTREE_REPO_MODE_BARE_USER_ONLY:
ret_mode = "bare-user-only";
break;
case OSTREE_REPO_MODE_ARCHIVE_Z2:
case OSTREE_REPO_MODE_ARCHIVE:
/* Legacy alias */
ret_mode ="archive-z2";
break;
default:
@@ -1779,7 +1778,7 @@ ostree_repo_mode_from_string (const char *mode,
ret_mode = OSTREE_REPO_MODE_BARE_USER_ONLY;
else if (strcmp (mode, "archive-z2") == 0 ||
strcmp (mode, "archive") == 0)
ret_mode = OSTREE_REPO_MODE_ARCHIVE_Z2;
ret_mode = OSTREE_REPO_MODE_ARCHIVE;
else
return glnx_throw (error, "Invalid mode '%s' in repository configuration", mode);
@@ -1809,7 +1808,9 @@ repo_create_at_internal (int dfd,
/* Early return if we have an existing repo */
{ g_autofree char *objects_path = g_build_filename (path, "objects", NULL);
if (fstatat (dfd, objects_path, &stbuf, 0) == 0)
if (!glnx_fstatat_allow_noent (dfd, objects_path, &stbuf, 0, error))
return FALSE;
if (errno == 0)
{
glnx_fd_close int repo_dfd = -1;
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
@@ -1819,8 +1820,6 @@ repo_create_at_internal (int dfd,
*out_dfd = glnx_steal_fd (&repo_dfd);
return TRUE;
}
else if (errno != ENOENT)
return glnx_throw_errno_prefix (error, "fstatat");
}
if (mkdirat (dfd, path, 0755) != 0)
@@ -1833,32 +1832,29 @@ repo_create_at_internal (int dfd,
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
return FALSE;
if (fstatat (repo_dfd, "config", &stbuf, 0) < 0)
if (!glnx_fstatat_allow_noent (repo_dfd, "config", &stbuf, 0, error))
return FALSE;
if (errno == ENOENT)
{
if (errno == ENOENT)
{
const char *mode_str = NULL;
g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
const char *mode_str = NULL;
g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
if (!ostree_repo_mode_to_string (mode, &mode_str, error))
return FALSE;
g_assert (mode_str);
if (!ostree_repo_mode_to_string (mode, &mode_str, error))
return FALSE;
g_assert (mode_str);
g_string_append_printf (config_data, "mode=%s\n", mode_str);
g_string_append_printf (config_data, "mode=%s\n", mode_str);
const char *collection_id = NULL;
if (options)
g_variant_lookup (options, "collection-id", "&s", &collection_id);
if (collection_id != NULL)
g_string_append_printf (config_data, "collection-id=%s\n", collection_id);
const char *collection_id = NULL;
if (options)
g_variant_lookup (options, "collection-id", "&s", &collection_id);
if (collection_id != NULL)
g_string_append_printf (config_data, "collection-id=%s\n", collection_id);
if (!glnx_file_replace_contents_at (repo_dfd, "config",
(guint8*)config_data->str, config_data->len,
0, cancellable, error))
return FALSE;
}
else
return glnx_throw_errno_prefix (error, "fstatat");
if (!glnx_file_replace_contents_at (repo_dfd, "config",
(guint8*)config_data->str, config_data->len,
0, cancellable, error))
return FALSE;
}
for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++)
@@ -2480,7 +2476,7 @@ ostree_repo_open (OstreeRepo *self,
return FALSE;
/* TODO - delete this */
if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2 && self->enable_uncompressed_cache)
if (self->mode == OSTREE_REPO_MODE_ARCHIVE && self->enable_uncompressed_cache)
{
if (!glnx_shutil_mkdir_p_at (self->repo_dir_fd, "uncompressed-objects-cache", 0755,
cancellable, error))
@@ -2615,6 +2611,61 @@ ostree_repo_get_dfd (OstreeRepo *self)
return self->repo_dir_fd;
}
/**
* ostree_repo_hash:
* @self: an #OstreeRepo
*
* Calculate a hash value for the given open repository, suitable for use when
* putting it into a hash table. It is an error to call this on an #OstreeRepo
* which is not yet open, as a persistent hash value cannot be calculated until
* the repository is open and the inode of its root directory has been loaded.
*
* This function does no I/O.
*
* Returns: hash value for the #OstreeRepo
* Since: 2017.12
*/
guint
ostree_repo_hash (OstreeRepo *self)
{
g_return_val_if_fail (OSTREE_IS_REPO (self), 0);
/* We cannot hash non-open repositories, since their hash value would change
* once they’re opened, resulting in false lookup misses and the inability to
* remove them from a hash table. */
g_assert (self->repo_dir_fd >= 0);
/* device and inode numbers are distributed fairly uniformly, so we can’t
* do much better than just combining them. No need to rehash to even out
* the distribution. */
return (self->device ^ self->inode);
}
/**
* ostree_repo_equal:
* @a: an #OstreeRepo
* @b: an #OstreeRepo
*
* Check whether two opened repositories are the same on disk: if their root
* directories are the same inode. If @a or @b are not open yet (due to
* ostree_repo_open() not being called on them yet), %FALSE will be returned.
*
* Returns: %TRUE if @a and @b are the same repository on disk, %FALSE otherwise
* Since: 2017.12
*/
gboolean
ostree_repo_equal (OstreeRepo *a,
OstreeRepo *b)
{
g_return_val_if_fail (OSTREE_IS_REPO (a), FALSE);
g_return_val_if_fail (OSTREE_IS_REPO (b), FALSE);
if (a->repo_dir_fd < 0 || b->repo_dir_fd < 0)
return FALSE;
return (a->device == b->device && a->inode == b->inode);
}
OstreeRepoMode
ostree_repo_get_mode (OstreeRepo *self)
{
@@ -2676,7 +2727,7 @@ list_loose_objects_at (OstreeRepo *self,
continue;
OstreeObjectType objtype;
if ((self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2
if ((self->mode == OSTREE_REPO_MODE_ARCHIVE
&& strcmp (dot, ".filez") == 0) ||
((_ostree_repo_mode_is_bare (self->mode))
&& strcmp (dot, ".file") == 0))
@@ -2793,9 +2844,9 @@ load_metadata_internal (OstreeRepo *self,
error))
return FALSE;
if (fd < 0 && self->commit_stagedir_fd != -1)
if (fd < 0 && self->commit_stagedir.initialized)
{
if (!ot_openat_ignore_enoent (self->commit_stagedir_fd, loose_path_buf, &fd,
if (!ot_openat_ignore_enoent (self->commit_stagedir.fd, loose_path_buf, &fd,
error))
return FALSE;
}
@@ -2906,9 +2957,9 @@ repo_load_file_archive (OstreeRepo *self,
error))
return FALSE;
if (fd < 0 && self->commit_stagedir_fd != -1)
if (fd < 0 && self->commit_stagedir.initialized)
{
if (!ot_openat_ignore_enoent (self->commit_stagedir_fd, loose_path_buf, &fd,
if (!ot_openat_ignore_enoent (self->commit_stagedir.fd, loose_path_buf, &fd,
error))
return FALSE;
}
@@ -2967,9 +3018,9 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
int objdir_fd = self->objects_dir_fd;
int res;
if ((res = TEMP_FAILURE_RETRY (fstatat (objdir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW))) < 0
&& errno == ENOENT && self->commit_stagedir_fd != -1)
&& errno == ENOENT && self->commit_stagedir.initialized)
{
objdir_fd = self->commit_stagedir_fd;
objdir_fd = self->commit_stagedir.fd;
res = TEMP_FAILURE_RETRY (fstatat (objdir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW));
}
if (res < 0 && errno != ENOENT)
@@ -3102,7 +3153,7 @@ ostree_repo_load_file (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
if (self->mode == OSTREE_REPO_MODE_ARCHIVE)
return repo_load_file_archive (self, checksum, out_input, out_file_info, out_xattrs,
cancellable, error);
else
@@ -3214,7 +3265,9 @@ _ostree_repo_has_loose_object (OstreeRepo *self,
gboolean found = FALSE;
/* It's easier to share code if we make this an array */
const int dfd_searches[] = { self->commit_stagedir_fd, self->objects_dir_fd };
int dfd_searches[] = { -1, self->objects_dir_fd };
if (self->commit_stagedir.initialized)
dfd_searches[0] = self->commit_stagedir.fd;
for (guint i = 0; i < G_N_ELEMENTS (dfd_searches); i++)
{
int dfd = dfd_searches[i];
@@ -3346,114 +3399,6 @@ ostree_repo_delete_object (OstreeRepo *self,
return TRUE;
}
static gboolean
copy_detached_metadata (OstreeRepo *self,
OstreeRepo *source,
const char *checksum,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GVariant) detached_meta = NULL;
if (!ostree_repo_read_commit_detached_metadata (source,
checksum, &detached_meta,
cancellable, error))
return FALSE;
if (detached_meta)
{
if (!ostree_repo_write_commit_detached_metadata (self,
checksum, detached_meta,
cancellable, error))
return FALSE;
}
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_is_bareuser_only_conversion (OstreeRepo *src_repo,
OstreeRepo *dest_repo,
OstreeObjectType objtype)
{
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
import_one_object_link (OstreeRepo *self,
OstreeRepo *source,
const char *checksum,
OstreeObjectType objtype,
gboolean *out_was_supported,
GCancellable *cancellable,
GError **error)
{
const char *errprefix = glnx_strjoina ("Importing ", checksum, ".",
ostree_object_type_to_string (objtype));
GLNX_AUTO_PREFIX_ERROR (errprefix, error);
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))
{
struct stat stbuf;
if (!_ostree_repo_load_file_bare (source, checksum, NULL, &stbuf,
NULL, NULL, cancellable, error))
return FALSE;
if (S_ISREG (stbuf.st_mode))
{
/* This is OK, we'll drop through and try a hardlink */
}
else if (S_ISLNK (stbuf.st_mode))
{
/* NOTE early return */
*out_was_supported = FALSE;
return TRUE;
}
else
g_assert_not_reached ();
}
if (!_ostree_repo_ensure_loose_objdir_at (self->objects_dir_fd, loose_path_buf, cancellable, error))
return FALSE;
*out_was_supported = TRUE;
if (linkat (source->objects_dir_fd, loose_path_buf, self->objects_dir_fd, loose_path_buf, 0) != 0)
{
if (errno == EEXIST)
return TRUE;
else if (errno == EMLINK || errno == EXDEV || errno == EPERM)
{
/* EMLINK, EXDEV and EPERM shouldn't be fatal; we just can't do the
* optimization of hardlinking instead of copying.
*/
*out_was_supported = FALSE;
return TRUE;
}
else
return glnx_throw_errno_prefix (error, "linkat");
}
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
if (!copy_detached_metadata (self, source, checksum, cancellable, error))
return FALSE;
}
return TRUE;
}
/**
* ostree_repo_import_object_from:
* @self: Destination repo
@@ -3483,28 +3428,6 @@ 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
@@ -3531,103 +3454,12 @@ ostree_repo_import_object_from_with_trust (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
/* 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;
}
/* The copy path */
/* 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 (trusted)
{
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;
}
}
return TRUE;
/* This just wraps a currently internal API, may make it public later */
OstreeRepoImportFlags flags = trusted ? _OSTREE_REPO_IMPORT_FLAGS_TRUSTED : 0;
return _ostree_repo_import_object (self, source, objtype, checksum,
flags, cancellable, error);
}
/**
* ostree_repo_query_object_storage_size:
* @self: Repo
@@ -3654,8 +3486,8 @@ ostree_repo_query_object_storage_size (OstreeRepo *self,
struct stat stbuf;
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 && errno == ENOENT && self->commit_stagedir.initialized)
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));
@@ -4023,7 +3855,7 @@ ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress
gpointer user_data)
{
g_autofree char *status = NULL;
gboolean scanning;
gboolean caught_error, scanning;
guint outstanding_fetches;
guint outstanding_metadata_fetches;
guint outstanding_writes;
@@ -4039,6 +3871,7 @@ ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress
"outstanding-fetches", "u", &outstanding_fetches,
"outstanding-metadata-fetches", "u", &outstanding_metadata_fetches,
"outstanding-writes", "u", &outstanding_writes,
"caught-error", "b", &caught_error,
"scanning", "u", &scanning,
"scanned-metadata", "u", &n_scanned_metadata,
"fetched-delta-parts", "u", &fetched_delta_parts,
@@ -4052,6 +3885,10 @@ ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress
{
g_string_append (buf, status);
}
else if (caught_error)
{
g_string_append_printf (buf, "Caught error, waiting for outstanding tasks");
}
else if (outstanding_fetches)
{
guint64 bytes_transferred, start_time, total_delta_part_size;
@@ -4191,88 +4028,52 @@ sign_data (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_auto(GLnxTmpfile) tmpf = { 0, };
g_autoptr(GOutputStream) tmp_signature_output = NULL;
gpgme_ctx_t context = NULL;
g_autoptr(GBytes) ret_signature = NULL;
gpgme_error_t err;
gpgme_key_t key = NULL;
gpgme_data_t commit_buffer = NULL;
gpgme_data_t signature_buffer = NULL;
g_autoptr(GMappedFile) signature_file = NULL;
if (!glnx_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_RDWR | O_CLOEXEC,
&tmpf, error))
goto out;
tmp_signature_output = g_unix_output_stream_new (tmpf.fd, FALSE);
return FALSE;
g_autoptr(GOutputStream) tmp_signature_output = g_unix_output_stream_new (tmpf.fd, FALSE);
context = ot_gpgme_new_ctx (homedir, error);
g_auto(gpgme_ctx_t) context = ot_gpgme_new_ctx (homedir, error);
if (!context)
goto out;
return FALSE;
/* Get the secret keys with the given key id */
err = gpgme_get_key (context, key_id, &key, 1);
g_auto(gpgme_key_t) key = NULL;
gpgme_error_t err = gpgme_get_key (context, key_id, &key, 1);
if (gpgme_err_code (err) == GPG_ERR_EOF)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No gpg key found with ID %s (homedir: %s)", key_id,
homedir ? homedir : "<default>");
goto out;
}
return glnx_throw (error, "No gpg key found with ID %s (homedir: %s)", key_id,
homedir ? homedir : "<default>");
else if (err != GPG_ERR_NO_ERROR)
{
ot_gpgme_throw (err, error, "Unable to lookup key ID %s", key_id);
goto out;
}
return ot_gpgme_throw (err, error, "Unable to lookup key ID %s", key_id);
/* Add the key to the context as a signer */
if ((err = gpgme_signers_add (context, key)) != GPG_ERR_NO_ERROR)
{
ot_gpgme_throw (err, error, "Error signing commit");
goto out;
}
return ot_gpgme_throw (err, error, "Error signing commit");
{
gsize len;
const char *buf = g_bytes_get_data (input_data, &len);
if ((err = gpgme_data_new_from_mem (&commit_buffer, buf, len, FALSE)) != GPG_ERR_NO_ERROR)
{
ot_gpgme_throw (err, error, "Failed to create buffer from commit file");
goto out;
}
}
signature_buffer = ot_gpgme_data_output (tmp_signature_output);
/* Get a gpg buffer from the commit */
g_auto(gpgme_data_t) commit_buffer = NULL;
gsize len;
const char *buf = g_bytes_get_data (input_data, &len);
if ((err = gpgme_data_new_from_mem (&commit_buffer, buf, len, FALSE)) != GPG_ERR_NO_ERROR)
return ot_gpgme_throw (err, error, "Failed to create buffer from commit file");
/* Sign it */
g_auto(gpgme_data_t) signature_buffer = ot_gpgme_data_output (tmp_signature_output);
if ((err = gpgme_op_sign (context, commit_buffer, signature_buffer, GPGME_SIG_MODE_DETACH))
!= GPG_ERR_NO_ERROR)
{
ot_gpgme_throw (err, error, "Failure signing commit file");
goto out;
}
return ot_gpgme_throw (err, error, "Failure signing commit file");
if (!g_output_stream_close (tmp_signature_output, cancellable, error))
goto out;
signature_file = g_mapped_file_new_from_fd (tmpf.fd, FALSE, error);
return FALSE;
/* Return a mmap() reference */
g_autoptr(GMappedFile) signature_file = g_mapped_file_new_from_fd (tmpf.fd, FALSE, error);
if (!signature_file)
goto out;
ret_signature = g_mapped_file_get_bytes (signature_file);
ret = TRUE;
return FALSE;
if (out_signature)
*out_signature = g_steal_pointer (&ret_signature);
out:
if (commit_buffer)
gpgme_data_release (commit_buffer);
if (signature_buffer)
gpgme_data_release (signature_buffer);
if (key)
gpgme_key_release (key);
if (context)
gpgme_release (context);
return ret;
*out_signature = g_mapped_file_get_bytes (signature_file);
return TRUE;
}
/**
@@ -5097,8 +4898,7 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
gboolean
_ostree_repo_is_locked_tmpdir (const char *filename)
{
return g_str_has_prefix (filename, OSTREE_REPO_TMPDIR_STAGING) ||
g_str_has_prefix (filename, OSTREE_REPO_TMPDIR_FETCHER);
return g_str_has_prefix (filename, OSTREE_REPO_TMPDIR_STAGING);
}
gboolean
@@ -5141,8 +4941,7 @@ _ostree_repo_try_lock_tmpdir (int tmpdir_dfd,
gboolean
_ostree_repo_allocate_tmpdir (int tmpdir_dfd,
const char *tmpdir_prefix,
char **tmpdir_name_out,
int *tmpdir_fd_out,
GLnxTmpDir *tmpdir_out,
GLnxLockFile *file_lock_out,
gboolean *reusing_dir_out,
GCancellable *cancellable,
@@ -5157,9 +4956,8 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd,
gboolean reusing_dir = FALSE;
gboolean did_lock = FALSE;
g_autofree char *tmpdir_name = NULL;
glnx_fd_close int tmpdir_fd = -1;
while (tmpdir_name == NULL)
g_auto(GLnxTmpDir) ret_tmpdir = { 0, };
while (!ret_tmpdir.initialized)
{
struct dirent *dent;
glnx_fd_close int existing_tmpdir_fd = -1;
@@ -5179,8 +4977,9 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd,
dent->d_type != DT_DIR)
continue;
glnx_fd_close int target_dfd = -1;
if (!glnx_opendirat (dfd_iter.fd, dent->d_name, FALSE,
&existing_tmpdir_fd, &local_error))
&target_dfd, &local_error))
{
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY))
continue;
@@ -5203,45 +5002,40 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd,
/* Touch the reused directory so that we don't accidentally
* remove it due to being old when cleaning up the tmpdir.
*/
(void)futimens (existing_tmpdir_fd, NULL);
(void)futimens (target_dfd, NULL);
/* We found an existing tmpdir which we managed to lock */
tmpdir_name = g_strdup (dent->d_name);
tmpdir_fd = glnx_steal_fd (&existing_tmpdir_fd);
reusing_dir = TRUE;
ret_tmpdir.src_dfd = tmpdir_dfd;
ret_tmpdir.fd = glnx_steal_fd (&target_dfd);
ret_tmpdir.path = g_strdup (dent->d_name);
ret_tmpdir.initialized = TRUE;
}
while (tmpdir_name == NULL)
const char *tmpdir_name_template = glnx_strjoina (tmpdir_prefix, "XXXXXX");
while (!ret_tmpdir.initialized)
{
g_auto(GLnxTmpDir) new_tmpdir = { 0, };
/* No existing tmpdir found, create a new */
g_autofree char *tmpdir_name_template = g_strconcat (tmpdir_prefix, "XXXXXX", NULL);
if (!glnx_mkdtempat (tmpdir_dfd, tmpdir_name_template, 0777, error))
return FALSE;
glnx_fd_close int new_tmpdir_fd = -1;
if (!glnx_opendirat (tmpdir_dfd, tmpdir_name_template, FALSE,
&new_tmpdir_fd, error))
if (!glnx_mkdtempat (tmpdir_dfd, tmpdir_name_template, 0755,
&new_tmpdir, error))
return FALSE;
/* Note, at this point we can race with another process that picks up this
* new directory. If that happens we need to retry, making a new directory. */
if (!_ostree_repo_try_lock_tmpdir (tmpdir_dfd, tmpdir_name_template,
if (!_ostree_repo_try_lock_tmpdir (new_tmpdir.src_dfd, new_tmpdir.path,
file_lock_out, &did_lock,
error))
return FALSE;
if (!did_lock)
continue;
tmpdir_name = g_steal_pointer (&tmpdir_name_template);
tmpdir_fd = glnx_steal_fd (&new_tmpdir_fd);
ret_tmpdir = new_tmpdir; /* Transfer ownership */
new_tmpdir.initialized = FALSE;
}
if (tmpdir_name_out)
*tmpdir_name_out = g_steal_pointer (&tmpdir_name);
if (tmpdir_fd_out)
*tmpdir_fd_out = glnx_steal_fd (&tmpdir_fd);
if (reusing_dir_out)
*reusing_dir_out = reusing_dir;
*tmpdir_out = ret_tmpdir; /* Transfer ownership */
ret_tmpdir.initialized = FALSE;
*reusing_dir_out = reusing_dir;
return TRUE;
}
+26 -35
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
@@ -123,6 +122,12 @@ GFile * ostree_repo_get_path (OstreeRepo *self);
_OSTREE_PUBLIC
int ostree_repo_get_dfd (OstreeRepo *self);
_OSTREE_PUBLIC
guint ostree_repo_hash (OstreeRepo *self);
_OSTREE_PUBLIC
gboolean ostree_repo_equal (OstreeRepo *a,
OstreeRepo *b);
_OSTREE_PUBLIC
OstreeRepoMode ostree_repo_get_mode (OstreeRepo *self);
@@ -466,6 +471,17 @@ gboolean ostree_repo_resolve_rev_ext (OstreeRepo *self,
char **out_rev,
GError **error);
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
_OSTREE_PUBLIC
gboolean ostree_repo_resolve_collection_ref (OstreeRepo *self,
const OstreeCollectionRef *ref,
gboolean allow_noent,
OstreeRepoResolveRevExtFlags flags,
char **out_rev,
GCancellable *cancellable,
GError **error);
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
_OSTREE_PUBLIC
gboolean ostree_repo_list_refs (OstreeRepo *self,
const char *refspec_prefix,
@@ -1121,15 +1137,17 @@ gboolean ostree_repo_prune_from_reachable (OstreeRepo *self,
* @OSTREE_REPO_PULL_FLAGS_NONE: No special options for pull
* @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors and fetch all refs if none requested
* @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_UNTRUSTED: Do verify checksums of local (filesystem-accessible) repositories (defaults on for HTTP)
* @OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES: Since 2017.7. Reject writes of content objects with modes outside of 0775.
* @OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP: Don't verify checksums of objects HTTP repositories (Since: 2017.12)
*/
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_BAREUSERONLY_FILES = (1 << 3)
OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES = (1 << 3),
OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP = (1 << 4),
} OstreeRepoPullFlags;
_OSTREE_PUBLIC
@@ -1152,33 +1170,6 @@ ostree_repo_pull_one_dir (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
#if 0
FIXME
Called with: remote_name, refs, override-commit-ids
or: URL, refs, override-commit-ids
=> we only need refs; could use the remote_name or URL as additional results
Summary file is downloaded first, so this would result in multiple downloads of
the summary, but we don’t care because of caching.
Big problem preventing this from being the overall API: presenting the download
sizes in the gnome-software UI before the user chooses to download.
_OSTREE_PUBLIC
gboolean ostree_repo_find_remotes_squashed (OstreeRepo *self,
const gchar * const *refs, -> options
GVariant *options,
OstreeRepoFinder **finders, -> options
GMainContext *context, -> nope
OstreeAsyncProgress *progress,
GCancellable *cancellable,
GError **error);
#endif
_OSTREE_PUBLIC
gboolean ostree_repo_pull_with_options (OstreeRepo *self,
const char *remote_name_or_baseurl,
@@ -1217,10 +1208,10 @@ gboolean ostree_repo_pull_from_remotes_finish (OstreeRepo *self,
GError **error);
_OSTREE_PUBLIC
gchar *ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
const gchar *collection_id,
GCancellable *cancellable,
GError **error);
OstreeRemote *ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
const gchar *collection_id,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_list_collection_refs (OstreeRepo *self,
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2015 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2015 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
+1 -2
View File
@@ -1,5 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
/*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
Loaded 100 of 283 files, more files were not shown because too many files have changed in this diff. Show more