New upstream version 2017.12
This commit is contained in:
commit
d5964d6850
283 files changed
+4566
-2286
No files matched your search
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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,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) 2016 Endless Mobile, Inc.
|
||||
*
|
||||
* 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 © 2017 Endless Mobile, Inc.
|
||||
*
|
||||
* 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 © 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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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,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,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,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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,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,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,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,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,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) 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,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,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,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,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) 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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
+489
-185
File diff suppressed because it is too large.
Load diff
@@ -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,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,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,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
|
||||
|
||||
@@ -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,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,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,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,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,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,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,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,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, "/",
|
||||
|
||||
@@ -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,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
@@ -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,
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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,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) 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) 2017 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) 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
Reference in new issue
Block a user