2017-09-21 22:26:06 +03:00
/*
2016-03-02 18:05:08 +03:00
* Copyright ( C ) 2016 Red Hat , Inc .
*
2018-01-30 22:26:26 +03:00
* SPDX - License - Identifier : LGPL - 2.0 +
*
2016-03-02 18:05:08 +03: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 .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
2021-12-07 04:20:55 +03:00
* License along with this library . If not , see < https : //www.gnu.org/licenses/>.
2016-03-02 18:05:08 +03:00
*/
# include "config.h"
2023-05-01 21:24:29 +03:00
# include <err.h>
2016-03-02 18:05:08 +03:00
# include <gio/gio.h>
2023-05-01 21:24:29 +03:00
# include <stdbool.h>
# include <stdlib.h>
2016-03-02 18:05:08 +03:00
# include <string.h>
# include "libglnx.h"
# include "libostreetest.h"
static void
test_repo_is_not_system ( gconstpointer data )
{
2023-05-01 21:24:29 +03:00
OstreeRepo * repo = ( void * ) data ;
2016-03-03 21:49:54 +03:00
g_assert ( ! ostree_repo_is_system ( repo ) ) ;
2016-03-02 18:05:08 +03:00
}
2016-05-23 14:28:04 +03:00
static GBytes *
input_stream_to_bytes ( GInputStream * input )
{
2023-05-01 21:24:29 +03:00
g_autoptr ( GOutputStream ) mem_out_stream = NULL ;
g_autoptr ( GError ) error = NULL ;
2016-05-23 14:28:04 +03:00
if ( input = = NULL )
return g_bytes_new ( NULL , 0 ) ;
mem_out_stream = g_memory_output_stream_new ( NULL , 0 , g_realloc , g_free ) ;
2023-05-01 21:24:29 +03:00
g_output_stream_splice ( mem_out_stream , input , G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET , NULL , & error ) ;
2016-05-23 14:28:04 +03:00
g_assert_no_error ( error ) ;
return g_memory_output_stream_steal_as_bytes ( G_MEMORY_OUTPUT_STREAM ( mem_out_stream ) ) ;
}
static void
2017-09-01 23:15:33 +03:00
test_raw_file_to_archive_stream ( gconstpointer data )
2016-05-23 14:28:04 +03:00
{
OstreeRepo * repo = OSTREE_REPO ( data ) ;
g_autofree gchar * commit_checksum = NULL ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GHashTable ) reachable = NULL ;
g_autoptr ( GError ) error = NULL ;
2016-05-23 14:28:04 +03:00
/* branch name of the test repository, see setup_test_repository in libtest.sh */
const gchar * rev = " test2 " ;
GHashTableIter iter ;
GVariant * serialized_object ;
guint checks = 0 ;
2023-05-01 21:24:29 +03:00
ostree_repo_resolve_rev ( repo , rev , FALSE , & commit_checksum , & error ) ;
2016-05-23 14:28:04 +03:00
g_assert_no_error ( error ) ;
2023-05-01 21:24:29 +03:00
ostree_repo_traverse_commit ( repo , commit_checksum , - 1 , & reachable , NULL , & error ) ;
2016-05-23 14:28:04 +03:00
g_assert_no_error ( error ) ;
g_hash_table_iter_init ( & iter , reachable ) ;
2023-05-01 21:24:29 +03:00
while ( g_hash_table_iter_next ( & iter , ( gpointer * ) & serialized_object , NULL ) )
2016-05-23 14:28:04 +03:00
{
const gchar * object_checksum ;
OstreeObjectType object_type ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GInputStream ) input = NULL ;
g_autoptr ( GFileInfo ) info = NULL ;
g_autoptr ( GVariant ) xattrs = NULL ;
g_autoptr ( GBytes ) input_bytes = NULL ;
g_autoptr ( GInputStream ) mem_input = NULL ;
g_autoptr ( GInputStream ) zlib_stream = NULL ;
g_autoptr ( GBytes ) zlib_bytes = NULL ;
g_autoptr ( GInputStream ) mem_zlib = NULL ;
g_autoptr ( GInputStream ) input2 = NULL ;
g_autoptr ( GFileInfo ) info2 = NULL ;
g_autoptr ( GVariant ) xattrs2 = NULL ;
g_autoptr ( GBytes ) input2_bytes = NULL ;
2016-05-23 14:28:04 +03:00
ostree_object_name_deserialize ( serialized_object , & object_checksum , & object_type ) ;
if ( object_type ! = OSTREE_OBJECT_TYPE_FILE )
continue ;
2023-05-01 21:24:29 +03:00
ostree_repo_load_file ( repo , object_checksum , & input , & info , & xattrs , NULL , & error ) ;
2016-05-23 14:28:04 +03:00
g_assert_no_error ( error ) ;
input_bytes = input_stream_to_bytes ( input ) ;
/* This is to simulate NULL input received from
* ostree_repo_load_file . Instead of creating the mem_input
* variable , I could also rewind the input stream and pass it to
* the function below , but this would assume that the input
* stream implements either the GSeekable or
* GFileDescriptorBased interface . */
if ( input ! = NULL )
mem_input = g_memory_input_stream_new_from_bytes ( input_bytes ) ;
2023-05-01 21:24:29 +03:00
ostree_raw_file_to_archive_z2_stream ( mem_input , info , xattrs , & zlib_stream , NULL , & error ) ;
2016-05-23 14:28:04 +03:00
g_assert_no_error ( error ) ;
zlib_bytes = input_stream_to_bytes ( zlib_stream ) ;
mem_zlib = g_memory_input_stream_new_from_bytes ( zlib_bytes ) ;
2023-05-01 21:24:29 +03:00
ostree_content_stream_parse ( FALSE , mem_zlib , g_bytes_get_size ( zlib_bytes ) , FALSE , & input2 ,
& info2 , & xattrs2 , NULL , & error ) ;
2016-05-23 14:28:04 +03:00
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ) ;
g_clear_error ( & error ) ;
2023-05-01 21:24:29 +03:00
g_seekable_seek ( G_SEEKABLE ( mem_zlib ) , 0 , G_SEEK_SET , NULL , & error ) ;
2016-05-23 14:28:04 +03:00
g_assert_no_error ( error ) ;
2023-05-01 21:24:29 +03:00
ostree_content_stream_parse ( TRUE , mem_zlib , g_bytes_get_size ( zlib_bytes ) , FALSE , & input2 ,
& info2 , & xattrs2 , NULL , & error ) ;
2016-05-23 14:28:04 +03:00
g_assert_no_error ( error ) ;
input2_bytes = input_stream_to_bytes ( input2 ) ;
g_assert_true ( g_bytes_equal ( input_bytes , input2_bytes ) ) ;
g_assert_true ( g_variant_equal ( xattrs , xattrs2 ) ) ;
/* TODO: Not sure how to compare fileinfos */
+ + checks ;
}
/* to make sure we really tested the function */
g_assert_cmpint ( checks , > , 0 ) ;
}
2023-05-01 21:24:29 +03:00
static gboolean
hi_content_stream_new ( GInputStream * * out_stream , guint64 * out_length , GError * * error )
2017-05-24 23:43:39 +03:00
{
static const char hi [ ] = " hi " ;
2023-05-01 21:24:29 +03:00
const size_t len = sizeof ( hi ) - 1 ;
g_autoptr ( GMemoryInputStream ) hi_memstream
= ( GMemoryInputStream * ) g_memory_input_stream_new_from_data ( hi , len , NULL ) ;
g_autoptr ( GFileInfo ) finfo = g_file_info_new ( ) ;
2017-05-24 23:43:39 +03:00
g_file_info_set_attribute_uint32 ( finfo , " standard::type " , G_FILE_TYPE_REGULAR ) ;
g_file_info_set_attribute_boolean ( finfo , " standard::is-symlink " , FALSE ) ;
2023-03-17 01:31:03 +03:00
g_file_info_set_size ( finfo , len ) ;
2017-05-24 23:43:39 +03:00
g_file_info_set_attribute_uint32 ( finfo , " unix::uid " , 0 ) ;
g_file_info_set_attribute_uint32 ( finfo , " unix::gid " , 0 ) ;
2023-05-01 21:24:29 +03:00
g_file_info_set_attribute_uint32 ( finfo , " unix::mode " , S_IFREG | 0644 ) ;
return ostree_raw_file_to_content_stream ( ( GInputStream * ) hi_memstream , finfo , NULL , out_stream ,
out_length , NULL , error ) ;
2017-05-24 23:43:39 +03:00
}
2017-06-14 14:28:52 +03:00
static void
test_validate_remotename ( void )
{
2023-05-01 21:24:29 +03:00
const char * valid [ ] = { " foo " , " hello-world " } ;
const char * invalid [ ] = { " foo/bar " , " " } ;
for ( guint i = 0 ; i < G_N_ELEMENTS ( valid ) ; i + + )
2017-06-14 14:28:52 +03:00
{
2023-05-01 21:24:29 +03:00
g_autoptr ( GError ) error = NULL ;
2017-06-14 14:28:52 +03:00
g_assert ( ostree_validate_remote_name ( valid [ i ] , & error ) ) ;
g_assert_no_error ( error ) ;
}
2023-05-01 21:24:29 +03:00
for ( guint i = 0 ; i < G_N_ELEMENTS ( invalid ) ; i + + )
2017-06-14 14:28:52 +03:00
{
2023-05-01 21:24:29 +03:00
g_autoptr ( GError ) error = NULL ;
2017-06-14 14:28:52 +03:00
g_assert ( ! ostree_validate_remote_name ( invalid [ i ] , & error ) ) ;
g_assert ( error ! = NULL ) ;
}
}
2017-05-24 23:43:39 +03:00
static void
test_object_writes ( gconstpointer data )
{
OstreeRepo * repo = OSTREE_REPO ( data ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GError ) error = NULL ;
2017-05-24 23:43:39 +03:00
2023-05-01 21:24:29 +03:00
static const char hi_sha256 [ ]
= " 2301b5923720c3edc1f0467addb5c287fd5559e3e0cd1396e7f1edb6b01be9f0 " ;
2017-05-24 23:43:39 +03:00
/* Successful content write */
2023-05-01 21:24:29 +03:00
{
g_autoptr ( GInputStream ) hi_memstream = NULL ;
2017-05-24 23:43:39 +03:00
guint64 len ;
hi_content_stream_new ( & hi_memstream , & len , & error ) ;
g_assert_no_error ( error ) ;
g_autofree guchar * csum = NULL ;
2023-05-01 21:24:29 +03:00
( void ) ostree_repo_write_content ( repo , hi_sha256 , hi_memstream , len , & csum , NULL , & error ) ;
2017-05-24 23:43:39 +03:00
g_assert_no_error ( error ) ;
}
/* Invalid content write */
2023-05-01 21:24:29 +03:00
{
g_autoptr ( GInputStream ) hi_memstream = NULL ;
2017-05-24 23:43:39 +03:00
guint64 len ;
hi_content_stream_new ( & hi_memstream , & len , & error ) ;
g_assert_no_error ( error ) ;
g_autofree guchar * csum = NULL ;
2023-05-01 21:24:29 +03:00
static const char invalid_hi_sha256 [ ]
= " cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe " ;
g_assert ( ! ostree_repo_write_content ( repo , invalid_hi_sha256 , hi_memstream , len , & csum , NULL ,
& error ) ) ;
2017-05-24 23:43:39 +03:00
g_assert ( error ) ;
g_assert ( strstr ( error - > message , " Corrupted file object " ) ) ;
}
}
2017-12-14 19:10:35 +03:00
static gboolean
2023-05-01 21:24:29 +03:00
impl_test_break_hardlink ( int tmp_dfd , const char * path , GError * * error )
2017-12-14 19:10:35 +03:00
{
const char * linkedpath = glnx_strjoina ( path , " .link " ) ;
struct stat orig_stbuf ;
if ( ! glnx_fstatat ( tmp_dfd , path , & orig_stbuf , AT_SYMLINK_NOFOLLOW , error ) )
return FALSE ;
/* Calling ostree_break_hardlink() should be a noop */
struct stat stbuf ;
if ( ! ostree_break_hardlink ( tmp_dfd , path , TRUE , NULL , error ) )
return FALSE ;
if ( ! glnx_fstatat ( tmp_dfd , path , & stbuf , AT_SYMLINK_NOFOLLOW , error ) )
return FALSE ;
g_assert_cmpint ( orig_stbuf . st_dev , = = , stbuf . st_dev ) ;
g_assert_cmpint ( orig_stbuf . st_ino , = = , stbuf . st_ino ) ;
if ( linkat ( tmp_dfd , path , tmp_dfd , linkedpath , 0 ) < 0 )
return glnx_throw_errno_prefix ( error , " linkat " ) ;
if ( ! ostree_break_hardlink ( tmp_dfd , path , TRUE , NULL , error ) )
return FALSE ;
if ( ! glnx_fstatat ( tmp_dfd , path , & stbuf , AT_SYMLINK_NOFOLLOW , error ) )
return FALSE ;
/* This file should be different */
g_assert_cmpint ( orig_stbuf . st_dev , = = , stbuf . st_dev ) ;
g_assert_cmpint ( orig_stbuf . st_ino , ! = , stbuf . st_ino ) ;
/* But this one is still the same */
if ( ! glnx_fstatat ( tmp_dfd , linkedpath , & stbuf , AT_SYMLINK_NOFOLLOW , error ) )
return FALSE ;
g_assert_cmpint ( orig_stbuf . st_dev , = = , stbuf . st_dev ) ;
g_assert_cmpint ( orig_stbuf . st_ino , = = , stbuf . st_ino ) ;
2023-05-01 21:24:29 +03:00
( void ) unlinkat ( tmp_dfd , path , 0 ) ;
( void ) unlinkat ( tmp_dfd , linkedpath , 0 ) ;
2017-12-14 19:10:35 +03:00
return TRUE ;
}
static void
test_break_hardlink ( void )
{
int tmp_dfd = AT_FDCWD ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GError ) error = NULL ;
2017-12-14 19:10:35 +03:00
/* Regular file */
const char hello_hardlinked_content [ ] = " hello hardlinked content " ;
2023-05-01 21:24:29 +03:00
glnx_file_replace_contents_at ( tmp_dfd , " test-hardlink " , ( guint8 * ) hello_hardlinked_content ,
strlen ( hello_hardlinked_content ) , GLNX_FILE_REPLACE_NODATASYNC ,
2017-12-14 19:10:35 +03:00
NULL , & error ) ;
g_assert_no_error ( error ) ;
( void ) impl_test_break_hardlink ( tmp_dfd , " test-hardlink " , & error ) ;
g_assert_no_error ( error ) ;
/* Symlink */
if ( symlinkat ( " some-path " , tmp_dfd , " test-symhardlink " ) < 0 )
err ( 1 , " symlinkat " ) ;
( void ) impl_test_break_hardlink ( tmp_dfd , " test-symhardlink " , & error ) ;
g_assert_no_error ( error ) ;
}
2023-05-01 21:24:29 +03:00
static GVariant *
xattr_cb ( OstreeRepo * repo , const char * path , GFileInfo * file_info , gpointer user_data )
2017-09-28 22:08:06 +03:00
{
GVariant * xattr = user_data ;
if ( g_str_equal ( path , " /baz/cow " ) )
return g_variant_ref ( xattr ) ;
return NULL ;
}
/* check that using a devino cache doesn't cause us to ignore xattr callbacks */
static void
test_devino_cache_xattrs ( void )
{
2023-05-01 21:24:29 +03:00
g_autoptr ( GError ) error = NULL ;
2017-09-28 22:08:06 +03:00
gboolean ret = FALSE ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GFile ) repo_path = g_file_new_for_path ( " repo " ) ;
2017-09-28 22:08:06 +03:00
/* re-initialize as bare */
ret = ot_test_run_libtest ( " setup_test_repository bare " , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2017-09-28 21:57:33 +03:00
gboolean can_relabel ;
ret = ot_check_relabeling ( & can_relabel , & error ) ;
2017-09-28 22:08:06 +03:00
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2017-09-28 21:57:33 +03:00
gboolean has_user_xattrs ;
ret = ot_check_user_xattrs ( & has_user_xattrs , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
/* we need both because we're bare and our tests target user xattrs */
if ( ! can_relabel | | ! has_user_xattrs )
2017-09-28 22:08:06 +03:00
{
2017-09-28 21:57:33 +03:00
g_test_skip ( " this test requires full xattr support " ) ;
2017-09-28 22:08:06 +03:00
return ;
}
2023-05-01 21:24:29 +03:00
g_autoptr ( OstreeRepo ) repo = ostree_repo_new ( repo_path ) ;
2017-09-28 22:08:06 +03:00
ret = ostree_repo_open ( repo , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
g_autofree char * csum = NULL ;
ret = ostree_repo_resolve_rev ( repo , " test2 " , FALSE , & csum , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( OstreeRepoDevInoCache ) cache = ostree_repo_devino_cache_new ( ) ;
2017-09-28 22:08:06 +03:00
2023-05-01 21:24:29 +03:00
OstreeRepoCheckoutAtOptions options = {
0 ,
} ;
2017-09-28 22:08:06 +03:00
options . no_copy_fallback = TRUE ;
options . devino_to_csum_cache = cache ;
ret = ostree_repo_checkout_at ( repo , & options , AT_FDCWD , " checkout " , csum , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( OstreeMutableTree ) mtree = ostree_mutable_tree_new ( ) ;
g_autoptr ( OstreeRepoCommitModifier ) modifier
= ostree_repo_commit_modifier_new ( 0 , NULL , NULL , NULL ) ;
2017-09-28 22:08:06 +03:00
ostree_repo_commit_modifier_set_devino_cache ( modifier , cache ) ;
2023-05-01 21:24:29 +03:00
g_auto ( GVariantBuilder ) builder ;
g_variant_builder_init ( & builder , ( GVariantType * ) " a(ayay) " ) ;
g_variant_builder_add ( & builder , " (@ay@ay) " , g_variant_new_bytestring ( " user.myattr " ) ,
2017-09-28 22:08:06 +03:00
g_variant_new_bytestring ( " data " ) ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GVariant ) orig_xattrs = g_variant_ref_sink ( g_variant_builder_end ( & builder ) ) ;
2017-09-28 22:08:06 +03:00
ret = ostree_repo_prepare_transaction ( repo , NULL , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
ostree_repo_commit_modifier_set_xattr_callback ( modifier , xattr_cb , NULL , orig_xattrs ) ;
2023-05-01 21:24:29 +03:00
ret = ostree_repo_write_dfd_to_mtree ( repo , AT_FDCWD , " checkout " , mtree , modifier , NULL , & error ) ;
2017-09-28 22:08:06 +03:00
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GFile ) root = NULL ;
2017-09-28 22:08:06 +03:00
ret = ostree_repo_write_mtree ( repo , mtree , & root , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
/* now check that the final xattr matches */
2023-05-01 21:24:29 +03:00
g_autoptr ( GFile ) baz_child = g_file_get_child ( root , " baz " ) ;
g_autoptr ( GFile ) cow_child = g_file_get_child ( baz_child , " cow " ) ;
2017-09-28 22:08:06 +03:00
2023-05-01 21:24:29 +03:00
g_autoptr ( GVariant ) xattrs = NULL ;
2017-09-28 22:08:06 +03:00
ret = ostree_repo_file_get_xattrs ( OSTREE_REPO_FILE ( cow_child ) , & xattrs , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
gboolean found_xattr = FALSE ;
gsize n = g_variant_n_children ( xattrs ) ;
for ( gsize i = 0 ; i < n ; i + + )
{
2023-05-01 21:24:29 +03:00
const guint8 * name ;
const guint8 * value ;
2017-09-28 22:08:06 +03:00
g_variant_get_child ( xattrs , i , " (^&ay^&ay) " , & name , & value ) ;
2023-05-01 21:24:29 +03:00
if ( g_str_equal ( ( const char * ) name , " user.myattr " ) )
2017-09-28 22:08:06 +03:00
{
2023-05-01 21:24:29 +03:00
g_assert_cmpstr ( ( const char * ) value , = = , " data " ) ;
2017-09-28 22:08:06 +03:00
found_xattr = TRUE ;
break ;
}
}
g_assert ( found_xattr ) ;
OstreeRepoTransactionStats stats ;
ret = ostree_repo_commit_transaction ( repo , & stats , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
/* we should only have had to checksum /baz/cow */
g_assert_cmpint ( stats . content_objects_written , = = , 1 ) ;
}
2018-10-01 03:10:14 +03:00
/* https://github.com/ostreedev/ostree/issues/1721
* We should be able to commit large metadata objects now .
*/
static void
test_big_metadata ( void )
{
2023-05-01 21:24:29 +03:00
g_autoptr ( GError ) error = NULL ;
2018-10-01 03:10:14 +03:00
gboolean ret = FALSE ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GFile ) repo_path = g_file_new_for_path ( " repo " ) ;
2018-10-01 03:10:14 +03:00
/* init as bare-user-only so we run everywhere */
ret = ot_test_run_libtest ( " setup_test_repository bare-user-only " , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( OstreeRepo ) repo = ostree_repo_new ( repo_path ) ;
2018-10-01 03:10:14 +03:00
ret = ostree_repo_open ( repo , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GFile ) object_to_commit = NULL ;
2018-10-01 03:10:14 +03:00
ret = ostree_repo_read_commit ( repo , " test2 " , & object_to_commit , NULL , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( OstreeMutableTree ) mtree = ostree_mutable_tree_new ( ) ;
ret = ostree_repo_write_directory_to_mtree ( repo , object_to_commit , mtree , NULL , NULL , & error ) ;
2018-10-01 03:10:14 +03:00
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
2023-05-26 13:09:13 +03:00
const size_t len = OSTREE_MAX_METADATA_SIZE + 1 ;
2018-10-01 03:10:14 +03:00
g_assert_cmpint ( len , > , OSTREE_MAX_METADATA_SIZE ) ;
g_autofree char * large_buf = g_malloc ( len ) ;
memset ( large_buf , 0x42 , len ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GVariantBuilder ) builder = g_variant_builder_new ( G_VARIANT_TYPE ( " a{sv} " ) ) ;
2018-10-01 03:10:14 +03:00
g_autofree char * commit_checksum = NULL ;
2023-05-01 21:24:29 +03:00
g_variant_builder_add (
builder , " {sv} " , " large-value " ,
g_variant_new_fixed_array ( ( GVariantType * ) " y " , large_buf , len , sizeof ( char ) ) ) ;
2018-10-01 03:10:14 +03:00
ret = ostree_repo_write_commit ( repo , NULL , NULL , NULL , g_variant_builder_end ( builder ) ,
2023-05-01 21:24:29 +03:00
OSTREE_REPO_FILE ( object_to_commit ) , & commit_checksum , NULL ,
& error ) ;
2018-10-01 03:10:14 +03:00
g_assert_no_error ( error ) ;
g_assert ( ret ) ;
}
2022-05-07 20:51:31 +03:00
static void
compare_xattrs ( GVariant * orig , GVariant * new )
{
g_assert_cmpint ( g_variant_n_children ( orig ) + 1 , = = , g_variant_n_children ( new ) ) ;
GVariant * kp , * vp ;
GVariantIter iter ;
g_variant_iter_init ( & iter , new ) ;
bool found = false ;
while ( g_variant_iter_loop ( & iter , " (@ay@ay) " , & kp , & vp ) )
{
const char * k = g_variant_get_bytestring ( kp ) ;
if ( ! g_str_equal ( k , " user.ostreetesting " ) )
continue ;
g_assert_cmpint ( g_variant_get_size ( vp ) , = = , 4 ) ;
found = true ;
}
g_assert ( found ) ;
}
static void
test_read_xattrs ( void )
{
2023-05-01 21:24:29 +03:00
g_autoptr ( GError ) local_error = NULL ;
2022-05-07 20:51:31 +03:00
GError * * error = & local_error ;
2023-05-01 21:24:29 +03:00
g_auto ( GLnxTmpDir ) tmpd = {
0 ,
} ;
2022-05-07 20:51:31 +03:00
// Use /var/tmp to hope we get xattr support
glnx_mkdtempat ( AT_FDCWD , " /var/tmp/ostree-xattrs-test.XXXXXX " , 0700 , & tmpd , error ) ;
g_assert_no_error ( local_error ) ;
const char value [ ] = " foo " ;
{
2023-05-01 21:24:29 +03:00
g_autoptr ( GVariant ) current_xattrs = ostree_fs_get_all_xattrs ( tmpd . fd , NULL , error ) ;
2022-05-07 20:51:31 +03:00
g_assert_no_error ( local_error ) ;
2023-02-08 00:48:15 +03:00
2022-05-07 20:51:31 +03:00
int r = fsetxattr ( tmpd . fd , " user.ostreetesting " , value , sizeof ( value ) , 0 ) ;
2022-06-17 16:15:35 +03:00
if ( r ! = 0 )
{
2023-05-01 21:24:29 +03:00
g_autofree gchar * message = g_strdup_printf (
" Unable to set extended attributes in /var/tmp: %s " , g_strerror ( errno ) ) ;
2022-06-17 16:15:35 +03:00
g_test_skip ( message ) ;
return ;
}
2023-05-01 21:24:29 +03:00
g_autoptr ( GVariant ) new_xattrs = ostree_fs_get_all_xattrs ( tmpd . fd , NULL , error ) ;
2022-05-07 20:51:31 +03:00
g_assert_no_error ( local_error ) ;
2023-02-08 00:48:15 +03:00
2022-05-07 20:51:31 +03:00
compare_xattrs ( current_xattrs , new_xattrs ) ;
}
{
if ( symlinkat ( " nosuchtarget " , tmpd . fd , " somelink " ) < 0 )
glnx_throw_errno_prefix ( error , " symlinkat " ) ;
g_assert_no_error ( local_error ) ;
2023-05-01 21:24:29 +03:00
g_autoptr ( GVariant ) current_xattrs
= ostree_fs_get_all_xattrs_at ( tmpd . fd , " somelink " , NULL , error ) ;
2022-05-07 20:51:31 +03:00
g_assert_no_error ( local_error ) ;
2023-05-01 21:24:29 +03:00
( void ) current_xattrs ;
2022-05-07 20:51:31 +03:00
// OK, can't do user. xattrs on symlinks unfortunately.
// char pathbuf[PATH_MAX];
// snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", tmpd.fd, "somelink");
// int r = lsetxattr (pathbuf, "user.ostreetesting", value, sizeof (value), 0);
// if (r < 0)
// glnx_throw_errno_prefix (error, "lsetxattr");
// g_assert_no_error (local_error);
2023-02-08 00:48:15 +03:00
2023-05-01 21:24:29 +03:00
// g_autoptr(GVariant) new_xattrs = ostree_fs_get_all_xattrs_at (tmpd.fd, "somelink", NULL,
// error); g_assert_no_error (local_error);
2023-02-08 00:48:15 +03:00
2022-05-07 20:51:31 +03:00
// compare_xattrs (current_xattrs, new_xattrs);
}
}
2024-06-01 18:29:13 +03:00
static void
test_dirmeta_xattrs ( void )
{
g_autoptr ( GError ) local_error = NULL ;
GError * * error = & local_error ;
const guint32 uidgid = GUINT32_TO_BE ( 42 ) ;
const guint32 mode = GUINT32_TO_BE ( S_IFDIR | S_IRWXU ) ;
g_autoptr ( GVariantBuilder ) xattr_builder = g_variant_builder_new ( G_VARIANT_TYPE ( " a(ayay) " ) ) ;
const char * data = " data " ;
g_variant_builder_add ( xattr_builder , " (@ay@ay) " , g_variant_new_bytestring ( " " ) ,
g_variant_new_bytestring ( data ) ) ;
g_autoptr ( GVariant ) dirmeta = g_variant_new ( " (uuu@a(ayay)) " , uidgid , uidgid , mode ,
g_variant_builder_end ( xattr_builder ) ) ;
g_assert ( ! ostree_validate_structureof_dirmeta ( dirmeta , error ) ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_FAILED ) ;
}
2023-05-01 21:24:29 +03:00
int
main ( int argc , char * * argv )
2016-03-02 18:05:08 +03:00
{
2023-05-01 21:24:29 +03:00
g_autoptr ( GError ) error = NULL ;
2016-03-03 21:49:54 +03:00
glnx_unref_object OstreeRepo * repo = NULL ;
2016-03-02 18:05:08 +03:00
g_test_init ( & argc , & argv , NULL ) ;
2017-09-28 22:08:06 +03:00
repo = ot_test_setup_repo ( NULL , & error ) ;
2016-03-03 21:49:54 +03:00
if ( ! repo )
2016-03-02 18:05:08 +03:00
goto out ;
2017-05-24 23:43:39 +03:00
2016-03-03 21:49:54 +03:00
g_test_add_data_func ( " /repo-not-system " , repo , test_repo_is_not_system ) ;
2017-09-01 23:15:33 +03:00
g_test_add_data_func ( " /raw-file-to-archive-stream " , repo , test_raw_file_to_archive_stream ) ;
2017-05-24 23:43:39 +03:00
g_test_add_data_func ( " /objectwrites " , repo , test_object_writes ) ;
2017-09-28 22:08:06 +03:00
g_test_add_func ( " /xattrs-devino-cache " , test_devino_cache_xattrs ) ;
2017-12-14 19:10:35 +03:00
g_test_add_func ( " /break-hardlink " , test_break_hardlink ) ;
2017-06-14 14:28:52 +03:00
g_test_add_func ( " /remotename " , test_validate_remotename ) ;
2018-10-01 03:10:14 +03:00
g_test_add_func ( " /big-metadata " , test_big_metadata ) ;
2022-05-07 20:51:31 +03:00
g_test_add_func ( " /read-xattrs " , test_read_xattrs ) ;
2024-06-01 18:29:13 +03:00
g_test_add_func ( " /dirmeta-xattrs " , test_dirmeta_xattrs ) ;
2016-03-02 18:05:08 +03:00
2023-05-01 21:24:29 +03:00
return g_test_run ( ) ;
out :
2016-03-02 18:05:08 +03:00
if ( error )
g_error ( " %s " , error - > message ) ;
return 1 ;
}