De-recursify source tree

This commit is contained in:
Colin Walters committed 2011-11-02 15:45:32 -04:00
1 parent 2b00cf3810
commit 21c7ff74b6
32 files changed
+107 -67

No files matched your search

-361
View File
@@ -1,361 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ostree.h"
#include "otutil.h"
enum {
PROP_0,
PROP_REPO,
PROP_PATH
};
G_DEFINE_TYPE (OstreeCheckout, ostree_checkout, G_TYPE_OBJECT)
#define GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), OSTREE_TYPE_CHECKOUT, OstreeCheckoutPrivate))
typedef struct _OstreeCheckoutPrivate OstreeCheckoutPrivate;
struct _OstreeCheckoutPrivate {
OstreeRepo *repo;
char *path;
};
static void
ostree_checkout_finalize (GObject *object)
{
OstreeCheckout *self = OSTREE_CHECKOUT (object);
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
g_free (priv->path);
g_clear_object (&priv->repo);
G_OBJECT_CLASS (ostree_checkout_parent_class)->finalize (object);
}
static void
ostree_checkout_set_property(GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
OstreeCheckout *self = OSTREE_CHECKOUT (object);
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
switch (prop_id)
{
case PROP_PATH:
priv->path = g_value_dup_string (value);
break;
case PROP_REPO:
priv->repo = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
ostree_checkout_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
OstreeCheckout *self = OSTREE_CHECKOUT (object);
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
switch (prop_id)
{
case PROP_PATH:
g_value_set_string (value, priv->path);
break;
case PROP_REPO:
g_value_set_object (value, priv->repo);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GObject *
ostree_checkout_constructor (GType gtype,
guint n_properties,
GObjectConstructParam *properties)
{
GObject *object;
GObjectClass *parent_class;
OstreeCheckoutPrivate *priv;
parent_class = G_OBJECT_CLASS (ostree_checkout_parent_class);
object = parent_class->constructor (gtype, n_properties, properties);
priv = GET_PRIVATE (object);
g_assert (priv->path != NULL);
return object;
}
static void
ostree_checkout_class_init (OstreeCheckoutClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (OstreeCheckoutPrivate));
object_class->constructor = ostree_checkout_constructor;
object_class->get_property = ostree_checkout_get_property;
object_class->set_property = ostree_checkout_set_property;
object_class->finalize = ostree_checkout_finalize;
g_object_class_install_property (object_class,
PROP_PATH,
g_param_spec_string ("path", "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_REPO,
g_param_spec_object ("repo", "", "",
OSTREE_TYPE_REPO,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
ostree_checkout_init (OstreeCheckout *self)
{
}
OstreeCheckout*
ostree_checkout_new (OstreeRepo *repo,
const char *path)
{
return g_object_new (OSTREE_TYPE_CHECKOUT, "repo", repo, "path", path, NULL);
}
static gboolean
executable_exists_in_checkout (const char *path,
const char *executable)
{
int i;
const char *subdirs[] = {"bin", "sbin", "usr/bin", "usr/sbin"};
for (i = 0; i < G_N_ELEMENTS (subdirs); i++)
{
char *possible_path = g_build_filename (path, subdirs[i], executable, NULL);
gboolean exists;
exists = g_file_test (possible_path, G_FILE_TEST_EXISTS);
g_free (possible_path);
if (exists)
return TRUE;
}
return FALSE;
}
static gboolean
run_trigger (OstreeCheckout *self,
GFile *trigger,
gboolean requires_chroot,
GError **error)
{
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
gboolean ret = FALSE;
char *path = NULL;
char *temp_path = NULL;
char *rel_temp_path = NULL;
GFile *temp_copy = NULL;
char *basename = NULL;
GPtrArray *args = NULL;
int estatus;
path = g_file_get_path (trigger);
basename = g_path_get_basename (path);
args = g_ptr_array_new ();
if (requires_chroot)
{
temp_path = g_build_filename (priv->path, basename, NULL);
rel_temp_path = g_strconcat ("./", basename, NULL);
temp_copy = ot_util_new_file_for_path (temp_path);
if (!g_file_copy (trigger, temp_copy, 0, NULL, NULL, NULL, error))
goto out;
g_ptr_array_add (args, "chroot");
g_ptr_array_add (args, ".");
g_ptr_array_add (args, rel_temp_path);
g_ptr_array_add (args, NULL);
}
else
{
g_ptr_array_add (args, path);
g_ptr_array_add (args, NULL);
}
g_print ("Running trigger: %s\n", path);
if (!g_spawn_sync (priv->path,
(char**)args->pdata,
NULL,
G_SPAWN_SEARCH_PATH,
NULL, NULL, NULL, NULL,
&estatus,
error))
{
g_prefix_error (error, "Failed to run trigger %s: ", basename);
goto out;
}
ret = TRUE;
out:
if (requires_chroot && temp_path)
(void)unlink (temp_path);
g_free (path);
g_free (basename);
g_free (temp_path);
g_free (rel_temp_path);
g_clear_object (&temp_copy);
if (args)
g_ptr_array_free (args, TRUE);
return ret;
}
static gboolean
check_trigger (OstreeCheckout *self,
GFile *trigger,
GError **error)
{
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
gboolean ret = FALSE;
GInputStream *instream = NULL;
GDataInputStream *datain = NULL;
GError *temp_error = NULL;
char *line;
gsize len;
gboolean requires_chroot = TRUE;
gboolean matches = FALSE;
instream = (GInputStream*)g_file_read (trigger, NULL, error);
if (!instream)
goto out;
datain = g_data_input_stream_new (instream);
while ((line = g_data_input_stream_read_line (datain, &len, NULL, &temp_error)) != NULL)
{
if (g_str_has_prefix (line, "# IfExecutable: "))
{
char *executable = g_strdup (line + strlen ("# IfExecutable: "));
g_strchomp (executable);
matches = executable_exists_in_checkout (priv->path, executable);
g_free (executable);
}
g_free (line);
}
if (line == NULL && temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
if (matches)
{
if (!run_trigger (self, trigger, requires_chroot, error))
goto out;
}
ret = TRUE;
out:
g_clear_object (&instream);
g_clear_object (&datain);
return ret;
}
gboolean
ostree_checkout_run_triggers (OstreeCheckout *self,
GError **error)
{
gboolean ret = FALSE;
GError *temp_error = NULL;
char *triggerdir_path = NULL;
GFile *triggerdir = NULL;
GFileInfo *file_info = NULL;
GFileEnumerator *enumerator = NULL;
triggerdir_path = g_build_filename (LIBEXECDIR, "ostree", "triggers.d", NULL);
triggerdir = ot_util_new_file_for_path (triggerdir_path);
enumerator = g_file_enumerate_children (triggerdir, "standard::name,standard::type,unix::*",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL,
error);
if (!enumerator)
goto out;
while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &temp_error)) != NULL)
{
const char *name;
guint32 type;
char *child_path = NULL;
GFile *child = NULL;
gboolean success;
name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
if (type == G_FILE_TYPE_REGULAR && g_str_has_suffix (name, ".trigger"))
{
child_path = g_build_filename (triggerdir_path, name, NULL);
child = ot_util_new_file_for_path (child_path);
success = check_trigger (self, child, error);
}
else
success = TRUE;
g_object_unref (file_info);
g_free (child_path);
g_clear_object (&child);
if (!success)
goto out;
}
if (file_info == NULL && temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
ret = TRUE;
out:
g_free (triggerdir_path);
g_clear_object (&triggerdir);
g_clear_object (&enumerator);
return ret;
}
-59
View File
@@ -1,59 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#ifndef _OSTREE_CHECKOUT
#define _OSTREE_CHECKOUT
#include <ostree-repo.h>
G_BEGIN_DECLS
#define OSTREE_TYPE_CHECKOUT ostree_checkout_get_type()
#define OSTREE_CHECKOUT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_CHECKOUT, OstreeCheckout))
#define OSTREE_CHECKOUT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), OSTREE_TYPE_CHECKOUT, OstreeCheckoutClass))
#define OSTREE_IS_CHECKOUT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_CHECKOUT))
#define OSTREE_IS_CHECKOUT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), OSTREE_TYPE_CHECKOUT))
#define OSTREE_CHECKOUT_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), OSTREE_TYPE_CHECKOUT, OstreeCheckoutClass))
typedef struct {
GObject parent;
} OstreeCheckout;
typedef struct {
GObjectClass parent_class;
} OstreeCheckoutClass;
GType ostree_checkout_get_type (void);
OstreeCheckout* ostree_checkout_new (OstreeRepo *repo,
const char *path);
gboolean ostree_checkout_run_triggers (OstreeCheckout *checkout,
GError **error);
G_END_DECLS
#endif /* _OSTREE_CHECKOUT */
-814
View File
@@ -1,814 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ostree.h"
#include "otutil.h"
#include <sys/types.h>
#include <attr/xattr.h>
gboolean
ostree_validate_checksum_string (const char *sha256,
GError **error)
{
if (strlen (sha256) != 64)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid rev '%s'", sha256);
return FALSE;
}
return TRUE;
}
void
ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode)
{
guint32 perms = (mode & ~S_IFMT);
g_checksum_update (checksum, (guint8*) &uid, 4);
g_checksum_update (checksum, (guint8*) &gid, 4);
g_checksum_update (checksum, (guint8*) &perms, 4);
}
static char *
canonicalize_xattrs (char *xattr_string, size_t len)
{
char *p;
GSList *xattrs = NULL;
GSList *iter;
GString *result;
result = g_string_new (0);
p = xattr_string;
while (p < xattr_string+len)
{
xattrs = g_slist_prepend (xattrs, p);
p += strlen (p) + 1;
}
xattrs = g_slist_sort (xattrs, (GCompareFunc) strcmp);
for (iter = xattrs; iter; iter = iter->next)
g_string_append (result, iter->data);
g_slist_free (xattrs);
return g_string_free (result, FALSE);
}
static gboolean
read_xattr_name_array (const char *path,
const char *xattrs,
size_t len,
GVariantBuilder *builder,
GError **error)
{
gboolean ret = FALSE;
const char *p;
p = xattrs;
while (p < xattrs+len)
{
ssize_t bytes_read;
char *buf;
bytes_read = lgetxattr (path, p, NULL, 0);
if (bytes_read < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
if (bytes_read == 0)
continue;
buf = g_malloc (bytes_read);
if (lgetxattr (path, p, buf, bytes_read) < 0)
{
ot_util_set_error_from_errno (error, errno);
g_free (buf);
goto out;
}
g_variant_builder_add (builder, "(@ay@ay)",
g_variant_new_bytestring (p),
g_variant_new_from_data (G_VARIANT_TYPE ("ay"),
buf, bytes_read, FALSE, g_free, buf));
p = p + strlen (p) + 1;
}
ret = TRUE;
out:
return ret;
}
GVariant *
ostree_get_xattrs_for_path (const char *path,
GError **error)
{
GVariant *ret = NULL;
GVariantBuilder builder;
char *xattr_names = NULL;
char *xattr_names_canonical = NULL;
ssize_t bytes_read;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)"));
bytes_read = llistxattr (path, NULL, 0);
if (bytes_read < 0)
{
if (errno != ENOTSUP)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
}
else if (bytes_read > 0)
{
xattr_names = g_malloc (bytes_read);
if (llistxattr (path, xattr_names, bytes_read) < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read);
if (!read_xattr_name_array (path, xattr_names_canonical, bytes_read, &builder, error))
goto out;
}
ret = g_variant_builder_end (&builder);
g_variant_ref_sink (ret);
out:
if (!ret)
g_variant_builder_clear (&builder);
g_free (xattr_names);
g_free (xattr_names_canonical);
return ret;
}
gboolean
ostree_stat_and_checksum_file (int dir_fd, const char *path,
OstreeObjectType objtype,
GChecksum **out_checksum,
struct stat *out_stbuf,
GError **error)
{
GChecksum *content_sha256 = NULL;
GChecksum *content_and_meta_sha256 = NULL;
char *stat_string = NULL;
ssize_t bytes_read;
GVariant *xattrs = NULL;
int fd = -1;
DIR *temp_dir = NULL;
char *basename = NULL;
gboolean ret = FALSE;
char *symlink_target = NULL;
char *device_id = NULL;
struct stat stbuf;
basename = g_path_get_basename (path);
if (dir_fd == -1)
{
char *dirname = g_path_get_dirname (path);
temp_dir = opendir (dirname);
if (temp_dir == NULL)
{
ot_util_set_error_from_errno (error, errno);
g_free (dirname);
}
g_free (dirname);
dir_fd = dirfd (temp_dir);
}
if (fstatat (dir_fd, basename, &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
if (S_ISREG(stbuf.st_mode))
{
fd = ot_util_open_file_read_at (dir_fd, basename, error);
if (fd < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
}
if (objtype == OSTREE_OBJECT_TYPE_FILE)
{
xattrs = ostree_get_xattrs_for_path (path, error);
if (!xattrs)
goto out;
}
content_sha256 = g_checksum_new (G_CHECKSUM_SHA256);
if (S_ISREG(stbuf.st_mode))
{
guint8 buf[8192];
while ((bytes_read = read (fd, buf, sizeof (buf))) > 0)
g_checksum_update (content_sha256, buf, bytes_read);
if (bytes_read < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
}
else if (S_ISLNK(stbuf.st_mode))
{
symlink_target = g_malloc (PATH_MAX);
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
bytes_read = readlinkat (dir_fd, basename, symlink_target, PATH_MAX);
if (bytes_read < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
g_checksum_update (content_sha256, (guint8*)symlink_target, bytes_read);
}
else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode))
{
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
device_id = g_strdup_printf ("%u", (guint)stbuf.st_rdev);
g_checksum_update (content_sha256, (guint8*)device_id, strlen (device_id));
}
else
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Unsupported file '%s' (must be regular, symbolic link, or device)",
path);
goto out;
}
content_and_meta_sha256 = g_checksum_copy (content_sha256);
if (objtype == OSTREE_OBJECT_TYPE_FILE)
{
ostree_checksum_update_stat (content_and_meta_sha256, stbuf.st_uid,
stbuf.st_gid, stbuf.st_mode);
g_checksum_update (content_and_meta_sha256, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
}
*out_stbuf = stbuf;
*out_checksum = content_and_meta_sha256;
ret = TRUE;
out:
if (fd >= 0)
close (fd);
if (temp_dir != NULL)
closedir (temp_dir);
g_free (symlink_target);
g_free (basename);
g_free (stat_string);
if (xattrs)
g_variant_unref (xattrs);
if (content_sha256)
g_checksum_free (content_sha256);
return ret;
}
gboolean
ostree_set_xattrs (const char *path, GVariant *xattrs, GError **error)
{
gboolean ret = FALSE;
int i, n;
n = g_variant_n_children (xattrs);
for (i = 0; i < n; i++)
{
const guint8* name;
GVariant *value;
const guint8* value_data;
gsize value_len;
gboolean loop_err;
g_variant_get_child (xattrs, i, "(^&ay@ay)",
&name, &value);
value_data = g_variant_get_fixed_array (value, &value_len, 1);
loop_err = lsetxattr (path, (char*)name, (char*)value_data, value_len, XATTR_REPLACE) < 0;
g_variant_unref (value);
if (loop_err)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
}
ret = TRUE;
out:
return ret;
}
gboolean
ostree_parse_metadata_file (const char *path,
OstreeSerializedVariantType *out_type,
GVariant **out_variant,
GError **error)
{
GMappedFile *mfile = NULL;
gboolean ret = FALSE;
GVariant *ret_variant = NULL;
GVariant *container = NULL;
guint32 ret_type;
mfile = g_mapped_file_new (path, FALSE, error);
if (mfile == NULL)
{
goto out;
}
else
{
container = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_SERIALIZED_VARIANT_FORMAT),
g_mapped_file_get_contents (mfile),
g_mapped_file_get_length (mfile),
FALSE,
(GDestroyNotify) g_mapped_file_unref,
mfile);
mfile = NULL;
g_variant_ref_sink (container);
g_variant_get (container, "(uv)",
&ret_type, &ret_variant);
ret_type = GUINT32_FROM_BE (ret_type);
if (ret_type <= 0 || ret_type > OSTREE_SERIALIZED_VARIANT_LAST)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted metadata object '%s'; invalid type %d", path, ret_type);
goto out;
}
}
ret = TRUE;
*out_type = ret_type;
*out_variant = g_variant_ref_sink (ret_variant);
ret_variant = NULL;
out:
if (ret_variant)
g_variant_unref (ret_variant);
if (container != NULL)
g_variant_unref (container);
if (mfile != NULL)
g_mapped_file_unref (mfile);
return ret;
}
char *
ostree_get_relative_object_path (const char *checksum,
OstreeObjectType type,
gboolean archive)
{
GString *path;
const char *type_string;
g_assert (strlen (checksum) == 64);
path = g_string_new ("objects/");
g_string_append_len (path, checksum, 2);
g_string_append_c (path, '/');
g_string_append (path, checksum + 2);
switch (type)
{
case OSTREE_OBJECT_TYPE_FILE:
if (archive)
type_string = ".packfile";
else
type_string = ".file";
break;
case OSTREE_OBJECT_TYPE_META:
type_string = ".meta";
break;
default:
g_assert_not_reached ();
}
g_string_append (path, type_string);
return g_string_free (path, FALSE);
}
gboolean
ostree_pack_object (GOutputStream *output,
GFile *file,
OstreeObjectType objtype,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
char *path = NULL;
GFileInfo *finfo = NULL;
GFileInputStream *instream = NULL;
gboolean pack_builder_initialized = FALSE;
GVariantBuilder pack_builder;
GVariant *pack_variant = NULL;
GVariant *xattrs = NULL;
gsize bytes_written;
path = g_file_get_path (file);
finfo = g_file_query_info (file, "standard::type,standard::size,standard::is-symlink,standard::symlink-target,unix::*",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error);
if (!finfo)
goto out;
if (objtype == OSTREE_OBJECT_TYPE_META)
{
guint64 object_size_be = GUINT64_TO_BE ((guint64)g_file_info_get_size (finfo));
if (!g_output_stream_write_all (output, &object_size_be, 8, &bytes_written, cancellable, error))
goto out;
instream = g_file_read (file, NULL, error);
if (!instream)
goto out;
if (g_output_stream_splice (output, (GInputStream*)instream, 0, cancellable, error) < 0)
goto out;
}
else
{
guint32 uid, gid, mode;
guint32 device = 0;
guint32 metadata_size_be;
const char *target = NULL;
guint64 object_size;
uid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_UID);
gid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_GID);
mode = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_MODE);
g_variant_builder_init (&pack_builder, G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT));
pack_builder_initialized = TRUE;
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (0));
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (uid));
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (gid));
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (mode));
xattrs = ostree_get_xattrs_for_path (path, error);
if (!xattrs)
goto out;
g_variant_builder_add (&pack_builder, "@a(ayay)", xattrs);
if (S_ISREG (mode))
{
object_size = (guint64)g_file_info_get_size (finfo);
}
else if (S_ISLNK (mode))
{
target = g_file_info_get_attribute_byte_string (finfo, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
object_size = strlen (target);
}
else if (S_ISBLK (mode) || S_ISCHR (mode))
{
device = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_DEVICE);
object_size = 4;
}
else
g_assert_not_reached ();
g_variant_builder_add (&pack_builder, "t", GUINT64_TO_BE (object_size));
pack_variant = g_variant_builder_end (&pack_builder);
pack_builder_initialized = FALSE;
metadata_size_be = GUINT32_TO_BE (g_variant_get_size (pack_variant));
if (!g_output_stream_write_all (output, &metadata_size_be, 4,
&bytes_written, cancellable, error))
goto out;
g_assert (bytes_written == 4);
if (!g_output_stream_write_all (output, g_variant_get_data (pack_variant), g_variant_get_size (pack_variant),
&bytes_written, cancellable, error))
goto out;
if (S_ISREG (mode))
{
instream = g_file_read (file, NULL, error);
if (!instream)
goto out;
bytes_written = g_output_stream_splice (output, (GInputStream*)instream, 0, cancellable, error);
if (bytes_written < 0)
goto out;
if (bytes_written != object_size)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"File size changed unexpectedly");
goto out;
}
}
else if (S_ISLNK (mode))
{
if (!g_output_stream_write_all (output, target, object_size,
&bytes_written, cancellable, error))
goto out;
}
else if (S_ISBLK (mode) || S_ISCHR (mode))
{
guint32 device_be = GUINT32_TO_BE (device);
g_assert (object_size == 4);
if (!g_output_stream_write_all (output, &device_be, object_size,
&bytes_written, cancellable, error))
goto out;
g_assert (bytes_written == 4);
}
else
g_assert_not_reached ();
}
ret = TRUE;
out:
g_free (path);
g_clear_object (&finfo);
g_clear_object (&instream);
if (xattrs)
g_variant_unref (xattrs);
if (pack_builder_initialized)
g_variant_builder_clear (&pack_builder);
if (pack_variant)
g_variant_unref (pack_variant);
return ret;
}
static gboolean
splice_and_checksum (GOutputStream *out,
GInputStream *in,
GChecksum *checksum,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
if (checksum != NULL)
{
gsize bytes_read, bytes_written;
char buf[4096];
do
{
if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error))
goto out;
if (checksum)
g_checksum_update (checksum, (guint8*)buf, bytes_read);
if (!g_output_stream_write_all (out, buf, bytes_read, &bytes_written, cancellable, error))
goto out;
}
while (bytes_read > 0);
}
else
{
if (g_output_stream_splice (out, in, 0, cancellable, error) < 0)
goto out;
}
ret = TRUE;
out:
return ret;
}
static gboolean
unpack_meta (const char *path,
const char *dest_path,
GChecksum **out_checksum,
GError **error)
{
gboolean ret = FALSE;
GFile *file = NULL;
GFile *dest_file = NULL;
GFileInputStream *in = NULL;
GChecksum *ret_checksum = NULL;
GFileOutputStream *out = NULL;
file = ot_util_new_file_for_path (path);
dest_file = ot_util_new_file_for_path (dest_path);
if (out_checksum)
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
in = g_file_read (file, NULL, error);
if (!in)
goto out;
out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
if (!out)
goto out;
if (!splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, ret_checksum, NULL, error))
goto out;
if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
goto out;
ret = TRUE;
if (out_checksum)
*out_checksum = ret_checksum;
ret_checksum = NULL;
out:
if (!ret)
(void) unlink (dest_path);
if (ret_checksum)
g_checksum_free (ret_checksum);
g_clear_object (&file);
g_clear_object (&dest_file);
g_clear_object (&in);
return ret;
}
static gboolean
unpack_file (const char *path,
const char *dest_path,
GChecksum **out_checksum,
GError **error)
{
gboolean ret = FALSE;
GFile *file = NULL;
GFile *dest_file = NULL;
char *metadata_buf = NULL;
GVariant *metadata = NULL;
GVariant *xattrs = NULL;
GFileInputStream *in = NULL;
GFileOutputStream *out = NULL;
GChecksum *ret_checksum = NULL;
guint32 metadata_len;
guint32 version, uid, gid, mode;
guint64 content_len;
gsize bytes_read, bytes_written;
int temp_fd = -1;
file = ot_util_new_file_for_path (path);
in = g_file_read (file, NULL, error);
if (!in)
goto out;
if (!g_input_stream_read_all ((GInputStream*)in, &metadata_len, 4, &bytes_read, NULL, error))
goto out;
if (bytes_read != 4)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted packfile; too short while reading metadata length");
goto out;
}
metadata_len = GUINT32_FROM_BE (metadata_len);
metadata_buf = g_malloc (metadata_len);
if (!g_input_stream_read_all ((GInputStream*)in, metadata_buf, metadata_len, &bytes_read, NULL, error))
goto out;
if (bytes_read != metadata_len)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted packfile; too short while reading metadata");
goto out;
}
metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT),
metadata_buf, metadata_len, FALSE, NULL, NULL);
g_variant_get (metadata, "(uuuu@a(ayay)t)",
&version, &uid, &gid, &mode,
&xattrs, &content_len);
uid = GUINT32_FROM_BE (uid);
gid = GUINT32_FROM_BE (gid);
mode = GUINT32_FROM_BE (mode);
content_len = GUINT64_FROM_BE (content_len);
dest_file = ot_util_new_file_for_path (dest_path);
if (out_checksum)
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
if (S_ISREG (mode))
{
out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
if (!out)
goto out;
if (!splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, ret_checksum, NULL, error))
goto out;
if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
goto out;
}
else if (S_ISLNK (mode))
{
char target[PATH_MAX+1];
if (!g_input_stream_read_all ((GInputStream*)in, target, sizeof(target)-1, &bytes_read, NULL, error))
goto out;
target[bytes_read] = '\0';
if (ret_checksum)
g_checksum_update (ret_checksum, (guint8*)target, bytes_read);
if (symlink (target, dest_path) < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
}
else if (S_ISCHR (mode) || S_ISBLK (mode))
{
guint32 dev;
if (!g_input_stream_read_all ((GInputStream*)in, &dev, 4, &bytes_read, NULL, error))
goto out;
if (bytes_read != 4)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted packfile; too short while reading device id");
goto out;
}
dev = GUINT32_FROM_BE (dev);
if (ret_checksum)
g_checksum_update (ret_checksum, (guint8*)&dev, 4);
if (mknod (dest_path, mode, dev) < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
}
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted packfile; invalid mode %u", mode);
goto out;
}
if (!S_ISLNK (mode))
{
if (chmod (dest_path, mode) < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
}
if (!ostree_set_xattrs (dest_path, xattrs, error))
goto out;
if (ret_checksum)
{
ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
}
ret = TRUE;
if (out_checksum)
*out_checksum = ret_checksum;
ret_checksum = NULL;
out:
if (!ret)
(void) unlink (dest_path);
if (ret_checksum)
g_checksum_free (ret_checksum);
g_free (metadata_buf);
g_clear_object (&file);
g_clear_object (&dest_file);
g_clear_object (&in);
g_clear_object (&out);
if (metadata)
g_variant_unref (metadata);
if (xattrs)
g_variant_unref (xattrs);
return ret;
}
gboolean
ostree_unpack_object (const char *path,
OstreeObjectType objtype,
const char *dest_path,
GChecksum **out_checksum,
GError **error)
{
if (objtype == OSTREE_OBJECT_TYPE_META)
return unpack_meta (path, dest_path, out_checksum, error);
else
return unpack_file (path, dest_path, out_checksum, error);
}
-143
View File
@@ -1,143 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#ifndef _OSTREE_CORE
#define _OSTREE_CORE
#include <otutil.h>
G_BEGIN_DECLS
#define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
typedef enum {
OSTREE_OBJECT_TYPE_FILE = 1,
OSTREE_OBJECT_TYPE_META = 2,
} OstreeObjectType;
typedef enum {
OSTREE_SERIALIZED_TREE_VARIANT = 1,
OSTREE_SERIALIZED_COMMIT_VARIANT = 2,
OSTREE_SERIALIZED_DIRMETA_VARIANT = 3,
OSTREE_SERIALIZED_XATTR_VARIANT = 4
} OstreeSerializedVariantType;
#define OSTREE_SERIALIZED_VARIANT_LAST 4
#define OSTREE_SERIALIZED_VARIANT_FORMAT "(uv)"
/*
* xattr objects:
* a(ayay) - array of (name, value) pairs, both binary data, though name is a bytestring
*/
#define OSTREE_XATTR_GVARIANT_FORMAT "a(ayay)"
#define OSTREE_DIR_META_VERSION 0
/*
* dirmeta objects:
* u - Version
* u - uid
* u - gid
* u - mode
* a(ayay) - xattrs
*/
#define OSTREE_DIRMETA_GVARIANT_FORMAT "(uuuua(ayay))"
#define OSTREE_TREE_VERSION 0
/*
* Tree objects:
* u - Version
* a{sv} - Metadata
* a(ss) - array of (filename, checksum) for files
* a(sss) - array of (dirname, tree_checksum, meta_checksum) for directories
*/
#define OSTREE_TREE_GVARIANT_FORMAT "(ua{sv}a(ss)a(sss)"
#define OSTREE_COMMIT_VERSION 0
/*
* Commit objects:
* u - Version
* a{sv} - Metadata
* s - parent checksum (empty string for initial)
* s - subject
* s - body
* t - Timestamp in seconds since the epoch (UTC)
* s - Root tree contents
* s - Root tree metadata
*/
#define OSTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}ssstss)"
gboolean ostree_validate_checksum_string (const char *sha256,
GError **error);
char *ostree_get_relative_object_path (const char *checksum,
OstreeObjectType type,
gboolean archive);
GVariant *ostree_get_xattrs_for_path (const char *path,
GError **error);
gboolean ostree_set_xattrs (const char *path, GVariant *xattrs, GError **error);
gboolean ostree_parse_metadata_file (const char *path,
OstreeSerializedVariantType *out_type,
GVariant **out_variant,
GError **error);
gboolean ostree_stat_and_checksum_file (int dirfd, const char *path,
OstreeObjectType type,
GChecksum **out_checksum,
struct stat *out_stbuf,
GError **error);
/* Packed files:
*
* guint32 metadata_length [metadata gvariant] [content]
*
* metadata variant:
* u - Version
* u - uid
* u - gid
* u - mode
* a(ayay) - xattrs
* t - content length
*
* And then following the end of the variant is the content. If
* symlink, then this is the target; if device, then device ID as
* network byte order uint32.
*/
#define OSTREE_PACK_FILE_VARIANT_FORMAT "(uuuua(ayay)t)"
gboolean ostree_pack_object (GOutputStream *output,
GFile *path,
OstreeObjectType objtype,
GCancellable *cancellable,
GError **error);
gboolean ostree_unpack_object (const char *path,
OstreeObjectType objtype,
const char *dest_path,
GChecksum **out_checksum,
GError **error);
void ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode);
#endif /* _OSTREE_REPO */
File diff suppressed because it is too large. Load diff
-151
View File
@@ -1,151 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
/* ostree-repo.h */
#ifndef _OSTREE_REPO
#define _OSTREE_REPO
#include <glib-object.h>
G_BEGIN_DECLS
#define OSTREE_TYPE_REPO ostree_repo_get_type()
#define OSTREE_REPO(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_REPO, OstreeRepo))
#define OSTREE_REPO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), OSTREE_TYPE_REPO, OstreeRepoClass))
#define OSTREE_IS_REPO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_REPO))
#define OSTREE_IS_REPO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), OSTREE_TYPE_REPO))
#define OSTREE_REPO_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), OSTREE_TYPE_REPO, OstreeRepoClass))
typedef struct {
GObject parent;
} OstreeRepo;
typedef struct {
GObjectClass parent_class;
} OstreeRepoClass;
GType ostree_repo_get_type (void);
OstreeRepo* ostree_repo_new (const char *path);
gboolean ostree_repo_check (OstreeRepo *self, GError **error);
const char * ostree_repo_get_path (OstreeRepo *self);
gboolean ostree_repo_is_archive (OstreeRepo *self);
GKeyFile * ostree_repo_get_config (OstreeRepo *self);
GKeyFile * ostree_repo_copy_config (OstreeRepo *self);
gboolean ostree_repo_write_config (OstreeRepo *self,
GKeyFile *new_config,
GError **error);
gboolean ostree_repo_link_file (OstreeRepo *self,
const char *path,
gboolean ignore_exists,
gboolean force,
GError **error);
gboolean ostree_repo_store_packfile (OstreeRepo *self,
const char *expected_checksum,
const char *path,
OstreeObjectType objtype,
GError **error);
gboolean ostree_repo_store_object_trusted (OstreeRepo *self,
const char *path,
const char *checksum,
OstreeObjectType objtype,
gboolean ignore_exists,
gboolean force,
gboolean *did_exist,
GError **error);
gboolean ostree_repo_resolve_rev (OstreeRepo *self,
const char *rev,
char **out_resolved,
GError **error);
gboolean ostree_repo_write_ref (OstreeRepo *self,
gboolean is_local,
const char *name,
const char *rev,
GError **error);
gboolean ostree_repo_load_variant (OstreeRepo *self,
const char *sha256,
OstreeSerializedVariantType *out_type,
GVariant **out_variant,
GError **error);
gboolean ostree_repo_load_variant_checked (OstreeRepo *self,
OstreeSerializedVariantType expected_type,
const char *sha256,
GVariant **out_variant,
GError **error);
gboolean ostree_repo_commit (OstreeRepo *self,
const char *branch,
const char *parent,
const char *subject,
const char *body,
GVariant *metadata,
const char *base,
GPtrArray *modified_files,
GPtrArray *removed_files,
GChecksum **out_commit,
GError **error);
gboolean ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
const char *branch,
const char *parent,
const char *subject,
const char *body,
GVariant *metadata,
const char *base,
int fd,
char separator,
GChecksum **out_commit,
GError **error);
gboolean ostree_repo_checkout (OstreeRepo *self,
const char *ref,
const char *destination,
GError **error);
typedef void (*OstreeRepoObjectIter) (OstreeRepo *self, const char *path,
GFileInfo *fileinfo, gpointer user_data);
gboolean ostree_repo_iter_objects (OstreeRepo *self,
OstreeRepoObjectIter callback,
gpointer user_data,
GError **error);
G_END_DECLS
#endif /* _OSTREE_REPO */
-28
View File
@@ -1,28 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#ifndef __OSTREE_H__
#include <ostree-core.h>
#include <ostree-repo.h>
#include <ostree-checkout.h>
#endif
-148
View File
@@ -1,148 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include <gio/gio.h>
#include <gio/gunixinputstream.h>
#include <string.h>
#include "otutil.h"
gboolean
ot_util_ensure_directory (const char *path, gboolean with_parents, GError **error)
{
GFile *dir;
GError *temp_error = NULL;
gboolean ret = FALSE;
dir = g_file_new_for_path (path);
if (with_parents)
ret = g_file_make_directory_with_parents (dir, NULL, &temp_error);
else
ret = g_file_make_directory (dir, NULL, &temp_error);
if (!ret)
{
if (!g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
{
g_propagate_error (error, temp_error);
goto out;
}
else
g_clear_error (&temp_error);
}
ret = TRUE;
out:
g_clear_object (&dir);
return ret;
}
char *
ot_util_get_file_contents_utf8 (const char *path,
GError **error)
{
GFile *file = NULL;
char *ret = NULL;
file = ot_util_new_file_for_path (path);
if (!ot_util_gfile_load_contents_utf8 (file, NULL, &ret, NULL, error))
goto out;
out:
g_clear_object (&file);
return ret;
}
gboolean
ot_util_gfile_load_contents_utf8 (GFile *file,
GCancellable *cancellable,
char **contents_out,
char **etag_out,
GError **error)
{
char *ret_contents = NULL;
char *ret_etag = NULL;
gsize len;
gboolean ret = FALSE;
if (!g_file_load_contents (file, cancellable, &ret_contents, &len, &ret_etag, error))
goto out;
if (!g_utf8_validate (ret_contents, len, NULL))
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"Invalid UTF-8");
goto out;
}
if (contents_out)
*contents_out = ret_contents;
else
g_free (ret_contents);
ret_contents = NULL;
if (etag_out)
*etag_out = ret_etag;
else
g_free (ret_etag);
ret_etag = NULL;
ret = TRUE;
out:
g_free (ret_contents);
g_free (ret_etag);
return ret;
}
GInputStream *
ot_util_read_file_noatime (GFile *file, GCancellable *cancellable, GError **error)
{
GInputStream *ret = NULL;
int fd;
int flags = O_RDONLY;
char *path = NULL;
path = g_file_get_path (file);
#ifdef O_NOATIME
flags |= O_NOATIME;
#endif
fd = open (path, flags);
if (fd < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
ret = (GInputStream*)g_unix_input_stream_new (fd, TRUE);
out:
g_free (path);
return ret;
}
/* Like g_file_new_for_path, but only do local stuff, not GVFS */
GFile *
ot_util_new_file_for_path (const char *path)
{
return g_vfs_get_file_for_path (g_vfs_get_local (), path);
}
-45
View File
@@ -1,45 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#ifndef __OSTREE_GIO_UTILS_H__
#define __OSTREE_GIO_UTILS_H__
#include <gio/gio.h>
G_BEGIN_DECLS
GFile *ot_util_new_file_for_path (const char *path);
gboolean ot_util_ensure_directory (const char *path, gboolean with_parents, GError **error);
char * ot_util_get_file_contents_utf8 (const char *path, GError **error);
gboolean ot_util_gfile_load_contents_utf8 (GFile *file,
GCancellable *cancellable,
char **contents_out,
char **etag_out,
GError **error);
GInputStream *ot_util_read_file_noatime (GFile *file, GCancellable *cancellable, GError **error);
G_END_DECLS
#endif
-37
View File
@@ -1,37 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include <gio/gio.h>
#include <string.h>
#include "otutil.h"
void
ot_util_usage_error (GOptionContext *context, const char *message, GError **error)
{
gchar *help = g_option_context_get_help (context, TRUE, NULL);
g_printerr ("%s\n", help);
g_free (help);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, message);
}
-33
View File
@@ -1,33 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#ifndef __OSTREE_GIO_UTILS_H__
#define __OSTREE_GIO_UTILS_H__
#include <gio/gio.h>
G_BEGIN_DECLS
void ot_util_usage_error (GOptionContext *context, const char *message, GError **error);
G_END_DECLS
#endif
-256
View File
@@ -1,256 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-unix-utils.h"
#include <gio/gio.h>
#include <gio/gunixoutputstream.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
gboolean
ot_util_spawn_pager (GOutputStream **out_stream,
GError **error)
{
const char *pager;
char *argv[2];
int stdin_fd;
pid_t pid;
gboolean ret = FALSE;
GOutputStream *ret_stream = NULL;
if (!isatty (1))
{
ret_stream = (GOutputStream*)g_unix_output_stream_new (1, TRUE);
}
else
{
pager = g_getenv ("GIT_PAGER");
if (pager == NULL)
pager = "less";
argv[0] = (char*)pager;
argv[1] = NULL;
if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, &pid, &stdin_fd, NULL, NULL, error))
{
g_prefix_error (error, "%s", "Failed to spawn pager: ");
goto out;
}
ret_stream = (GOutputStream*)g_unix_output_stream_new (stdin_fd, TRUE);
}
*out_stream = ret_stream;
ret_stream = NULL;
ret = TRUE;
out:
g_clear_object (&ret_stream);
return ret;
}
static int
compare_filenames_by_component_length (const char *a,
const char *b)
{
char *a_slash, *b_slash;
a_slash = strchr (a, '/');
b_slash = strchr (b, '/');
while (a_slash && b_slash)
{
a = a_slash + 1;
b = b_slash + 1;
a_slash = strchr (a, '/');
b_slash = strchr (b, '/');
}
if (a_slash)
return -1;
else if (b_slash)
return 1;
else
return 0;
}
GPtrArray *
ot_util_sort_filenames_by_component_length (GPtrArray *files)
{
GPtrArray *array = g_ptr_array_sized_new (files->len);
memcpy (array->pdata, files->pdata, sizeof (gpointer) * files->len);
g_ptr_array_sort (array, (GCompareFunc) compare_filenames_by_component_length);
return array;
}
int
ot_util_count_filename_components (const char *path)
{
int i = 0;
while (path)
{
i++;
path = strchr (path, '/');
if (path)
path++;
}
return i;
}
gboolean
ot_util_filename_has_dotdot (const char *path)
{
char *p;
char last;
if (strcmp (path, "..") == 0)
return TRUE;
if (g_str_has_prefix (path, "../"))
return TRUE;
p = strstr (path, "/..");
if (!p)
return FALSE;
last = *(p + 1);
return last == '\0' || last == '/';
}
GPtrArray *
ot_util_path_split (const char *path)
{
GPtrArray *ret = NULL;
const char *p;
const char *slash;
int i;
g_return_val_if_fail (path[0] != '/', NULL);
ret = g_ptr_array_new ();
g_ptr_array_set_free_func (ret, g_free);
p = path;
do {
slash = strchr (p, '/');
if (!slash)
{
g_ptr_array_add (ret, g_strdup (p));
p = NULL;
}
else
{
g_ptr_array_add (ret, g_strndup (p, slash - p));
p = slash + 1;
}
} while (p && *p);
/* Canonicalize by removing duplicate '.' */
for (i = ret->len-1; i >= 0; i--)
{
if (strcmp (ret->pdata[i], ".") == 0)
g_ptr_array_remove_index (ret, i);
}
return ret;
}
char *
ot_util_path_join_n (const char *base, GPtrArray *components, int n)
{
int max = MIN(n+1, components->len);
GPtrArray *subcomponents;
char *path;
int i;
subcomponents = g_ptr_array_new ();
if (base != NULL)
g_ptr_array_add (subcomponents, (char*)base);
for (i = 0; i < max; i++)
{
g_ptr_array_add (subcomponents, components->pdata[i]);
}
g_ptr_array_add (subcomponents, NULL);
path = g_build_filenamev ((char**)subcomponents->pdata);
g_ptr_array_free (subcomponents, TRUE);
return path;
}
void
ot_util_set_error_from_errno (GError **error,
gint saved_errno)
{
g_set_error_literal (error,
G_IO_ERROR,
0,
g_strerror (saved_errno));
errno = saved_errno;
}
int
ot_util_open_file_read (const char *path, GError **error)
{
char *dirname = NULL;
char *basename = NULL;
DIR *dir = NULL;
int fd = -1;
dirname = g_path_get_dirname (path);
basename = g_path_get_basename (path);
dir = opendir (dirname);
if (dir == NULL)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
fd = ot_util_open_file_read_at (dirfd (dir), basename, error);
out:
g_free (basename);
g_free (dirname);
if (dir != NULL)
closedir (dir);
return fd;
}
int
ot_util_open_file_read_at (int dirfd, const char *name, GError **error)
{
int fd;
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
#ifdef O_NOATIME
flags |= O_NOATIME;
#endif
fd = openat (dirfd, name, flags);
if (fd < 0)
ot_util_set_error_from_errno (error, errno);
return fd;
}
-59
View File
@@ -1,59 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#ifndef __OSTREE_UNIX_UTILS_H__
#define __OSTREE_UNIX_UTILS_H__
#include <gio/gio.h>
/* I just put all this shit here. Sue me. */
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
G_BEGIN_DECLS
gboolean ot_util_spawn_pager (GOutputStream **out_stream, GError **error);
gboolean ot_util_filename_has_dotdot (const char *path);
GPtrArray *ot_util_sort_filenames_by_component_length (GPtrArray *files);
GPtrArray* ot_util_path_split (const char *path);
char *ot_util_path_join_n (const char *base, GPtrArray *components, int n);
int ot_util_count_filename_components (const char *path);
int ot_util_open_file_read (const char *path, GError **error);
int ot_util_open_file_read_at (int dirfd, const char *name, GError **error);
void ot_util_set_error_from_errno (GError **error, gint saved_errno);
G_END_DECLS
#endif
-28
View File
@@ -1,28 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#ifndef __OSTREE_UTIL_H__
#include <ot-unix-utils.h>
#include <ot-gio-utils.h>
#include <ot-opt-utils.h>
#endif
-118
View File
@@ -1,118 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include <gio/gio.h>
#include <string.h>
#include "ot-builtins.h"
static OstreeBuiltin builtins[] = {
{ "checkout", ostree_builtin_checkout, 0 },
{ "init", ostree_builtin_init, 0 },
{ "commit", ostree_builtin_commit, 0 },
{ "link-file", ostree_builtin_link_file, 0 },
{ "log", ostree_builtin_log, 0 },
{ "pull", ostree_builtin_pull, 0 },
{ "fsck", ostree_builtin_fsck, 0 },
{ "remote", ostree_builtin_remote, 0 },
{ "rev-parse", ostree_builtin_rev_parse, 0 },
{ "remote", ostree_builtin_remote, 0 },
{ "run-triggers", ostree_builtin_run_triggers, 0 },
{ "show", ostree_builtin_show, 0 },
{ NULL }
};
static int
usage (char **argv, gboolean is_error)
{
OstreeBuiltin *builtin = builtins;
void (*print_func) (const gchar *format, ...);
if (is_error)
print_func = g_printerr;
else
print_func = g_print;
print_func ("usage: %s COMMAND [options]\n",
argv[0]);
print_func ("Builtin commands:\n");
while (builtin->name)
{
print_func (" %s\n", builtin->name);
builtin++;
}
return (is_error ? 1 : 0);
}
int
main (int argc,
char **argv)
{
OstreeBuiltin *builtin;
const char *cmd;
g_type_init ();
g_set_prgname (argv[0]);
builtin = builtins;
if (argc < 2)
return usage (argv, 1);
cmd = argv[1];
while (builtin->name)
{
GError *error = NULL;
if (strcmp (cmd, builtin->name) == 0)
{
int i;
int tmp_argc;
char **tmp_argv;
tmp_argc = argc - 1;
tmp_argv = g_new0 (char *, tmp_argc + 1);
tmp_argv[0] = (char*)builtin->name;
for (i = 0; i < tmp_argc; i++)
tmp_argv[i+1] = argv[i+2];
if (!builtin->fn (tmp_argc, tmp_argv, NULL, &error))
{
g_free (tmp_argv);
g_printerr ("%s\n", error->message);
g_clear_error (&error);
return 1;
}
g_free (tmp_argv);
return 0;
}
builtin++;
}
g_printerr ("Unknown command '%s'\n", cmd);
return usage (argv, 1);
}
-82
View File
@@ -1,82 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ NULL }
};
gboolean
ostree_builtin_checkout (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
OstreeCheckout *checkout = NULL;
const char *commit;
const char *destination;
context = g_option_context_new ("COMMIT DESTINATION - Check out a commit into a filesystem tree");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
if (argc < 3)
{
gchar *help = g_option_context_get_help (context, TRUE, NULL);
g_printerr ("%s\n", help);
g_free (help);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"COMMIT and DESTINATION must be specified");
goto out;
}
commit = argv[1];
destination = argv[2];
if (!ostree_repo_checkout (repo, commit, destination, error))
goto out;
ret = TRUE;
out:
if (context)
g_option_context_free (context);
g_clear_object (&repo);
g_clear_object (&checkout);
return ret;
}
-176
View File
@@ -1,176 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static gboolean separator_null;
static int from_fd = -1;
static gboolean from_stdin;
static char *from_file;
static char *subject;
static char *body;
static char *parent;
static char *branch;
static char **additions;
static char **removals;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ "subject", 's', 0, G_OPTION_ARG_STRING, &subject, "One line subject", "subject" },
{ "body", 'm', 0, G_OPTION_ARG_STRING, &body, "Full description", "body" },
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
{ "from-fd", 0, 0, G_OPTION_ARG_INT, &from_fd, "Read new tree files from fd", "file descriptor" },
{ "from-stdin", 0, 0, G_OPTION_ARG_NONE, &from_stdin, "Read new tree files from stdin", "file descriptor" },
{ "from-file", 0, 0, G_OPTION_ARG_FILENAME, &from_file, "Read new tree files from another file", "path" },
{ "separator-null", 0, 0, G_OPTION_ARG_NONE, &separator_null, "", "Use '\\0' as filename separator, as with find -print0" },
{ "add", 'a', 0, G_OPTION_ARG_FILENAME_ARRAY, &additions, "Relative file path to add", "filename" },
{ "remove", 'r', 0, G_OPTION_ARG_FILENAME_ARRAY, &removals, "Relative file path to remove", "filename" },
{ NULL }
};
gboolean
ostree_builtin_commit (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
gboolean using_filename_cmdline;
gboolean using_filedescriptors;
GPtrArray *additions_array = NULL;
GPtrArray *removals_array = NULL;
GChecksum *commit_checksum = NULL;
char **iter;
context = g_option_context_new ("- Commit a new revision");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
if (prefix == NULL)
prefix = ".";
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
using_filename_cmdline = (removals || additions);
using_filedescriptors = (from_file || from_fd >= 0 || from_stdin);
if (!(using_filename_cmdline || using_filedescriptors))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No additions or removals specified");
goto out;
}
if (using_filename_cmdline && using_filedescriptors)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"File descriptors may not be combined with --add or --remove");
goto out;
}
if (!branch)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"A branch must be specified with --branch");
goto out;
}
if (!subject)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"A subject must be specified with --subject");
goto out;
}
if (using_filename_cmdline)
{
g_assert (removals || additions);
additions_array = g_ptr_array_new ();
removals_array = g_ptr_array_new ();
if (additions)
for (iter = additions; *iter; iter++)
g_ptr_array_add (additions_array, *iter);
if (removals)
for (iter = removals; *iter; iter++)
g_ptr_array_add (removals_array, *iter);
if (!ostree_repo_commit (repo, branch, parent, subject, body, NULL,
prefix, additions_array,
removals_array,
&commit_checksum,
error))
goto out;
}
else if (using_filedescriptors)
{
char separator = separator_null ? '\0' : '\n';
gboolean temp_fd = -1;
if (from_stdin)
from_fd = 0;
else if (from_file)
{
temp_fd = ot_util_open_file_read (from_file, error);
if (temp_fd < 0)
{
g_prefix_error (error, "Failed to open '%s': ", from_file);
goto out;
}
from_fd = temp_fd;
}
if (!ostree_repo_commit_from_filelist_fd (repo, branch, parent, subject, body, NULL,
prefix, from_fd, separator,
&commit_checksum, error))
{
if (temp_fd >= 0)
close (temp_fd);
goto out;
}
if (temp_fd >= 0)
close (temp_fd);
}
ret = TRUE;
g_print ("%s\n", g_checksum_get_string (commit_checksum));
out:
if (context)
g_option_context_free (context);
g_clear_object (&repo);
if (removals_array)
g_ptr_array_free (removals_array, TRUE);
if (additions_array)
g_ptr_array_free (additions_array, TRUE);
if (commit_checksum)
g_checksum_free (commit_checksum);
return ret;
}
-229
View File
@@ -1,229 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static gboolean quiet;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", NULL },
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Don't display informational messages", NULL },
{ NULL }
};
typedef struct {
guint n_objects;
} HtFsckData;
static gboolean
checksum_packed_file (HtFsckData *data,
const char *path,
GChecksum **out_checksum,
GError **error)
{
gboolean ret = FALSE;
GChecksum *ret_checksum = NULL;
GFile *file = NULL;
char *metadata_buf = NULL;
GVariant *metadata = NULL;
GVariant *xattrs = NULL;
GFileInputStream *in = NULL;
guint32 metadata_len;
guint32 version, uid, gid, mode;
guint64 content_len;
gsize bytes_read;
char buf[8192];
file = ot_util_new_file_for_path (path);
in = g_file_read (file, NULL, error);
if (!in)
goto out;
if (!g_input_stream_read_all ((GInputStream*)in, &metadata_len, 4, &bytes_read, NULL, error))
goto out;
metadata_len = GUINT32_FROM_BE (metadata_len);
metadata_buf = g_malloc (metadata_len);
if (!g_input_stream_read_all ((GInputStream*)in, metadata_buf, metadata_len, &bytes_read, NULL, error))
goto out;
metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT),
metadata_buf, metadata_len, FALSE, NULL, NULL);
g_variant_get (metadata, "(uuuu@a(ayay)t)",
&version, &uid, &gid, &mode,
&xattrs, &content_len);
uid = GUINT32_FROM_BE (uid);
gid = GUINT32_FROM_BE (gid);
mode = GUINT32_FROM_BE (mode);
content_len = GUINT64_FROM_BE (content_len);
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
do
{
if (!g_input_stream_read_all ((GInputStream*)in, buf, sizeof(buf), &bytes_read, NULL, error))
goto out;
g_checksum_update (ret_checksum, (guint8*)buf, bytes_read);
}
while (bytes_read > 0);
ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
ret = TRUE;
*out_checksum = ret_checksum;
ret_checksum = NULL;
out:
if (ret_checksum)
g_checksum_free (ret_checksum);
g_free (metadata_buf);
g_clear_object (&file);
g_clear_object (&in);
if (metadata)
g_variant_unref (metadata);
if (xattrs)
g_variant_unref (xattrs);
return ret;
}
static void
object_iter_callback (OstreeRepo *repo,
const char *path,
GFileInfo *file_info,
gpointer user_data)
{
HtFsckData *data = user_data;
struct stat stbuf;
GChecksum *checksum = NULL;
GError *error = NULL;
char *dirname = NULL;
char *checksum_prefix = NULL;
char *checksum_string = NULL;
char *filename_checksum = NULL;
gboolean packed = FALSE;
OstreeObjectType objtype;
char *dot;
/* nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink");
if (nlinks < 2 && !quiet)
g_printerr ("note: floating object: %s\n", path); */
if (g_str_has_suffix (path, ".meta"))
objtype = OSTREE_OBJECT_TYPE_META;
else if (g_str_has_suffix (path, ".file"))
objtype = OSTREE_OBJECT_TYPE_FILE;
else if (g_str_has_suffix (path, ".packfile"))
{
objtype = OSTREE_OBJECT_TYPE_FILE;
packed = TRUE;
}
else
g_assert_not_reached ();
if (packed && objtype == OSTREE_OBJECT_TYPE_FILE)
{
if (!checksum_packed_file (data, path, &checksum, &error))
goto out;
}
else
{
if (!ostree_stat_and_checksum_file (-1, path, objtype, &checksum, &stbuf, &error))
goto out;
}
filename_checksum = g_strdup (g_file_info_get_name (file_info));
dot = strrchr (filename_checksum, '.');
g_assert (dot != NULL);
*dot = '\0';
dirname = g_path_get_dirname (path);
checksum_prefix = g_path_get_basename (dirname);
checksum_string = g_strconcat (checksum_prefix, filename_checksum, NULL);
if (strcmp (checksum_string, g_checksum_get_string (checksum)) != 0)
{
g_printerr ("ERROR: corrupted object '%s' expected checksum: %s\n",
path, g_checksum_get_string (checksum));
}
data->n_objects++;
out:
if (checksum != NULL)
g_checksum_free (checksum);
g_free (dirname);
g_free (checksum_prefix);
g_free (checksum_string);
g_free (filename_checksum);
if (error != NULL)
{
g_printerr ("%s\n", error->message);
g_clear_error (&error);
}
}
gboolean
ostree_builtin_fsck (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
HtFsckData data;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
context = g_option_context_new ("- Check the repository for consistency");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
data.n_objects = 0;
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
if (!ostree_repo_iter_objects (repo, object_iter_callback, &data, error))
goto out;
if (!quiet)
g_printerr ("Total Objects: %u\n", data.n_objects);
ret = TRUE;
out:
if (context)
g_option_context_free (context);
g_clear_object (&repo);
return ret;
}
-111
View File
@@ -1,111 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static gboolean archive;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", NULL },
{ "archive", 0, 0, G_OPTION_ARG_NONE, &archive, "Initialize repository as archive", NULL },
{ NULL }
};
#define DEFAULT_CONFIG_CONTENTS ("[core]\n" \
"repo_version=0\n")
gboolean
ostree_builtin_init (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context = NULL;
gboolean ret = FALSE;
GFile *repodir = NULL;
GFile *child = NULL;
GFile *grandchild = NULL;
GString *config_data = NULL;
context = g_option_context_new ("- Initialize a new empty repository");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
repodir = ot_util_new_file_for_path (repo_path);
child = g_file_get_child (repodir, "config");
config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
g_string_append_printf (config_data, "archive=%s\n", archive ? "true" : "false");
if (!g_file_replace_contents (child,
config_data->str,
config_data->len,
NULL, FALSE, 0, NULL,
NULL, error))
goto out;
g_clear_object (&child);
child = g_file_get_child (repodir, "objects");
if (!g_file_make_directory (child, NULL, error))
goto out;
g_clear_object (&child);
child = g_file_get_child (repodir, "refs");
if (!g_file_make_directory (child, NULL, error))
goto out;
grandchild = g_file_get_child (child, "heads");
if (!g_file_make_directory (grandchild, NULL, error))
goto out;
g_clear_object (&grandchild);
grandchild = g_file_get_child (child, "remotes");
if (!g_file_make_directory (grandchild, NULL, error))
goto out;
g_clear_object (&grandchild);
g_clear_object (&child);
child = g_file_get_child (repodir, "tags");
if (!g_file_make_directory (child, NULL, error))
goto out;
g_clear_object (&child);
ret = TRUE;
out:
if (context)
g_option_context_free (context);
if (config_data)
g_string_free (config_data, TRUE);
g_clear_object (&repodir);
g_clear_object (&child);
g_clear_object (&grandchild);
return ret;
}
-73
View File
@@ -1,73 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static gboolean ignore_exists;
static gboolean force;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ "ignore-exists", 'n', 0, G_OPTION_ARG_NONE, &ignore_exists, "Don't error if file exists", NULL },
{ "force", 'f', 0, G_OPTION_ARG_NONE, &force, "If object exists, relink file", NULL },
{ NULL }
};
gboolean
ostree_builtin_link_file (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
int i;
context = g_option_context_new ("- Create a new hard link in the repository");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
for (i = 0; i < argc-1; i++)
{
if (!ostree_repo_link_file (repo, argv[i+1], ignore_exists, force, error))
goto out;
}
ret = TRUE;
out:
if (context)
g_option_context_free (context);
g_clear_object (&repo);
return ret;
}
-161
View File
@@ -1,161 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ NULL }
};
gboolean
ostree_builtin_log (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
GOutputStream *pager = NULL;
const char *rev;
GVariant *commit = NULL;
char *resolved_rev = NULL;
context = g_option_context_new ("- Show revision log");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
if (prefix == NULL)
prefix = ".";
if (argc < 2)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"A revision must be specified");
goto out;
}
rev = argv[1];
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
if (!ot_util_spawn_pager (&pager, error))
goto out;
if (!ostree_repo_resolve_rev (repo, rev, &resolved_rev, error))
goto out;
while (TRUE)
{
OstreeSerializedVariantType type;
char *formatted = NULL;
guint32 version;
const char *parent;
const char *subject;
const char *body;
guint64 timestamp;
const char *contents;
const char *root_metadata;
GDateTime *time_obj = NULL;
char *formatted_date = NULL;
const char *body_newline;
gsize bytes_written;
GVariant *commit_metadata = NULL;
char *formatted_metadata = NULL;
if (commit)
g_variant_unref (commit);
if (!ostree_repo_load_variant (repo, resolved_rev, &type, &commit, error))
goto out;
/* Ignore commit metadata for now */
g_variant_get (commit, "(u@a{sv}&s&s&st&s&s)",
&version, &commit_metadata, &parent, &subject, &body,
&timestamp, &contents, &root_metadata);
version = GUINT32_FROM_BE (version);
timestamp = GUINT64_FROM_BE (timestamp);
time_obj = g_date_time_new_from_unix_utc (timestamp);
formatted_date = g_date_time_format (time_obj, "%a %b %d %H:%M:%S %Y %z");
g_date_time_unref (time_obj);
time_obj = NULL;
formatted_metadata = g_variant_print (commit_metadata, TRUE);
g_variant_unref (commit_metadata);
formatted = g_strdup_printf ("commit %s\nSubject: %s\nDate: %s\nMetadata: %s\n\n",
resolved_rev, subject, formatted_date, formatted_metadata);
g_free (formatted_metadata);
g_free (formatted_date);
formatted_date = NULL;
if (!g_output_stream_write_all (pager, formatted, strlen (formatted), &bytes_written, NULL, error))
{
g_free (formatted);
goto out;
}
g_free (formatted);
body_newline = strchr (body, '\n');
do {
gsize len;
if (!g_output_stream_write_all (pager, " ", 4, &bytes_written, NULL, error))
goto out;
len = body_newline ? body_newline - body : strlen (body);
if (!g_output_stream_write_all (pager, body, len, &bytes_written, NULL, error))
goto out;
if (!g_output_stream_write_all (pager, "\n\n", 2, &bytes_written, NULL, error))
goto out;
body_newline = strchr (body, '\n');
if (!body_newline)
break;
else
body_newline += 1;
} while (*body_newline);
if (strcmp (parent, "") == 0)
break;
g_free (resolved_rev);
resolved_rev = g_strdup (parent);
}
if (!g_output_stream_close (pager, NULL, error))
goto out;
ret = TRUE;
out:
g_free (resolved_rev);
if (context)
g_option_context_free (context);
if (commit)
g_variant_unref (commit);
g_clear_object (&repo);
return ret;
}
-355
View File
@@ -1,355 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
#include <libsoup/soup-gnome.h>
static char *repo_path;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ NULL }
};
static gboolean
fetch_uri (OstreeRepo *repo,
SoupSession *soup,
SoupURI *uri,
char **temp_filename,
GError **error)
{
gboolean ret = FALSE;
SoupMessage *msg = NULL;
guint response;
char *template = NULL;
int fd;
SoupBuffer *buf = NULL;
GFile *tempf = NULL;
msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
response = soup_session_send_message (soup, msg);
if (response != 200)
{
char *uri_string = soup_uri_to_string (uri, FALSE);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to retrieve '%s': %d %s",
uri_string, response, msg->reason_phrase);
g_free (uri_string);
goto out;
}
template = g_strdup_printf ("%s/tmp-fetchXXXXXX", ostree_repo_get_path (repo));
fd = g_mkstemp (template);
if (fd < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
close (fd);
tempf = ot_util_new_file_for_path (template);
buf = soup_message_body_flatten (msg->response_body);
if (!g_file_replace_contents (tempf, buf->data, buf->length, NULL, FALSE, 0, NULL, NULL, error))
goto out;
*temp_filename = template;
template = NULL;
ret = TRUE;
out:
g_free (template);
g_clear_object (&msg);
g_clear_object (&tempf);
return ret;
}
static gboolean
store_object (OstreeRepo *repo,
SoupSession *soup,
SoupURI *baseuri,
const char *object,
OstreeObjectType objtype,
gboolean *did_exist,
GError **error)
{
gboolean ret = FALSE;
char *filename = NULL;
char *objpath = NULL;
char *relpath = NULL;
SoupURI *obj_uri = NULL;
objpath = ostree_get_relative_object_path (object, objtype, TRUE);
obj_uri = soup_uri_copy (baseuri);
relpath = g_build_filename (soup_uri_get_path (obj_uri), objpath, NULL);
soup_uri_set_path (obj_uri, relpath);
if (!fetch_uri (repo, soup, obj_uri, &filename, error))
goto out;
if (!ostree_repo_store_packfile (repo, object, filename, objtype, error))
goto out;
ret = TRUE;
out:
if (obj_uri)
soup_uri_free (obj_uri);
if (filename)
(void) unlink (filename);
g_free (filename);
g_free (objpath);
g_free (relpath);
return ret;
}
static gboolean
store_tree_recurse (OstreeRepo *repo,
SoupSession *soup,
SoupURI *base_uri,
const char *rev,
GError **error)
{
gboolean ret = FALSE;
GVariant *tree = NULL;
GVariant *files_variant = NULL;
GVariant *dirs_variant = NULL;
OstreeSerializedVariantType metatype;
gboolean did_exist;
int i, n;
if (!store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_META, &did_exist, error))
goto out;
if (!did_exist)
{
if (!ostree_repo_load_variant (repo, rev, &metatype, &tree, error))
goto out;
if (metatype != OSTREE_SERIALIZED_TREE_VARIANT)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Tree metadata '%s' has wrong type %d, expected %d",
rev, metatype, OSTREE_SERIALIZED_TREE_VARIANT);
goto out;
}
/* PARSE OSTREE_SERIALIZED_TREE_VARIANT */
g_variant_get_child (tree, 2, "@a(ss)", &files_variant);
g_variant_get_child (tree, 3, "@a(sss)", &dirs_variant);
n = g_variant_n_children (files_variant);
for (i = 0; i < n; i++)
{
const char *filename;
const char *checksum;
g_variant_get_child (files_variant, i, "(ss)", &filename, &checksum);
if (!store_object (repo, soup, base_uri, checksum, OSTREE_OBJECT_TYPE_FILE, &did_exist, error))
goto out;
}
for (i = 0; i < n; i++)
{
const char *dirname;
const char *tree_checksum;
const char *meta_checksum;
g_variant_get_child (dirs_variant, i, "(sss)",
&dirname, &tree_checksum, &meta_checksum);
if (!store_tree_recurse (repo, soup, base_uri, tree_checksum, error))
goto out;
if (!store_object (repo, soup, base_uri, meta_checksum, OSTREE_OBJECT_TYPE_META, &did_exist, error))
goto out;
}
}
ret = TRUE;
out:
if (tree)
g_variant_unref (tree);
if (files_variant)
g_variant_unref (files_variant);
if (dirs_variant)
g_variant_unref (dirs_variant);
return ret;
}
static gboolean
store_commit_recurse (OstreeRepo *repo,
SoupSession *soup,
SoupURI *base_uri,
const char *rev,
GError **error)
{
gboolean ret = FALSE;
GVariant *commit = NULL;
OstreeSerializedVariantType metatype;
const char *tree_contents_checksum;
const char *tree_meta_checksum;
gboolean did_exist;
if (!store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_META, &did_exist, error))
goto out;
if (!did_exist)
{
if (!ostree_repo_load_variant (repo, rev, &metatype, &commit, error))
goto out;
if (metatype != OSTREE_SERIALIZED_COMMIT_VARIANT)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Commit '%s' has wrong type %d, expected %d",
rev, metatype, OSTREE_SERIALIZED_COMMIT_VARIANT);
goto out;
}
/* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
g_variant_get_child (commit, 6, "&s", &tree_contents_checksum);
g_variant_get_child (commit, 7, "&s", &tree_meta_checksum);
if (!store_object (repo, soup, base_uri, tree_meta_checksum, OSTREE_OBJECT_TYPE_META, &did_exist, error))
goto out;
if (!store_tree_recurse (repo, soup, base_uri, tree_contents_checksum, error))
goto out;
}
ret = TRUE;
out:
if (commit)
g_variant_unref (commit);
return ret;
}
gboolean
ostree_builtin_pull (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
const char *remote;
const char *branch;
char *remote_branch_ref_path = NULL;
char *key = NULL;
char *baseurl = NULL;
char *refpath = NULL;
char *temppath = NULL;
GKeyFile *config = NULL;
SoupURI *base_uri = NULL;
SoupURI *target_uri = NULL;
SoupSession *soup = NULL;
char *rev = NULL;
context = g_option_context_new ("REMOTE BRANCH - Download data from remote repository");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
if (argc < 3)
{
ot_util_usage_error (context, "REMOTE and BRANCH must be specified", error);
goto out;
}
remote = argv[1];
branch = argv[2];
config = ostree_repo_get_config (repo);
key = g_strdup_printf ("remote \"%s\"", remote);
baseurl = g_key_file_get_string (config, key, "url", error);
if (!baseurl)
goto out;
base_uri = soup_uri_new (baseurl);
if (!base_uri)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to parse url '%s'", baseurl);
goto out;
}
target_uri = soup_uri_copy (base_uri);
g_free (refpath);
refpath = g_build_filename (soup_uri_get_path (target_uri), "refs", "heads", branch, NULL);
soup_uri_set_path (target_uri, refpath);
soup = soup_session_sync_new_with_options (SOUP_SESSION_USER_AGENT, "ostree ",
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_GNOME_FEATURES_2_26,
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
NULL);
if (!fetch_uri (repo, soup, target_uri, &temppath, error))
goto out;
rev = ot_util_get_file_contents_utf8 (temppath, error);
if (!rev)
goto out;
g_strchomp (rev);
if (!ostree_validate_checksum_string (rev, error))
goto out;
if (!store_commit_recurse (repo, soup, base_uri, rev, error))
goto out;
if (!ostree_repo_write_ref (repo, FALSE, branch, rev, error))
goto out;
ret = TRUE;
out:
if (context)
g_option_context_free (context);
if (temppath)
(void) unlink (temppath);
g_free (temppath);
g_free (key);
g_free (rev);
g_free (baseurl);
g_free (refpath);
g_free (remote_branch_ref_path);
g_clear_object (&soup);
if (base_uri)
soup_uri_free (base_uri);
if (target_uri)
soup_uri_free (target_uri);
g_clear_object (&repo);
g_clear_object (&soup);
return ret;
}
-109
View File
@@ -1,109 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ NULL }
};
static void
usage_error (GOptionContext *context, const char *message, GError **error)
{
gchar *help = g_option_context_get_help (context, TRUE, NULL);
g_printerr ("%s\n", help);
g_free (help);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
message);
}
gboolean
ostree_builtin_remote (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
OstreeCheckout *checkout = NULL;
const char *op;
GKeyFile *config = NULL;
context = g_option_context_new ("OPERATION [args] - Control remote repository configuration");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
if (argc < 2)
{
usage_error (context, "OPERATION must be specified", error);
goto out;
}
op = argv[1];
config = ostree_repo_copy_config (repo);
if (!strcmp (op, "add"))
{
char *key;
if (argc < 4)
{
usage_error (context, "NAME and URL must be specified", error);
goto out;
}
key = g_strdup_printf ("remote \"%s\"", argv[2]);
g_key_file_set_string (config, key, "url", argv[3]);
g_free (key);
}
else
{
usage_error (context, "Unknown operation", error);
goto out;
}
if (!ostree_repo_write_config (repo, config, error))
goto out;
ret = TRUE;
out:
if (context)
g_option_context_free (context);
if (config)
g_key_file_unref (config);
g_clear_object (&repo);
g_clear_object (&checkout);
return ret;
}
-82
View File
@@ -1,82 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ NULL }
};
gboolean
ostree_builtin_rev_parse (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
const char *rev = "master";
char *resolved_rev = NULL;
GVariant *variant = NULL;
char *formatted_variant = NULL;
context = g_option_context_new ("REV - Output the target of a rev");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
if (argc < 2)
{
ot_util_usage_error (context, "REV must be specified", error);
goto out;
}
rev = argv[1];
if (!ostree_repo_resolve_rev (repo, rev, &resolved_rev, error))
goto out;
g_print ("%s\n", resolved_rev);
ret = TRUE;
out:
g_free (resolved_rev);
if (context)
g_option_context_free (context);
g_clear_object (&repo);
if (variant)
g_variant_unref (variant);
g_free (formatted_variant);
return ret;
}
-83
View File
@@ -1,83 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static gboolean quiet;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Don't display informational messages", NULL },
{ NULL }
};
gboolean
ostree_builtin_run_triggers (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
OstreeCheckout *checkout = NULL;
const char *dir;
context = g_option_context_new ("DIR - Run trigger scripts for directory");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
if (argc < 1)
{
gchar *help = g_option_context_get_help (context, TRUE, NULL);
g_printerr ("%s\n", help);
g_free (help);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"DIR must be specified");
goto out;
}
dir = argv[1];
checkout = ostree_checkout_new (repo, dir);
if (!ostree_checkout_run_triggers (checkout, error))
goto out;
ret = TRUE;
out:
if (context)
g_option_context_free (context);
g_clear_object (&repo);
g_clear_object (&checkout);
return ret;
}
-84
View File
@@ -1,84 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "ot-builtins.h"
#include "ostree.h"
#include <glib/gi18n.h>
static char *repo_path;
static GOptionEntry options[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
{ NULL }
};
gboolean
ostree_builtin_show (int argc, char **argv, const char *prefix, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
const char *rev = "master";
char *resolved_rev = NULL;
OstreeSerializedVariantType type;
GVariant *variant = NULL;
char *formatted_variant = NULL;
context = g_option_context_new ("- Output a metadata object");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
if (repo_path == NULL)
repo_path = ".";
repo = ostree_repo_new (repo_path);
if (!ostree_repo_check (repo, error))
goto out;
if (argc > 1)
rev = argv[1];
if (!ostree_repo_resolve_rev (repo, rev, &resolved_rev, error))
goto out;
if (!ostree_repo_load_variant (repo, resolved_rev, &type, &variant, error))
goto out;
g_print ("Object: %s\nType: %d\n", resolved_rev, type);
formatted_variant = g_variant_print (variant, TRUE);
g_print ("%s\n", formatted_variant);
ret = TRUE;
out:
g_free (resolved_rev);
if (context)
g_option_context_free (context);
g_clear_object (&repo);
if (variant)
g_variant_unref (variant);
g_free (formatted_variant);
return ret;
}
-53
View File
@@ -1,53 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#ifndef __OSTREE_BUILTINS__
#define __OSTREE_BUILTINS__
#include <glib-object.h>
G_BEGIN_DECLS
typedef enum {
OSTREE_BUILTIN_FLAG_NONE = 0,
} OstreeBuiltinFlags;
typedef struct {
const char *name;
gboolean (*fn) (int argc, char **argv, const char *prefix, GError **error);
int flags; /* OstreeBuiltinFlags */
} OstreeBuiltin;
gboolean ostree_builtin_checkout (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_commit (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_init (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_log (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_link_file (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_pull (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_run_triggers (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_fsck (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_show (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_rev_parse (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_remote (int argc, char **argv, const char *prefix, GError **error);
G_END_DECLS
#endif