@@ -636,6 +636,52 @@ impl<'a, W: std::io::Write> OstreeTarWriter<'a, W> {
636
636
. append_data ( & mut header, "var/tmp" , std:: io:: empty ( ) ) ?;
637
637
Ok ( ( ) )
638
638
}
639
+
640
+ fn write_parents_of (
641
+ & mut self ,
642
+ path : & Utf8Path ,
643
+ cache : & mut HashSet < Utf8PathBuf > ,
644
+ ) -> Result < ( ) > {
645
+ let Some ( parent) = path. parent ( ) else {
646
+ return Ok ( ( ) ) ;
647
+ } ;
648
+
649
+ if parent. components ( ) . count ( ) == 0 {
650
+ return Ok ( ( ) ) ;
651
+ }
652
+
653
+ if cache. contains ( parent) {
654
+ return Ok ( ( ) ) ;
655
+ }
656
+
657
+ self . write_parents_of ( parent, cache) ?;
658
+
659
+ let inserted = cache. insert ( parent. to_owned ( ) ) ;
660
+ debug_assert ! ( inserted) ;
661
+
662
+ let root = self
663
+ . repo
664
+ . read_commit ( & self . commit_checksum , gio:: Cancellable :: NONE ) ?
665
+ . 0 ;
666
+ let parent_file = root. resolve_relative_path ( unmap_path ( parent) . as_ref ( ) ) ;
667
+ let queryattrs = "unix::*" ;
668
+ let queryflags = gio:: FileQueryInfoFlags :: NOFOLLOW_SYMLINKS ;
669
+ let stat = parent_file. query_info ( & queryattrs, queryflags, gio:: Cancellable :: NONE ) ?;
670
+ let uid = stat. attribute_uint32 ( gio:: FILE_ATTRIBUTE_UNIX_UID ) ;
671
+ let gid = stat. attribute_uint32 ( gio:: FILE_ATTRIBUTE_UNIX_GID ) ;
672
+ let orig_mode = stat. attribute_uint32 ( gio:: FILE_ATTRIBUTE_UNIX_MODE ) ;
673
+ let mode = self . filter_mode ( orig_mode) ;
674
+
675
+ let mut header = tar:: Header :: new_gnu ( ) ;
676
+ header. set_entry_type ( tar:: EntryType :: Directory ) ;
677
+ header. set_size ( 0 ) ;
678
+ header. set_uid ( uid as u64 ) ;
679
+ header. set_gid ( gid as u64 ) ;
680
+ header. set_mode ( mode) ;
681
+ self . out
682
+ . append_data ( & mut header, parent, std:: io:: empty ( ) ) ?;
683
+ Ok ( ( ) )
684
+ }
639
685
}
640
686
641
687
/// Recursively walk an OSTree commit and generate data into a `[tar::Builder]`
@@ -684,12 +730,17 @@ fn path_for_tar_v1(p: &Utf8Path) -> &Utf8Path {
684
730
fn write_chunk < W : std:: io:: Write > (
685
731
writer : & mut OstreeTarWriter < W > ,
686
732
chunk : chunking:: ChunkMapping ,
733
+ create_parent_dirs : bool ,
687
734
) -> Result < ( ) > {
735
+ let mut cache = std:: collections:: HashSet :: new ( ) ;
688
736
for ( checksum, ( _size, paths) ) in chunk. into_iter ( ) {
689
737
let ( objpath, h) = writer. append_content ( checksum. borrow ( ) ) ?;
690
738
for path in paths. iter ( ) {
691
739
let path = path_for_tar_v1 ( path) ;
692
740
let h = h. clone ( ) ;
741
+ if create_parent_dirs {
742
+ writer. write_parents_of ( & path, & mut cache) ?;
743
+ }
693
744
writer. append_content_hardlink ( & objpath, h, path) ?;
694
745
}
695
746
}
@@ -702,13 +753,14 @@ pub(crate) fn export_chunk<W: std::io::Write>(
702
753
commit : & str ,
703
754
chunk : chunking:: ChunkMapping ,
704
755
out : & mut tar:: Builder < W > ,
756
+ create_parent_dirs : bool ,
705
757
) -> Result < ( ) > {
706
758
// For chunking, we default to format version 1
707
759
#[ allow( clippy:: needless_update) ]
708
760
let opts = ExportOptions ;
709
761
let writer = & mut OstreeTarWriter :: new ( repo, commit, out, opts) ?;
710
762
writer. write_repo_structure ( ) ?;
711
- write_chunk ( writer, chunk)
763
+ write_chunk ( writer, chunk, create_parent_dirs )
712
764
}
713
765
714
766
/// Output the last chunk in a chunking.
@@ -718,6 +770,7 @@ pub(crate) fn export_final_chunk<W: std::io::Write>(
718
770
commit_checksum : & str ,
719
771
remainder : chunking:: Chunk ,
720
772
out : & mut tar:: Builder < W > ,
773
+ create_parent_dirs : bool ,
721
774
) -> Result < ( ) > {
722
775
let options = ExportOptions ;
723
776
let writer = & mut OstreeTarWriter :: new ( repo, commit_checksum, out, options) ?;
@@ -726,7 +779,7 @@ pub(crate) fn export_final_chunk<W: std::io::Write>(
726
779
writer. structure_only = true ;
727
780
writer. write_commit ( ) ?;
728
781
writer. structure_only = false ;
729
- write_chunk ( writer, remainder. content )
782
+ write_chunk ( writer, remainder. content , create_parent_dirs )
730
783
}
731
784
732
785
/// Process an exported tar stream, and update the detached metadata.
0 commit comments