@@ -8,8 +8,10 @@ use crate::container::{Config, ExportOpts, ImageReference, Transport};
88use crate :: objectsource:: { ObjectMeta , ObjectSourceMeta } ;
99use crate :: objgv:: gv_dirtree;
1010use crate :: prelude:: * ;
11+ use crate :: tar:: SECURITY_SELINUX_XATTR_C ;
1112use crate :: { gio, glib} ;
1213use anyhow:: { anyhow, Context , Result } ;
14+ use bootc_utils:: CommandRunExt ;
1315use camino:: { Utf8Component , Utf8Path , Utf8PathBuf } ;
1416use cap_std:: fs:: Dir ;
1517use cap_std_ext:: cap_std;
@@ -25,6 +27,7 @@ use ocidir::oci_spec::image::ImageConfigurationBuilder;
2527use once_cell:: sync:: Lazy ;
2628use regex:: Regex ;
2729use std:: borrow:: Cow ;
30+ use std:: ffi:: CString ;
2831use std:: fmt:: Write as _;
2932use std:: io:: { self , Write } ;
3033use std:: ops:: Add ;
@@ -46,12 +49,19 @@ enum FileDefType {
4649 Directory ,
4750}
4851
52+ #[ derive( Debug ) ]
53+ struct Xattr {
54+ key : CString ,
55+ value : Box < [ u8 ] > ,
56+ }
57+
4958#[ derive( Debug ) ]
5059pub struct FileDef {
5160 uid : u32 ,
5261 gid : u32 ,
5362 mode : u32 ,
5463 path : Cow < ' static , Utf8Path > ,
64+ xattrs : Box < [ Xattr ] > ,
5565 ty : FileDefType ,
5666}
5767
@@ -66,9 +76,21 @@ impl TryFrom<&'static str> for FileDef {
6676 let name = parts. next ( ) . ok_or_else ( || anyhow ! ( "Missing file name" ) ) ?;
6777 let contents = parts. next ( ) ;
6878 let contents = move || contents. ok_or_else ( || anyhow ! ( "Missing file contents: {}" , value) ) ;
69- if parts. next ( ) . is_some ( ) {
70- anyhow:: bail!( "Invalid filedef: {}" , value) ;
71- }
79+ let xattrs: Result < Vec < _ > > = parts
80+ . map ( |xattr| -> Result < Xattr > {
81+ let ( k, v) = xattr
82+ . split_once ( '=' )
83+ . ok_or_else ( || anyhow:: anyhow!( "Invalid xattr: {xattr}" ) ) ?;
84+ let mut k: Vec < u8 > = k. to_owned ( ) . into ( ) ;
85+ k. push ( 0 ) ;
86+ let r = Xattr {
87+ key : CString :: from_vec_with_nul ( k) . unwrap ( ) ,
88+ value : Vec :: from ( v. to_owned ( ) ) . into ( ) ,
89+ } ;
90+ Ok ( r)
91+ } )
92+ . collect ( ) ;
93+ let xattrs = xattrs?. into ( ) ;
7294 let ty = match tydef {
7395 "r" => FileDefType :: Regular ( contents ( ) ?. into ( ) ) ,
7496 "l" => FileDefType :: Symlink ( Cow :: Borrowed ( contents ( ) ?. into ( ) ) ) ,
@@ -80,6 +102,7 @@ impl TryFrom<&'static str> for FileDef {
80102 gid : 0 ,
81103 mode : 0o644 ,
82104 path : Cow :: Borrowed ( name. into ( ) ) ,
105+ xattrs,
83106 ty,
84107 } )
85108 }
@@ -165,6 +188,7 @@ static OWNERS: Lazy<Vec<(Regex, &str)>> = Lazy::new(|| {
165188 ( "usr/lib/modules/.*/initramfs" , "initramfs" ) ,
166189 ( "usr/lib/modules" , "kernel" ) ,
167190 ( "usr/bin/(ba)?sh" , "bash" ) ,
191+ ( "usr/bin/arping" , "arping" ) ,
168192 ( "usr/lib.*/emptyfile.*" , "bash" ) ,
169193 ( "usr/bin/hardlink.*" , "testlink" ) ,
170194 ( "usr/etc/someconfig.conf" , "someconfig" ) ,
@@ -184,6 +208,7 @@ r usr/lib/modules/5.10.18-200.x86_64/initramfs this-is-an-initramfs
184208m 0 0 755
185209r usr/bin/bash the-bash-shell
186210l usr/bin/sh bash
211+ r usr/bin/arping arping-binary security.capability=0sAAAAAgAgAAAAAAAAAAAAAAAAAAA=
187212m 0 0 644
188213# Some empty files
189214r usr/lib/emptyfile
@@ -206,7 +231,7 @@ m 0 0 1755
206231d tmp
207232"## } ;
208233pub const CONTENTS_CHECKSUM_V0 : & str =
209- "acc42fb5c796033f034941dc688643bf8beddfd9068d87165344d2b99906220a " ;
234+ "bd3d13c3059e63e6f8a3d6d046923ded730d90bd7a055c9ad93312111ea7d395 " ;
210235// 1 for ostree commit, 2 for max frequency packages, 3 as empty layer
211236pub const LAYERS_V0_LEN : usize = 3usize ;
212237pub const PKGS_V0_LEN : usize = 7usize ;
@@ -267,11 +292,10 @@ impl SeLabel {
267292 }
268293
269294 pub fn xattrs ( & self ) -> Vec < ( & [ u8 ] , & [ u8 ] ) > {
270- vec ! [ ( b"security.selinux\0 " , self . to_str( ) . as_bytes( ) ) ]
271- }
272-
273- pub fn new_xattrs ( & self ) -> glib:: Variant {
274- self . xattrs ( ) . to_variant ( )
295+ vec ! [ (
296+ SECURITY_SELINUX_XATTR_C . to_bytes_with_nul( ) ,
297+ self . to_str( ) . as_bytes( ) ,
298+ ) ]
275299 }
276300}
277301
@@ -286,7 +310,7 @@ pub fn create_dirmeta(path: &Utf8Path, selinux: bool) -> glib::Variant {
286310 } else {
287311 None
288312 } ;
289- let xattrs = label. map ( |v| v. new_xattrs ( ) ) ;
313+ let xattrs = label. map ( |v| v. xattrs ( ) . to_variant ( ) ) ;
290314 ostree:: create_directory_metadata ( & finfo, xattrs. as_ref ( ) )
291315}
292316
@@ -632,7 +656,18 @@ impl Fixture {
632656 } else {
633657 None
634658 } ;
635- let xattrs = label. map ( |v| v. new_xattrs ( ) ) ;
659+ let mut xattrs = label. as_ref ( ) . map ( |v| v. xattrs ( ) ) . unwrap_or_default ( ) ;
660+ xattrs. extend (
661+ def. xattrs
662+ . iter ( )
663+ . map ( |xattr| ( xattr. key . as_bytes_with_nul ( ) , & xattr. value [ ..] ) ) ,
664+ ) ;
665+ let xattrs = if xattrs. is_empty ( ) {
666+ None
667+ } else {
668+ xattrs. sort_by ( |a, b| a. 0 . cmp ( b. 0 ) ) ;
669+ Some ( xattrs. to_variant ( ) )
670+ } ;
636671 let xattrs = xattrs. as_ref ( ) ;
637672 let checksum = match & def. ty {
638673 FileDefType :: Regular ( contents) => self
@@ -724,6 +759,21 @@ impl Fixture {
724759 gio:: Cancellable :: NONE ,
725760 ) ?;
726761
762+ // Verify that this is what is expected.
763+ let commit_object = self . srcrepo . load_commit ( & commit) ?. 0 ;
764+ let content_checksum = ostree:: commit_get_content_checksum ( & commit_object) . unwrap ( ) ;
765+ if content_checksum != CONTENTS_CHECKSUM_V0 {
766+ // Only spew this once
767+ static DUMP_OSTREE : std:: sync:: Once = std:: sync:: Once :: new ( ) ;
768+ DUMP_OSTREE . call_once ( || {
769+ let _ = Command :: new ( "ostree" )
770+ . arg ( format ! ( "--repo={}" , self . path. join( "src/repo" ) ) )
771+ . args ( [ "ls" , "-X" , "-C" , "-R" , commit. as_str ( ) ] )
772+ . run ( ) ;
773+ } ) ;
774+ }
775+ assert_eq ! ( CONTENTS_CHECKSUM_V0 , content_checksum. as_str( ) ) ;
776+
727777 Ok ( ( ) )
728778 }
729779
0 commit comments