Imported Upstream version 2016.6
This commit is contained in:
1 parent
a7b5654e44
commit
24762929e2
115 files changed
+4857
-2074
No files matched your search
@@ -323,11 +323,6 @@ global:
|
||||
ostree_deployment_unlocked_state_to_string;
|
||||
} LIBOSTREE_2016.3;
|
||||
|
||||
/* NOTE NOTE NOTE
|
||||
* Versions above here are released. Only add symbols below this line.
|
||||
* NOTE NOTE NOTE
|
||||
*/
|
||||
|
||||
LIBOSTREE_2016.5 {
|
||||
global:
|
||||
ostree_repo_import_object_from_with_trust;
|
||||
@@ -337,3 +332,24 @@ global:
|
||||
ostree_repo_get_remote_boolean_option;
|
||||
ostree_repo_set_cache_dir;
|
||||
} LIBOSTREE_2016.4;
|
||||
|
||||
LIBOSTREE_2016.6 {
|
||||
global:
|
||||
ostree_gpg_verify_result_require_valid_signature;
|
||||
ostree_raw_file_to_archive_z2_stream;
|
||||
ostree_repo_gpg_verify_data;
|
||||
ostree_repo_remote_fetch_summary_with_options;
|
||||
} LIBOSTREE_2016.5;
|
||||
|
||||
/* NOTE NOTE NOTE
|
||||
* Versions above here are released. Only add symbols below this line.
|
||||
* NOTE NOTE NOTE
|
||||
*/
|
||||
|
||||
/* Uncomment this when adding a new symbol */
|
||||
/*
|
||||
LIBOSTREE_2016.7 {
|
||||
global:
|
||||
ostree_some_new_symbol;
|
||||
} LIBOSTREE_2016.6;
|
||||
*/
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "ostree-async-progress.h"
|
||||
|
||||
/**
|
||||
* SECTION:libostree-async-progress
|
||||
* SECTION:ostree-async-progress
|
||||
* @title: Progress notification system for asynchronous operations
|
||||
* @short_description: Values representing progress
|
||||
*
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/* -*- 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
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: Krzesimir Nowak <krzesimir@kinvolk.io>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostree.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifndef OSTREE_WITH_AUTOCLEANUPS
|
||||
#define OSTREE_WITH_AUTOCLEANUPS 0
|
||||
#endif
|
||||
|
||||
/* ostree can use g_autoptr backports from libglnx when glib is too
|
||||
* old, but still avoid exposing them to users that also have an old
|
||||
* glib */
|
||||
#if defined(OSTREE_COMPILATION) || (OSTREE_WITH_AUTOCLEANUPS && GLIB_CHECK_VERSION(2, 44, 0))
|
||||
|
||||
/*
|
||||
* The following types have no specific clear/free/unref functions, so
|
||||
* they can be used as the stack-allocated variables or as the
|
||||
* g_autofree heap-allocated variables.
|
||||
*
|
||||
* OstreeRepoTransactionStats
|
||||
* OstreeRepoImportArchiveOptions
|
||||
* OstreeRepoExportArchiveOptions
|
||||
* OstreeRepoCheckoutOptions
|
||||
*/
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeDiffItem, ostree_diff_item_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoCommitModifier, ostree_repo_commit_modifier_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoDevInoCache, ostree_repo_devino_cache_unref)
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeAsyncProgress, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeBootconfigParser, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeDeployment, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeGpgVerifyResult, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMutableTree, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepo, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFile, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSePolicy, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSysroot, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSysrootUpgrader, g_object_unref)
|
||||
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (OstreeRepoCommitTraverseIter, ostree_repo_commit_traverse_iter_clear)
|
||||
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
@@ -138,7 +138,8 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader,
|
||||
bootversion);
|
||||
|
||||
/* This should follow the symbolic link to the current bootversion. */
|
||||
config_contents = gs_file_load_contents_utf8 (self->config_path, cancellable, error);
|
||||
config_contents = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL,
|
||||
cancellable, error);
|
||||
if (!config_contents)
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -113,7 +113,8 @@ _ostree_bootloader_uboot_write_config (OstreeBootloader *bootloader,
|
||||
g_autoptr(GPtrArray) new_lines = NULL;
|
||||
|
||||
/* This should follow the symbolic link to the current bootversion. */
|
||||
config_contents = gs_file_load_contents_utf8 (self->config_path, cancellable, error);
|
||||
config_contents = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL,
|
||||
cancellable, error);
|
||||
if (!config_contents)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ _ostree_make_temporary_symlink_at (int tmp_dirfd,
|
||||
|
||||
GFileInfo * _ostree_header_gfile_info_new (mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
/* XX + / + checksum-2 + . + extension, but let's just use 256 for a
|
||||
/* XX/checksum-2.extension, but let's just use 256 for a
|
||||
* bit of overkill.
|
||||
*/
|
||||
#define _OSTREE_LOOSE_PATH_MAX (256)
|
||||
@@ -112,8 +112,7 @@ _ostree_get_relative_static_delta_part_path (const char *from,
|
||||
const char *to,
|
||||
guint i);
|
||||
|
||||
static inline char *
|
||||
_ostree_get_commitpartial_path (const char *checksum)
|
||||
static inline char * _ostree_get_commitpartial_path (const char *checksum)
|
||||
{
|
||||
return g_strconcat ("state/", checksum, ".commitpartial", NULL);
|
||||
}
|
||||
|
||||
+106
-39
@@ -26,11 +26,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <gio/gfiledescriptorbased.h>
|
||||
#include "libglnx.h"
|
||||
#include "ostree.h"
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-chain-input-stream.h"
|
||||
#include "otutil.h"
|
||||
#include "libglnx.h"
|
||||
|
||||
#define ALIGN_VALUE(this, boundary) \
|
||||
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
|
||||
@@ -47,7 +47,7 @@ zlib_file_header_parse (GVariant *metadata,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* SECTION:libostree-core
|
||||
* SECTION:ostree-core
|
||||
* @title: Core repository-independent functions
|
||||
* @short_description: Create, validate, and convert core data types
|
||||
*
|
||||
@@ -400,6 +400,98 @@ write_file_header_update_checksum (GOutputStream *out,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* header_and_input_to_stream:
|
||||
* @file_header: A file header
|
||||
* @input: File raw content stream
|
||||
* @out_input: (out): Serialized object stream
|
||||
* @out_header_size: (out): Length of the header
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Combines @file_header and @input into a single stream.
|
||||
*/
|
||||
static gboolean
|
||||
header_and_input_to_stream (GVariant *file_header,
|
||||
GInputStream *input,
|
||||
GInputStream **out_input,
|
||||
guint64 *out_header_size,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gpointer header_data;
|
||||
gsize header_size;
|
||||
g_autoptr(GInputStream) ret_input = NULL;
|
||||
g_autoptr(GPtrArray) streams = NULL;
|
||||
g_autoptr(GOutputStream) header_out_stream = NULL;
|
||||
g_autoptr(GInputStream) header_in_stream = NULL;
|
||||
|
||||
header_out_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
|
||||
|
||||
if (!_ostree_write_variant_with_size (header_out_stream, file_header, 0, NULL, NULL,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!g_output_stream_close (header_out_stream, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
header_size = g_memory_output_stream_get_data_size ((GMemoryOutputStream*) header_out_stream);
|
||||
header_data = g_memory_output_stream_steal_data ((GMemoryOutputStream*) header_out_stream);
|
||||
header_in_stream = g_memory_input_stream_new_from_data (header_data, header_size, g_free);
|
||||
|
||||
streams = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
|
||||
|
||||
g_ptr_array_add (streams, g_object_ref (header_in_stream));
|
||||
if (input)
|
||||
g_ptr_array_add (streams, g_object_ref (input));
|
||||
|
||||
ret_input = (GInputStream*)ostree_chain_input_stream_new (streams);
|
||||
ot_transfer_out_value (out_input, &ret_input);
|
||||
if (out_header_size)
|
||||
*out_header_size = header_size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_raw_file_to_archive_z2_stream:
|
||||
* @input: File raw content stream
|
||||
* @file_info: A file info
|
||||
* @xattrs: (allow-none): Optional extended attributes
|
||||
* @out_input: (out): Serialized object stream
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Convert from a "bare" file representation into an
|
||||
* OSTREE_OBJECT_TYPE_FILE stream suitable for ostree pull.
|
||||
*/
|
||||
gboolean
|
||||
ostree_raw_file_to_archive_z2_stream (GInputStream *input,
|
||||
GFileInfo *file_info,
|
||||
GVariant *xattrs,
|
||||
GInputStream **out_input,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GVariant) file_header = NULL;
|
||||
g_autoptr(GInputStream) zlib_input = NULL;
|
||||
|
||||
file_header = _ostree_zlib_file_header_new (file_info, xattrs);
|
||||
if (input != NULL)
|
||||
{
|
||||
g_autoptr(GConverter) zlib_compressor = NULL;
|
||||
|
||||
zlib_compressor = G_CONVERTER (g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW, 9));
|
||||
zlib_input = g_converter_input_stream_new (input, zlib_compressor);
|
||||
}
|
||||
return header_and_input_to_stream (file_header,
|
||||
zlib_input,
|
||||
out_input,
|
||||
NULL,
|
||||
cancellable,
|
||||
error);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_raw_file_to_content_stream:
|
||||
* @input: File raw content stream
|
||||
@@ -423,44 +515,20 @@ ostree_raw_file_to_content_stream (GInputStream *input,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gpointer header_data;
|
||||
gsize header_size;
|
||||
g_autoptr(GInputStream) ret_input = NULL;
|
||||
g_autoptr(GVariant) file_header = NULL;
|
||||
g_autoptr(GPtrArray) streams = NULL;
|
||||
g_autoptr(GOutputStream) header_out_stream = NULL;
|
||||
g_autoptr(GInputStream) header_in_stream = NULL;
|
||||
guint64 header_size;
|
||||
|
||||
file_header = file_header_new (file_info, xattrs);
|
||||
|
||||
header_out_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
|
||||
|
||||
if (!_ostree_write_variant_with_size (header_out_stream, file_header, 0, NULL, NULL,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!g_output_stream_close (header_out_stream, cancellable, error))
|
||||
goto out;
|
||||
|
||||
header_size = g_memory_output_stream_get_data_size ((GMemoryOutputStream*) header_out_stream);
|
||||
header_data = g_memory_output_stream_steal_data ((GMemoryOutputStream*) header_out_stream);
|
||||
header_in_stream = g_memory_input_stream_new_from_data (header_data, header_size, g_free);
|
||||
|
||||
streams = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
|
||||
|
||||
g_ptr_array_add (streams, g_object_ref (header_in_stream));
|
||||
if (input)
|
||||
g_ptr_array_add (streams, g_object_ref (input));
|
||||
|
||||
ret_input = (GInputStream*)ostree_chain_input_stream_new (streams);
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value (out_input, &ret_input);
|
||||
if (!header_and_input_to_stream (file_header,
|
||||
input,
|
||||
out_input,
|
||||
&header_size,
|
||||
cancellable,
|
||||
error))
|
||||
return FALSE;
|
||||
if (out_length)
|
||||
*out_length = header_size + g_file_info_get_size (file_info);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -613,7 +681,7 @@ ostree_content_file_parse_at (gboolean compressed,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!gs_stream_fstat ((GFileDescriptorBased*)file_input, &stbuf, cancellable, error))
|
||||
if (!glnx_stream_fstat ((GFileDescriptorBased*)file_input, &stbuf, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_content_stream_parse (compressed, file_input, stbuf.st_size, trusted,
|
||||
@@ -921,14 +989,13 @@ _ostree_make_temporary_symlink_at (int tmp_dirfd,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *tmpname = NULL;
|
||||
char *tmpname = g_strdup ("tmplink.XXXXXX");
|
||||
guint i;
|
||||
const int max_attempts = 128;
|
||||
|
||||
for (i = 0; i < max_attempts; i++)
|
||||
{
|
||||
g_free (tmpname);
|
||||
tmpname = gs_fileutil_gen_tmp_name (NULL, NULL);
|
||||
glnx_gen_temp_name (tmpname);
|
||||
if (symlinkat (target, tmp_dirfd, tmpname) < 0)
|
||||
{
|
||||
if (errno == EEXIST)
|
||||
|
||||
+37
-29
@@ -59,7 +59,7 @@ G_BEGIN_DECLS
|
||||
* @OSTREE_OBJECT_TYPE_DIR_TREE: List of children (trees or files), and metadata
|
||||
* @OSTREE_OBJECT_TYPE_DIR_META: Directory metadata
|
||||
* @OSTREE_OBJECT_TYPE_COMMIT: Toplevel object, refers to tree and dirmeta for root
|
||||
* @OSTREE_OBJECT_TYPE_COMMIT_TOMBSTONE: Toplevel object, refers to a deleted commit
|
||||
* @OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT: Toplevel object, refers to a deleted commit
|
||||
*
|
||||
* Enumeration for core object types; %OSTREE_OBJECT_TYPE_FILE is for
|
||||
* content, the other types are metadata.
|
||||
@@ -90,10 +90,10 @@ typedef enum {
|
||||
/**
|
||||
* OSTREE_DIRMETA_GVARIANT_FORMAT:
|
||||
*
|
||||
* u - uid
|
||||
* u - gid
|
||||
* u - mode
|
||||
* a(ayay) - xattrs
|
||||
* - u - uid
|
||||
* - u - gid
|
||||
* - u - mode
|
||||
* - a(ayay) - xattrs
|
||||
*/
|
||||
#define OSTREE_DIRMETA_GVARIANT_STRING "(uuua(ayay))"
|
||||
#define OSTREE_DIRMETA_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_DIRMETA_GVARIANT_STRING)
|
||||
@@ -106,10 +106,10 @@ typedef enum {
|
||||
* can't store in the real filesystem but we can still use a regular .file object
|
||||
* that we can hardlink to in the case of a user-mode checkout.
|
||||
*
|
||||
* u - uid
|
||||
* u - gid
|
||||
* u - mode
|
||||
* a(ayay) - xattrs
|
||||
* - u - uid
|
||||
* - u - gid
|
||||
* - u - mode
|
||||
* - a(ayay) - xattrs
|
||||
*/
|
||||
#define OSTREE_FILEMETA_GVARIANT_STRING "(uuua(ayay))"
|
||||
#define OSTREE_FILEMETA_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_FILEMETA_GVARIANT_STRING)
|
||||
@@ -117,8 +117,8 @@ typedef enum {
|
||||
/**
|
||||
* OSTREE_TREE_GVARIANT_FORMAT:
|
||||
*
|
||||
* a(say) - array of (filename, checksum) for files
|
||||
* a(sayay) - array of (dirname, tree_checksum, meta_checksum) for directories
|
||||
* - a(say) - array of (filename, checksum) for files
|
||||
* - a(sayay) - array of (dirname, tree_checksum, meta_checksum) for directories
|
||||
*/
|
||||
#define OSTREE_TREE_GVARIANT_STRING "(a(say)a(sayay))"
|
||||
#define OSTREE_TREE_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_TREE_GVARIANT_STRING)
|
||||
@@ -126,14 +126,14 @@ typedef enum {
|
||||
/**
|
||||
* OSTREE_COMMIT_GVARIANT_FORMAT:
|
||||
*
|
||||
* a{sv} - Metadata
|
||||
* ay - parent checksum (empty string for initial)
|
||||
* a(say) - Related objects
|
||||
* s - subject
|
||||
* s - body
|
||||
* t - Timestamp in seconds since the epoch (UTC)
|
||||
* ay - Root tree contents
|
||||
* ay - Root tree metadata
|
||||
* - a{sv} - Metadata
|
||||
* - ay - parent checksum (empty string for initial)
|
||||
* - a(say) - Related objects
|
||||
* - s - subject
|
||||
* - s - body
|
||||
* - t - Timestamp in seconds since the epoch (UTC)
|
||||
* - ay - Root tree contents
|
||||
* - ay - Root tree metadata
|
||||
*/
|
||||
#define OSTREE_COMMIT_GVARIANT_STRING "(a{sv}aya(say)sstayay)"
|
||||
#define OSTREE_COMMIT_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_COMMIT_GVARIANT_STRING)
|
||||
@@ -141,8 +141,9 @@ typedef enum {
|
||||
/**
|
||||
* OSTREE_SUMMARY_GVARIANT_FORMAT:
|
||||
*
|
||||
* refs: a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name
|
||||
* extensions: a{sv} - Additional metadata, none defined at the current time
|
||||
* - a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name
|
||||
* - a{sv} - Additional metadata, at the current time the following are defined:
|
||||
* - key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum
|
||||
*/
|
||||
#define OSTREE_SUMMARY_GVARIANT_STRING "(a(s(taya{sv}))a{sv})"
|
||||
#define OSTREE_SUMMARY_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_SUMMARY_GVARIANT_STRING)
|
||||
@@ -152,9 +153,9 @@ typedef enum {
|
||||
|
||||
/**
|
||||
* OstreeRepoMode:
|
||||
* @OSTREE_REPO_MODE_BARE: Files are stored as themselves; can only be written as root
|
||||
* @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_BARE_USER: Files are stored as themselves, except ownership; can be written by user
|
||||
* @OSTREE_REPO_MODE_BARE_USER: Files are stored as themselves, except ownership; can be written by user. Hardlinks work only in user checkouts.
|
||||
*
|
||||
* See the documentation of #OstreeRepo for more information about the
|
||||
* possible modes.
|
||||
@@ -165,8 +166,8 @@ typedef enum {
|
||||
OSTREE_REPO_MODE_BARE_USER
|
||||
} OstreeRepoMode;
|
||||
|
||||
const _OSTREE_PUBLIC
|
||||
GVariantType *ostree_metadata_variant_type (OstreeObjectType objtype);
|
||||
_OSTREE_PUBLIC
|
||||
const GVariantType *ostree_metadata_variant_type (OstreeObjectType objtype);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_validate_checksum_string (const char *sha256,
|
||||
@@ -214,9 +215,6 @@ gboolean ostree_parse_refspec (const char *refspec,
|
||||
char **out_ref,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_checksum_update_meta (GChecksum *checksum, GFileInfo *file_info, GVariant *xattrs);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
const char * ostree_object_type_to_string (OstreeObjectType objtype);
|
||||
|
||||
@@ -244,7 +242,8 @@ void ostree_object_from_string (const char *str,
|
||||
gchar **out_checksum,
|
||||
OstreeObjectType *out_objtype);
|
||||
|
||||
_OSTREE_PUBLIC gboolean
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_content_stream_parse (gboolean compressed,
|
||||
GInputStream *input,
|
||||
guint64 input_length,
|
||||
@@ -276,6 +275,15 @@ gboolean ostree_content_file_parse_at (gboolean compressed,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_raw_file_to_archive_z2_stream (GInputStream *input,
|
||||
GFileInfo *file_info,
|
||||
GVariant *xattrs,
|
||||
GInputStream **out_input,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_raw_file_to_content_stream (GInputStream *input,
|
||||
GFileInfo *file_info,
|
||||
|
||||
@@ -24,19 +24,33 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
/**
|
||||
* OstreeDeployment:
|
||||
* @parent_instance:
|
||||
* @index: Global offset
|
||||
* @osname:
|
||||
* @csum: OSTree checksum of tree
|
||||
* @deployserial: How many times this particular csum appears in deployment list
|
||||
* @bootcsum: Checksum of kernel+initramfs
|
||||
* @bootserial: An integer assigned to this tree per its ${bootcsum}
|
||||
* @bootconfig: Bootloader configuration
|
||||
* @origin: How to construct an upgraded version of this tree
|
||||
* @unlocked: The unlocked state
|
||||
*/
|
||||
struct _OstreeDeployment
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
int index; /* Global offset */
|
||||
char *osname; /* osname */
|
||||
char *csum; /* OSTree checksum of tree */
|
||||
int deployserial; /* How many times this particular csum appears in deployment list */
|
||||
char *bootcsum; /* Checksum of kernel+initramfs */
|
||||
int bootserial; /* An integer assigned to this tree per its ${bootcsum} */
|
||||
OstreeBootconfigParser *bootconfig; /* Bootloader configuration */
|
||||
GKeyFile *origin; /* How to construct an upgraded version of this tree */
|
||||
OstreeDeploymentUnlockedState unlocked; /* The unlocked state */
|
||||
int index;
|
||||
char *osname;
|
||||
char *csum;
|
||||
int deployserial;
|
||||
char *bootcsum;
|
||||
int bootserial;
|
||||
OstreeBootconfigParser *bootconfig;
|
||||
GKeyFile *origin;
|
||||
OstreeDeploymentUnlockedState unlocked;
|
||||
};
|
||||
|
||||
void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libglnx.h"
|
||||
#include "ostree.h"
|
||||
#include "otutil.h"
|
||||
|
||||
@@ -209,6 +210,8 @@ diff_add_dir_recurse (GFile *d,
|
||||
* @modified: (element-type OstreeDiffItem): Modified files
|
||||
* @removed: (element-type Gio.File): Removed files
|
||||
* @added: (element-type Gio.File): Added files
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Compute the difference between directory @a and @b as 3 separate
|
||||
* sets of #OstreeDiffItem in @modified, @removed, and @added.
|
||||
|
||||
@@ -27,11 +27,17 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* OstreeDiffFlags:
|
||||
*/
|
||||
typedef enum {
|
||||
OSTREE_DIFF_FLAGS_NONE = 0,
|
||||
OSTREE_DIFF_FLAGS_IGNORE_XATTRS = (1 << 0)
|
||||
} OstreeDiffFlags;
|
||||
|
||||
/**
|
||||
* OstreeDiffItem:
|
||||
*/
|
||||
typedef struct _OstreeDiffItem OstreeDiffItem;
|
||||
struct _OstreeDiffItem
|
||||
{
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/* This file declares a stub function that is only exported
|
||||
* to pacify ABI checkers - no one could really have used it.
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "ostree-dummy-enumtypes.h"
|
||||
|
||||
/* Exported for backwards compat - see
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=764131
|
||||
*/
|
||||
GType
|
||||
ostree_fetcher_config_flags_get_type (void)
|
||||
{
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* This file declares a stub function that is only exported
|
||||
* to pacify ABI checkers - no one could really have used it.
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#ifndef __GI_SCANNER__
|
||||
_OSTREE_PUBLIC GType
|
||||
ostree_fetcher_config_flags_get_type (void);
|
||||
#endif
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType
|
||||
@enum_name@_get_type (void)
|
||||
_@enum_name@_get_type (void)
|
||||
{
|
||||
static volatile gsize the_type__volatile = 0;
|
||||
|
||||
|
||||
@@ -32,9 +32,8 @@ G_BEGIN_DECLS
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN enumeration-production ***/
|
||||
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
|
||||
_OSTREE_PUBLIC
|
||||
GType @enum_name@_get_type (void) G_GNUC_CONST;
|
||||
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (_@enum_name@_get_type ())
|
||||
GType _@enum_name@_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/*** END enumeration-production ***/
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <gio/gfiledescriptorbased.h>
|
||||
#include <gio/gunixoutputstream.h>
|
||||
|
||||
#include "libglnx.h"
|
||||
#include "ostree-fetcher.h"
|
||||
#ifdef HAVE_LIBSOUP_CLIENT_CERTS
|
||||
#include "ostree-tls-cert-interaction.h"
|
||||
@@ -66,7 +67,12 @@ typedef struct {
|
||||
guint64 total_downloaded;
|
||||
} ThreadClosure;
|
||||
|
||||
static void
|
||||
session_thread_process_pending_queue (ThreadClosure *thread_closure);
|
||||
|
||||
typedef struct {
|
||||
volatile int ref_count;
|
||||
|
||||
ThreadClosure *thread_closure;
|
||||
SoupURI *uri;
|
||||
|
||||
@@ -185,10 +191,22 @@ pending_task_compare (gconstpointer a,
|
||||
(priority_a < priority_b) ? -1 : 1;
|
||||
}
|
||||
|
||||
static void
|
||||
pending_uri_free (OstreeFetcherPendingURI *pending)
|
||||
static OstreeFetcherPendingURI *
|
||||
pending_uri_ref (OstreeFetcherPendingURI *pending)
|
||||
{
|
||||
g_hash_table_remove (pending->thread_closure->outstanding, pending);
|
||||
g_return_val_if_fail (pending != NULL, NULL);
|
||||
g_return_val_if_fail (pending->ref_count > 0, NULL);
|
||||
|
||||
g_atomic_int_inc (&pending->ref_count);
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
static void
|
||||
pending_uri_unref (OstreeFetcherPendingURI *pending)
|
||||
{
|
||||
if (!g_atomic_int_dec_and_test (&pending->ref_count))
|
||||
return;
|
||||
|
||||
g_clear_pointer (&pending->thread_closure, thread_closure_unref);
|
||||
|
||||
@@ -273,6 +291,7 @@ session_thread_set_proxy_cb (ThreadClosure *thread_closure,
|
||||
proxy_uri, NULL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSOUP_CLIENT_CERTS
|
||||
static void
|
||||
session_thread_set_tls_interaction_cb (ThreadClosure *thread_closure,
|
||||
gpointer data)
|
||||
@@ -288,6 +307,7 @@ session_thread_set_tls_interaction_cb (ThreadClosure *thread_closure,
|
||||
SOUP_SESSION_TLS_INTERACTION,
|
||||
interaction, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
session_thread_set_tls_database_cb (ThreadClosure *thread_closure,
|
||||
@@ -328,8 +348,7 @@ session_thread_process_pending_queue (ThreadClosure *thread_closure)
|
||||
pending = g_task_get_task_data (task);
|
||||
cancellable = g_task_get_cancellable (task);
|
||||
|
||||
/* pending_uri_free() removes this. */
|
||||
g_hash_table_add (thread_closure->outstanding, pending);
|
||||
g_hash_table_add (thread_closure->outstanding, pending_uri_ref (pending));
|
||||
|
||||
soup_request_send_async (pending->request,
|
||||
cancellable,
|
||||
@@ -383,7 +402,7 @@ session_thread_request_uri (ThreadClosure *thread_closure,
|
||||
if (thread_closure->tmpdir_name == NULL)
|
||||
{
|
||||
if (!_ostree_repo_allocate_tmpdir (thread_closure->base_tmpdir_dfd,
|
||||
"fetcher-",
|
||||
OSTREE_REPO_TMPDIR_FETCHER,
|
||||
&thread_closure->tmpdir_name,
|
||||
&thread_closure->tmpdir_dfd,
|
||||
&thread_closure->tmpdir_lock,
|
||||
@@ -537,7 +556,7 @@ _ostree_fetcher_constructed (GObject *object)
|
||||
self->thread_closure->tmpdir_dfd = -1;
|
||||
self->thread_closure->tmpdir_lock = empty_lockfile;
|
||||
|
||||
self->thread_closure->outstanding = g_hash_table_new (NULL, NULL);
|
||||
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,
|
||||
(GDestroyNotify) NULL,
|
||||
(GDestroyNotify) g_object_unref);
|
||||
@@ -739,6 +758,18 @@ on_stream_read (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data);
|
||||
|
||||
static void
|
||||
remove_pending_rerun_queue (OstreeFetcherPendingURI *pending)
|
||||
{
|
||||
/* Hold a temporary ref to ensure the reference to
|
||||
* pending->thread_closure is valid.
|
||||
*/
|
||||
pending_uri_ref (pending);
|
||||
g_hash_table_remove (pending->thread_closure->outstanding, pending);
|
||||
session_thread_process_pending_queue (pending->thread_closure);
|
||||
pending_uri_unref (pending);
|
||||
}
|
||||
|
||||
static void
|
||||
on_out_splice_complete (GObject *object,
|
||||
GAsyncResult *result,
|
||||
@@ -767,7 +798,10 @@ on_out_splice_complete (GObject *object,
|
||||
|
||||
out:
|
||||
if (local_error)
|
||||
g_task_return_error (task, local_error);
|
||||
{
|
||||
g_task_return_error (task, local_error);
|
||||
remove_pending_rerun_queue (pending);
|
||||
}
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
@@ -799,6 +833,7 @@ on_stream_read (GObject *object,
|
||||
g_task_return_pointer (task,
|
||||
g_strdup (pending->out_tmpfile),
|
||||
(GDestroyNotify) g_free);
|
||||
remove_pending_rerun_queue (pending);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -834,7 +869,10 @@ on_stream_read (GObject *object,
|
||||
|
||||
out:
|
||||
if (local_error)
|
||||
g_task_return_error (task, local_error);
|
||||
{
|
||||
g_task_return_error (task, local_error);
|
||||
remove_pending_rerun_queue (pending);
|
||||
}
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
@@ -880,6 +918,7 @@ on_request_sent (GObject *object,
|
||||
g_strdup (pending->out_tmpfile),
|
||||
(GDestroyNotify) g_free);
|
||||
}
|
||||
remove_pending_rerun_queue (pending);
|
||||
goto out;
|
||||
}
|
||||
else if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
|
||||
@@ -944,6 +983,7 @@ on_request_sent (GObject *object,
|
||||
g_task_return_pointer (task,
|
||||
g_object_ref (pending->request_body),
|
||||
(GDestroyNotify) g_object_unref);
|
||||
remove_pending_rerun_queue (pending);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -952,6 +992,7 @@ on_request_sent (GObject *object,
|
||||
if (pending->request_body)
|
||||
(void) g_input_stream_close (pending->request_body, NULL, NULL);
|
||||
g_task_return_error (task, local_error);
|
||||
remove_pending_rerun_queue (pending);
|
||||
}
|
||||
|
||||
g_object_unref (task);
|
||||
@@ -976,6 +1017,7 @@ ostree_fetcher_request_uri_internal (OstreeFetcher *self,
|
||||
|
||||
/* SoupRequest is created in session thread. */
|
||||
pending = g_new0 (OstreeFetcherPendingURI, 1);
|
||||
pending->ref_count = 1;
|
||||
pending->thread_closure = thread_closure_ref (self->thread_closure);
|
||||
pending->uri = soup_uri_copy (uri);
|
||||
pending->max_size = max_size;
|
||||
@@ -983,7 +1025,7 @@ ostree_fetcher_request_uri_internal (OstreeFetcher *self,
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, source_tag);
|
||||
g_task_set_task_data (task, pending, (GDestroyNotify) pending_uri_free);
|
||||
g_task_set_task_data (task, pending, (GDestroyNotify) pending_uri_unref);
|
||||
|
||||
/* We'll use the GTask priority for our own priority queue. */
|
||||
g_task_set_priority (task, priority);
|
||||
@@ -1067,7 +1109,7 @@ _ostree_fetcher_bytes_transferred (OstreeFetcher *self)
|
||||
|
||||
if (G_IS_FILE_DESCRIPTOR_BASED (stream))
|
||||
{
|
||||
if (gs_stream_fstat ((GFileDescriptorBased*)stream, &stbuf, NULL, NULL))
|
||||
if (glnx_stream_fstat ((GFileDescriptorBased*)stream, &stbuf, NULL))
|
||||
ret += stbuf.st_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct OstreeGpgVerifier OstreeGpgVerifier;
|
||||
|
||||
/* If this type becomes public in future, move this autoptr cleanup
|
||||
* definition to the ostree-autocleanups.h header file. Right now it
|
||||
* relies on glnx's fallback definition of the macro. */
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeGpgVerifier, g_object_unref)
|
||||
|
||||
GType _ostree_gpg_verifier_get_type (void);
|
||||
|
||||
OstreeGpgVerifier *_ostree_gpg_verifier_new (void);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "ostree-gpg-verify-result-private.h"
|
||||
|
||||
/**
|
||||
* SECTION: libostree-gpg-verify-result
|
||||
* SECTION: ostree-gpg-verify-result
|
||||
* @title: GPG signature verification results
|
||||
* @short_description: Inspect detached GPG signatures
|
||||
*
|
||||
@@ -622,3 +622,33 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_gpg_verify_result_require_valid_signature:
|
||||
* @result: (nullable): an #OstreeGpgVerifyResult
|
||||
* @error: A #GError
|
||||
*
|
||||
* Checks if the result contains at least one signature from the
|
||||
* trusted keyring. You can call this function immediately after
|
||||
* ostree_repo_verify_summary() or ostree_repo_verify_commit_ext() -
|
||||
* it will handle the %NULL @result and filled @error too.
|
||||
*
|
||||
* Returns: %TRUE if @result was not %NULL and had at least one
|
||||
* signature from trusted keyring, otherwise %FALSE
|
||||
*/
|
||||
gboolean
|
||||
ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result,
|
||||
GError **error)
|
||||
{
|
||||
if (result == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (ostree_gpg_verify_result_count_valid (result) == 0)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"GPG signatures found, but none are in trusted keyring");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -133,4 +133,8 @@ void ostree_gpg_verify_result_describe_variant (GVariant *variant,
|
||||
const gchar *line_prefix,
|
||||
OstreeGpgSignatureFormatFlags flags);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -107,7 +107,7 @@ _ostree_linuxfs_alter_immutable_flag (GFile *path,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int fd = -1;
|
||||
glnx_fd_close int fd = -1;
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
return FALSE;
|
||||
@@ -129,7 +129,5 @@ _ostree_linuxfs_alter_immutable_flag (GFile *path,
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (fd != -1)
|
||||
(void) close (fd);
|
||||
return ret;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ enum {
|
||||
|
||||
/**
|
||||
* SECTION:ostree-lzma-compressor
|
||||
* @short_description: LZMA compressor
|
||||
* @title: LZMA compressor
|
||||
*
|
||||
* An implementation of #GConverter that compresses data using
|
||||
* LZMA.
|
||||
|
||||
@@ -29,6 +29,14 @@ enum {
|
||||
PROP_0,
|
||||
};
|
||||
|
||||
/**
|
||||
* SECTION:ostree-lzma-decompressor
|
||||
* @title: LZMA decompressor
|
||||
*
|
||||
* An implementation of #GConverter that decompresses data using
|
||||
* LZMA.
|
||||
*/
|
||||
|
||||
static void _ostree_lzma_decompressor_iface_init (GConverterIface *iface);
|
||||
|
||||
struct _OstreeLzmaDecompressor
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "ostree-core.h"
|
||||
|
||||
/**
|
||||
* SECTION:libostree-mutable-tree
|
||||
* SECTION:ostree-mutable-tree
|
||||
* @title: In-memory modifiable filesystem tree
|
||||
* @short_description: Modifiable filesystem tree
|
||||
*
|
||||
@@ -159,6 +159,11 @@ ostree_mutable_tree_replace_file (OstreeMutableTree *self,
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
|
||||
if (!ot_util_filename_validate (name, error))
|
||||
goto out;
|
||||
|
||||
if (g_hash_table_lookup (self->subdirs, name))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
@@ -187,6 +192,9 @@ ostree_mutable_tree_ensure_dir (OstreeMutableTree *self,
|
||||
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
|
||||
if (!ot_util_filename_validate (name, error))
|
||||
goto out;
|
||||
|
||||
if (g_hash_table_lookup (self->files, name))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
|
||||
@@ -84,7 +84,8 @@ gboolean ostree_mutable_tree_lookup (OstreeMutableTree *self,
|
||||
OstreeMutableTree **out_subdir,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC gboolean
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_mutable_tree_ensure_parent_dirs (OstreeMutableTree *self,
|
||||
GPtrArray *split_path,
|
||||
const char *metadata_checksum,
|
||||
|
||||
@@ -632,7 +632,7 @@ checkout_tree_at (OstreeRepo *self,
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gboolean did_exist = FALSE;
|
||||
int destination_dfd = -1;
|
||||
glnx_fd_close int destination_dfd = -1;
|
||||
int res;
|
||||
g_autoptr(GVariant) xattrs = NULL;
|
||||
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
||||
@@ -752,12 +752,12 @@ checkout_tree_at (OstreeRepo *self,
|
||||
}
|
||||
}
|
||||
|
||||
/* Set directory mtime to 0, so that it is constant for all checkouts.
|
||||
/* Set directory mtime to OSTREE_TIMESTAMP, so that it is constant for all checkouts.
|
||||
* Must be done after setting permissions and creating all children.
|
||||
*/
|
||||
if (!did_exist)
|
||||
{
|
||||
const struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, } };
|
||||
const struct timespec times[2] = { { OSTREE_TIMESTAMP, UTIME_OMIT }, { OSTREE_TIMESTAMP, 0} };
|
||||
do
|
||||
res = futimens (destination_dfd, times);
|
||||
while (G_UNLIKELY (res == -1 && errno == EINTR));
|
||||
@@ -779,8 +779,6 @@ checkout_tree_at (OstreeRepo *self,
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (destination_dfd != -1)
|
||||
(void) close (destination_dfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -957,38 +955,36 @@ ostree_repo_checkout_gc (OstreeRepo *self,
|
||||
g_hash_table_iter_init (&iter, to_clean_dirs);
|
||||
while (to_clean_dirs && g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
g_autoptr(GFile) objdir = NULL;
|
||||
g_autoptr(GFileEnumerator) enumerator = NULL;
|
||||
g_autofree char *objdir_name = NULL;
|
||||
g_autofree char *objdir_name = g_strdup_printf ("%02x", GPOINTER_TO_UINT (key));
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
|
||||
objdir_name = g_strdup_printf ("%02x", GPOINTER_TO_UINT (key));
|
||||
objdir = g_file_get_child (self->uncompressed_objects_dir, objdir_name);
|
||||
|
||||
enumerator = g_file_enumerate_children (objdir, "standard::name,standard::type,unix::inode,unix::nlink",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable,
|
||||
error);
|
||||
if (!enumerator)
|
||||
if (!glnx_dirfd_iterator_init_at (self->uncompressed_objects_dir_fd, objdir_name, FALSE,
|
||||
&dfd_iter, error))
|
||||
goto out;
|
||||
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
GFileInfo *file_info;
|
||||
guint32 nlinks;
|
||||
struct dirent *dent;
|
||||
struct stat stbuf;
|
||||
|
||||
if (!gs_file_enumerator_iterate (enumerator, &file_info, NULL,
|
||||
cancellable, error))
|
||||
if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
|
||||
goto out;
|
||||
if (file_info == NULL)
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink");
|
||||
if (nlinks == 1)
|
||||
|
||||
if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
{
|
||||
g_autoptr(GFile) objpath = NULL;
|
||||
objpath = g_file_get_child (objdir, g_file_info_get_name (file_info));
|
||||
if (!gs_file_unlink (objpath, cancellable, error))
|
||||
goto out;
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (stbuf.st_nlink == 1)
|
||||
{
|
||||
if (unlinkat (dfd_iter.fd, dent->d_name, 0) != 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,22 +36,6 @@
|
||||
#include <sys/xattr.h>
|
||||
#include <glib/gprintf.h>
|
||||
|
||||
struct OstreeRepoCommitModifier {
|
||||
volatile gint refcount;
|
||||
|
||||
OstreeRepoCommitModifierFlags flags;
|
||||
OstreeRepoCommitFilter filter;
|
||||
gpointer user_data;
|
||||
GDestroyNotify destroy_notify;
|
||||
|
||||
OstreeRepoCommitModifierXattrCallback xattr_callback;
|
||||
GDestroyNotify xattr_destroy;
|
||||
gpointer xattr_user_data;
|
||||
|
||||
OstreeSePolicy *sepolicy;
|
||||
GHashTable *devino_cache;
|
||||
};
|
||||
|
||||
gboolean
|
||||
_ostree_repo_ensure_loose_objdir_at (int dfd,
|
||||
const char *loose_path,
|
||||
@@ -226,7 +210,6 @@ commit_loose_object_trusted (OstreeRepo *self,
|
||||
else
|
||||
{
|
||||
int res;
|
||||
struct timespec times[2];
|
||||
|
||||
if (objtype == OSTREE_OBJECT_TYPE_FILE && self->mode == OSTREE_REPO_MODE_BARE)
|
||||
{
|
||||
@@ -282,12 +265,9 @@ commit_loose_object_trusted (OstreeRepo *self,
|
||||
{
|
||||
/* To satisfy tools such as guile which compare mtimes
|
||||
* to determine whether or not source files need to be compiled,
|
||||
* set the modification time to 0.
|
||||
* set the modification time to OSTREE_TIMESTAMP.
|
||||
*/
|
||||
times[0].tv_sec = 0; /* atime */
|
||||
times[0].tv_nsec = UTIME_OMIT;
|
||||
times[1].tv_sec = 0; /* mtime */
|
||||
times[1].tv_nsec = 0;
|
||||
const struct timespec times[2] = { { OSTREE_TIMESTAMP, UTIME_OMIT }, { OSTREE_TIMESTAMP, 0} };
|
||||
do
|
||||
res = futimens (fd, times);
|
||||
while (G_UNLIKELY (res == -1 && errno == EINTR));
|
||||
@@ -573,11 +553,8 @@ _ostree_repo_open_trusted_content_bare (OstreeRepo *self,
|
||||
g_autofree char *temp_filename = NULL;
|
||||
g_autoptr(GOutputStream) ret_stream = NULL;
|
||||
gboolean have_obj;
|
||||
char loose_objpath[_OSTREE_LOOSE_PATH_MAX];
|
||||
|
||||
if (!_ostree_repo_has_loose_object (self, checksum, OSTREE_OBJECT_TYPE_FILE,
|
||||
&have_obj, loose_objpath,
|
||||
NULL,
|
||||
if (!_ostree_repo_has_loose_object (self, checksum, OSTREE_OBJECT_TYPE_FILE, &have_obj,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
@@ -662,7 +639,6 @@ write_object (OstreeRepo *self,
|
||||
gboolean temp_file_is_regular;
|
||||
gboolean temp_file_is_symlink;
|
||||
gboolean object_is_symlink = FALSE;
|
||||
char loose_objpath[_OSTREE_LOOSE_PATH_MAX];
|
||||
gssize unpacked_size = 0;
|
||||
gboolean indexable = FALSE;
|
||||
|
||||
@@ -673,9 +649,8 @@ write_object (OstreeRepo *self,
|
||||
|
||||
if (expected_checksum)
|
||||
{
|
||||
if (!_ostree_repo_has_loose_object (self, expected_checksum, objtype,
|
||||
&have_obj, loose_objpath,
|
||||
NULL, cancellable, error))
|
||||
if (!_ostree_repo_has_loose_object (self, expected_checksum, objtype, &have_obj,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
if (have_obj)
|
||||
{
|
||||
@@ -852,8 +827,7 @@ write_object (OstreeRepo *self,
|
||||
repo_store_size_entry (self, actual_checksum, unpacked_size, stbuf.st_size);
|
||||
}
|
||||
|
||||
if (!_ostree_repo_has_loose_object (self, actual_checksum, objtype,
|
||||
&have_obj, loose_objpath, NULL,
|
||||
if (!_ostree_repo_has_loose_object (self, actual_checksum, objtype, &have_obj,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
@@ -1167,7 +1141,6 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gboolean ret_transaction_resume = FALSE;
|
||||
g_autofree char *stagedir_boot_id_prefix = NULL;
|
||||
g_autofree char *stagedir_name = NULL;
|
||||
glnx_fd_close int stagedir_fd = -1;
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
@@ -1178,10 +1151,8 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
|
||||
|
||||
self->in_transaction = TRUE;
|
||||
|
||||
stagedir_boot_id_prefix = g_strconcat ("staging-", self->boot_id, "-", NULL);
|
||||
|
||||
if (!_ostree_repo_allocate_tmpdir (self->tmp_dir_fd,
|
||||
stagedir_boot_id_prefix,
|
||||
self->stagedir_prefix,
|
||||
&self->commit_stagedir_name,
|
||||
&self->commit_stagedir_fd,
|
||||
&self->commit_stagedir_lock,
|
||||
@@ -1287,44 +1258,87 @@ cleanup_tmpdir (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFileEnumerator) enumerator = NULL;
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
guint64 curtime_secs;
|
||||
|
||||
enumerator = g_file_enumerate_children (self->tmp_dir, "standard::name,time::modified",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable,
|
||||
error);
|
||||
if (!enumerator)
|
||||
goto out;
|
||||
|
||||
curtime_secs = g_get_real_time () / 1000000;
|
||||
|
||||
if (!glnx_dirfd_iterator_init_at (self->tmp_dir_fd, ".", TRUE, &dfd_iter, error))
|
||||
goto out;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
GFileInfo *file_info;
|
||||
GFile *path;
|
||||
guint64 mtime;
|
||||
guint64 delta;
|
||||
struct dirent *dent;
|
||||
struct stat stbuf;
|
||||
g_auto(GLnxLockFile) lockfile = GLNX_LOCK_FILE_INIT;
|
||||
gboolean did_lock;
|
||||
|
||||
if (!gs_file_enumerator_iterate (enumerator, &file_info, &path,
|
||||
cancellable, error))
|
||||
if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
|
||||
goto out;
|
||||
if (file_info == NULL)
|
||||
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
mtime = g_file_info_get_attribute_uint64 (file_info, "time::modified");
|
||||
if (mtime > curtime_secs)
|
||||
continue;
|
||||
/* Only delete files older than a day. To do better, we would
|
||||
* need to coordinate between multiple processes in a reliable
|
||||
* fashion. See
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=709115
|
||||
*/
|
||||
delta = curtime_secs - mtime;
|
||||
if (delta > 60*60*24)
|
||||
if (TEMP_FAILURE_RETRY (fstatat (dfd_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0)
|
||||
{
|
||||
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (path), cancellable, error))
|
||||
if (errno == ENOENT) /* Did another cleanup win? */
|
||||
continue;
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* First, if it's a directory which needs locking, but it's
|
||||
* busy, skip it.
|
||||
*/
|
||||
if (_ostree_repo_is_locked_tmpdir (dent->d_name))
|
||||
{
|
||||
if (!_ostree_repo_try_lock_tmpdir (dfd_iter.fd, dent->d_name,
|
||||
&lockfile, &did_lock, error))
|
||||
goto out;
|
||||
if (!did_lock)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If however this is the staging directory for the *current*
|
||||
* boot, then don't delete it now - we may end up reusing it, as
|
||||
* is the point.
|
||||
*/
|
||||
if (g_str_has_prefix (dent->d_name, self->stagedir_prefix))
|
||||
continue;
|
||||
else if (g_str_has_prefix (dent->d_name, OSTREE_REPO_TMPDIR_STAGING))
|
||||
{
|
||||
/* But, crucially we can now clean up staging directories
|
||||
* from *other* boots
|
||||
*/
|
||||
if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
/* FIXME - move OSTREE_REPO_TMPDIR_FETCHER underneath the
|
||||
* staging/boot-id scheme as well, since all of the "did it get
|
||||
* fsync'd" concerns apply to that as well. Then we can skip
|
||||
* this special case.
|
||||
*/
|
||||
else if (g_str_has_prefix (dent->d_name, OSTREE_REPO_TMPDIR_FETCHER))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
/* Now we do time-based cleanup. Ignore it if it's somehow
|
||||
* in the future...
|
||||
*/
|
||||
if (stbuf.st_mtime > curtime_secs)
|
||||
continue;
|
||||
|
||||
/* Now, we're pruning content based on the expiry, which
|
||||
* defaults to a day. That's what we were doing before we
|
||||
* had locking...but in future we can be smarter here.
|
||||
*/
|
||||
delta = curtime_secs - stbuf.st_mtime;
|
||||
if (delta > self->tmp_expiry_seconds)
|
||||
{
|
||||
if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1448,12 +1462,25 @@ ostree_repo_commit_transaction (OstreeRepo *self,
|
||||
|
||||
g_return_val_if_fail (self->in_transaction == TRUE, FALSE);
|
||||
|
||||
if (syncfs (self->tmp_dir_fd) < 0)
|
||||
if ((self->test_error_flags & OSTREE_REPO_TEST_ERROR_PRE_COMMIT) > 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"OSTREE_REPO_TEST_ERROR_PRE_COMMIT specified");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME: Added since valgrind in el7 doesn't know about
|
||||
* `syncfs`...we should delete this later.
|
||||
*/
|
||||
if (g_getenv ("OSTREE_SUPPRESS_SYNCFS") == NULL)
|
||||
{
|
||||
if (syncfs (self->tmp_dir_fd) < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rename_pending_loose_objects (self, cancellable, error))
|
||||
goto out;
|
||||
|
||||
@@ -1937,7 +1964,7 @@ create_empty_gvariant_dict (void)
|
||||
* ostree_repo_write_commit:
|
||||
* @self: Repo
|
||||
* @parent: (allow-none): ASCII SHA256 checksum for parent, or %NULL for none
|
||||
* @subject: Subject
|
||||
* @subject: (allow-none): Subject
|
||||
* @body: (allow-none): Body
|
||||
* @metadata: (allow-none): GVariant of type a{sv}, or %NULL for none
|
||||
* @root: The tree to point the commit to
|
||||
@@ -1981,10 +2008,11 @@ ostree_repo_write_commit (OstreeRepo *self,
|
||||
* ostree_repo_write_commit_with_time:
|
||||
* @self: Repo
|
||||
* @parent: (allow-none): ASCII SHA256 checksum for parent, or %NULL for none
|
||||
* @subject: Subject
|
||||
* @subject: (allow-none): Subject
|
||||
* @body: (allow-none): Body
|
||||
* @metadata: (allow-none): GVariant of type a{sv}, or %NULL for none
|
||||
* @root: The tree to point the commit to
|
||||
* @time: The time to use to stamp the commit
|
||||
* @out_commit: (out): Resulting ASCII SHA256 checksum for commit
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
@@ -2011,8 +2039,6 @@ ostree_repo_write_commit_with_time (OstreeRepo *self,
|
||||
g_autofree guchar *commit_csum = NULL;
|
||||
OstreeRepoFile *repo_root = OSTREE_REPO_FILE (root);
|
||||
|
||||
g_return_val_if_fail (subject != NULL, FALSE);
|
||||
|
||||
/* Add sizes information to our metadata object */
|
||||
if (!add_size_index_to_metadata (self, metadata, &new_metadata,
|
||||
cancellable, error))
|
||||
@@ -2022,7 +2048,7 @@ ostree_repo_write_commit_with_time (OstreeRepo *self,
|
||||
new_metadata ? new_metadata : create_empty_gvariant_dict (),
|
||||
parent ? ostree_checksum_to_bytes_v (parent) : ot_gvariant_new_bytearray (NULL, 0),
|
||||
g_variant_new_array (G_VARIANT_TYPE ("(say)"), NULL, 0),
|
||||
subject, body ? body : "",
|
||||
subject ? subject : "", body ? body : "",
|
||||
GUINT64_TO_BE (time),
|
||||
ostree_checksum_to_bytes_v (ostree_repo_file_tree_get_contents_checksum (repo_root)),
|
||||
ostree_checksum_to_bytes_v (ostree_repo_file_tree_get_metadata_checksum (repo_root)));
|
||||
@@ -2073,21 +2099,13 @@ ostree_repo_read_commit_detached_metadata (OstreeRepo *self,
|
||||
g_autoptr(GFile) metadata_path =
|
||||
_ostree_repo_get_commit_metadata_loose_path (self, checksum);
|
||||
g_autoptr(GVariant) ret_metadata = NULL;
|
||||
GError *temp_error = NULL;
|
||||
|
||||
if (!ot_util_variant_map (metadata_path, G_VARIANT_TYPE ("a{sv}"),
|
||||
TRUE, &ret_metadata, &temp_error))
|
||||
if (!ot_util_variant_map_at (AT_FDCWD, gs_file_get_path_cached (metadata_path),
|
||||
G_VARIANT_TYPE ("a{sv}"),
|
||||
OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error))
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
g_clear_error (&temp_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_prefix_error (error, "Unable to read existing detached metadata: ");
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
g_prefix_error (error, "Unable to read existing detached metadata: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
@@ -2184,6 +2202,10 @@ create_tree_variant_from_hashes (GHashTable *file_checksums,
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
{
|
||||
const char *name = key;
|
||||
|
||||
/* Should have been validated earlier, but be paranoid */
|
||||
g_assert (ot_util_filename_validate (name, NULL));
|
||||
|
||||
sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name);
|
||||
}
|
||||
|
||||
@@ -2355,7 +2377,7 @@ get_modified_xattrs (OstreeRepo *self,
|
||||
|
||||
if (label)
|
||||
{
|
||||
GVariantBuilder *builder;
|
||||
g_autoptr(GVariantBuilder) builder = NULL;
|
||||
|
||||
/* ret_xattrs may be NULL */
|
||||
builder = ot_util_variant_builder_from_variant (ret_xattrs,
|
||||
|
||||
@@ -58,9 +58,6 @@ OstreeRepo * ostree_repo_file_get_repo (OstreeRepoFile *self);
|
||||
_OSTREE_PUBLIC
|
||||
OstreeRepoFile * ostree_repo_file_get_root (OstreeRepoFile *self);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_repo_file_make_empty_tree (OstreeRepoFile *self);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_repo_file_tree_set_metadata (OstreeRepoFile *self,
|
||||
const char *checksum,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -23,10 +23,6 @@
|
||||
#include "ostree-repo.h"
|
||||
#include "libglnx.h"
|
||||
|
||||
#ifdef HAVE_LIBSOUP
|
||||
#include "ostree-fetcher.h"
|
||||
#endif
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define OSTREE_DELTAPART_VERSION (0)
|
||||
@@ -36,6 +32,28 @@ G_BEGIN_DECLS
|
||||
#define _OSTREE_SUMMARY_CACHE_DIR "summaries"
|
||||
#define _OSTREE_CACHE_DIR "cache"
|
||||
|
||||
#define OSTREE_TIMESTAMP (1)
|
||||
|
||||
typedef enum {
|
||||
OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0)
|
||||
} OstreeRepoTestErrorFlags;
|
||||
|
||||
struct OstreeRepoCommitModifier {
|
||||
volatile gint refcount;
|
||||
|
||||
OstreeRepoCommitModifierFlags flags;
|
||||
OstreeRepoCommitFilter filter;
|
||||
gpointer user_data;
|
||||
GDestroyNotify destroy_notify;
|
||||
|
||||
OstreeRepoCommitModifierXattrCallback xattr_callback;
|
||||
GDestroyNotify xattr_destroy;
|
||||
gpointer xattr_user_data;
|
||||
|
||||
OstreeSePolicy *sepolicy;
|
||||
GHashTable *devino_cache;
|
||||
};
|
||||
|
||||
/**
|
||||
* OstreeRepo:
|
||||
*
|
||||
@@ -44,7 +62,7 @@ G_BEGIN_DECLS
|
||||
struct OstreeRepo {
|
||||
GObject parent;
|
||||
|
||||
char *boot_id;
|
||||
char *stagedir_prefix;
|
||||
int commit_stagedir_fd;
|
||||
char *commit_stagedir_name;
|
||||
GLnxLockFile commit_stagedir_lock;
|
||||
@@ -86,12 +104,15 @@ struct OstreeRepo {
|
||||
uid_t target_owner_uid;
|
||||
gid_t target_owner_gid;
|
||||
|
||||
guint test_error_flags; /* OstreeRepoTestErrorFlags */
|
||||
|
||||
GKeyFile *config;
|
||||
GHashTable *remotes;
|
||||
GMutex remotes_lock;
|
||||
OstreeRepoMode mode;
|
||||
gboolean enable_uncompressed_cache;
|
||||
gboolean generate_sizes;
|
||||
guint64 tmp_expiry_seconds;
|
||||
|
||||
OstreeRepo *parent_repo;
|
||||
};
|
||||
@@ -102,6 +123,9 @@ typedef struct {
|
||||
char checksum[65];
|
||||
} OstreeDevIno;
|
||||
|
||||
#define OSTREE_REPO_TMPDIR_STAGING "staging-"
|
||||
#define OSTREE_REPO_TMPDIR_FETCHER "fetcher-"
|
||||
|
||||
gboolean
|
||||
_ostree_repo_allocate_tmpdir (int tmpdir_dfd,
|
||||
const char *tmpdir_prefix,
|
||||
@@ -112,6 +136,16 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_repo_is_locked_tmpdir (const char *filename);
|
||||
|
||||
gboolean
|
||||
_ostree_repo_try_lock_tmpdir (int tmpdir_dfd,
|
||||
const char *tmpdir_name,
|
||||
GLnxLockFile *file_lock_out,
|
||||
gboolean *out_did_lock,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_repo_ensure_loose_objdir_at (int dfd,
|
||||
const char *loose_path,
|
||||
@@ -135,8 +169,6 @@ _ostree_repo_has_loose_object (OstreeRepo *self,
|
||||
const char *checksum,
|
||||
OstreeObjectType objtype,
|
||||
gboolean *out_is_stored,
|
||||
char *loose_path_buf,
|
||||
GFile **out_stored_path,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
@@ -199,13 +231,6 @@ _ostree_repo_commit_modifier_apply (OstreeRepo *self,
|
||||
gboolean
|
||||
_ostree_repo_remote_name_is_file (const char *remote_name);
|
||||
|
||||
#ifdef HAVE_LIBSOUP
|
||||
OstreeFetcher *
|
||||
_ostree_repo_remote_new_fetcher (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
GError **error);
|
||||
#endif
|
||||
|
||||
OstreeGpgVerifyResult *
|
||||
_ostree_repo_gpg_verify_with_metadata (OstreeRepo *self,
|
||||
GBytes *signed_data,
|
||||
@@ -293,22 +318,4 @@ gboolean
|
||||
_ostree_repo_update_mtime (OstreeRepo *self,
|
||||
GError **error);
|
||||
|
||||
/* Load the summary from the cache if the provided .sig file is the same as the
|
||||
cached version. */
|
||||
gboolean
|
||||
_ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
|
||||
const char *remote,
|
||||
GBytes *summary_sig,
|
||||
GBytes **summary,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_repo_cache_summary (OstreeRepo *self,
|
||||
const char *remote,
|
||||
GBytes *summary,
|
||||
GBytes *summary_sig,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -23,11 +23,15 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "ostree.h"
|
||||
#include "otutil.h"
|
||||
|
||||
#ifdef HAVE_LIBSOUP
|
||||
|
||||
#include "libglnx.h"
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-repo-private.h"
|
||||
#include "ostree-repo-static-delta-private.h"
|
||||
#include "ostree-metalink.h"
|
||||
#include "otutil.h"
|
||||
#include "ot-fs-utils.h"
|
||||
|
||||
#include <gio/gunixinputstream.h>
|
||||
@@ -629,6 +633,7 @@ content_fetch_on_write_complete (GObject *object,
|
||||
const char *expected_checksum;
|
||||
g_autofree guchar *csum = NULL;
|
||||
g_autofree char *checksum = NULL;
|
||||
g_autofree char *checksum_obj = NULL;
|
||||
|
||||
if (!ostree_repo_write_content_finish ((OstreeRepo*)object, result,
|
||||
&csum, error))
|
||||
@@ -639,7 +644,8 @@ content_fetch_on_write_complete (GObject *object,
|
||||
ostree_object_name_deserialize (fetch_data->object, &expected_checksum, &objtype);
|
||||
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
|
||||
|
||||
g_debug ("write of %s complete", ostree_object_to_string (checksum, objtype));
|
||||
checksum_obj = ostree_object_to_string (checksum, objtype);
|
||||
g_debug ("write of %s complete", checksum_obj);
|
||||
|
||||
if (strcmp (checksum, expected_checksum) != 0)
|
||||
{
|
||||
@@ -675,6 +681,7 @@ content_fetch_on_complete (GObject *object,
|
||||
g_autoptr(GInputStream) object_input = NULL;
|
||||
g_autofree char *temp_path = NULL;
|
||||
const char *checksum;
|
||||
g_autofree char *checksum_obj = NULL;
|
||||
OstreeObjectType objtype;
|
||||
|
||||
temp_path = _ostree_fetcher_request_uri_with_partial_finish (fetcher, result, error);
|
||||
@@ -684,7 +691,8 @@ content_fetch_on_complete (GObject *object,
|
||||
ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype);
|
||||
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
|
||||
|
||||
g_debug ("fetch of %s complete", ostree_object_to_string (checksum, objtype));
|
||||
checksum_obj = ostree_object_to_string (checksum, objtype);
|
||||
g_debug ("fetch of %s complete", checksum_obj);
|
||||
|
||||
if (pull_data->is_mirror && pull_data->repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
|
||||
{
|
||||
@@ -796,13 +804,16 @@ meta_fetch_on_complete (GObject *object,
|
||||
g_autoptr(GVariant) metadata = NULL;
|
||||
g_autofree char *temp_path = NULL;
|
||||
const char *checksum;
|
||||
g_autofree char *checksum_obj = NULL;
|
||||
OstreeObjectType objtype;
|
||||
GError *local_error = NULL;
|
||||
GError **error = &local_error;
|
||||
glnx_fd_close int fd = -1;
|
||||
gboolean free_fetch_data = FALSE;
|
||||
|
||||
ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype);
|
||||
g_debug ("fetch of %s%s complete", ostree_object_to_string (checksum, objtype),
|
||||
checksum_obj = ostree_object_to_string (checksum, objtype);
|
||||
g_debug ("fetch of %s%s complete", checksum_obj,
|
||||
fetch_data->is_detached_meta ? " (detached)" : "");
|
||||
|
||||
temp_path = _ostree_fetcher_request_uri_with_partial_finish (fetcher, result, error);
|
||||
@@ -864,6 +875,8 @@ meta_fetch_on_complete (GObject *object,
|
||||
|
||||
if (!fetch_data->object_is_stored)
|
||||
enqueue_one_object_request (pull_data, checksum, objtype, FALSE, FALSE);
|
||||
|
||||
free_fetch_data = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -901,7 +914,7 @@ meta_fetch_on_complete (GObject *object,
|
||||
pull_data->n_outstanding_metadata_fetches--;
|
||||
pull_data->n_fetched_metadata++;
|
||||
check_outstanding_requests_handle_error (pull_data, local_error);
|
||||
if (local_error)
|
||||
if (local_error || free_fetch_data)
|
||||
{
|
||||
g_variant_unref (fetch_data->object);
|
||||
g_free (fetch_data);
|
||||
@@ -1445,6 +1458,7 @@ request_static_delta_superblock_sync (OtPullData *pull_data,
|
||||
if (out_delta_superblock)
|
||||
*out_delta_superblock = g_steal_pointer (&ret_delta_superblock);
|
||||
out:
|
||||
g_clear_pointer (&target_uri, (GDestroyNotify) soup_uri_free);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1734,47 +1748,9 @@ validate_variant_is_csum (GVariant *csum,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* documented in ostree-repo.c */
|
||||
gboolean
|
||||
ostree_repo_pull (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
char **refs_to_fetch,
|
||||
OstreeRepoPullFlags flags,
|
||||
OstreeAsyncProgress *progress,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
return ostree_repo_pull_one_dir (self, remote_name, NULL, refs_to_fetch, flags, progress, cancellable, error);
|
||||
}
|
||||
|
||||
/* Documented in ostree-repo.c */
|
||||
gboolean
|
||||
ostree_repo_pull_one_dir (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
const char *dir_to_pull,
|
||||
char **refs_to_fetch,
|
||||
OstreeRepoPullFlags flags,
|
||||
OstreeAsyncProgress *progress,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
|
||||
if (dir_to_pull)
|
||||
g_variant_builder_add (&builder, "{s@v}", "subdir",
|
||||
g_variant_new_variant (g_variant_new_string (dir_to_pull)));
|
||||
g_variant_builder_add (&builder, "{s@v}", "flags",
|
||||
g_variant_new_variant (g_variant_new_int32 (flags)));
|
||||
if (refs_to_fetch)
|
||||
g_variant_builder_add (&builder, "{s@v}", "refs",
|
||||
g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch, -1)));
|
||||
|
||||
return ostree_repo_pull_with_options (self, remote_name, g_variant_builder_end (&builder),
|
||||
progress, cancellable, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
/* Load the summary from the cache if the provided .sig file is the same as the
|
||||
cached version. */
|
||||
static gboolean
|
||||
_ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
|
||||
const char *remote,
|
||||
GBytes *summary_sig,
|
||||
@@ -1836,7 +1812,7 @@ _ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
static gboolean
|
||||
_ostree_repo_cache_summary (OstreeRepo *self,
|
||||
const char *remote,
|
||||
GBytes *summary,
|
||||
@@ -1876,7 +1852,311 @@ _ostree_repo_cache_summary (OstreeRepo *self,
|
||||
|
||||
}
|
||||
|
||||
/* Documented in ostree-repo.c */
|
||||
static OstreeFetcher *
|
||||
_ostree_repo_remote_new_fetcher (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
GError **error)
|
||||
{
|
||||
OstreeFetcher *fetcher = NULL;
|
||||
OstreeFetcherConfigFlags fetcher_flags = 0;
|
||||
gboolean tls_permissive = FALSE;
|
||||
gboolean success = FALSE;
|
||||
|
||||
g_return_val_if_fail (OSTREE_IS_REPO (self), NULL);
|
||||
g_return_val_if_fail (remote_name != NULL, NULL);
|
||||
|
||||
if (!ostree_repo_get_remote_boolean_option (self, remote_name,
|
||||
"tls-permissive", FALSE,
|
||||
&tls_permissive, error))
|
||||
goto out;
|
||||
|
||||
if (tls_permissive)
|
||||
fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE;
|
||||
|
||||
fetcher = _ostree_fetcher_new (self->tmp_dir_fd, fetcher_flags);
|
||||
|
||||
{
|
||||
g_autofree char *tls_client_cert_path = NULL;
|
||||
g_autofree char *tls_client_key_path = NULL;
|
||||
|
||||
if (!ostree_repo_get_remote_option (self, remote_name,
|
||||
"tls-client-cert-path", NULL,
|
||||
&tls_client_cert_path, error))
|
||||
goto out;
|
||||
if (!ostree_repo_get_remote_option (self, remote_name,
|
||||
"tls-client-key-path", NULL,
|
||||
&tls_client_key_path, error))
|
||||
goto out;
|
||||
|
||||
if ((tls_client_cert_path != NULL) != (tls_client_key_path != NULL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Remote \"%s\" must specify both "
|
||||
"\"tls-client-cert-path\" and \"tls-client-key-path\"",
|
||||
remote_name);
|
||||
goto out;
|
||||
}
|
||||
else if (tls_client_cert_path != NULL)
|
||||
{
|
||||
g_autoptr(GTlsCertificate) client_cert = NULL;
|
||||
|
||||
g_assert (tls_client_key_path != NULL);
|
||||
|
||||
client_cert = g_tls_certificate_new_from_files (tls_client_cert_path,
|
||||
tls_client_key_path,
|
||||
error);
|
||||
if (client_cert == NULL)
|
||||
goto out;
|
||||
|
||||
_ostree_fetcher_set_client_cert (fetcher, client_cert);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
g_autofree char *tls_ca_path = NULL;
|
||||
|
||||
if (!ostree_repo_get_remote_option (self, remote_name,
|
||||
"tls-ca-path", NULL,
|
||||
&tls_ca_path, error))
|
||||
goto out;
|
||||
|
||||
if (tls_ca_path != NULL)
|
||||
{
|
||||
g_autoptr(GTlsDatabase) db = NULL;
|
||||
|
||||
db = g_tls_file_database_new (tls_ca_path, error);
|
||||
if (db == NULL)
|
||||
goto out;
|
||||
|
||||
_ostree_fetcher_set_tls_database (fetcher, db);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
g_autofree char *http_proxy = NULL;
|
||||
|
||||
if (!ostree_repo_get_remote_option (self, remote_name,
|
||||
"proxy", NULL,
|
||||
&http_proxy, error))
|
||||
goto out;
|
||||
|
||||
if (http_proxy != NULL)
|
||||
_ostree_fetcher_set_proxy (fetcher, http_proxy);
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
|
||||
out:
|
||||
if (!success)
|
||||
g_clear_object (&fetcher);
|
||||
|
||||
return fetcher;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_ostree_preload_metadata_file (OstreeRepo *self,
|
||||
OstreeFetcher *fetcher,
|
||||
SoupURI *base_uri,
|
||||
const char *filename,
|
||||
gboolean is_metalink,
|
||||
GBytes **out_bytes,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (is_metalink)
|
||||
{
|
||||
glnx_unref_object OstreeMetalink *metalink = NULL;
|
||||
GError *local_error = NULL;
|
||||
|
||||
metalink = _ostree_metalink_new (fetcher, filename,
|
||||
OSTREE_MAX_METADATA_SIZE,
|
||||
base_uri);
|
||||
|
||||
_ostree_metalink_request_sync (metalink, NULL, out_bytes, NULL,
|
||||
cancellable, &local_error);
|
||||
|
||||
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
g_clear_error (&local_error);
|
||||
*out_bytes = NULL;
|
||||
}
|
||||
else if (local_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, local_error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SoupURI *uri;
|
||||
const char *base_path;
|
||||
g_autofree char *path = NULL;
|
||||
|
||||
base_path = soup_uri_get_path (base_uri);
|
||||
path = g_build_filename (base_path, filename, NULL);
|
||||
uri = soup_uri_new_with_base (base_uri, path);
|
||||
|
||||
ret = _ostree_fetcher_request_uri_to_membuf (fetcher, uri,
|
||||
FALSE, TRUE,
|
||||
out_bytes,
|
||||
OSTREE_MAX_METADATA_SIZE,
|
||||
cancellable, error);
|
||||
soup_uri_free (uri);
|
||||
|
||||
if (!ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
repo_remote_fetch_summary (OstreeRepo *self,
|
||||
const char *name,
|
||||
const char *metalink_url_string,
|
||||
GVariant *options,
|
||||
GBytes **out_summary,
|
||||
GBytes **out_signatures,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeFetcher *fetcher = NULL;
|
||||
g_autoptr(GMainContext) mainctx = NULL;
|
||||
gboolean ret = FALSE;
|
||||
SoupURI *base_uri = NULL;
|
||||
gboolean from_cache = FALSE;
|
||||
g_autofree char *url_override = NULL;
|
||||
|
||||
if (options)
|
||||
(void) g_variant_lookup (options, "override-url", "&s", &url_override);
|
||||
|
||||
mainctx = g_main_context_new ();
|
||||
g_main_context_push_thread_default (mainctx);
|
||||
|
||||
fetcher = _ostree_repo_remote_new_fetcher (self, name, error);
|
||||
if (fetcher == NULL)
|
||||
goto out;
|
||||
|
||||
{
|
||||
g_autofree char *url_string = NULL;
|
||||
if (metalink_url_string)
|
||||
url_string = g_strdup (metalink_url_string);
|
||||
else if (url_override)
|
||||
url_string = g_strdup (url_override);
|
||||
else if (!ostree_repo_remote_get_url (self, name, &url_string, error))
|
||||
goto out;
|
||||
|
||||
base_uri = soup_uri_new (url_string);
|
||||
if (base_uri == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid URL '%s'", url_string);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_ostree_preload_metadata_file (self,
|
||||
fetcher,
|
||||
base_uri,
|
||||
"summary.sig",
|
||||
metalink_url_string ? TRUE : FALSE,
|
||||
out_signatures,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (*out_signatures)
|
||||
{
|
||||
if (!_ostree_repo_load_cache_summary_if_same_sig (self,
|
||||
name,
|
||||
*out_signatures,
|
||||
out_summary,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*out_summary)
|
||||
from_cache = TRUE;
|
||||
else
|
||||
{
|
||||
if (!_ostree_preload_metadata_file (self,
|
||||
fetcher,
|
||||
base_uri,
|
||||
"summary",
|
||||
metalink_url_string ? TRUE : FALSE,
|
||||
out_summary,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!from_cache && *out_summary && *out_signatures)
|
||||
{
|
||||
g_autoptr(GError) temp_error = NULL;
|
||||
|
||||
if (!_ostree_repo_cache_summary (self,
|
||||
name,
|
||||
*out_summary,
|
||||
*out_signatures,
|
||||
cancellable,
|
||||
&temp_error))
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
|
||||
g_debug ("No permissions to save summary cache");
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, g_steal_pointer (&temp_error));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (mainctx)
|
||||
g_main_context_pop_thread_default (mainctx);
|
||||
if (base_uri != NULL)
|
||||
soup_uri_free (base_uri);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------
|
||||
* Below is the libsoup-invariant API; these should match
|
||||
* the stub functions in the #else clause
|
||||
* ------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* ostree_repo_pull_with_options:
|
||||
* @self: Repo
|
||||
* @remote_name: Name of remote
|
||||
* @options: A GVariant a{sv} with an extensible set of flags.
|
||||
* @progress: (allow-none): Progress
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Like ostree_repo_pull(), but supports an extensible set of flags.
|
||||
* The following are currently defined:
|
||||
*
|
||||
* * refs (as): Array of string refs
|
||||
* * flags (i): An instance of #OstreeRepoPullFlags
|
||||
* * subdir (s): Pull just this subdirectory
|
||||
* * override-remote-name (s): If local, add this remote to refspec
|
||||
* * gpg-verify (b): GPG verify commits
|
||||
* * gpg-verify-summary (b): GPG verify summary
|
||||
* * depth (i): How far in the history to traverse; default is 0, -1 means infinite
|
||||
* * disable-static-deltas (b): Do not use static deltas
|
||||
* * require-static-deltas (b): Require static deltas
|
||||
* * override-commit-ids (as): Array of specific commit IDs to fetch for refs
|
||||
* * dry-run (b): Only print information on what will be downloaded (requires static deltas)
|
||||
* * override-url (s): Fetch objects from this URL if remote specifies no metalink in options
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
const char *remote_name_or_baseurl,
|
||||
@@ -1889,8 +2169,6 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
GHashTableIter hash_iter;
|
||||
gpointer key, value;
|
||||
g_autoptr(GBytes) bytes_summary = NULL;
|
||||
g_autofree char *remote_key = NULL;
|
||||
g_autofree char *path = NULL;
|
||||
g_autofree char *metalink_url_str = NULL;
|
||||
g_autoptr(GHashTable) requested_refs_to_fetch = NULL;
|
||||
g_autoptr(GHashTable) commits_to_fetch = NULL;
|
||||
@@ -1904,13 +2182,14 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
guint64 end_time;
|
||||
OstreeRepoPullFlags flags = 0;
|
||||
const char *dir_to_pull = NULL;
|
||||
char **refs_to_fetch = NULL;
|
||||
g_autofree char **refs_to_fetch = NULL;
|
||||
char **override_commit_ids = NULL;
|
||||
GSource *update_timeout = NULL;
|
||||
gboolean disable_static_deltas = FALSE;
|
||||
gboolean require_static_deltas = FALSE;
|
||||
gboolean opt_gpg_verify = FALSE;
|
||||
gboolean opt_gpg_verify_summary = FALSE;
|
||||
const char *url_override = NULL;
|
||||
|
||||
if (options)
|
||||
{
|
||||
@@ -1928,6 +2207,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
(void) g_variant_lookup (options, "require-static-deltas", "b", &require_static_deltas);
|
||||
(void) g_variant_lookup (options, "override-commit-ids", "^a&s", &override_commit_ids);
|
||||
(void) g_variant_lookup (options, "dry-run", "b", &pull_data->dry_run);
|
||||
(void) g_variant_lookup (options, "override-url", "&s", &url_override);
|
||||
}
|
||||
|
||||
g_return_val_if_fail (pull_data->maxdepth >= -1, FALSE);
|
||||
@@ -2023,7 +2303,9 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
{
|
||||
g_autofree char *baseurl = NULL;
|
||||
|
||||
if (!ostree_repo_remote_get_url (self, remote_name_or_baseurl, &baseurl, error))
|
||||
if (url_override != NULL)
|
||||
baseurl = g_strdup (url_override);
|
||||
else if (!ostree_repo_remote_get_url (self, remote_name_or_baseurl, &baseurl, error))
|
||||
goto out;
|
||||
|
||||
pull_data->base_uri = soup_uri_new (baseurl);
|
||||
@@ -2587,3 +2869,121 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
g_clear_pointer (&remote_config, (GDestroyNotify) g_key_file_unref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_remote_fetch_summary_with_options:
|
||||
* @self: Self
|
||||
* @name: name of a remote
|
||||
* @options: (nullable): A GVariant a{sv} with an extensible set of flags
|
||||
* @out_summary: (nullable): return location for raw summary data, or %NULL
|
||||
* @out_signatures: (nullable): return location for raw summary signature
|
||||
* data, or %NULL
|
||||
* @cancellable: a #GCancellable
|
||||
* @error: a #GError
|
||||
*
|
||||
* Like ostree_repo_remote_fetch_summary(), but supports an extensible set of flags.
|
||||
* The following are currently defined:
|
||||
*
|
||||
* - override-url (s): Fetch summary from this URL if remote specifies no metalink in options
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE on failure
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
const char *name,
|
||||
GVariant *options,
|
||||
GBytes **out_summary,
|
||||
GBytes **out_signatures,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *metalink_url_string = NULL;
|
||||
g_autoptr(GBytes) summary = NULL;
|
||||
g_autoptr(GBytes) signatures = NULL;
|
||||
gboolean ret = FALSE;
|
||||
gboolean gpg_verify_summary;
|
||||
|
||||
g_return_val_if_fail (OSTREE_REPO (self), FALSE);
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
|
||||
if (!ostree_repo_get_remote_option (self, name, "metalink", NULL,
|
||||
&metalink_url_string, error))
|
||||
goto out;
|
||||
|
||||
if (!repo_remote_fetch_summary (self,
|
||||
name,
|
||||
metalink_url_string,
|
||||
options,
|
||||
&summary,
|
||||
&signatures,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_remote_get_gpg_verify_summary (self, name, &gpg_verify_summary, error))
|
||||
goto out;
|
||||
|
||||
if (gpg_verify_summary && signatures == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Verify any summary signatures. */
|
||||
if (gpg_verify_summary && summary != NULL && signatures != NULL)
|
||||
{
|
||||
glnx_unref_object OstreeGpgVerifyResult *result = NULL;
|
||||
|
||||
result = ostree_repo_verify_summary (self,
|
||||
name,
|
||||
summary,
|
||||
signatures,
|
||||
cancellable,
|
||||
error);
|
||||
if (!ostree_gpg_verify_result_require_valid_signature (result, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (out_summary != NULL)
|
||||
*out_summary = g_steal_pointer (&summary);
|
||||
|
||||
if (out_signatures != NULL)
|
||||
*out_signatures = g_steal_pointer (&signatures);
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* HAVE_LIBSOUP */
|
||||
|
||||
gboolean
|
||||
ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
GVariant *options,
|
||||
OstreeAsyncProgress *progress,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
"This version of ostree was built without libsoup, and cannot fetch over HTTP");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
const char *name,
|
||||
GVariant *options,
|
||||
GBytes **out_summary,
|
||||
GBytes **out_signatures,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
"This version of ostree was built without libsoup, and cannot fetch over HTTP");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBSOUP */
|
||||
@@ -1226,7 +1226,7 @@ get_fallback_headers (OstreeRepo *self,
|
||||
*
|
||||
* The @params argument should be an a{sv}. The following attributes
|
||||
* are known:
|
||||
* - min-fallback-size: u: Minimume uncompressed size in megabytes to use fallback, 0 to disable fallbacks
|
||||
* - min-fallback-size: u: Minimum uncompressed size in megabytes to use fallback, 0 to disable fallbacks
|
||||
* - max-chunk-size: u: Maximum size in megabytes of a delta part
|
||||
* - max-bsdiff-size: u: Maximum size in megabytes to consider bsdiff compression
|
||||
* for input files
|
||||
@@ -1253,7 +1253,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
|
||||
guint min_fallback_size;
|
||||
guint max_bsdiff_size;
|
||||
guint max_chunk_size;
|
||||
GVariantBuilder metadata_builder;
|
||||
g_auto(GVariantBuilder) metadata_builder = {{0,}};
|
||||
DeltaOpts delta_opts = DELTAOPT_FLAG_NONE;
|
||||
guint64 total_compressed_size = 0;
|
||||
guint64 total_uncompressed_size = 0;
|
||||
@@ -1384,16 +1384,18 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
|
||||
g_autoptr(GVariant) delta_part_content = NULL;
|
||||
g_autoptr(GVariant) delta_part = NULL;
|
||||
g_autoptr(GVariant) delta_part_header = NULL;
|
||||
GVariantBuilder *mode_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(uuu)"));
|
||||
GVariantBuilder *xattr_builder = g_variant_builder_new (G_VARIANT_TYPE ("aa(ayay)"));
|
||||
g_auto(GVariantBuilder) mode_builder = {{0,}};
|
||||
g_auto(GVariantBuilder) xattr_builder = {{0,}};
|
||||
guint8 compression_type_char;
|
||||
|
||||
g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uuu)"));
|
||||
g_variant_builder_init (&xattr_builder, G_VARIANT_TYPE ("aa(ayay)"));
|
||||
{ guint j;
|
||||
for (j = 0; j < part_builder->modes->len; j++)
|
||||
g_variant_builder_add_value (mode_builder, part_builder->modes->pdata[j]);
|
||||
g_variant_builder_add_value (&mode_builder, part_builder->modes->pdata[j]);
|
||||
|
||||
for (j = 0; j < part_builder->xattrs->len; j++)
|
||||
g_variant_builder_add_value (xattr_builder, part_builder->xattrs->pdata[j]);
|
||||
g_variant_builder_add_value (&xattr_builder, part_builder->xattrs->pdata[j]);
|
||||
}
|
||||
|
||||
payload_b = g_string_free_to_bytes (part_builder->payload);
|
||||
@@ -1403,7 +1405,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
|
||||
part_builder->operations = NULL;
|
||||
/* FIXME - avoid duplicating memory here */
|
||||
delta_part_content = g_variant_new ("(a(uuu)aa(ayay)@ay@ay)",
|
||||
mode_builder, xattr_builder,
|
||||
&mode_builder, &xattr_builder,
|
||||
ot_gvariant_new_ay_bytes (payload_b),
|
||||
ot_gvariant_new_ay_bytes (operations_b));
|
||||
g_variant_ref_sink (delta_part_content);
|
||||
@@ -1481,7 +1483,8 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
|
||||
|
||||
descriptor_dir = g_file_get_parent (descriptor_path);
|
||||
|
||||
if (!gs_file_ensure_directory (descriptor_dir, TRUE, cancellable, error))
|
||||
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, gs_file_get_path_cached (descriptor_dir), 0755,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < part_tempfiles->len; i++)
|
||||
|
||||
@@ -126,8 +126,8 @@ ostree_repo_list_static_delta_names (OstreeRepo *self,
|
||||
if (g_file_info_get_file_type (file_info2) != G_FILE_TYPE_DIRECTORY)
|
||||
continue;
|
||||
|
||||
name1 = gs_file_get_basename_cached (child);
|
||||
name2 = gs_file_get_basename_cached (child2);
|
||||
name1 = g_file_info_get_name (file_info);
|
||||
name2 = g_file_info_get_name (file_info2);
|
||||
|
||||
{
|
||||
g_autoptr(GFile) meta_path = g_file_get_child (child2, "superblock");
|
||||
@@ -159,7 +159,8 @@ ostree_repo_list_static_delta_names (OstreeRepo *self,
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
gs_transfer_out_value (out_deltas, &ret_deltas);
|
||||
if (out_deltas)
|
||||
*out_deltas = g_steal_pointer (&ret_deltas);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -512,6 +513,7 @@ _ostree_static_delta_part_open (GInputStream *part_in,
|
||||
g_bytes_get_size (inline_part_bytes) - 1);
|
||||
ret_part = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0),
|
||||
content_bytes, trusted);
|
||||
g_variant_ref_sink (ret_part);
|
||||
}
|
||||
|
||||
if (!skip_checksum)
|
||||
@@ -840,7 +842,7 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
|
||||
|
||||
if (!ot_util_variant_map_at (self->repo_dir_fd, superblock_path,
|
||||
(GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
|
||||
TRUE, &delta_superblock, error))
|
||||
OT_VARIANT_MAP_TRUSTED, &delta_superblock, error))
|
||||
goto out;
|
||||
|
||||
g_print ("%s\n", g_variant_print (delta_superblock, 1));
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libglnx.h"
|
||||
#include "ostree.h"
|
||||
#include "otutil.h"
|
||||
|
||||
|
||||
+389
-612
File diff suppressed because it is too large.
Load diff
+48
-10
@@ -115,6 +115,10 @@ gboolean ostree_repo_remote_delete (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* OstreeRepoRemoteChange:
|
||||
* The remote change operation.
|
||||
*/
|
||||
typedef enum {
|
||||
OSTREE_REPO_REMOTE_CHANGE_ADD,
|
||||
OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS,
|
||||
@@ -194,6 +198,15 @@ gboolean ostree_repo_remote_fetch_summary (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
const char *name,
|
||||
GVariant *options,
|
||||
GBytes **out_summary,
|
||||
GBytes **out_signatures,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
OstreeRepo * ostree_repo_get_parent (OstreeRepo *self);
|
||||
|
||||
@@ -214,6 +227,10 @@ gboolean ostree_repo_write_config (OstreeRepo *self,
|
||||
* were written to the repository in this transaction.
|
||||
* @content_bytes_written: The amount of data added to the repository,
|
||||
* in bytes, counting only content objects.
|
||||
* @padding1: reserved
|
||||
* @padding2: reserved
|
||||
* @padding3: reserved
|
||||
* @padding4: reserved
|
||||
*
|
||||
* A list of statistics for each transaction that may be
|
||||
* interesting for reporting purposes.
|
||||
@@ -582,7 +599,9 @@ gboolean ostree_repo_write_archive_to_mtree (OstreeRepo *
|
||||
typedef struct {
|
||||
guint ignore_unsupported_content : 1;
|
||||
guint autocreate_parents : 1;
|
||||
guint reserved : 30;
|
||||
guint use_ostree_convention : 1;
|
||||
guint callback_with_entry_pathname : 1;
|
||||
guint reserved : 28;
|
||||
|
||||
guint unused_uint[8];
|
||||
gpointer unused_ptrs[8];
|
||||
@@ -610,7 +629,10 @@ typedef struct {
|
||||
guint64 timestamp_secs;
|
||||
|
||||
guint unused_uint[8];
|
||||
gpointer unused_ptrs[8];
|
||||
|
||||
char *path_prefix;
|
||||
|
||||
gpointer unused_ptrs[7];
|
||||
} OstreeRepoExportArchiveOptions;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
@@ -685,7 +707,8 @@ typedef enum {
|
||||
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1
|
||||
} OstreeRepoCheckoutOverwriteMode;
|
||||
|
||||
_OSTREE_PUBLIC gboolean
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_repo_checkout_tree (OstreeRepo *self,
|
||||
OstreeRepoCheckoutMode mode,
|
||||
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
||||
@@ -852,14 +875,16 @@ typedef enum {
|
||||
OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE = (1 << 0)
|
||||
} OstreeRepoCommitTraverseFlags;
|
||||
|
||||
_OSTREE_PUBLIC gboolean
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_repo_commit_traverse_iter_init_commit (OstreeRepoCommitTraverseIter *iter,
|
||||
OstreeRepo *repo,
|
||||
GVariant *commit,
|
||||
OstreeRepoCommitTraverseFlags flags,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC gboolean
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_repo_commit_traverse_iter_init_dirtree (OstreeRepoCommitTraverseIter *iter,
|
||||
OstreeRepo *repo,
|
||||
GVariant *dirtree,
|
||||
@@ -889,8 +914,8 @@ void ostree_repo_commit_traverse_iter_get_dir (OstreeRepoCommitTraverseIter *ite
|
||||
char **out_content_checksum,
|
||||
char **out_meta_checksum);
|
||||
|
||||
_OSTREE_PUBLIC void
|
||||
ostree_repo_commit_traverse_iter_clear (OstreeRepoCommitTraverseIter *iter);
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_repo_commit_traverse_iter_clear (OstreeRepoCommitTraverseIter *iter);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_repo_commit_traverse_iter_cleanup (void *p);
|
||||
@@ -909,7 +934,8 @@ typedef enum {
|
||||
OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY
|
||||
} OstreeRepoPruneFlags;
|
||||
|
||||
_OSTREE_PUBLIC gboolean
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
@@ -947,7 +973,8 @@ gboolean ostree_repo_pull (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC gboolean
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_repo_pull_one_dir (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
const char *dir_to_pull,
|
||||
@@ -986,7 +1013,8 @@ gboolean ostree_repo_sign_delta (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC gboolean
|
||||
_OSTREE_PUBLIC
|
||||
gboolean
|
||||
ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
|
||||
const gchar **key_id,
|
||||
const gchar *homedir,
|
||||
@@ -1016,6 +1044,16 @@ OstreeGpgVerifyResult * ostree_repo_verify_commit_ext (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
OstreeGpgVerifyResult * ostree_repo_gpg_verify_data (OstreeRepo *self,
|
||||
const gchar *remote_name,
|
||||
GBytes *data,
|
||||
GBytes *signatures,
|
||||
GFile *keyringdir,
|
||||
GFile *extra_keyring,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
OstreeGpgVerifyResult * ostree_repo_verify_summary (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "ostree-bootloader-syslinux.h"
|
||||
|
||||
/**
|
||||
* SECTION:libostree-sepolicy
|
||||
* SECTION:ostree-sepolicy
|
||||
* @title: SELinux policy management
|
||||
* @short_description: Read SELinux policy and manage filesystem labels
|
||||
*
|
||||
|
||||
@@ -32,7 +32,7 @@ _ostree_sysroot_list_deployment_dirs_for_os (GFile *osdir,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *osname = gs_file_get_basename_cached (osdir);
|
||||
const char *osname = glnx_basename (gs_file_get_path_cached (osdir));
|
||||
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
||||
g_autoptr(GFile) osdeploy_dir = NULL;
|
||||
GError *temp_error = NULL;
|
||||
@@ -370,7 +370,7 @@ cleanup_old_deployments (OstreeSysroot *self,
|
||||
g_autofree char *osname = NULL;
|
||||
g_autofree char *bootcsum = NULL;
|
||||
|
||||
if (!parse_bootdir_name (gs_file_get_basename_cached (bootdir),
|
||||
if (!parse_bootdir_name (glnx_basename (gs_file_get_path_cached (bootdir)),
|
||||
&osname, &bootcsum))
|
||||
g_assert_not_reached ();
|
||||
|
||||
|
||||
@@ -87,6 +87,39 @@ symlink_at_replace (const char *oldpath,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Try a hardlink if we can, otherwise fall back to copying. Used
|
||||
* right now for kernels/initramfs in /boot, where we can just
|
||||
* hardlink if we're on the same partition.
|
||||
*/
|
||||
static gboolean
|
||||
hardlink_or_copy_at (int src_dfd,
|
||||
const char *src_subpath,
|
||||
int dest_dfd,
|
||||
const char *dest_subpath,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (linkat (src_dfd, src_subpath, dest_dfd, dest_subpath, 0) != 0)
|
||||
{
|
||||
if (errno == EMLINK || errno == EXDEV)
|
||||
{
|
||||
return glnx_file_copy_at (src_dfd, src_subpath, NULL, dest_dfd, dest_subpath, 0,
|
||||
cancellable, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dirfd_copy_attributes_and_xattrs (int src_parent_dfd,
|
||||
const char *src_name,
|
||||
@@ -139,8 +172,8 @@ copy_dir_recurse (int src_parent_dfd,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int src_dfd = -1;
|
||||
int dest_dfd = -1;
|
||||
glnx_fd_close int src_dfd = -1;
|
||||
glnx_fd_close int dest_dfd = -1;
|
||||
DIR *srcd = NULL;
|
||||
struct dirent *dent;
|
||||
|
||||
@@ -207,10 +240,6 @@ copy_dir_recurse (int src_parent_dfd,
|
||||
/* Note the srcd owns src_dfd */
|
||||
src_dfd = -1;
|
||||
}
|
||||
if (src_dfd != -1)
|
||||
(void) close (src_dfd);
|
||||
if (dest_dfd != -1)
|
||||
(void) close (dest_dfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -224,8 +253,8 @@ ensure_directory_from_template (int orig_etc_fd,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int src_dfd = -1;
|
||||
int target_dfd = -1;
|
||||
glnx_fd_close int src_dfd = -1;
|
||||
glnx_fd_close int target_dfd = -1;
|
||||
|
||||
g_assert (path != NULL);
|
||||
g_assert (*path != '/' && *path != '\0');
|
||||
@@ -283,10 +312,6 @@ ensure_directory_from_template (int orig_etc_fd,
|
||||
target_dfd = -1;
|
||||
}
|
||||
out:
|
||||
if (src_dfd != -1)
|
||||
(void) close (src_dfd);
|
||||
if (target_dfd != -1)
|
||||
(void) close (target_dfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -308,7 +333,7 @@ copy_modified_config_file (int orig_etc_fd,
|
||||
gboolean ret = FALSE;
|
||||
struct stat modified_stbuf;
|
||||
struct stat new_stbuf;
|
||||
int dest_parent_dfd = -1;
|
||||
glnx_fd_close int dest_parent_dfd = -1;
|
||||
|
||||
if (fstatat (modified_etc_fd, path, &modified_stbuf, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
{
|
||||
@@ -398,8 +423,6 @@ copy_modified_config_file (int orig_etc_fd,
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (dest_parent_dfd != -1)
|
||||
(void) close (dest_parent_dfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -426,9 +449,9 @@ merge_etc_changes (GFile *orig_etc,
|
||||
g_autoptr(GPtrArray) removed = NULL;
|
||||
g_autoptr(GPtrArray) added = NULL;
|
||||
guint i;
|
||||
int orig_etc_fd = -1;
|
||||
int modified_etc_fd = -1;
|
||||
int new_etc_fd = -1;
|
||||
glnx_fd_close int orig_etc_fd = -1;
|
||||
glnx_fd_close int modified_etc_fd = -1;
|
||||
glnx_fd_close int new_etc_fd = -1;
|
||||
|
||||
modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref);
|
||||
removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
|
||||
@@ -505,12 +528,6 @@ merge_etc_changes (GFile *orig_etc,
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (orig_etc_fd != -1)
|
||||
(void) close (orig_etc_fd);
|
||||
if (modified_etc_fd != -1)
|
||||
(void) close (modified_etc_fd);
|
||||
if (new_etc_fd != -1)
|
||||
(void) close (new_etc_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -651,7 +668,7 @@ relabel_recursively (OstreeSysroot *sysroot,
|
||||
if (file_info == NULL)
|
||||
break;
|
||||
|
||||
g_ptr_array_add (path_parts, (char*)gs_file_get_basename_cached (child));
|
||||
g_ptr_array_add (path_parts, (char*)g_file_info_get_name (file_info));
|
||||
|
||||
ftype = g_file_info_get_file_type (file_info);
|
||||
if (ftype == G_FILE_TYPE_DIRECTORY)
|
||||
@@ -723,12 +740,12 @@ selinux_relabel_file (OstreeSysroot *sysroot,
|
||||
goto out;
|
||||
|
||||
g_ptr_array_add (path_parts, (char*)prefix);
|
||||
g_ptr_array_add (path_parts, (char*)gs_file_get_basename_cached (path));
|
||||
g_ptr_array_add (path_parts, (char*)g_file_info_get_name (file_info));
|
||||
if (!relabel_one_path (sysroot, sepolicy, path, file_info, path_parts,
|
||||
cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Relabeling /%s/%s: ", prefix,
|
||||
gs_file_get_basename_cached (path));
|
||||
g_file_info_get_name (file_info));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1277,7 +1294,6 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
struct stat stbuf;
|
||||
const char *osname = ostree_deployment_get_osname (deployment);
|
||||
const char *bootcsum = ostree_deployment_get_bootcsum (deployment);
|
||||
g_autoptr(GFile) bootdir = NULL;
|
||||
g_autofree char *bootcsumdir = NULL;
|
||||
g_autofree char *bootconfdir = NULL;
|
||||
g_autofree char *bootconf_name = NULL;
|
||||
@@ -1293,10 +1309,6 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
g_autofree char *contents = NULL;
|
||||
g_autofree char *deployment_version = NULL;
|
||||
g_autoptr(GHashTable) osrelease_values = NULL;
|
||||
g_autofree char *linux_relpath = NULL;
|
||||
g_autofree char *linux_key = NULL;
|
||||
g_autofree char *initramfs_relpath = NULL;
|
||||
g_autofree char *initrd_key = NULL;
|
||||
g_autofree char *version_key = NULL;
|
||||
g_autofree char *ostree_kernel_arg = NULL;
|
||||
g_autofree char *options_key = NULL;
|
||||
@@ -1342,9 +1354,9 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
glnx_set_prefix_error_from_errno (error, "fstat %s", dest_kernel_name);
|
||||
goto out;
|
||||
}
|
||||
if (!glnx_file_copy_at (tree_boot_dfd, tree_kernel_name, NULL,
|
||||
bootcsum_dfd, dest_kernel_name, 0,
|
||||
cancellable, error))
|
||||
if (!hardlink_or_copy_at (tree_boot_dfd, tree_kernel_name,
|
||||
bootcsum_dfd, dest_kernel_name,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1359,9 +1371,9 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
glnx_set_prefix_error_from_errno (error, "fstat %s", dest_initramfs_name);
|
||||
goto out;
|
||||
}
|
||||
if (!glnx_file_copy_at (tree_boot_dfd, tree_initramfs_name, NULL,
|
||||
bootcsum_dfd, dest_initramfs_name, 0,
|
||||
cancellable, error))
|
||||
if (!hardlink_or_copy_at (tree_boot_dfd, tree_initramfs_name,
|
||||
bootcsum_dfd, dest_initramfs_name,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ typedef enum {
|
||||
|
||||
} OstreeSysrootDebugFlags;
|
||||
|
||||
/**
|
||||
* OstreeSysroot:
|
||||
* Internal struct
|
||||
*/
|
||||
struct OstreeSysroot {
|
||||
GObject parent;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "ostree-sysroot-upgrader.h"
|
||||
|
||||
/**
|
||||
* SECTION:libostree-sysroot-upgrader
|
||||
* SECTION:ostree-sysroot-upgrader
|
||||
* @title: Simple upgrade class
|
||||
* @short_description: Upgrade OSTree systems
|
||||
*
|
||||
|
||||
@@ -37,7 +37,7 @@ find_booted_deployment (OstreeSysroot *self,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* SECTION:libostree-sysroot
|
||||
* SECTION:ostree-sysroot
|
||||
* @title: Root partition mount point
|
||||
* @short_description: Manage physical root filesystem
|
||||
*
|
||||
@@ -70,10 +70,12 @@ ostree_sysroot_finalize (GObject *object)
|
||||
g_clear_object (&self->path);
|
||||
g_clear_object (&self->sepolicy);
|
||||
g_clear_object (&self->repo);
|
||||
g_clear_pointer (&self->deployments, g_ptr_array_unref);
|
||||
g_clear_object (&self->booted_deployment);
|
||||
|
||||
glnx_release_lock_file (&self->lock);
|
||||
|
||||
(void) ostree_sysroot_unload (self);
|
||||
ostree_sysroot_unload (self);
|
||||
|
||||
G_OBJECT_CLASS (ostree_sysroot_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -276,28 +278,34 @@ ostree_sysroot_ensure_initialized (OstreeSysroot *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFile) dir = NULL;
|
||||
g_autoptr(GFile) ostree_dir = NULL;
|
||||
g_autoptr(GFile) repo_dir = NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
ostree_dir = g_file_get_child (self->path, "ostree");
|
||||
repo_dir = g_file_get_child (ostree_dir, "repo");
|
||||
if (!gs_file_ensure_directory (repo_dir, TRUE, cancellable, error))
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
|
||||
g_clear_object (&dir);
|
||||
dir = g_file_get_child (ostree_dir, "deploy");
|
||||
if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
|
||||
goto out;
|
||||
|
||||
g_clear_object (&dir);
|
||||
dir = ot_gfile_get_child_build_path (ostree_dir, "repo", "objects", NULL);
|
||||
if (!g_file_query_exists (dir, NULL))
|
||||
{
|
||||
glnx_unref_object OstreeRepo *repo = ostree_repo_new (repo_dir);
|
||||
if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE,
|
||||
if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, "ostree/repo", 0755,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
goto out;
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, "ostree/deploy", 0755,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (fstatat (self->sysroot_fd, "ostree/repo/objects", &stbuf, 0) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "stat %s", "ostree/repo/objects");
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(GFile) repo_dir = g_file_resolve_relative_path (self->path, "ostree/repo");
|
||||
glnx_unref_object OstreeRepo *repo = ostree_repo_new (repo_dir);
|
||||
if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
@@ -873,7 +881,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
}
|
||||
|
||||
g_clear_pointer (&self->deployments, g_ptr_array_unref);
|
||||
g_clear_pointer (&self->booted_deployment, g_object_unref);
|
||||
g_clear_object (&self->booted_deployment);
|
||||
self->bootversion = -1;
|
||||
self->subbootversion = -1;
|
||||
|
||||
|
||||
@@ -31,3 +31,5 @@
|
||||
#include <ostree-bootconfig-parser.h>
|
||||
#include <ostree-diff.h>
|
||||
#include <ostree-gpg-verify-result.h>
|
||||
|
||||
#include <ostree-autocleanups.h>
|
||||
@@ -230,3 +230,24 @@ ot_openat_ignore_enoent (int dfd,
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
ot_file_mapat_bytes (int dfd,
|
||||
const char *path,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int fd = openat (dfd, path, O_RDONLY | O_CLOEXEC);
|
||||
g_autoptr(GMappedFile) mfile = NULL;
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
|
||||
if (!mfile)
|
||||
return FALSE;
|
||||
|
||||
return g_mapped_file_get_bytes (mfile);
|
||||
}
|
||||
@@ -66,4 +66,8 @@ gboolean ot_openat_ignore_enoent (int dfd,
|
||||
int *out_fd,
|
||||
GError **error);
|
||||
|
||||
GBytes *ot_file_mapat_bytes (int dfd,
|
||||
const char *path,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -254,7 +254,8 @@ ot_gfile_load_contents_utf8_allow_noent (GFile *path,
|
||||
GError *temp_error = NULL;
|
||||
g_autofree char *ret_contents = NULL;
|
||||
|
||||
ret_contents = gs_file_load_contents_utf8 (path, cancellable, &temp_error);
|
||||
ret_contents = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (path), NULL,
|
||||
cancellable, &temp_error);
|
||||
if (!ret_contents)
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
@@ -356,8 +357,8 @@ ot_gfile_replace_contents_fsync (GFile *path,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int parent_dfd;
|
||||
const char *target_basename = gs_file_get_basename_cached (path);
|
||||
glnx_fd_close int parent_dfd = -1;
|
||||
const char *target_basename = glnx_basename (gs_file_get_path_cached (path));
|
||||
g_autoptr(GFile) parent = NULL;
|
||||
|
||||
parent = g_file_get_parent (path);
|
||||
@@ -373,8 +374,6 @@ ot_gfile_replace_contents_fsync (GFile *path,
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (parent_dfd != -1)
|
||||
(void) close (parent_dfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -389,25 +388,12 @@ ot_gfile_ensure_unlinked (GFile *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GError *temp_error = NULL;
|
||||
|
||||
if (!gs_file_unlink (path, cancellable, &temp_error))
|
||||
if (unlink (gs_file_get_path_cached (path)) != 0)
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
g_clear_error (&temp_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,7 +410,7 @@ ot_util_fsync_directory (GFile *dir,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int dfd = -1;
|
||||
glnx_fd_close int dfd = -1;
|
||||
|
||||
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (dir), TRUE,
|
||||
&dfd, error))
|
||||
@@ -438,8 +424,6 @@ ot_util_fsync_directory (GFile *dir,
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (dfd != -1)
|
||||
(void) close (dfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -458,8 +442,8 @@ ot_util_ensure_directory_and_fsync (GFile *dir,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int parentfd = -1;
|
||||
const char *basename = gs_file_get_basename_cached (dir);
|
||||
glnx_fd_close int parentfd = -1;
|
||||
const char *basename = glnx_basename (gs_file_get_path_cached (dir));
|
||||
g_autoptr(GFile) parent = g_file_get_parent (dir);
|
||||
|
||||
again:
|
||||
@@ -507,7 +491,5 @@ ot_util_ensure_directory_and_fsync (GFile *dir,
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (parentfd != -1)
|
||||
(void) close (parentfd);
|
||||
return ret;
|
||||
}
|
||||
@@ -33,7 +33,10 @@
|
||||
GVariant *
|
||||
ot_gvariant_new_empty_string_dict (void)
|
||||
{
|
||||
return g_variant_builder_end (g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")));
|
||||
g_auto(GVariantBuilder) builder = {{0,}};
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
return g_variant_builder_end (&builder);
|
||||
}
|
||||
|
||||
GVariant *
|
||||
@@ -114,63 +117,31 @@ ot_util_variant_take_ref (GVariant *variant)
|
||||
return g_variant_take_ref (variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* ot_util_variant_map:
|
||||
* @src: a #GFile
|
||||
* @type: Use this for variant
|
||||
* @trusted: See documentation of g_variant_new_from_data()
|
||||
* @out_variant: (out): Return location for new variant
|
||||
* @error:
|
||||
*
|
||||
* Memory-map @src, and store a new #GVariant referring to this memory
|
||||
* in @out_variant. Note the returned @out_variant is not floating.
|
||||
*/
|
||||
gboolean
|
||||
ot_util_variant_map (GFile *src,
|
||||
const GVariantType *type,
|
||||
gboolean trusted,
|
||||
GVariant **out_variant,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GVariant) ret_variant = NULL;
|
||||
GMappedFile *mfile = NULL;
|
||||
|
||||
mfile = gs_file_map_noatime (src, NULL, error);
|
||||
if (!mfile)
|
||||
goto out;
|
||||
|
||||
ret_variant = g_variant_new_from_data (type,
|
||||
g_mapped_file_get_contents (mfile),
|
||||
g_mapped_file_get_length (mfile),
|
||||
trusted,
|
||||
(GDestroyNotify) g_mapped_file_unref,
|
||||
mfile);
|
||||
g_variant_ref_sink (ret_variant);
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_variant, &ret_variant);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_util_variant_map_at (int dfd,
|
||||
const char *path,
|
||||
const GVariantType *type,
|
||||
gboolean trusted,
|
||||
OtVariantMapFlags flags,
|
||||
GVariant **out_variant,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int fd = -1;
|
||||
g_autoptr(GVariant) ret_variant = NULL;
|
||||
const gboolean trusted = (flags & OT_VARIANT_MAP_TRUSTED) > 0;
|
||||
|
||||
fd = openat (dfd, path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
g_prefix_error (error, "Opening %s: ", path);
|
||||
return FALSE;
|
||||
if (errno == ENOENT && (flags & OT_VARIANT_MAP_ALLOW_NOENT) > 0)
|
||||
{
|
||||
*out_variant = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
g_prefix_error (error, "Opening %s: ", path);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return ot_util_variant_map_fd (fd, 0, type, trusted, out_variant, error);
|
||||
@@ -186,6 +157,7 @@ variant_map_data_destroy (gpointer data)
|
||||
{
|
||||
VariantMapData *mdata = data;
|
||||
(void) munmap (mdata->addr, mdata->len);
|
||||
g_free (mdata);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -221,8 +193,8 @@ ot_util_variant_map_fd (int fd,
|
||||
mdata->len = len;
|
||||
|
||||
ret = TRUE;
|
||||
*out_variant = g_variant_new_from_data (type, map, len, trusted,
|
||||
variant_map_data_destroy, mdata);
|
||||
*out_variant = g_variant_ref_sink (g_variant_new_from_data (type, map, len, trusted,
|
||||
variant_map_data_destroy, mdata));
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -42,16 +42,15 @@ gboolean ot_util_variant_save (GFile *dest,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean ot_util_variant_map (GFile *src,
|
||||
const GVariantType *type,
|
||||
gboolean trusted,
|
||||
GVariant **out_variant,
|
||||
GError **error);
|
||||
typedef enum {
|
||||
OT_VARIANT_MAP_TRUSTED = (1 << 0),
|
||||
OT_VARIANT_MAP_ALLOW_NOENT = (1 << 1)
|
||||
} OtVariantMapFlags;
|
||||
|
||||
gboolean ot_util_variant_map_at (int dfd,
|
||||
const char *path,
|
||||
const GVariantType *type,
|
||||
gboolean trusted,
|
||||
OtVariantMapFlags flags,
|
||||
GVariant **out_variant,
|
||||
GError **error);
|
||||
|
||||
|
||||
@@ -39,8 +39,7 @@ ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GErr
|
||||
GOptionContext *context;
|
||||
glnx_unref_object OstreeSysroot *sysroot = NULL;
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFile) dir = NULL;
|
||||
g_autoptr(GFile) child = NULL;
|
||||
glnx_fd_close int root_dfd = -1;
|
||||
glnx_unref_object OstreeSysroot *target_sysroot = NULL;
|
||||
guint i;
|
||||
const char *normal_toplevels[] = {"boot", "dev", "home", "proc", "run", "sys"};
|
||||
@@ -58,36 +57,31 @@ ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GErr
|
||||
goto out;
|
||||
}
|
||||
|
||||
dir = g_file_new_for_path (argv[1]);
|
||||
target_sysroot = ostree_sysroot_new (dir);
|
||||
if (!glnx_opendirat (AT_FDCWD, argv[1], TRUE, &root_dfd, error))
|
||||
goto out;
|
||||
{ g_autoptr(GFile) dir = g_file_new_for_path (argv[1]);
|
||||
target_sysroot = ostree_sysroot_new (dir);
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(normal_toplevels); i++)
|
||||
{
|
||||
child = g_file_get_child (dir, normal_toplevels[i]);
|
||||
if (!gs_file_ensure_directory_mode (child, 0755, cancellable, error))
|
||||
if (!glnx_shutil_mkdir_p_at (root_dfd, normal_toplevels[i], 0755,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
g_clear_object (&child);
|
||||
}
|
||||
|
||||
child = g_file_get_child (dir, "root");
|
||||
if (!gs_file_ensure_directory_mode (child, 0700, cancellable, error))
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (root_dfd, "root", 0700,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
g_clear_object (&child);
|
||||
|
||||
child = g_file_get_child (dir, "tmp");
|
||||
if (!gs_file_ensure_directory_mode (child, 01777, cancellable, error))
|
||||
if (!glnx_shutil_mkdir_p_at (root_dfd, "tmp", 01777,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
/* FIXME - we should be using an API that explicitly ignores umask;
|
||||
*/
|
||||
{
|
||||
const char *path = gs_file_get_path_cached (child);
|
||||
if (chmod (path, 01777) == -1)
|
||||
{
|
||||
gs_set_prefix_error_from_errno (error, errno, "chmod");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
g_clear_object (&child);
|
||||
if (fchmodat (root_dfd, "tmp", 01777, 0) == -1)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "chmod: %s", "tmp");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ostree_sysroot_ensure_initialized (target_sysroot, cancellable, error))
|
||||
goto out;
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ot-main.h"
|
||||
#include "ot-builtins.h"
|
||||
#include "ot-admin-instutil-builtins.h"
|
||||
#include "ot-admin-builtins.h"
|
||||
#include "ot-admin-functions.h"
|
||||
#include "ot-main.h"
|
||||
#include "ostree.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
@@ -61,8 +61,6 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL;
|
||||
glnx_unref_object OstreeAsyncProgress *progress = NULL;
|
||||
gboolean changed;
|
||||
GSConsole *console = NULL;
|
||||
gboolean in_status_line = FALSE;
|
||||
GKeyFile *old_origin;
|
||||
GKeyFile *new_origin = NULL;
|
||||
|
||||
@@ -125,28 +123,24 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error))
|
||||
goto out;
|
||||
|
||||
console = gs_console_get ();
|
||||
if (console)
|
||||
{
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
in_status_line = TRUE;
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console);
|
||||
}
|
||||
{ g_auto(GLnxConsoleRef) console = { 0, };
|
||||
glnx_console_lock (&console);
|
||||
|
||||
/* Always allow older...there's not going to be a chronological
|
||||
* relationship necessarily.
|
||||
*/
|
||||
if (!ostree_sysroot_upgrader_pull (upgrader, 0,
|
||||
OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER,
|
||||
progress, &changed,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
if (console.is_tty)
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console);
|
||||
|
||||
if (in_status_line)
|
||||
{
|
||||
gs_console_end_status_line (console, NULL, NULL);
|
||||
in_status_line = FALSE;
|
||||
}
|
||||
/* Always allow older...there's not going to be a chronological
|
||||
* relationship necessarily.
|
||||
*/
|
||||
if (!ostree_sysroot_upgrader_pull (upgrader, 0,
|
||||
OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER,
|
||||
progress, &changed,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (progress)
|
||||
ostree_async_progress_finish (progress);
|
||||
}
|
||||
|
||||
if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
|
||||
goto out;
|
||||
@@ -171,8 +165,6 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (in_status_line)
|
||||
gs_console_end_status_line (console, NULL, NULL);
|
||||
if (new_origin)
|
||||
g_key_file_unref (new_origin);
|
||||
if (context)
|
||||
|
||||
@@ -55,8 +55,6 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr
|
||||
g_autoptr(GFile) deployment_path = NULL;
|
||||
g_autoptr(GFile) deployment_origin_path = NULL;
|
||||
g_autoptr(GKeyFile) origin = NULL;
|
||||
GSConsole *console = NULL;
|
||||
gboolean in_status_line = FALSE;
|
||||
glnx_unref_object OstreeAsyncProgress *progress = NULL;
|
||||
gboolean changed;
|
||||
OstreeSysrootUpgraderPullFlags upgraderpullflags = 0;
|
||||
@@ -108,27 +106,23 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr
|
||||
}
|
||||
}
|
||||
|
||||
console = gs_console_get ();
|
||||
if (console)
|
||||
{
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
in_status_line = TRUE;
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console);
|
||||
}
|
||||
{ g_auto(GLnxConsoleRef) console = { 0, };
|
||||
glnx_console_lock (&console);
|
||||
|
||||
if (opt_allow_downgrade)
|
||||
upgraderpullflags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER;
|
||||
if (console.is_tty)
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console);
|
||||
|
||||
if (!ostree_sysroot_upgrader_pull (upgrader, 0, upgraderpullflags,
|
||||
progress, &changed,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
if (opt_allow_downgrade)
|
||||
upgraderpullflags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER;
|
||||
|
||||
if (!ostree_sysroot_upgrader_pull (upgrader, 0, upgraderpullflags,
|
||||
progress, &changed,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (in_status_line)
|
||||
{
|
||||
gs_console_end_status_line (console, NULL, NULL);
|
||||
in_status_line = FALSE;
|
||||
}
|
||||
if (progress)
|
||||
ostree_async_progress_finish (progress);
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
{
|
||||
@@ -148,8 +142,6 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (in_status_line)
|
||||
gs_console_end_status_line (console, NULL, NULL);
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
return ret;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libglnx.h"
|
||||
#include "ot-admin-functions.h"
|
||||
#include "otutil.h"
|
||||
#include "ostree.h"
|
||||
|
||||
@@ -120,7 +120,7 @@ relabel_recursively (OstreeSePolicy *sepolicy,
|
||||
if (file_info == NULL)
|
||||
break;
|
||||
|
||||
g_ptr_array_add (path_parts, (char*)gs_file_get_basename_cached (child));
|
||||
g_ptr_array_add (path_parts, (char*)g_file_info_get_name (file_info));
|
||||
|
||||
ftype = g_file_info_get_file_type (file_info);
|
||||
if (ftype == G_FILE_TYPE_DIRECTORY)
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ot-main.h"
|
||||
#include "ot-builtins.h"
|
||||
#include "ot-admin-builtins.h"
|
||||
#include "ot-admin-functions.h"
|
||||
#include "ot-main.h"
|
||||
#include "ostree.h"
|
||||
#include "ostree-repo-file.h"
|
||||
|
||||
|
||||
+111
-52
@@ -32,10 +32,12 @@
|
||||
|
||||
static char *opt_subject;
|
||||
static char *opt_body;
|
||||
static gboolean opt_editor;
|
||||
static char *opt_parent;
|
||||
static gboolean opt_orphan;
|
||||
static char *opt_branch;
|
||||
static char *opt_statoverride_file;
|
||||
static char *opt_skiplist_file;
|
||||
static char **opt_metadata_strings;
|
||||
static char **opt_detached_metadata_strings;
|
||||
static gboolean opt_link_checkout_speedup;
|
||||
@@ -72,6 +74,7 @@ static GOptionEntry options[] = {
|
||||
{ "parent", 0, 0, G_OPTION_ARG_STRING, &opt_parent, "Parent ref, or \"none\"", "REF" },
|
||||
{ "subject", 's', 0, G_OPTION_ARG_STRING, &opt_subject, "One line subject", "SUBJECT" },
|
||||
{ "body", 'm', 0, G_OPTION_ARG_STRING, &opt_body, "Full description", "BODY" },
|
||||
{ "editor", 'e', 0, G_OPTION_ARG_NONE, &opt_editor, "Use an editor to write the commit message", NULL },
|
||||
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &opt_branch, "Branch", "BRANCH" },
|
||||
{ "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL },
|
||||
{ "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" },
|
||||
@@ -84,6 +87,7 @@ static GOptionEntry options[] = {
|
||||
{ "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL },
|
||||
{ "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &opt_skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL },
|
||||
{ "statoverride", 0, 0, G_OPTION_ARG_FILENAME, &opt_statoverride_file, "File containing list of modifications to make to permissions", "PATH" },
|
||||
{ "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" },
|
||||
{ "table-output", 0, 0, G_OPTION_ARG_NONE, &opt_table_output, "Output more information in a KEY: VALUE format", NULL },
|
||||
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"},
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
|
||||
@@ -95,65 +99,85 @@ static GOptionEntry options[] = {
|
||||
};
|
||||
|
||||
static gboolean
|
||||
parse_statoverride_file (GHashTable **out_mode_add,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
parse_file_by_line (const char *path,
|
||||
gboolean (*cb)(const char*, void*, GError**),
|
||||
void *cbdata,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gsize len;
|
||||
char **iter = NULL; /* nofree */
|
||||
g_autoptr(GHashTable) ret_hash = NULL;
|
||||
g_autoptr(GFile) path = NULL;
|
||||
g_autofree char *contents = NULL;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
char **lines = NULL;
|
||||
|
||||
path = g_file_new_for_path (opt_statoverride_file);
|
||||
|
||||
if (!g_file_load_contents (path, cancellable, &contents, &len, NULL,
|
||||
error))
|
||||
file = g_file_new_for_path (path);
|
||||
if (!g_file_load_contents (file, cancellable, &contents, NULL, NULL, error))
|
||||
goto out;
|
||||
|
||||
ret_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
lines = g_strsplit (contents, "\n", -1);
|
||||
|
||||
for (iter = lines; iter && *iter; iter++)
|
||||
for (char **iter = lines; iter && *iter; iter++)
|
||||
{
|
||||
const char *line = *iter;
|
||||
/* skip empty lines at least */
|
||||
if (**iter == '\0')
|
||||
continue;
|
||||
|
||||
if (*line == '+')
|
||||
{
|
||||
const char *spc;
|
||||
guint mode_add;
|
||||
|
||||
spc = strchr (line + 1, ' ');
|
||||
if (!spc)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Malformed statoverride file");
|
||||
goto out;
|
||||
}
|
||||
|
||||
mode_add = (guint32)(gint32)g_ascii_strtod (line + 1, NULL);
|
||||
g_hash_table_insert (ret_hash,
|
||||
g_strdup (spc + 1),
|
||||
GUINT_TO_POINTER((gint32)mode_add));
|
||||
}
|
||||
if (!cb (*iter, cbdata, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value (out_mode_add, &ret_hash);
|
||||
out:
|
||||
out:
|
||||
g_strfreev (lines);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_statoverride_line (const char *line,
|
||||
void *data,
|
||||
GError **error)
|
||||
{
|
||||
GHashTable *files = data;
|
||||
const char *spc;
|
||||
guint mode_add;
|
||||
|
||||
spc = strchr (line, ' ');
|
||||
if (spc == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Malformed statoverride file (no space found)");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mode_add = (guint32)(gint32)g_ascii_strtod (line, NULL);
|
||||
g_hash_table_insert (files, g_strdup (spc + 1),
|
||||
GUINT_TO_POINTER((gint32)mode_add));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_skiplist_line (const char *line,
|
||||
void *data,
|
||||
GError **error)
|
||||
{
|
||||
GHashTable *files = data;
|
||||
g_hash_table_add (files, g_strdup (line));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct CommitFilterData {
|
||||
GHashTable *mode_adds;
|
||||
GHashTable *skip_list;
|
||||
};
|
||||
|
||||
static OstreeRepoCommitFilterResult
|
||||
commit_filter (OstreeRepo *self,
|
||||
const char *path,
|
||||
GFileInfo *file_info,
|
||||
gpointer user_data)
|
||||
{
|
||||
GHashTable *mode_adds = user_data;
|
||||
struct CommitFilterData *data = user_data;
|
||||
GHashTable *mode_adds = data->mode_adds;
|
||||
GHashTable *skip_list = data->skip_list;
|
||||
gpointer value;
|
||||
|
||||
if (opt_owner_uid >= 0)
|
||||
@@ -169,7 +193,13 @@ commit_filter (OstreeRepo *self,
|
||||
current_mode | mode_add);
|
||||
g_hash_table_remove (mode_adds, path);
|
||||
}
|
||||
|
||||
|
||||
if (skip_list && g_hash_table_contains (skip_list, path))
|
||||
{
|
||||
g_hash_table_remove (skip_list, path);
|
||||
return OSTREE_REPO_COMMIT_FILTER_SKIP;
|
||||
}
|
||||
|
||||
return OSTREE_REPO_COMMIT_FILTER_ALLOW;
|
||||
}
|
||||
|
||||
@@ -188,14 +218,18 @@ commit_editor (OstreeRepo *repo,
|
||||
char **lines = NULL;
|
||||
int i;
|
||||
|
||||
*subject = NULL;
|
||||
*body = NULL;
|
||||
|
||||
input = g_strdup_printf ("\n"
|
||||
"# Please enter the commit message for your changes. The first line will\n"
|
||||
"# become the subject, and the remainder the body. Lines starting\n"
|
||||
"# with '#' will be ignored, and an empty message aborts the commit."
|
||||
"%s%s\n", branch ? "\n#\n# Branch: " : "", branch ?: "");
|
||||
"%s%s%s%s%s%s\n"
|
||||
, branch ? "\n#\n# Branch: " : "", branch ? branch : ""
|
||||
, *subject ? "\n" : "", *subject ? *subject : ""
|
||||
, *body ? "\n" : "", *body ? *body : ""
|
||||
);
|
||||
|
||||
*subject = NULL;
|
||||
*body = NULL;
|
||||
|
||||
output = ot_editor_prompt (repo, input, cancellable, error);
|
||||
if (output == NULL)
|
||||
@@ -310,9 +344,11 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
|
||||
glnx_unref_object OstreeMutableTree *mtree = NULL;
|
||||
g_autofree char *tree_type = NULL;
|
||||
g_autoptr(GHashTable) mode_adds = NULL;
|
||||
g_autoptr(GHashTable) skip_list = NULL;
|
||||
OstreeRepoCommitModifierFlags flags = 0;
|
||||
OstreeRepoCommitModifier *modifier = NULL;
|
||||
OstreeRepoTransactionStats stats;
|
||||
struct CommitFilterData filter_data = { 0, };
|
||||
|
||||
context = g_option_context_new ("[PATH] - Commit a new revision");
|
||||
|
||||
@@ -324,7 +360,17 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
|
||||
|
||||
if (opt_statoverride_file)
|
||||
{
|
||||
if (!parse_statoverride_file (&mode_adds, cancellable, error))
|
||||
mode_adds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
if (!parse_file_by_line (opt_statoverride_file, handle_statoverride_line,
|
||||
mode_adds, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_skiplist_file)
|
||||
{
|
||||
skip_list = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
if (!parse_file_by_line (opt_skiplist_file, handle_skiplist_line,
|
||||
skip_list, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -359,9 +405,13 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
|
||||
|| opt_owner_uid >= 0
|
||||
|| opt_owner_gid >= 0
|
||||
|| opt_statoverride_file != NULL
|
||||
|| opt_skiplist_file != NULL
|
||||
|| opt_no_xattrs)
|
||||
{
|
||||
modifier = ostree_repo_commit_modifier_new (flags, commit_filter, mode_adds, NULL);
|
||||
filter_data.mode_adds = mode_adds;
|
||||
filter_data.skip_list = skip_list;
|
||||
modifier = ostree_repo_commit_modifier_new (flags, commit_filter,
|
||||
&filter_data, NULL);
|
||||
}
|
||||
|
||||
if (opt_parent)
|
||||
@@ -381,19 +431,12 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!opt_subject && !opt_body)
|
||||
if (opt_editor)
|
||||
{
|
||||
if (!commit_editor (repo, opt_branch, &opt_subject, &opt_body, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!opt_subject)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"A subject must be specified with --subject");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
|
||||
goto out;
|
||||
|
||||
@@ -491,6 +534,22 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (skip_list && g_hash_table_size (skip_list) > 0)
|
||||
{
|
||||
GHashTableIter hash_iter;
|
||||
gpointer key;
|
||||
|
||||
g_hash_table_iter_init (&hash_iter, skip_list);
|
||||
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, NULL))
|
||||
{
|
||||
g_printerr ("Unmatched skip-list path: %s\n", (char*)key);
|
||||
}
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Unmatched skip-list paths");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ostree_repo_write_mtree (repo, mtree, &root, cancellable, error))
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -32,10 +32,14 @@
|
||||
#endif
|
||||
|
||||
static char *opt_output_path;
|
||||
static char *opt_subpath;
|
||||
static char *opt_prefix;
|
||||
static gboolean opt_no_xattrs;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Skip output of extended attributes", NULL },
|
||||
{ "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
|
||||
{ "prefix", 0, 0, G_OPTION_ARG_STRING, &opt_prefix, "Add PATH as prefix to archive pathnames", "PATH" },
|
||||
{ "output", 'o', 0, G_OPTION_ARG_STRING, &opt_output_path, "Output to PATH ", "PATH" },
|
||||
{ NULL }
|
||||
};
|
||||
@@ -60,6 +64,7 @@ ostree_builtin_export (int argc, char **argv, GCancellable *cancellable, GError
|
||||
gboolean ret = FALSE;
|
||||
const char *rev;
|
||||
g_autoptr(GFile) root = NULL;
|
||||
g_autoptr(GFile) subtree = NULL;
|
||||
g_autofree char *commit = NULL;
|
||||
g_autoptr(GVariant) commit_data = NULL;
|
||||
struct archive *a;
|
||||
@@ -124,7 +129,14 @@ ostree_builtin_export (int argc, char **argv, GCancellable *cancellable, GError
|
||||
|
||||
opts.timestamp_secs = ostree_commit_get_timestamp (commit_data);
|
||||
|
||||
if (!ostree_repo_export_tree_to_archive (repo, &opts, (OstreeRepoFile*)root, a,
|
||||
if (opt_subpath)
|
||||
subtree = g_file_resolve_relative_path (root, opt_subpath);
|
||||
else
|
||||
subtree = g_object_ref (root);
|
||||
|
||||
opts.path_prefix = opt_prefix;
|
||||
|
||||
if (!ostree_repo_export_tree_to_archive (repo, &opts, (OstreeRepoFile*)subtree, a,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ gboolean
|
||||
ostree_builtin_init (int argc, char **argv, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
GOptionContext *context = NULL;
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
g_autoptr(OstreeRepo) repo = NULL;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepoMode mode;
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GEr
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
int i;
|
||||
const char *src_repo_arg;
|
||||
GSConsole *console = NULL;
|
||||
g_autofree char *src_repo_uri = NULL;
|
||||
glnx_unref_object OstreeAsyncProgress *progress = NULL;
|
||||
g_autoptr(GPtrArray) refs_to_fetch = NULL;
|
||||
@@ -132,14 +131,11 @@ ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GEr
|
||||
g_ptr_array_add (refs_to_fetch, NULL);
|
||||
}
|
||||
|
||||
console = gs_console_get ();
|
||||
if (console)
|
||||
{
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console);
|
||||
}
|
||||
|
||||
{ GVariantBuilder builder;
|
||||
g_auto(GLnxConsoleRef) console = { 0, };
|
||||
|
||||
glnx_console_lock (&console);
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
|
||||
g_variant_builder_add (&builder, "{s@v}", "flags",
|
||||
@@ -158,17 +154,21 @@ ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GEr
|
||||
g_variant_builder_add (&builder, "{s@v}", "depth",
|
||||
g_variant_new_variant (g_variant_new_int32 (opt_depth)));
|
||||
|
||||
if (console.is_tty)
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console);
|
||||
|
||||
if (!ostree_repo_pull_with_options (repo, src_repo_uri,
|
||||
g_variant_builder_end (&builder),
|
||||
progress,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (progress)
|
||||
ostree_async_progress_finish (progress);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (progress)
|
||||
ostree_async_progress_finish (progress);
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
if (repo)
|
||||
|
||||
@@ -37,7 +37,8 @@ static gboolean opt_untrusted;
|
||||
static char* opt_subpath;
|
||||
static char* opt_cache_dir;
|
||||
static int opt_depth = 0;
|
||||
|
||||
static char* opt_url;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL },
|
||||
{ "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL },
|
||||
@@ -49,6 +50,7 @@ static GOptionEntry options[] = {
|
||||
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL },
|
||||
{ "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL },
|
||||
{ "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" },
|
||||
{ "url", 0, 0, G_OPTION_ARG_STRING, &opt_url, "Pull objects from this URL instead of the one from the remote config", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -56,16 +58,17 @@ static void
|
||||
gpg_verify_result_cb (OstreeRepo *repo,
|
||||
const char *checksum,
|
||||
OstreeGpgVerifyResult *result,
|
||||
GSConsole *console)
|
||||
GLnxConsoleRef *console)
|
||||
{
|
||||
/* Temporarily place the GSConsole stream (which is just stdout)
|
||||
* back in normal mode before printing GPG verification results. */
|
||||
gs_console_end_status_line (console, NULL, NULL);
|
||||
/* Temporarily place the tty back in normal mode before printing GPG
|
||||
* verification results.
|
||||
*/
|
||||
glnx_console_unlock (console);
|
||||
|
||||
g_print ("\n");
|
||||
ostree_print_gpg_verify_result (result);
|
||||
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
glnx_console_lock (console);
|
||||
}
|
||||
|
||||
static gboolean printed_console_progress;
|
||||
@@ -109,7 +112,6 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError **
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *remote = NULL;
|
||||
OstreeRepoPullFlags pullflags = 0;
|
||||
GSConsole *console = NULL;
|
||||
g_autoptr(GPtrArray) refs_to_fetch = NULL;
|
||||
g_autoptr(GPtrArray) override_commit_ids = NULL;
|
||||
glnx_unref_object OstreeAsyncProgress *progress = NULL;
|
||||
@@ -204,30 +206,16 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError **
|
||||
g_ptr_array_add (refs_to_fetch, NULL);
|
||||
}
|
||||
|
||||
if (!opt_dry_run)
|
||||
{
|
||||
console = gs_console_get ();
|
||||
if (console)
|
||||
{
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console);
|
||||
signal_handler_id = g_signal_connect (repo, "gpg-verify-result",
|
||||
G_CALLBACK (gpg_verify_result_cb),
|
||||
console);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
progress = ostree_async_progress_new_and_connect (dry_run_console_progress_changed, console);
|
||||
signal_handler_id = g_signal_connect (repo, "gpg-verify-result",
|
||||
G_CALLBACK (gpg_verify_result_cb),
|
||||
console);
|
||||
}
|
||||
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
g_auto(GLnxConsoleRef) console = { 0, };
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
|
||||
glnx_console_lock (&console);
|
||||
|
||||
if (opt_url)
|
||||
g_variant_builder_add (&builder, "{s@v}", "override-url",
|
||||
g_variant_new_variant (g_variant_new_string (opt_url)));
|
||||
if (opt_subpath)
|
||||
g_variant_builder_add (&builder, "{s@v}", "subdir",
|
||||
g_variant_new_variant (g_variant_new_string (opt_subpath)));
|
||||
@@ -252,25 +240,38 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError **
|
||||
g_variant_builder_add (&builder, "{s@v}", "override-commit-ids",
|
||||
g_variant_new_variant (g_variant_new_strv ((const char*const*)override_commit_ids->pdata, override_commit_ids->len)));
|
||||
|
||||
if (!opt_dry_run)
|
||||
{
|
||||
if (console.is_tty)
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console);
|
||||
}
|
||||
else
|
||||
{
|
||||
progress = ostree_async_progress_new_and_connect (dry_run_console_progress_changed, NULL);
|
||||
}
|
||||
|
||||
if (console.is_tty)
|
||||
{
|
||||
signal_handler_id = g_signal_connect (repo, "gpg-verify-result",
|
||||
G_CALLBACK (gpg_verify_result_cb),
|
||||
&console);
|
||||
}
|
||||
|
||||
if (!ostree_repo_pull_with_options (repo, remote, g_variant_builder_end (&builder),
|
||||
progress, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (progress)
|
||||
ostree_async_progress_finish (progress);
|
||||
|
||||
if (opt_dry_run)
|
||||
g_assert (printed_console_progress);
|
||||
}
|
||||
|
||||
if (progress)
|
||||
ostree_async_progress_finish (progress);
|
||||
|
||||
if (opt_dry_run)
|
||||
g_assert (printed_console_progress);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (signal_handler_id > 0)
|
||||
g_signal_handler_disconnect (repo, signal_handler_id);
|
||||
|
||||
if (console)
|
||||
gs_console_end_status_line (console, NULL, NULL);
|
||||
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
return ret;
|
||||
|
||||
@@ -28,10 +28,12 @@
|
||||
|
||||
static gboolean opt_delete;
|
||||
static gboolean opt_list;
|
||||
static char *opt_create;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "delete", 0, 0, G_OPTION_ARG_NONE, &opt_delete, "Delete refs which match PREFIX, rather than listing them", NULL },
|
||||
{ "list", 0, 0, G_OPTION_ARG_NONE, &opt_list, "Do not remove the prefix from the refs", NULL },
|
||||
{ "create", 0, 0, G_OPTION_ARG_STRING, &opt_create, "Create a new ref for an existing commit", "NEWREF" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -48,10 +50,16 @@ static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellab
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else if (opt_create)
|
||||
{
|
||||
if (!ostree_repo_list_refs_ext (repo, NULL, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else if (!ostree_repo_list_refs (repo, refspec_prefix, &refs, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!opt_delete)
|
||||
if (!opt_delete && !opt_create)
|
||||
{
|
||||
g_hash_table_iter_init (&hashiter, refs);
|
||||
while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
|
||||
@@ -60,7 +68,30 @@ static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellab
|
||||
g_print ("%s\n", ref);
|
||||
}
|
||||
}
|
||||
else if (opt_create)
|
||||
{
|
||||
g_autofree char *checksum = NULL;
|
||||
g_autofree char *checksum_existing = NULL;
|
||||
|
||||
if (!ostree_repo_resolve_rev (repo, opt_create, TRUE, &checksum_existing, error))
|
||||
goto out;
|
||||
|
||||
if (checksum_existing != NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"--create specified but ref %s already exists", opt_create);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ostree_repo_resolve_rev (repo, refspec_prefix, FALSE, &checksum, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_set_ref_immediate (repo, NULL, opt_create, checksum,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
/* delete */
|
||||
{
|
||||
g_hash_table_iter_init (&hashiter, refs);
|
||||
while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
|
||||
@@ -97,6 +128,12 @@ ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError **
|
||||
|
||||
if (argc >= 2)
|
||||
{
|
||||
if (opt_create && argc > 2)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"You must specify only 1 existing ref when creating a new ref");
|
||||
goto out;
|
||||
}
|
||||
for (i = 1; i < argc; i++)
|
||||
if (!do_ref (repo, argv[i], cancellable, error))
|
||||
goto out;
|
||||
@@ -110,6 +147,13 @@ ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError **
|
||||
"At least one PREFIX is required when deleting refs");
|
||||
goto out;
|
||||
}
|
||||
else if (opt_create)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"You must specify an existing ref when creating a new ref");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = do_ref (repo, NULL, cancellable, error);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,12 +51,9 @@ do_print_variant_generic (const GVariantType *type,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFile) f = NULL;
|
||||
g_autoptr(GVariant) variant = NULL;
|
||||
|
||||
f = g_file_new_for_path (filename);
|
||||
|
||||
if (!ot_util_variant_map (f, type, TRUE, &variant, error))
|
||||
if (!ot_util_variant_map_at (AT_FDCWD, filename, type, TRUE, &variant, error))
|
||||
goto out;
|
||||
|
||||
ot_dump_variant (variant);
|
||||
|
||||
@@ -31,7 +31,7 @@ static char *opt_gpg_homedir;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL },
|
||||
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"},
|
||||
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the summary with", "KEY-ID"},
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include <libsoup/soup.h>
|
||||
|
||||
#include <gio/gunixoutputstream.h>
|
||||
|
||||
#include "ot-main.h"
|
||||
#include "ot-builtins.h"
|
||||
#include "ostree.h"
|
||||
@@ -32,6 +34,7 @@
|
||||
#include <signal.h>
|
||||
|
||||
static char *opt_port_file = NULL;
|
||||
static char *opt_log = NULL;
|
||||
static gboolean opt_daemonize;
|
||||
static gboolean opt_autoexit;
|
||||
static gboolean opt_force_ranges;
|
||||
@@ -40,6 +43,7 @@ static gint opt_port = 0;
|
||||
typedef struct {
|
||||
GFile *root;
|
||||
gboolean running;
|
||||
GOutputStream *log;
|
||||
} OtTrivialHttpd;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
@@ -48,9 +52,31 @@ static GOptionEntry options[] = {
|
||||
{ "port", 'P', 0, G_OPTION_ARG_INT, &opt_port, "Use the specified TCP port", NULL },
|
||||
{ "port-file", 'p', 0, G_OPTION_ARG_FILENAME, &opt_port_file, "Write port number to PATH (- for standard output)", "PATH" },
|
||||
{ "force-range-requests", 0, 0, G_OPTION_ARG_NONE, &opt_force_ranges, "Force range requests by only serving half of files", NULL },
|
||||
{ "log-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_log, "Put logs here", "PATH" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
httpd_log (OtTrivialHttpd *httpd, const gchar *format, ...) __attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
static void
|
||||
httpd_log (OtTrivialHttpd *httpd, const gchar *format, ...)
|
||||
{
|
||||
g_autoptr(GString) str = NULL;
|
||||
va_list args;
|
||||
gsize written;
|
||||
|
||||
if (!httpd->log)
|
||||
return;
|
||||
|
||||
str = g_string_new (NULL);
|
||||
va_start (args, format);
|
||||
g_string_vprintf (str, format, args);
|
||||
va_end (args);
|
||||
|
||||
g_output_stream_write_all (httpd->log, str->str, str->len, &written, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_strings (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
@@ -154,6 +180,7 @@ do_get (OtTrivialHttpd *self,
|
||||
struct stat stbuf;
|
||||
g_autofree char *safepath = NULL;
|
||||
|
||||
httpd_log (self, "serving %s\n", path);
|
||||
if (strstr (path, "../") != NULL)
|
||||
{
|
||||
soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
|
||||
@@ -296,6 +323,16 @@ do_get (OtTrivialHttpd *self,
|
||||
soup_message_set_status (msg, SOUP_STATUS_OK);
|
||||
}
|
||||
out:
|
||||
{
|
||||
guint status = 0;
|
||||
g_autofree gchar *reason = NULL;
|
||||
|
||||
g_object_get (msg,
|
||||
"status-code", &status,
|
||||
"reason-phrase", &reason,
|
||||
NULL);
|
||||
httpd_log (self, " status: %s (%u)\n", reason, status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -305,9 +342,6 @@ httpd_callback (SoupServer *server, SoupMessage *msg,
|
||||
SoupClientContext *context, gpointer data)
|
||||
{
|
||||
OtTrivialHttpd *self = data;
|
||||
SoupMessageHeadersIter iter;
|
||||
|
||||
soup_message_headers_iter_init (&iter, msg->request_headers);
|
||||
|
||||
if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD)
|
||||
do_get (self, server, msg, path, context);
|
||||
@@ -354,6 +388,37 @@ ostree_builtin_trivial_httpd (int argc, char **argv, GCancellable *cancellable,
|
||||
|
||||
app->root = g_file_new_for_path (dirpath);
|
||||
|
||||
if (opt_log)
|
||||
{
|
||||
GOutputStream *stream = NULL;
|
||||
|
||||
if (g_strcmp0 (opt_log, "-") == 0)
|
||||
{
|
||||
if (opt_daemonize)
|
||||
{
|
||||
ot_util_usage_error (context, "Cannot use --log-file=- and --daemonize at the same time", error);
|
||||
goto out;
|
||||
}
|
||||
stream = G_OUTPUT_STREAM (g_unix_output_stream_new (STDOUT_FILENO, FALSE));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(GFile) log_file;
|
||||
GFileOutputStream* log_stream;
|
||||
|
||||
log_file = g_file_new_for_path (opt_log);
|
||||
log_stream = g_file_create (log_file,
|
||||
G_FILE_CREATE_PRIVATE,
|
||||
cancellable,
|
||||
error);
|
||||
if (!log_stream)
|
||||
goto out;
|
||||
stream = G_OUTPUT_STREAM (log_stream);
|
||||
}
|
||||
|
||||
app->log = stream;
|
||||
}
|
||||
|
||||
#if SOUP_CHECK_VERSION(2, 48, 0)
|
||||
server = soup_server_new (SOUP_SERVER_SERVER_HEADER, "ostree-httpd ", NULL);
|
||||
if (!soup_server_listen_all (server, opt_port, 0, error))
|
||||
@@ -459,13 +524,17 @@ ostree_builtin_trivial_httpd (int argc, char **argv, GCancellable *cancellable,
|
||||
goto out;
|
||||
g_signal_connect (dirmon, "changed", G_CALLBACK (on_dir_changed), app);
|
||||
}
|
||||
|
||||
{
|
||||
g_autofree gchar *path = g_file_get_path (app->root);
|
||||
httpd_log (app, "serving at root %s\n", path);
|
||||
}
|
||||
while (app->running)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_clear_object (&app->root);
|
||||
g_clear_object (&app->log);
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
return ret;
|
||||
|
||||
@@ -118,8 +118,15 @@ dump_commit (GVariant *variant,
|
||||
g_print ("Version: %s\n", version);
|
||||
}
|
||||
|
||||
g_print ("\n");
|
||||
dump_indented_lines (subject);
|
||||
if (subject[0])
|
||||
{
|
||||
g_print ("\n");
|
||||
dump_indented_lines (subject);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("(no subject)\n");
|
||||
}
|
||||
|
||||
if (body[0])
|
||||
{
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libglnx.h"
|
||||
#include "ot-editor.h"
|
||||
#include "libgsystem.h"
|
||||
#include "libglnx.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <string.h>
|
||||
@@ -101,7 +101,8 @@ ot_editor_prompt (OstreeRepo *repo,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = gs_file_load_contents_utf8 (file, cancellable, error);
|
||||
ret = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (file), NULL,
|
||||
cancellable, error);
|
||||
|
||||
out:
|
||||
if (file)
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ot-main.h"
|
||||
#include "ostree.h"
|
||||
#include "ot-admin-functions.h"
|
||||
#include "ot-main.h"
|
||||
#include "otutil.h"
|
||||
|
||||
static char *opt_repo;
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ostree.h"
|
||||
#include "libglnx.h"
|
||||
#include "ostree.h"
|
||||
|
||||
typedef enum {
|
||||
OSTREE_BUILTIN_FLAG_NONE = 0,
|
||||
|
||||
Reference in new issue
Block a user