2011-10-11 20:58:50 -04:00
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright ( C ) 2011 Colin Walters < walters @ verbum . org >
*
2011-11-10 13:17:04 -05:00
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
2011-10-11 20:58:50 -04:00
*
2011-11-10 13:17:04 -05:00
* This library is distributed in the hope that it will be useful ,
2011-10-11 20:58:50 -04:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2011-11-10 13:17:04 -05:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
2011-10-11 20:58:50 -04:00
*
2011-11-10 13:17:04 -05:00
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the
* Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
2011-10-11 20:58:50 -04:00
*
* Author : Colin Walters < walters @ verbum . org >
*/
2011-10-26 14:10:20 -04:00
# define _GNU_SOURCE
2011-10-11 20:58:50 -04:00
# include "config.h"
2011-10-18 14:44:48 -04:00
# include "ostree.h"
# include "otutil.h"
2011-11-07 11:25:49 -05:00
# include "ostree-repo-file-enumerator.h"
2011-10-11 20:58:50 -04:00
2011-10-13 17:11:01 -04:00
# include <gio/gunixoutputstream.h>
2011-10-15 13:04:50 -04:00
# include <gio/gunixinputstream.h>
2011-10-13 17:11:01 -04:00
2011-10-11 20:58:50 -04:00
enum {
PROP_0 ,
PROP_PATH
} ;
2011-10-18 14:44:48 -04:00
G_DEFINE_TYPE ( OstreeRepo , ostree_repo , G_TYPE_OBJECT )
2011-10-11 20:58:50 -04:00
# define GET_PRIVATE(o) \
2011-10-18 14:44:48 -04:00
( G_TYPE_INSTANCE_GET_PRIVATE ( ( o ) , OSTREE_TYPE_REPO , OstreeRepoPrivate ) )
2011-10-11 20:58:50 -04:00
2011-10-18 14:44:48 -04:00
typedef struct _OstreeRepoPrivate OstreeRepoPrivate ;
2011-10-11 20:58:50 -04:00
2011-10-18 14:44:48 -04:00
struct _OstreeRepoPrivate {
2011-10-11 20:58:50 -04:00
char * path ;
2011-10-13 17:11:01 -04:00
GFile * repo_file ;
2011-11-08 18:17:07 -05:00
GFile * tmp_dir ;
2011-10-27 09:21:07 -04:00
GFile * local_heads_dir ;
2011-10-31 20:24:38 -04:00
GFile * remote_heads_dir ;
2011-10-11 20:58:50 -04:00
char * objects_path ;
2011-10-26 22:21:00 -04:00
char * config_path ;
2011-10-11 20:58:50 -04:00
gboolean inited ;
2011-10-26 22:21:00 -04:00
GKeyFile * config ;
2011-10-31 20:24:38 -04:00
gboolean archive ;
2011-10-11 20:58:50 -04:00
} ;
static void
2011-10-18 14:44:48 -04:00
ostree_repo_finalize ( GObject * object )
2011-10-11 20:58:50 -04:00
{
2011-10-18 14:44:48 -04:00
OstreeRepo * self = OSTREE_REPO ( object ) ;
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-11 22:05:16 -04:00
g_free ( priv - > path ) ;
2011-10-13 17:11:01 -04:00
g_clear_object ( & priv - > repo_file ) ;
2011-11-08 18:17:07 -05:00
g_clear_object ( & priv - > tmp_dir ) ;
2011-10-27 09:21:07 -04:00
g_clear_object ( & priv - > local_heads_dir ) ;
2011-10-31 20:24:38 -04:00
g_clear_object ( & priv - > remote_heads_dir ) ;
2011-10-11 22:05:16 -04:00
g_free ( priv - > objects_path ) ;
2011-10-26 22:21:00 -04:00
g_free ( priv - > config_path ) ;
if ( priv - > config )
g_key_file_free ( priv - > config ) ;
2011-10-11 22:05:16 -04:00
2011-10-18 14:44:48 -04:00
G_OBJECT_CLASS ( ostree_repo_parent_class ) - > finalize ( object ) ;
2011-10-11 20:58:50 -04:00
}
static void
2011-10-18 14:44:48 -04:00
ostree_repo_set_property ( GObject * object ,
2011-10-11 20:58:50 -04:00
guint prop_id ,
const GValue * value ,
GParamSpec * pspec )
{
2011-10-18 14:44:48 -04:00
OstreeRepo * self = OSTREE_REPO ( object ) ;
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-11 20:58:50 -04:00
switch ( prop_id )
{
case PROP_PATH :
priv - > path = g_value_dup_string ( value ) ;
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , prop_id , pspec ) ;
break ;
}
}
static void
2011-10-18 14:44:48 -04:00
ostree_repo_get_property ( GObject * object ,
2011-10-11 20:58:50 -04:00
guint prop_id ,
GValue * value ,
GParamSpec * pspec )
{
2011-10-18 14:44:48 -04:00
OstreeRepo * self = OSTREE_REPO ( object ) ;
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-11 20:58:50 -04:00
switch ( prop_id )
{
case PROP_PATH :
g_value_set_string ( value , priv - > path ) ;
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , prop_id , pspec ) ;
break ;
}
}
2011-10-11 22:05:16 -04:00
static GObject *
2011-10-18 14:44:48 -04:00
ostree_repo_constructor ( GType gtype ,
2011-10-11 22:05:16 -04:00
guint n_properties ,
GObjectConstructParam * properties )
{
GObject * object ;
GObjectClass * parent_class ;
2011-10-18 14:44:48 -04:00
OstreeRepoPrivate * priv ;
2011-10-11 22:05:16 -04:00
2011-10-18 14:44:48 -04:00
parent_class = G_OBJECT_CLASS ( ostree_repo_parent_class ) ;
2011-10-11 22:05:16 -04:00
object = parent_class - > constructor ( gtype , n_properties , properties ) ;
priv = GET_PRIVATE ( object ) ;
g_assert ( priv - > path ! = NULL ) ;
2011-10-13 17:11:01 -04:00
2011-10-18 14:44:48 -04:00
priv - > repo_file = ot_util_new_file_for_path ( priv - > path ) ;
2011-11-08 18:17:07 -05:00
priv - > tmp_dir = g_file_resolve_relative_path ( priv - > repo_file , " tmp " ) ;
2011-10-27 09:21:07 -04:00
priv - > local_heads_dir = g_file_resolve_relative_path ( priv - > repo_file , " refs/heads " ) ;
2011-10-31 20:24:38 -04:00
priv - > remote_heads_dir = g_file_resolve_relative_path ( priv - > repo_file , " refs/remotes " ) ;
2011-10-19 17:45:00 -04:00
priv - > objects_path = g_build_filename ( priv - > path , " objects " , NULL ) ;
2011-10-26 22:21:00 -04:00
priv - > config_path = g_build_filename ( priv - > path , " config " , NULL ) ;
2011-10-11 22:05:16 -04:00
return object ;
}
2011-10-11 20:58:50 -04:00
static void
2011-10-18 14:44:48 -04:00
ostree_repo_class_init ( OstreeRepoClass * klass )
2011-10-11 20:58:50 -04:00
{
GObjectClass * object_class = G_OBJECT_CLASS ( klass ) ;
2011-10-18 14:44:48 -04:00
g_type_class_add_private ( klass , sizeof ( OstreeRepoPrivate ) ) ;
2011-10-11 20:58:50 -04:00
2011-10-18 14:44:48 -04:00
object_class - > constructor = ostree_repo_constructor ;
object_class - > get_property = ostree_repo_get_property ;
object_class - > set_property = ostree_repo_set_property ;
object_class - > finalize = ostree_repo_finalize ;
2011-10-11 20:58:50 -04:00
g_object_class_install_property ( object_class ,
PROP_PATH ,
g_param_spec_string ( " path " ,
" " ,
" " ,
NULL ,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ) ) ;
}
static void
2011-10-18 14:44:48 -04:00
ostree_repo_init ( OstreeRepo * self )
2011-10-11 20:58:50 -04:00
{
}
2011-10-18 14:44:48 -04:00
OstreeRepo *
ostree_repo_new ( const char * path )
2011-10-11 20:58:50 -04:00
{
2011-10-18 14:44:48 -04:00
return g_object_new ( OSTREE_TYPE_REPO , " path " , path , NULL ) ;
2011-10-11 20:58:50 -04:00
}
2011-10-27 09:21:07 -04:00
static gboolean
parse_rev_file ( OstreeRepo * self ,
const char * path ,
char * * sha256 ,
GError * * error ) G_GNUC_UNUSED ;
static gboolean
parse_rev_file ( OstreeRepo * self ,
const char * path ,
char * * sha256 ,
GError * * error )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-13 17:11:01 -04:00
GError * temp_error = NULL ;
gboolean ret = FALSE ;
2011-10-27 09:21:07 -04:00
char * rev = NULL ;
2011-10-13 17:11:01 -04:00
2011-10-27 09:21:07 -04:00
rev = ot_util_get_file_contents_utf8 ( path , & temp_error ) ;
if ( rev = = NULL )
2011-10-13 17:11:01 -04:00
{
if ( g_error_matches ( temp_error , G_FILE_ERROR , G_FILE_ERROR_NOENT ) )
{
g_clear_error ( & temp_error ) ;
}
else
{
g_propagate_error ( error , temp_error ) ;
goto out ;
}
}
2011-10-14 22:56:40 -04:00
else
{
2011-10-27 09:21:07 -04:00
g_strchomp ( rev ) ;
}
if ( g_str_has_prefix ( rev , " ref: " ) )
{
GFile * ref ;
char * ref_path ;
char * ref_sha256 ;
gboolean subret ;
ref = g_file_resolve_relative_path ( priv - > local_heads_dir , rev + 5 ) ;
ref_path = g_file_get_path ( ref ) ;
subret = parse_rev_file ( self , ref_path , & ref_sha256 , error ) ;
g_clear_object ( & ref ) ;
g_free ( ref_path ) ;
if ( ! subret )
{
g_free ( ref_sha256 ) ;
goto out ;
}
g_free ( rev ) ;
rev = ref_sha256 ;
}
else
{
2011-10-31 20:24:38 -04:00
if ( ! ostree_validate_checksum_string ( rev , error ) )
2011-10-27 09:21:07 -04:00
goto out ;
2011-10-14 22:56:40 -04:00
}
2011-10-13 17:11:01 -04:00
2011-10-27 09:21:07 -04:00
* sha256 = rev ;
rev = NULL ;
2011-10-13 17:11:01 -04:00
ret = TRUE ;
out :
2011-10-27 09:21:07 -04:00
g_free ( rev ) ;
2011-10-13 17:11:01 -04:00
return ret ;
}
2011-10-14 22:56:40 -04:00
static gboolean
2011-10-27 09:21:07 -04:00
resolve_rev ( OstreeRepo * self ,
const char * rev ,
gboolean allow_noent ,
char * * sha256 ,
GError * * error )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
gboolean ret = FALSE ;
2011-11-02 13:22:13 -04:00
char * tmp = NULL ;
char * tmp2 = NULL ;
2011-10-27 09:21:07 -04:00
char * ret_rev = NULL ;
GFile * child = NULL ;
char * child_path = NULL ;
GError * temp_error = NULL ;
2011-11-02 13:22:13 -04:00
GVariant * commit = NULL ;
if ( strlen ( rev ) = = 0 )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Invalid empty rev " ) ;
goto out ;
}
else if ( strlen ( rev ) = = 64 )
{
ret_rev = g_strdup ( rev ) ;
}
else if ( g_str_has_suffix ( rev , " ^ " ) )
{
tmp = g_strdup ( rev ) ;
tmp [ strlen ( tmp ) - 1 ] = ' \0 ' ;
if ( ! resolve_rev ( self , tmp , allow_noent , & tmp2 , error ) )
goto out ;
if ( ! ostree_repo_load_variant_checked ( self , OSTREE_SERIALIZED_COMMIT_VARIANT , tmp2 , & commit , error ) )
goto out ;
g_variant_get_child ( commit , 2 , " s " , & ret_rev ) ;
if ( strlen ( ret_rev ) = = 0 )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Commit %s has no parent " , tmp2 ) ;
goto out ;
2011-10-27 09:21:07 -04:00
2011-11-02 13:22:13 -04:00
}
}
else
{
child = g_file_get_child ( priv - > local_heads_dir , rev ) ;
child_path = g_file_get_path ( child ) ;
if ( ! ot_util_gfile_load_contents_utf8 ( child , NULL , & ret_rev , NULL , & temp_error ) )
{
if ( allow_noent & & g_error_matches ( temp_error , G_IO_ERROR , G_IO_ERROR_NOT_FOUND ) )
{
g_free ( ret_rev ) ;
ret_rev = NULL ;
}
else
{
g_propagate_error ( error , temp_error ) ;
g_prefix_error ( error , " Couldn't open ref '%s': " , child_path ) ;
goto out ;
}
}
else
{
g_strchomp ( ret_rev ) ;
2011-10-27 09:21:07 -04:00
2011-11-02 13:22:13 -04:00
if ( ! ostree_validate_checksum_string ( ret_rev , error ) )
goto out ;
}
}
2011-10-27 09:21:07 -04:00
* sha256 = ret_rev ;
ret_rev = NULL ;
ret = TRUE ;
out :
2011-11-02 13:22:13 -04:00
if ( commit )
g_variant_unref ( commit ) ;
g_free ( tmp ) ;
g_free ( tmp2 ) ;
2011-10-27 09:21:07 -04:00
g_clear_object ( & child ) ;
g_free ( child_path ) ;
g_free ( ret_rev ) ;
return ret ;
}
gboolean
ostree_repo_resolve_rev ( OstreeRepo * self ,
const char * rev ,
char * * sha256 ,
GError * * error )
{
2011-11-03 21:50:00 -04:00
g_return_val_if_fail ( rev ! = NULL , FALSE ) ;
2011-10-27 09:21:07 -04:00
return resolve_rev ( self , rev , FALSE , sha256 , error ) ;
}
static gboolean
write_checksum_file ( GFile * parentdir ,
const char * name ,
2011-10-14 22:56:40 -04:00
const char * sha256 ,
2011-10-27 09:21:07 -04:00
GError * * error )
2011-10-14 22:56:40 -04:00
{
gboolean ret = FALSE ;
2011-10-27 09:21:07 -04:00
GFile * child = NULL ;
GOutputStream * out = NULL ;
gsize bytes_written ;
2011-10-14 22:56:40 -04:00
2011-10-27 09:21:07 -04:00
child = g_file_get_child ( parentdir , name ) ;
if ( ( out = ( GOutputStream * ) g_file_replace ( child , NULL , FALSE , 0 , NULL , error ) ) = = NULL )
goto out ;
if ( ! g_output_stream_write_all ( out , sha256 , strlen ( sha256 ) , & bytes_written , NULL , error ) )
goto out ;
if ( ! g_output_stream_write_all ( out , " \n " , 1 , & bytes_written , NULL , error ) )
goto out ;
if ( ! g_output_stream_close ( out , NULL , error ) )
2011-10-14 22:56:40 -04:00
goto out ;
ret = TRUE ;
out :
2011-10-27 09:21:07 -04:00
g_clear_object ( & child ) ;
g_clear_object ( & out ) ;
2011-10-14 22:56:40 -04:00
return ret ;
}
2011-10-31 20:24:38 -04:00
/**
* ostree_repo_get_config :
* @ self :
*
* Returns : ( transfer none ) : The repository configuration ; do not modify
*/
GKeyFile *
ostree_repo_get_config ( OstreeRepo * self )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
g_return_val_if_fail ( priv - > inited , NULL ) ;
return priv - > config ;
}
/**
* ostree_repo_copy_config :
* @ self :
*
* Returns : ( transfer full ) : A newly - allocated copy of the repository config
*/
GKeyFile *
ostree_repo_copy_config ( OstreeRepo * self )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
GKeyFile * copy ;
char * data ;
gsize len ;
g_return_val_if_fail ( priv - > inited , NULL ) ;
copy = g_key_file_new ( ) ;
data = g_key_file_to_data ( priv - > config , & len , NULL ) ;
if ( ! g_key_file_load_from_data ( copy , data , len , 0 , NULL ) )
g_assert_not_reached ( ) ;
g_free ( data ) ;
return copy ;
}
/**
* ostree_repo_write_config :
* @ self :
* @ new_config : Overwrite the config file with this data . Do not change later !
* @ error : a # GError
*
* Save @ new_config in place of this repository ' s config file . Note
* that @ new_config should not be modified after - this function
* simply adds a reference .
*/
gboolean
ostree_repo_write_config ( OstreeRepo * self ,
GKeyFile * new_config ,
GError * * error )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
char * data = NULL ;
gsize len ;
gboolean ret = FALSE ;
g_return_val_if_fail ( priv - > inited , FALSE ) ;
data = g_key_file_to_data ( new_config , & len , error ) ;
if ( ! g_file_set_contents ( priv - > config_path , data , len , error ) )
goto out ;
g_key_file_unref ( priv - > config ) ;
priv - > config = g_key_file_ref ( new_config ) ;
ret = TRUE ;
out :
g_free ( data ) ;
return ret ;
}
2011-10-11 20:58:50 -04:00
gboolean
2011-10-18 14:44:48 -04:00
ostree_repo_check ( OstreeRepo * self , GError * * error )
2011-10-11 20:58:50 -04:00
{
2011-10-18 14:44:48 -04:00
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-26 22:21:00 -04:00
gboolean ret = FALSE ;
char * version = NULL ; ;
2011-10-31 20:24:38 -04:00
GError * temp_error = NULL ;
2011-10-11 22:05:16 -04:00
2011-10-14 23:13:23 -04:00
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
2011-10-13 17:11:01 -04:00
if ( priv - > inited )
return TRUE ;
2011-10-11 22:05:16 -04:00
if ( ! g_file_test ( priv - > objects_path , G_FILE_TEST_IS_DIR ) )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Couldn't find objects directory '%s' " , priv - > objects_path ) ;
2011-10-26 22:21:00 -04:00
goto out ;
2011-10-11 22:05:16 -04:00
}
2011-10-11 20:58:50 -04:00
2011-10-26 22:21:00 -04:00
priv - > config = g_key_file_new ( ) ;
if ( ! g_key_file_load_from_file ( priv - > config , priv - > config_path , 0 , error ) )
{
g_prefix_error ( error , " Couldn't parse config file: " ) ;
goto out ;
}
2011-10-31 20:24:38 -04:00
version = g_key_file_get_value ( priv - > config , " core " , " repo_version " , & temp_error ) ;
if ( temp_error )
{
g_propagate_error ( error , temp_error ) ;
goto out ;
}
2011-10-13 17:11:01 -04:00
2011-10-26 22:21:00 -04:00
if ( strcmp ( version , " 0 " ) ! = 0 )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Invalid repository version '%s' " , version ) ;
goto out ;
}
2011-10-31 20:24:38 -04:00
priv - > archive = g_key_file_get_boolean ( priv - > config , " core " , " archive " , & temp_error ) ;
if ( temp_error )
{
if ( g_error_matches ( temp_error , G_KEY_FILE_ERROR , G_KEY_FILE_ERROR_NOT_FOUND ) )
{
g_clear_error ( & temp_error ) ;
}
else
{
g_propagate_error ( error , temp_error ) ;
goto out ;
}
}
2011-10-26 22:21:00 -04:00
priv - > inited = TRUE ;
ret = TRUE ;
out :
g_free ( version ) ;
return ret ;
2011-10-11 20:58:50 -04:00
}
2011-10-31 20:24:38 -04:00
const char *
ostree_repo_get_path ( OstreeRepo * self )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
return priv - > path ;
}
gboolean
ostree_repo_is_archive ( OstreeRepo * self )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
g_return_val_if_fail ( priv - > inited , FALSE ) ;
return priv - > archive ;
}
2011-10-13 17:11:01 -04:00
static gboolean
2011-11-08 18:17:07 -05:00
write_gvariant_to_tmp ( OstreeRepo * self ,
OstreeSerializedVariantType type ,
GVariant * variant ,
GChecksum * * out_checksum ,
GError * * error )
2011-10-13 17:11:01 -04:00
{
2011-10-18 14:44:48 -04:00
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-13 17:11:01 -04:00
GVariant * serialized = NULL ;
gboolean ret = FALSE ;
gsize bytes_written ;
char * tmp_name = NULL ;
2011-11-08 18:17:07 -05:00
char * dest_name = NULL ;
2011-10-13 17:11:01 -04:00
int fd = - 1 ;
GUnixOutputStream * stream = NULL ;
2011-11-08 18:17:07 -05:00
GChecksum * checksum ;
2011-10-13 17:11:01 -04:00
2011-10-31 22:41:50 -04:00
serialized = g_variant_new ( " (uv) " , GUINT32_TO_BE ( ( guint32 ) type ) , variant ) ;
2011-10-13 17:11:01 -04:00
2011-11-08 18:17:07 -05:00
tmp_name = g_build_filename ( ot_gfile_get_path_cached ( priv - > tmp_dir ) , " variant-tmp-XXXXXX " , NULL ) ;
2011-10-26 14:10:20 -04:00
fd = g_mkstemp ( tmp_name ) ;
2011-10-13 17:11:01 -04:00
if ( fd < 0 )
{
2011-10-18 14:44:48 -04:00
ot_util_set_error_from_errno ( error , errno ) ;
2011-10-13 17:11:01 -04:00
goto out ;
}
2011-11-08 18:17:07 -05:00
checksum = g_checksum_new ( G_CHECKSUM_SHA256 ) ;
2011-10-13 17:11:01 -04:00
stream = ( GUnixOutputStream * ) g_unix_output_stream_new ( fd , FALSE ) ;
if ( ! g_output_stream_write_all ( ( GOutputStream * ) stream ,
g_variant_get_data ( serialized ) ,
g_variant_get_size ( serialized ) ,
& bytes_written ,
NULL ,
error ) )
goto out ;
2011-11-08 18:17:07 -05:00
g_checksum_update ( checksum , ( guint8 * ) g_variant_get_data ( serialized ) , g_variant_get_size ( serialized ) ) ;
2011-10-13 17:11:01 -04:00
if ( ! g_output_stream_close ( ( GOutputStream * ) stream ,
NULL , error ) )
goto out ;
2011-11-08 18:17:07 -05:00
dest_name = g_build_filename ( ot_gfile_get_path_cached ( priv - > tmp_dir ) , g_checksum_get_string ( checksum ) , NULL ) ;
if ( rename ( tmp_name , dest_name ) < 0 )
{
ot_util_set_error_from_errno ( error , errno ) ;
goto out ;
}
2011-10-13 17:11:01 -04:00
ret = TRUE ;
2011-11-08 18:17:07 -05:00
* out_checksum = checksum ;
checksum = NULL ;
2011-10-13 17:11:01 -04:00
out :
/* Unconditionally unlink; if we suceeded, there's a new link, if not, clean up. */
( void ) unlink ( tmp_name ) ;
if ( fd ! = - 1 )
close ( fd ) ;
2011-11-08 18:17:07 -05:00
if ( checksum )
g_checksum_free ( checksum ) ;
2011-10-13 17:11:01 -04:00
if ( serialized ! = NULL )
g_variant_unref ( serialized ) ;
g_free ( tmp_name ) ;
2011-11-08 18:17:07 -05:00
g_free ( dest_name ) ;
2011-10-13 17:11:01 -04:00
g_clear_object ( & stream ) ;
return ret ;
}
2011-11-08 18:17:07 -05:00
static gboolean
import_gvariant_object ( OstreeRepo * self ,
OstreeSerializedVariantType type ,
GVariant * variant ,
GChecksum * * out_checksum ,
GError * * error )
{
gboolean ret = FALSE ;
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
char * tmp_name = NULL ;
GChecksum * ret_checksum = NULL ;
gboolean did_exist ;
if ( ! write_gvariant_to_tmp ( self , type , variant , & ret_checksum , error ) )
goto out ;
tmp_name = g_build_filename ( ot_gfile_get_path_cached ( priv - > tmp_dir ) ,
g_checksum_get_string ( ret_checksum ) , NULL ) ;
if ( ! ostree_repo_store_object_trusted ( self , tmp_name ,
g_checksum_get_string ( ret_checksum ) ,
OSTREE_OBJECT_TYPE_META ,
TRUE , FALSE , & did_exist , error ) )
goto out ;
ret = TRUE ;
* out_checksum = ret_checksum ;
ret_checksum = NULL ;
out :
( void ) unlink ( tmp_name ) ;
g_free ( tmp_name ) ;
if ( ret_checksum )
g_checksum_free ( ret_checksum ) ;
return ret ;
}
2011-11-02 13:22:13 -04:00
gboolean
ostree_repo_load_variant_checked ( OstreeRepo * self ,
OstreeSerializedVariantType expected_type ,
const char * sha256 ,
GVariant * * out_variant ,
GError * * error )
2011-10-14 22:09:44 -04:00
{
gboolean ret = FALSE ;
2011-10-18 14:44:48 -04:00
OstreeSerializedVariantType type ;
2011-10-14 22:09:44 -04:00
GVariant * ret_variant = NULL ;
2011-11-02 13:22:13 -04:00
if ( ! ostree_repo_load_variant ( self , sha256 , & type , & ret_variant , error ) )
2011-10-14 22:09:44 -04:00
goto out ;
if ( type ! = expected_type )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Corrupted metadata object '%s'; found type %u, expected %u " , sha256 ,
type , ( guint32 ) expected_type ) ;
goto out ;
}
ret = TRUE ;
* out_variant = ret_variant ;
2011-11-02 13:22:13 -04:00
ret_variant = NULL ;
2011-10-14 22:09:44 -04:00
out :
2011-11-02 13:22:13 -04:00
if ( ret_variant )
g_variant_unref ( ret_variant ) ;
2011-10-14 22:09:44 -04:00
return ret ;
}
2011-10-13 17:11:01 -04:00
static gboolean
2011-10-18 14:44:48 -04:00
import_directory_meta ( OstreeRepo * self ,
2011-10-13 17:11:01 -04:00
const char * path ,
GVariant * * out_variant ,
GChecksum * * out_checksum ,
GError * * error )
{
gboolean ret = FALSE ;
struct stat stbuf ;
GChecksum * ret_checksum = NULL ;
GVariant * dirmeta = NULL ;
2011-10-15 03:03:51 -04:00
GVariant * xattrs = NULL ;
2011-10-13 17:11:01 -04:00
if ( lstat ( path , & stbuf ) < 0 )
{
2011-10-18 14:44:48 -04:00
ot_util_set_error_from_errno ( error , errno ) ;
2011-10-13 17:11:01 -04:00
goto out ;
}
if ( ! S_ISDIR ( stbuf . st_mode ) )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Not a directory: '%s' " , path ) ;
goto out ;
}
2011-10-18 14:44:48 -04:00
xattrs = ostree_get_xattrs_for_path ( path , error ) ;
2011-10-15 03:03:51 -04:00
if ( ! xattrs )
2011-10-13 17:11:01 -04:00
goto out ;
2011-10-15 03:03:51 -04:00
dirmeta = g_variant_new ( " (uuuu@a(ayay)) " ,
2011-10-18 14:44:48 -04:00
OSTREE_DIR_META_VERSION ,
2011-10-31 22:41:50 -04:00
GUINT32_TO_BE ( ( guint32 ) stbuf . st_uid ) ,
GUINT32_TO_BE ( ( guint32 ) stbuf . st_gid ) ,
GUINT32_TO_BE ( ( guint32 ) stbuf . st_mode ) ,
2011-10-15 03:03:51 -04:00
xattrs ) ;
2011-10-13 17:11:01 -04:00
g_variant_ref_sink ( dirmeta ) ;
2011-10-18 14:44:48 -04:00
if ( ! import_gvariant_object ( self , OSTREE_SERIALIZED_DIRMETA_VARIANT ,
2011-10-13 17:11:01 -04:00
dirmeta , & ret_checksum , error ) )
goto out ;
ret = TRUE ;
out :
if ( ! ret )
{
if ( ret_checksum )
g_checksum_free ( ret_checksum ) ;
if ( dirmeta ! = NULL )
g_variant_unref ( dirmeta ) ;
}
else
{
* out_checksum = ret_checksum ;
* out_variant = dirmeta ;
}
2011-10-15 03:03:51 -04:00
if ( xattrs )
g_variant_unref ( xattrs ) ;
2011-10-13 17:11:01 -04:00
return ret ;
}
2011-11-08 19:38:42 -05:00
char *
ostree_repo_get_object_path ( OstreeRepo * self ,
const char * checksum ,
OstreeObjectType type )
2011-10-13 17:11:01 -04:00
{
2011-10-18 14:44:48 -04:00
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-13 17:11:01 -04:00
char * ret ;
2011-10-31 20:24:38 -04:00
char * relpath ;
2011-10-13 17:11:01 -04:00
2011-10-31 20:24:38 -04:00
relpath = ostree_get_relative_object_path ( checksum , type , priv - > archive ) ;
ret = g_build_filename ( priv - > path , relpath , NULL ) ;
g_free ( relpath ) ;
2011-10-13 17:11:01 -04:00
return ret ;
}
2011-10-11 20:58:50 -04:00
static char *
2011-10-18 14:44:48 -04:00
prepare_dir_for_checksum_get_object_path ( OstreeRepo * self ,
2011-10-31 20:24:38 -04:00
const char * checksum ,
2011-10-18 14:44:48 -04:00
OstreeObjectType type ,
2011-10-11 22:05:16 -04:00
GError * * error )
2011-10-11 20:58:50 -04:00
{
2011-10-11 22:05:16 -04:00
char * checksum_dir = NULL ;
char * object_path = NULL ;
2011-10-11 20:58:50 -04:00
2011-11-08 19:38:42 -05:00
object_path = ostree_repo_get_object_path ( self , checksum , type ) ;
2011-10-13 17:11:01 -04:00
checksum_dir = g_path_get_dirname ( object_path ) ;
2011-10-11 20:58:50 -04:00
2011-10-18 14:44:48 -04:00
if ( ! ot_util_ensure_directory ( checksum_dir , FALSE , error ) )
2011-10-11 20:58:50 -04:00
goto out ;
out :
2011-10-11 22:05:16 -04:00
g_free ( checksum_dir ) ;
return object_path ;
2011-10-11 20:58:50 -04:00
}
static gboolean
2011-10-31 20:24:38 -04:00
link_object_trusted ( OstreeRepo * self ,
const char * path ,
const char * checksum ,
OstreeObjectType objtype ,
gboolean ignore_exists ,
gboolean force ,
gboolean * did_exist ,
GError * * error )
2011-10-11 20:58:50 -04:00
{
2011-10-11 22:05:16 -04:00
char * src_basename = NULL ;
char * src_dirname = NULL ;
char * dest_basename = NULL ;
2011-10-12 13:45:19 -04:00
char * tmp_dest_basename = NULL ;
2011-10-11 22:05:16 -04:00
char * dest_dirname = NULL ;
DIR * src_dir = NULL ;
DIR * dest_dir = NULL ;
2011-10-11 20:58:50 -04:00
gboolean ret = FALSE ;
char * dest_path = NULL ;
2011-10-11 22:05:16 -04:00
src_basename = g_path_get_basename ( path ) ;
src_dirname = g_path_get_dirname ( path ) ;
2011-10-11 20:58:50 -04:00
2011-10-11 22:05:16 -04:00
src_dir = opendir ( src_dirname ) ;
if ( src_dir = = NULL )
2011-10-11 20:58:50 -04:00
{
2011-10-18 14:44:48 -04:00
ot_util_set_error_from_errno ( error , errno ) ;
2011-10-11 20:58:50 -04:00
goto out ;
}
2011-10-31 20:24:38 -04:00
dest_path = prepare_dir_for_checksum_get_object_path ( self , checksum , objtype , error ) ;
2011-10-11 20:58:50 -04:00
if ( ! dest_path )
goto out ;
2011-10-11 22:05:16 -04:00
dest_basename = g_path_get_basename ( dest_path ) ;
dest_dirname = g_path_get_dirname ( dest_path ) ;
dest_dir = opendir ( dest_dirname ) ;
if ( dest_dir = = NULL )
{
2011-10-18 14:44:48 -04:00
ot_util_set_error_from_errno ( error , errno ) ;
2011-10-11 22:05:16 -04:00
goto out ;
}
2011-10-12 13:45:19 -04:00
if ( force )
{
tmp_dest_basename = g_strconcat ( dest_basename , " .tmp " , NULL ) ;
( void ) unlinkat ( dirfd ( dest_dir ) , tmp_dest_basename , 0 ) ;
}
else
tmp_dest_basename = g_strdup ( dest_basename ) ;
2011-10-11 20:58:50 -04:00
2011-10-12 13:45:19 -04:00
if ( linkat ( dirfd ( src_dir ) , src_basename , dirfd ( dest_dir ) , tmp_dest_basename , 0 ) < 0 )
2011-10-11 20:58:50 -04:00
{
2011-10-12 13:45:19 -04:00
if ( errno ! = EEXIST | | ! ignore_exists )
{
2011-10-18 14:44:48 -04:00
ot_util_set_error_from_errno ( error , errno ) ;
2011-10-12 13:45:19 -04:00
goto out ;
}
2011-10-31 20:24:38 -04:00
else
* did_exist = TRUE ;
2011-10-12 13:45:19 -04:00
}
2011-10-31 20:24:38 -04:00
else
* did_exist = FALSE ;
2011-10-12 13:45:19 -04:00
if ( force )
{
if ( renameat ( dirfd ( dest_dir ) , tmp_dest_basename ,
dirfd ( dest_dir ) , dest_basename ) < 0 )
{
2011-10-18 14:44:48 -04:00
ot_util_set_error_from_errno ( error , errno ) ;
2011-10-12 13:45:19 -04:00
goto out ;
}
( void ) unlinkat ( dirfd ( dest_dir ) , tmp_dest_basename , 0 ) ;
2011-10-11 20:58:50 -04:00
}
ret = TRUE ;
out :
2011-10-11 22:05:16 -04:00
if ( src_dir ! = NULL )
closedir ( src_dir ) ;
if ( dest_dir ! = NULL )
closedir ( dest_dir ) ;
g_free ( src_basename ) ;
g_free ( src_dirname ) ;
g_free ( dest_basename ) ;
2011-10-12 13:45:19 -04:00
g_free ( tmp_dest_basename ) ;
2011-10-11 22:05:16 -04:00
g_free ( dest_dirname ) ;
2011-11-01 12:20:33 -04:00
g_free ( dest_path ) ;
2011-10-11 20:58:50 -04:00
return ret ;
}
2011-10-31 20:24:38 -04:00
static gboolean
archive_file_trusted ( OstreeRepo * self ,
const char * path ,
const char * checksum ,
OstreeObjectType objtype ,
gboolean ignore_exists ,
gboolean force ,
gboolean * did_exist ,
GError * * error )
{
GFile * infile = NULL ;
GFile * outfile = NULL ;
GFileOutputStream * out = NULL ;
gboolean ret = FALSE ;
char * dest_path = NULL ;
char * dest_tmp_path = NULL ;
infile = ot_util_new_file_for_path ( path ) ;
dest_path = prepare_dir_for_checksum_get_object_path ( self , checksum , objtype , error ) ;
if ( ! dest_path )
goto out ;
dest_tmp_path = g_strconcat ( dest_path , " .tmp " , NULL ) ;
outfile = ot_util_new_file_for_path ( dest_tmp_path ) ;
out = g_file_replace ( outfile , NULL , FALSE , 0 , NULL , error ) ;
if ( ! out )
goto out ;
if ( ! ostree_pack_object ( ( GOutputStream * ) out , infile , objtype , NULL , error ) )
goto out ;
if ( ! g_output_stream_close ( ( GOutputStream * ) out , NULL , error ) )
goto out ;
if ( rename ( dest_tmp_path , dest_path ) < 0 )
{
ot_util_set_error_from_errno ( error , errno ) ;
goto out ;
}
ret = TRUE ;
out :
g_free ( dest_path ) ;
g_free ( dest_tmp_path ) ;
g_clear_object ( & infile ) ;
g_clear_object ( & outfile ) ;
g_clear_object ( & out ) ;
return ret ;
}
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 )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
if ( priv - > archive & & objtype = = OSTREE_OBJECT_TYPE_FILE )
return archive_file_trusted ( self , path , checksum , objtype , ignore_exists , force , did_exist , error ) ;
else
return link_object_trusted ( self , path , checksum , objtype , ignore_exists , force , did_exist , error ) ;
}
gboolean
ostree_repo_store_packfile ( OstreeRepo * self ,
const char * expected_checksum ,
const char * path ,
OstreeObjectType objtype ,
GError * * error )
{
2011-11-01 10:59:07 -04:00
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-31 20:24:38 -04:00
gboolean ret = FALSE ;
2011-11-01 10:59:07 -04:00
GString * tempfile_path = NULL ;
2011-10-31 20:24:38 -04:00
GChecksum * checksum = NULL ;
gboolean did_exist ;
2011-11-01 10:59:07 -04:00
tempfile_path = g_string_new ( priv - > path ) ;
g_string_append_printf ( tempfile_path , " /tmp-unpack-%s " , expected_checksum ) ;
if ( ! ostree_unpack_object ( path , objtype , tempfile_path - > str , & checksum , error ) )
goto out ;
2011-10-31 20:24:38 -04:00
if ( strcmp ( g_checksum_get_string ( checksum ) , expected_checksum ) ! = 0 )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Corrupted object %s (actual checksum is %s) " ,
expected_checksum , g_checksum_get_string ( checksum ) ) ;
goto out ;
}
2011-11-01 10:59:07 -04:00
if ( ! ostree_repo_store_object_trusted ( self , tempfile_path ? tempfile_path - > str : path ,
2011-10-31 20:24:38 -04:00
expected_checksum ,
objtype ,
TRUE , FALSE , & did_exist , error ) )
goto out ;
ret = TRUE ;
out :
2011-11-01 10:59:07 -04:00
if ( tempfile_path )
{
( void ) unlink ( tempfile_path - > str ) ;
g_string_free ( tempfile_path , TRUE ) ;
}
2011-10-31 20:24:38 -04:00
if ( checksum )
g_checksum_free ( checksum ) ;
return ret ;
}
2011-10-13 17:11:01 -04:00
typedef struct _ParsedTreeData ParsedTreeData ;
typedef struct _ParsedDirectoryData ParsedDirectoryData ;
static void parsed_tree_data_free ( ParsedTreeData * pdata ) ;
struct _ParsedDirectoryData {
ParsedTreeData * tree_data ;
char * metadata_sha256 ;
GVariant * meta_data ;
} ;
static void
parsed_directory_data_free ( ParsedDirectoryData * pdata )
{
if ( pdata = = NULL )
return ;
parsed_tree_data_free ( pdata - > tree_data ) ;
g_free ( pdata - > metadata_sha256 ) ;
g_variant_unref ( pdata - > meta_data ) ;
g_free ( pdata ) ;
}
struct _ParsedTreeData {
GHashTable * files ; /* char* filename -> char* checksum */
GHashTable * directories ; /* char* dirname -> ParsedDirectoryData* */
} ;
static ParsedTreeData *
parsed_tree_data_new ( void )
{
ParsedTreeData * ret = g_new0 ( ParsedTreeData , 1 ) ;
ret - > files = g_hash_table_new_full ( g_str_hash , g_str_equal ,
( GDestroyNotify ) g_free ,
( GDestroyNotify ) g_free ) ;
ret - > directories = g_hash_table_new_full ( g_str_hash , g_str_equal ,
( GDestroyNotify ) g_free ,
( GDestroyNotify ) parsed_directory_data_free ) ;
return ret ;
}
static void
parsed_tree_data_free ( ParsedTreeData * pdata )
{
if ( pdata = = NULL )
return ;
g_hash_table_destroy ( pdata - > files ) ;
g_hash_table_destroy ( pdata - > directories ) ;
g_free ( pdata ) ;
}
static GVariant *
create_empty_gvariant_dict ( void )
{
GVariantBuilder builder ;
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " a{sv} " ) ) ;
return g_variant_builder_end ( & builder ) ;
}
static gboolean
2011-10-18 14:44:48 -04:00
import_parsed_tree ( OstreeRepo * self ,
2011-10-13 17:11:01 -04:00
ParsedTreeData * tree ,
GChecksum * * out_checksum ,
GError * * error )
{
gboolean ret = FALSE ;
GVariant * serialized_tree = NULL ;
gboolean builders_initialized = FALSE ;
GVariantBuilder files_builder ;
GVariantBuilder dirs_builder ;
GHashTableIter hash_iter ;
2011-11-07 12:26:47 -05:00
GSList * sorted_filenames = NULL ;
GSList * iter ;
2011-10-13 17:11:01 -04:00
gpointer key , value ;
g_variant_builder_init ( & files_builder , G_VARIANT_TYPE ( " a(ss) " ) ) ;
g_variant_builder_init ( & dirs_builder , G_VARIANT_TYPE ( " a(sss) " ) ) ;
builders_initialized = TRUE ;
g_hash_table_iter_init ( & hash_iter , tree - > files ) ;
while ( g_hash_table_iter_next ( & hash_iter , & key , & value ) )
{
const char * name = key ;
2011-11-07 12:26:47 -05:00
sorted_filenames = g_slist_prepend ( sorted_filenames , ( char * ) name ) ;
}
sorted_filenames = g_slist_sort ( sorted_filenames , ( GCompareFunc ) strcmp ) ;
for ( iter = sorted_filenames ; iter ; iter = iter - > next )
{
const char * name = iter - > data ;
const char * value ;
2011-10-13 17:11:01 -04:00
2011-11-07 12:26:47 -05:00
value = g_hash_table_lookup ( tree - > files , name ) ;
g_variant_builder_add ( & files_builder , " (ss) " , name , value ) ;
2011-10-13 17:11:01 -04:00
}
2011-11-07 12:26:47 -05:00
g_slist_free ( sorted_filenames ) ;
sorted_filenames = NULL ;
2011-10-13 17:11:01 -04:00
g_hash_table_iter_init ( & hash_iter , tree - > directories ) ;
while ( g_hash_table_iter_next ( & hash_iter , & key , & value ) )
{
const char * name = key ;
2011-11-07 12:26:47 -05:00
sorted_filenames = g_slist_prepend ( sorted_filenames , ( char * ) name ) ;
}
sorted_filenames = g_slist_sort ( sorted_filenames , ( GCompareFunc ) strcmp ) ;
for ( iter = sorted_filenames ; iter ; iter = iter - > next )
{
const char * name = iter - > data ;
2011-10-13 17:11:01 -04:00
GChecksum * dir_checksum = NULL ;
2011-11-07 12:26:47 -05:00
ParsedDirectoryData * dir ;
dir = g_hash_table_lookup ( tree - > directories , name ) ;
2011-10-13 17:11:01 -04:00
if ( ! import_parsed_tree ( self , dir - > tree_data , & dir_checksum , error ) )
goto out ;
g_variant_builder_add ( & dirs_builder , " (sss) " ,
name , g_checksum_get_string ( dir_checksum ) , dir - > metadata_sha256 ) ;
2011-11-01 12:20:33 -04:00
g_checksum_free ( dir_checksum ) ;
2011-10-13 17:11:01 -04:00
}
2011-11-07 12:26:47 -05:00
g_slist_free ( sorted_filenames ) ;
sorted_filenames = NULL ;
2011-10-13 17:11:01 -04:00
serialized_tree = g_variant_new ( " (u@a{sv}@a(ss)@a(sss)) " ,
2011-10-31 22:41:50 -04:00
GUINT32_TO_BE ( 0 ) ,
2011-10-13 17:11:01 -04:00
create_empty_gvariant_dict ( ) ,
g_variant_builder_end ( & files_builder ) ,
g_variant_builder_end ( & dirs_builder ) ) ;
builders_initialized = FALSE ;
g_variant_ref_sink ( serialized_tree ) ;
2011-10-18 14:44:48 -04:00
if ( ! import_gvariant_object ( self , OSTREE_SERIALIZED_TREE_VARIANT , serialized_tree , out_checksum , error ) )
2011-10-13 17:11:01 -04:00
goto out ;
ret = TRUE ;
out :
2011-11-07 12:26:47 -05:00
g_slist_free ( sorted_filenames ) ;
2011-10-13 17:11:01 -04:00
if ( builders_initialized )
{
g_variant_builder_clear ( & files_builder ) ;
g_variant_builder_clear ( & dirs_builder ) ;
}
if ( serialized_tree )
g_variant_unref ( serialized_tree ) ;
return ret ;
}
static gboolean
check_path ( const char * filename ,
GError * * error )
{
gboolean ret = FALSE ;
if ( ! * filename )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Invalid empty filename " ) ;
goto out ;
}
2011-10-15 13:04:50 -04:00
if ( strcmp ( filename , " . " ) = = 0 )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Self-reference '.' in filename '%s' not allowed (yet) " , filename ) ;
goto out ;
}
2011-10-18 14:44:48 -04:00
if ( ot_util_filename_has_dotdot ( filename ) )
2011-10-13 17:11:01 -04:00
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Path uplink '..' in filename '%s' not allowed (yet) " , filename ) ;
goto out ;
}
if ( g_path_is_absolute ( filename ) )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Absolute filename '%s' not allowed (yet) " , filename ) ;
goto out ;
}
ret = TRUE ;
out :
return ret ;
}
static gboolean
2011-10-18 14:44:48 -04:00
add_one_directory_to_tree_and_import ( OstreeRepo * self ,
2011-10-13 17:11:01 -04:00
const char * basename ,
const char * abspath ,
ParsedTreeData * tree ,
2011-10-15 03:02:51 -04:00
ParsedDirectoryData * * dir , /*inout*/
2011-10-13 17:11:01 -04:00
GError * * error )
{
gboolean ret = FALSE ;
GVariant * dirmeta = NULL ;
GChecksum * dir_meta_checksum = NULL ;
2011-10-15 03:02:51 -04:00
ParsedDirectoryData * dir_value = * dir ;
2011-10-13 17:11:01 -04:00
g_assert ( tree ! = NULL ) ;
if ( ! import_directory_meta ( self , abspath , & dirmeta , & dir_meta_checksum , error ) )
goto out ;
2011-10-15 03:02:51 -04:00
if ( dir_value )
2011-10-13 17:11:01 -04:00
{
2011-10-15 03:02:51 -04:00
g_variant_unref ( dir_value - > meta_data ) ;
dir_value - > meta_data = dirmeta ;
2011-10-13 17:11:01 -04:00
}
else
{
2011-10-15 03:02:51 -04:00
dir_value = g_new0 ( ParsedDirectoryData , 1 ) ;
dir_value - > tree_data = parsed_tree_data_new ( ) ;
dir_value - > metadata_sha256 = g_strdup ( g_checksum_get_string ( dir_meta_checksum ) ) ;
dir_value - > meta_data = dirmeta ;
g_hash_table_insert ( tree - > directories , g_strdup ( basename ) , dir_value ) ;
2011-10-13 17:11:01 -04:00
}
ret = TRUE ;
2011-10-15 03:02:51 -04:00
* dir = dir_value ;
2011-10-13 17:11:01 -04:00
out :
if ( dir_meta_checksum )
g_checksum_free ( dir_meta_checksum ) ;
return ret ;
}
static gboolean
2011-10-18 14:44:48 -04:00
add_one_file_to_tree_and_import ( OstreeRepo * self ,
2011-10-13 17:11:01 -04:00
const char * basename ,
const char * abspath ,
ParsedTreeData * tree ,
GError * * error )
{
gboolean ret = FALSE ;
GChecksum * checksum = NULL ;
2011-11-08 19:23:04 -05:00
struct stat stbuf ;
gboolean did_exist ;
2011-10-13 17:11:01 -04:00
2011-10-14 23:13:23 -04:00
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
2011-10-13 17:11:01 -04:00
g_assert ( tree ! = NULL ) ;
2011-11-08 19:23:04 -05:00
if ( ! ostree_stat_and_checksum_file ( - 1 , abspath , OSTREE_OBJECT_TYPE_FILE , & checksum , & stbuf , error ) )
goto out ;
if ( ! ostree_repo_store_object_trusted ( self , abspath , g_checksum_get_string ( checksum ) ,
OSTREE_OBJECT_TYPE_FILE , TRUE , FALSE , & did_exist , error ) )
2011-10-13 17:11:01 -04:00
goto out ;
g_hash_table_replace ( tree - > files , g_strdup ( basename ) ,
g_strdup ( g_checksum_get_string ( checksum ) ) ) ;
ret = TRUE ;
out :
if ( checksum )
g_checksum_free ( checksum ) ;
return ret ;
}
static gboolean
2011-10-19 18:06:06 -04:00
add_one_path_to_tree_and_import ( OstreeRepo * self ,
2011-10-13 17:11:01 -04:00
const char * base ,
const char * filename ,
ParsedTreeData * tree ,
GError * * error )
{
gboolean ret = FALSE ;
GPtrArray * components = NULL ;
struct stat stbuf ;
char * component_abspath = NULL ;
ParsedTreeData * current_tree = tree ;
const char * component = NULL ;
const char * file_sha1 ;
char * abspath = NULL ;
ParsedDirectoryData * dir ;
int i ;
gboolean is_directory ;
2011-10-14 23:13:23 -04:00
2011-10-13 17:11:01 -04:00
if ( ! check_path ( filename , error ) )
goto out ;
abspath = g_build_filename ( base , filename , NULL ) ;
if ( lstat ( abspath , & stbuf ) < 0 )
{
2011-10-18 14:44:48 -04:00
ot_util_set_error_from_errno ( error , errno ) ;
2011-10-13 17:11:01 -04:00
goto out ;
}
is_directory = S_ISDIR ( stbuf . st_mode ) ;
if ( components )
g_ptr_array_free ( components , TRUE ) ;
2011-10-18 14:44:48 -04:00
components = ot_util_path_split ( filename ) ;
2011-10-13 17:11:01 -04:00
g_assert ( components - > len > 0 ) ;
current_tree = tree ;
for ( i = 0 ; i < components - > len ; i + + )
{
component = components - > pdata [ i ] ;
g_free ( component_abspath ) ;
2011-10-18 14:44:48 -04:00
component_abspath = ot_util_path_join_n ( base , components , i ) ;
2011-10-13 17:11:01 -04:00
file_sha1 = g_hash_table_lookup ( current_tree - > files , component ) ;
dir = g_hash_table_lookup ( current_tree - > directories , component ) ;
2011-10-15 03:02:51 -04:00
2011-10-15 13:04:50 -04:00
g_assert_cmpstr ( component , ! = , " . " ) ;
2011-10-13 17:11:01 -04:00
if ( i < components - > len - 1 )
{
if ( file_sha1 ! = NULL )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Encountered non-directory '%s' in '%s' " ,
component ,
filename ) ;
goto out ;
}
/* Implicitly add intermediate directories */
if ( ! add_one_directory_to_tree_and_import ( self , component ,
2011-10-15 03:02:51 -04:00
component_abspath , current_tree , & dir ,
2011-10-13 17:11:01 -04:00
error ) )
goto out ;
2011-10-15 03:02:51 -04:00
g_assert ( dir ! = NULL ) ;
current_tree = dir - > tree_data ;
2011-10-13 17:11:01 -04:00
}
else if ( is_directory )
{
if ( file_sha1 ! = NULL )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" File '%s' can't be overwritten by directory " ,
filename ) ;
goto out ;
}
if ( ! add_one_directory_to_tree_and_import ( self , component ,
2011-10-15 03:02:51 -04:00
abspath , current_tree , & dir ,
2011-10-13 17:11:01 -04:00
error ) )
goto out ;
}
else
{
g_assert ( ! is_directory ) ;
if ( dir ! = NULL )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" File '%s' can't be overwritten by directory " ,
filename ) ;
goto out ;
}
if ( ! add_one_file_to_tree_and_import ( self , component , abspath ,
current_tree , error ) )
goto out ;
}
}
ret = TRUE ;
out :
2011-11-01 12:20:33 -04:00
if ( components )
g_ptr_array_unref ( components ) ;
2011-10-13 17:11:01 -04:00
g_free ( component_abspath ) ;
g_free ( abspath ) ;
return ret ;
}
2011-10-31 20:24:38 -04:00
gboolean
ostree_repo_write_ref ( OstreeRepo * self ,
gboolean is_local ,
const char * name ,
const char * rev ,
GError * * error )
{
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
return write_checksum_file ( is_local ? priv - > local_heads_dir : priv - > remote_heads_dir ,
name , rev , error ) ;
}
2011-10-15 13:04:50 -04:00
static gboolean
2011-10-18 14:44:48 -04:00
commit_parsed_tree ( OstreeRepo * self ,
2011-10-27 09:21:07 -04:00
const char * branch ,
const char * parent ,
2011-10-15 13:04:50 -04:00
const char * subject ,
const char * body ,
GVariant * metadata ,
2011-10-15 14:20:22 -04:00
ParsedDirectoryData * root ,
2011-10-15 13:04:50 -04:00
GChecksum * * out_commit ,
GError * * error )
{
gboolean ret = FALSE ;
GChecksum * root_checksum = NULL ;
GChecksum * ret_commit = NULL ;
GVariant * commit = NULL ;
GDateTime * now = NULL ;
2011-10-27 09:21:07 -04:00
g_assert ( branch ! = NULL ) ;
g_assert ( subject ! = NULL ) ;
2011-10-15 14:20:22 -04:00
if ( ! import_parsed_tree ( self , root - > tree_data , & root_checksum , error ) )
2011-10-15 13:04:50 -04:00
goto out ;
now = g_date_time_new_now_utc ( ) ;
2011-10-15 14:20:22 -04:00
commit = g_variant_new ( " (u@a{sv}ssstss) " ,
2011-10-31 22:41:50 -04:00
GUINT32_TO_BE ( OSTREE_COMMIT_VERSION ) ,
2011-11-04 12:32:08 -04:00
metadata ? metadata : create_empty_gvariant_dict ( ) ,
2011-10-27 09:21:07 -04:00
parent ? parent : " " ,
2011-10-15 13:04:50 -04:00
subject , body ? body : " " ,
2011-10-31 22:41:50 -04:00
GUINT64_TO_BE ( g_date_time_to_unix ( now ) ) ,
2011-10-15 14:20:22 -04:00
g_checksum_get_string ( root_checksum ) ,
root - > metadata_sha256 ) ;
2011-11-01 12:20:33 -04:00
g_variant_ref_sink ( commit ) ;
2011-10-18 14:44:48 -04:00
if ( ! import_gvariant_object ( self , OSTREE_SERIALIZED_COMMIT_VARIANT ,
2011-10-15 13:04:50 -04:00
commit , & ret_commit , error ) )
goto out ;
2011-10-31 20:24:38 -04:00
if ( ! ostree_repo_write_ref ( self , TRUE , branch , g_checksum_get_string ( ret_commit ) , error ) )
2011-10-15 13:04:50 -04:00
goto out ;
ret = TRUE ;
* out_commit = ret_commit ;
out :
if ( root_checksum )
g_checksum_free ( root_checksum ) ;
if ( commit )
g_variant_unref ( commit ) ;
if ( now )
g_date_time_unref ( now ) ;
return ret ;
}
2011-10-15 14:20:22 -04:00
static gboolean
2011-10-27 09:21:07 -04:00
import_root ( OstreeRepo * self ,
const char * base ,
2011-10-15 14:20:22 -04:00
ParsedDirectoryData * * out_root ,
GError * * error )
{
gboolean ret = FALSE ;
ParsedDirectoryData * ret_root = NULL ;
GVariant * root_metadata = NULL ;
GChecksum * root_meta_checksum = NULL ;
if ( ! import_directory_meta ( self , base , & root_metadata , & root_meta_checksum , error ) )
goto out ;
ret_root = g_new0 ( ParsedDirectoryData , 1 ) ;
ret_root - > tree_data = parsed_tree_data_new ( ) ;
ret_root - > meta_data = root_metadata ;
root_metadata = NULL ;
ret_root - > metadata_sha256 = g_strdup ( g_checksum_get_string ( root_meta_checksum ) ) ;
ret = TRUE ;
* out_root = ret_root ;
ret_root = NULL ;
out :
if ( root_metadata )
g_variant_unref ( root_metadata ) ;
if ( root_meta_checksum )
g_checksum_free ( root_meta_checksum ) ;
parsed_directory_data_free ( ret_root ) ;
return ret ;
}
2011-10-15 13:04:50 -04:00
gboolean
2011-10-18 14:44:48 -04:00
ostree_repo_commit_from_filelist_fd ( OstreeRepo * self ,
2011-10-27 09:21:07 -04:00
const char * branch ,
2011-10-27 21:40:42 -04:00
const char * parent ,
2011-10-27 09:21:07 -04:00
const char * subject ,
const char * body ,
GVariant * metadata ,
const char * base ,
int fd ,
char separator ,
GChecksum * * out_commit ,
GError * * error )
2011-10-15 13:04:50 -04:00
{
2011-10-18 14:44:48 -04:00
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-15 13:04:50 -04:00
gboolean ret = FALSE ;
2011-10-15 14:20:22 -04:00
ParsedDirectoryData * root = NULL ;
2011-10-15 13:04:50 -04:00
GChecksum * ret_commit_checksum = NULL ;
GUnixInputStream * in = NULL ;
GDataInputStream * datain = NULL ;
char * filename = NULL ;
gsize filename_len ;
GError * temp_error = NULL ;
2011-10-15 14:20:22 -04:00
GVariant * root_metadata = NULL ;
GChecksum * root_meta_checksum = NULL ;
2011-10-27 09:21:07 -04:00
char * current_head = NULL ;
2011-10-14 22:56:40 -04:00
2011-10-15 13:04:50 -04:00
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
g_return_val_if_fail ( priv - > inited , FALSE ) ;
2011-10-27 21:40:42 -04:00
g_return_val_if_fail ( branch ! = NULL , FALSE ) ;
g_return_val_if_fail ( subject ! = NULL , FALSE ) ;
2011-11-04 13:42:05 -04:00
g_return_val_if_fail ( metadata = = NULL | | g_variant_is_of_type ( metadata , G_VARIANT_TYPE ( " a{sv} " ) ) , FALSE ) ;
2011-10-15 13:04:50 -04:00
2011-10-27 21:40:42 -04:00
if ( parent = = NULL )
parent = branch ;
2011-10-27 09:21:07 -04:00
2011-10-15 13:04:50 -04:00
/* We're overwriting the tree */
2011-10-15 14:20:22 -04:00
if ( ! import_root ( self , base , & root , error ) )
goto out ;
2011-10-14 22:56:40 -04:00
2011-10-27 21:40:42 -04:00
if ( ! resolve_rev ( self , parent , TRUE , & current_head , error ) )
2011-10-27 09:21:07 -04:00
goto out ;
2011-10-15 13:04:50 -04:00
in = ( GUnixInputStream * ) g_unix_input_stream_new ( fd , FALSE ) ;
datain = g_data_input_stream_new ( ( GInputStream * ) in ) ;
while ( ( filename = g_data_input_stream_read_upto ( datain , & separator , 1 ,
& filename_len , NULL , & temp_error ) ) ! = NULL )
{
if ( ! g_data_input_stream_read_byte ( datain , NULL , & temp_error ) )
{
if ( temp_error ! = NULL )
{
g_propagate_prefixed_error ( error , temp_error , " %s " , " While reading filelist: " ) ;
goto out ;
}
}
2011-10-15 14:20:22 -04:00
if ( ! add_one_path_to_tree_and_import ( self , base , filename , root - > tree_data , error ) )
2011-10-15 13:04:50 -04:00
goto out ;
g_free ( filename ) ;
filename = NULL ;
}
if ( filename = = NULL & & temp_error ! = NULL )
{
g_propagate_prefixed_error ( error , temp_error , " %s " , " While reading filelist: " ) ;
goto out ;
}
2011-10-27 09:21:07 -04:00
if ( ! commit_parsed_tree ( self , branch , current_head , subject , body , metadata ,
2011-10-15 14:20:22 -04:00
root , & ret_commit_checksum , error ) )
2011-10-15 13:04:50 -04:00
goto out ;
2011-10-13 17:11:01 -04:00
ret = TRUE ;
2011-10-27 09:21:07 -04:00
* out_commit = ret_commit_checksum ;
ret_commit_checksum = NULL ;
2011-10-13 17:11:01 -04:00
out :
2011-10-27 09:21:07 -04:00
if ( ret_commit_checksum )
g_checksum_free ( ret_commit_checksum ) ;
g_free ( current_head ) ;
2011-10-15 14:20:22 -04:00
if ( root_metadata )
g_variant_unref ( root_metadata ) ;
if ( root_meta_checksum )
g_checksum_free ( root_meta_checksum ) ;
2011-10-15 13:04:50 -04:00
g_clear_object ( & datain ) ;
g_clear_object ( & in ) ;
g_free ( filename ) ;
2011-10-15 14:20:22 -04:00
parsed_directory_data_free ( root ) ;
2011-10-13 17:11:01 -04:00
return ret ;
2011-10-15 13:04:50 -04:00
2011-10-11 20:58:50 -04:00
}
2011-10-12 11:38:41 -04:00
static gboolean
2011-10-18 14:44:48 -04:00
iter_object_dir ( OstreeRepo * self ,
2011-10-12 11:38:41 -04:00
GFile * dir ,
2011-10-18 14:44:48 -04:00
OstreeRepoObjectIter callback ,
2011-10-12 11:38:41 -04:00
gpointer user_data ,
GError * * error )
{
gboolean ret = FALSE ;
GError * temp_error = NULL ;
GFileEnumerator * enumerator = NULL ;
GFileInfo * file_info = NULL ;
char * dirpath = NULL ;
dirpath = g_file_get_path ( dir ) ;
2011-11-06 16:24:11 -05:00
enumerator = g_file_enumerate_children ( dir , OSTREE_GIO_FAST_QUERYINFO ,
2011-10-12 11:38:41 -04:00
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 ;
name = g_file_info_get_attribute_byte_string ( file_info , " standard::name " ) ;
type = g_file_info_get_attribute_uint32 ( file_info , " standard::type " ) ;
2011-10-14 22:30:18 -04:00
if ( type ! = G_FILE_TYPE_DIRECTORY
& & ( g_str_has_suffix ( name , " .meta " )
2011-10-31 20:24:38 -04:00
| | g_str_has_suffix ( name , " .file " )
| | g_str_has_suffix ( name , " .packfile " ) ) )
2011-10-12 11:38:41 -04:00
{
2011-10-14 22:30:18 -04:00
char * dot ;
char * path ;
dot = strrchr ( name , ' . ' ) ;
g_assert ( dot ) ;
if ( ( dot - name ) = = 62 )
{
path = g_build_filename ( dirpath , name , NULL ) ;
callback ( self , path , file_info , user_data ) ;
g_free ( path ) ;
}
2011-10-12 11:38:41 -04:00
}
g_object_unref ( file_info ) ;
}
if ( file_info = = NULL & & temp_error ! = NULL )
{
g_propagate_error ( error , temp_error ) ;
goto out ;
}
if ( ! g_file_enumerator_close ( enumerator , NULL , error ) )
goto out ;
ret = TRUE ;
out :
g_free ( dirpath ) ;
return ret ;
}
gboolean
2011-10-18 14:44:48 -04:00
ostree_repo_iter_objects ( OstreeRepo * self ,
OstreeRepoObjectIter callback ,
2011-10-12 11:38:41 -04:00
gpointer user_data ,
GError * * error )
{
2011-10-18 14:44:48 -04:00
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-12 11:38:41 -04:00
GFile * objectdir = NULL ;
GFileEnumerator * enumerator = NULL ;
gboolean ret = FALSE ;
GFileInfo * file_info = NULL ;
GError * temp_error = NULL ;
2011-10-14 23:13:23 -04:00
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
2011-10-12 11:38:41 -04:00
g_return_val_if_fail ( priv - > inited , FALSE ) ;
2011-10-18 14:44:48 -04:00
objectdir = ot_util_new_file_for_path ( priv - > objects_path ) ;
2011-11-06 16:24:11 -05:00
enumerator = g_file_enumerate_children ( objectdir , OSTREE_GIO_FAST_QUERYINFO ,
2011-10-12 11:38:41 -04:00
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 ;
name = g_file_info_get_attribute_byte_string ( file_info , " standard::name " ) ;
type = g_file_info_get_attribute_uint32 ( file_info , " standard::type " ) ;
if ( strlen ( name ) = = 2 & & type = = G_FILE_TYPE_DIRECTORY )
{
GFile * objdir = g_file_get_child ( objectdir , name ) ;
if ( ! iter_object_dir ( self , objdir , callback , user_data , error ) )
{
g_object_unref ( objdir ) ;
goto out ;
}
g_object_unref ( objdir ) ;
}
g_object_unref ( file_info ) ;
}
if ( file_info = = NULL & & temp_error ! = NULL )
{
g_propagate_error ( error , temp_error ) ;
goto out ;
}
if ( ! g_file_enumerator_close ( enumerator , NULL , error ) )
goto out ;
ret = TRUE ;
out :
g_clear_object ( & file_info ) ;
g_clear_object ( & enumerator ) ;
g_clear_object ( & objectdir ) ;
return ret ;
}
2011-10-14 22:09:44 -04:00
gboolean
2011-11-02 13:22:13 -04:00
ostree_repo_load_variant ( OstreeRepo * self ,
const char * sha256 ,
OstreeSerializedVariantType * out_type ,
GVariant * * out_variant ,
GError * * error )
2011-10-14 22:09:44 -04:00
{
gboolean ret = FALSE ;
2011-10-18 14:44:48 -04:00
OstreeSerializedVariantType ret_type ;
2011-10-14 22:09:44 -04:00
GVariant * ret_variant = NULL ;
2011-11-02 13:22:13 -04:00
char * path = NULL ;
2011-10-14 23:13:23 -04:00
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
2011-11-02 13:22:13 -04:00
2011-11-08 19:38:42 -05:00
path = ostree_repo_get_object_path ( self , sha256 , OSTREE_OBJECT_TYPE_META ) ;
2011-11-02 13:22:13 -04:00
if ( ! ostree_parse_metadata_file ( path , & ret_type , & ret_variant , error ) )
2011-10-14 22:09:44 -04:00
goto out ;
ret = TRUE ;
* out_type = ret_type ;
* out_variant = ret_variant ;
2011-11-02 13:22:13 -04:00
ret_variant = NULL ;
2011-10-14 22:09:44 -04:00
out :
2011-11-02 13:22:13 -04:00
if ( ret_variant )
g_variant_unref ( ret_variant ) ;
g_free ( path ) ;
2011-10-14 22:09:44 -04:00
return ret ;
}
2011-10-15 00:45:07 -04:00
static gboolean
2011-10-18 14:44:48 -04:00
checkout_tree ( OstreeRepo * self ,
2011-11-07 11:25:49 -05:00
OstreeRepoFile * dir ,
2011-10-15 00:45:07 -04:00
const char * destination ,
2011-11-07 11:25:49 -05:00
GCancellable * cancellable ,
2011-10-15 00:45:07 -04:00
GError * * error ) ;
static gboolean
2011-10-18 14:44:48 -04:00
checkout_one_directory ( OstreeRepo * self ,
2011-10-15 00:45:07 -04:00
const char * destination ,
const char * dirname ,
2011-11-07 11:25:49 -05:00
OstreeRepoFile * dir ,
GFileInfo * dir_info ,
GCancellable * cancellable ,
2011-10-15 00:45:07 -04:00
GError * * error )
{
gboolean ret = FALSE ;
char * dest_path = NULL ;
GVariant * xattr_variant = NULL ;
dest_path = g_build_filename ( destination , dirname , NULL ) ;
2011-11-07 11:25:49 -05:00
if ( ! _ostree_repo_file_get_xattrs ( dir , & xattr_variant , NULL , error ) )
goto out ;
if ( mkdir ( dest_path , ( mode_t ) g_file_info_get_attribute_uint32 ( dir_info , " unix::mode " ) ) < 0 )
2011-10-15 00:45:07 -04:00
{
2011-10-18 14:44:48 -04:00
ot_util_set_error_from_errno ( error , errno ) ;
2011-10-15 13:04:50 -04:00
g_prefix_error ( error , " Failed to create directory '%s': " , dest_path ) ;
2011-10-15 00:45:07 -04:00
goto out ;
}
2011-11-07 11:25:49 -05:00
if ( ! ostree_set_xattrs ( dest_path , xattr_variant , cancellable , error ) )
goto out ;
if ( ! checkout_tree ( self , dir , dest_path , cancellable , error ) )
2011-11-01 10:59:07 -04:00
goto out ;
2011-10-15 00:45:07 -04:00
ret = TRUE ;
out :
g_free ( dest_path ) ;
2011-11-07 11:25:49 -05:00
if ( xattr_variant )
g_variant_unref ( xattr_variant ) ;
2011-10-15 00:45:07 -04:00
return ret ;
}
static gboolean
2011-10-18 14:44:48 -04:00
checkout_tree ( OstreeRepo * self ,
2011-11-07 11:25:49 -05:00
OstreeRepoFile * dir ,
2011-10-15 00:45:07 -04:00
const char * destination ,
2011-11-07 11:25:49 -05:00
GCancellable * cancellable ,
2011-10-15 00:45:07 -04:00
GError * * error )
{
2011-11-01 10:59:07 -04:00
OstreeRepoPrivate * priv = GET_PRIVATE ( self ) ;
2011-10-15 00:45:07 -04:00
gboolean ret = FALSE ;
2011-11-07 11:25:49 -05:00
GError * temp_error = NULL ;
GFileInfo * file_info = NULL ;
GFileEnumerator * dir_enum = NULL ;
GFile * child = NULL ;
char * object_path = NULL ;
char * dest_path = NULL ;
2011-10-15 00:45:07 -04:00
2011-11-07 11:25:49 -05:00
dir_enum = g_file_enumerate_children ( ( GFile * ) dir , OSTREE_GIO_FAST_QUERYINFO ,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS ,
cancellable ,
error ) ;
if ( ! dir_enum )
goto out ;
while ( ( file_info = g_file_enumerator_next_file ( dir_enum , cancellable , & temp_error ) ) ! = NULL )
2011-10-15 00:45:07 -04:00
{
2011-11-07 11:25:49 -05:00
const char * name ;
guint32 type ;
2011-10-15 00:45:07 -04:00
2011-11-07 11:25:49 -05:00
name = g_file_info_get_attribute_byte_string ( file_info , " standard::name " ) ;
type = g_file_info_get_attribute_uint32 ( file_info , " standard::type " ) ;
child = g_file_get_child ( ( GFile * ) dir , name ) ;
if ( type = = G_FILE_TYPE_DIRECTORY )
2011-10-15 00:45:07 -04:00
{
2011-11-07 11:25:49 -05:00
if ( ! checkout_one_directory ( self , destination , name , ( OstreeRepoFile * ) child , file_info , cancellable , error ) )
2011-11-01 10:59:07 -04:00
goto out ;
}
else
{
2011-11-07 11:25:49 -05:00
const char * checksum = _ostree_repo_file_nontree_get_checksum ( ( OstreeRepoFile * ) child ) ;
dest_path = g_build_filename ( destination , name , NULL ) ;
object_path = ostree_repo_get_object_path ( self , checksum , OSTREE_OBJECT_TYPE_FILE ) ;
if ( priv - > archive )
2011-11-01 10:59:07 -04:00
{
2011-11-07 11:25:49 -05:00
if ( ! ostree_unpack_object ( object_path , OSTREE_OBJECT_TYPE_FILE , dest_path , NULL , error ) )
goto out ;
}
else
{
if ( link ( object_path , dest_path ) < 0 )
{
ot_util_set_error_from_errno ( error , errno ) ;
goto out ;
}
2011-11-01 10:59:07 -04:00
}
2011-10-15 00:45:07 -04:00
}
2011-11-07 11:25:49 -05:00
g_free ( object_path ) ;
object_path = NULL ;
g_free ( dest_path ) ;
dest_path = NULL ;
g_clear_object ( & file_info ) ;
g_clear_object ( & child ) ;
}
if ( file_info = = NULL & & temp_error ! = NULL )
2011-10-15 00:45:07 -04:00
{
2011-11-07 11:25:49 -05:00
g_propagate_error ( error , temp_error ) ;
goto out ;
2011-10-15 00:45:07 -04:00
}
ret = TRUE ;
out :
2011-11-07 11:25:49 -05:00
g_clear_object ( & dir_enum ) ;
g_clear_object ( & file_info ) ;
g_clear_object ( & child ) ;
g_free ( object_path ) ;
g_free ( dest_path ) ;
2011-10-15 00:45:07 -04:00
return ret ;
}
gboolean
2011-10-18 14:44:48 -04:00
ostree_repo_checkout ( OstreeRepo * self ,
2011-10-27 09:21:07 -04:00
const char * rev ,
const char * destination ,
2011-11-07 11:25:49 -05:00
GCancellable * cancellable ,
2011-10-27 09:21:07 -04:00
GError * * error )
2011-10-15 00:45:07 -04:00
{
gboolean ret = FALSE ;
char * resolved = NULL ;
2011-11-07 11:25:49 -05:00
OstreeRepoFile * root = NULL ;
GFileInfo * root_info = NULL ;
2011-10-15 00:45:07 -04:00
if ( g_file_test ( destination , G_FILE_TEST_EXISTS ) )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Destination path '%s' already exists " ,
destination ) ;
goto out ;
}
2011-10-27 09:21:07 -04:00
if ( ! resolve_rev ( self , rev , FALSE , & resolved , error ) )
2011-10-15 00:45:07 -04:00
goto out ;
2011-11-07 11:25:49 -05:00
root = ( OstreeRepoFile * ) _ostree_repo_file_new_root ( self , resolved ) ;
if ( ! _ostree_repo_file_ensure_resolved ( root , error ) )
goto out ;
root_info = g_file_query_info ( ( GFile * ) root , OSTREE_GIO_FAST_QUERYINFO ,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS ,
NULL , error ) ;
if ( ! root_info )
2011-10-15 00:45:07 -04:00
goto out ;
2011-11-07 11:25:49 -05:00
if ( ! checkout_one_directory ( self , destination , NULL , root , root_info , cancellable , error ) )
2011-10-15 00:45:07 -04:00
goto out ;
ret = TRUE ;
out :
g_free ( resolved ) ;
2011-11-07 11:25:49 -05:00
g_clear_object ( & root ) ;
g_clear_object ( & root_info ) ;
2011-10-15 00:45:07 -04:00
return ret ;
}
2011-11-10 09:27:22 -05:00
gboolean
ostree_repo_diff ( OstreeRepo * self ,
const char * ref ,
GFile * target ,
GPtrArray * * out_modified ,
GPtrArray * * out_removed ,
GPtrArray * * out_added ,
GCancellable * cancellable ,
GError * * error )
{
gboolean ret = FALSE ;
GPtrArray * ret_modified = NULL ;
GPtrArray * ret_removed = NULL ;
GPtrArray * ret_added = NULL ;
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_NOT_SUPPORTED ,
" Not implemented yet " ) ;
goto out ;
ret = TRUE ;
out :
if ( ret_modified )
g_ptr_array_free ( ret_modified , TRUE ) ;
if ( ret_removed )
g_ptr_array_free ( ret_removed , TRUE ) ;
if ( ret_added )
g_ptr_array_free ( ret_added , TRUE ) ;
return ret ;
}