@@ -21,6 +21,7 @@ use core::mem::{MaybeUninit, offset_of};
2121use align_address:: Align ;
2222use async_lock:: { Mutex , RwLock } ;
2323use async_trait:: async_trait;
24+ use hermit_entry:: ThinTree ;
2425
2526use crate :: errno:: Errno ;
2627use crate :: executor:: block_on;
@@ -319,6 +320,10 @@ impl RomFile {
319320 pub fn new ( data : & ' static [ u8 ] , mode : AccessPermission ) -> Self {
320321 let microseconds = arch:: kernel:: systemtime:: now_micros ( ) ;
321322 let t = timespec:: from_usec ( microseconds as i64 ) ;
323+ Self :: new_with_timestamp ( data, mode, t)
324+ }
325+
326+ pub fn new_with_timestamp ( data : & ' static [ u8 ] , mode : AccessPermission , t : timespec ) -> Self {
322327 let attr = FileAttr {
323328 st_size : data. len ( ) . try_into ( ) . unwrap ( ) ,
324329 st_mode : mode | AccessPermission :: S_IFREG ,
@@ -477,6 +482,36 @@ pub(crate) struct MemDirectory {
477482 attr : FileAttr ,
478483}
479484
485+ fn thin_tree_to_vfs_node (
486+ thin_tree : ThinTree < ' static > ,
487+ t : timespec ,
488+ ) -> io:: Result < Box < dyn VfsNode + Send + Sync > > {
489+ Ok ( match thin_tree {
490+ ThinTree :: File { content, metadata } => {
491+ let mut st_mode = AccessPermission :: S_IRUSR ;
492+ if metadata. is_exec {
493+ st_mode |= AccessPermission :: S_IXUSR ;
494+ }
495+ Box :: new ( RomFile :: new_with_timestamp ( content, st_mode, t) )
496+ as Box < dyn VfsNode + Send + Sync >
497+ }
498+ ThinTree :: Directory ( d) => Box :: new ( MemDirectory {
499+ inner : Arc :: new ( RwLock :: new (
500+ d. into_iter ( )
501+ . map ( |( key, value) | Ok ( ( key. to_string ( ) , thin_tree_to_vfs_node ( value, t) ?) ) )
502+ . collect :: < io:: Result < _ > > ( ) ?,
503+ ) ) ,
504+ attr : FileAttr {
505+ st_mode : AccessPermission :: S_IRUSR | AccessPermission :: S_IFDIR ,
506+ st_atim : t,
507+ st_mtim : t,
508+ st_ctim : t,
509+ ..Default :: default ( )
510+ } ,
511+ } ) as Box < dyn VfsNode + Send + Sync > ,
512+ } )
513+ }
514+
480515impl MemDirectory {
481516 pub fn new ( mode : AccessPermission ) -> Self {
482517 let microseconds = arch:: kernel:: systemtime:: now_micros ( ) ;
@@ -494,6 +529,45 @@ impl MemDirectory {
494529 }
495530 }
496531
532+ /// Create a read-only memory tree from a tar image
533+ ///
534+ /// This ignores top-level files in the image
535+ pub fn try_from_image ( image : & ' static hermit_entry:: tar_parser:: Bytes ) -> io:: Result < Self > {
536+ let microseconds = arch:: kernel:: systemtime:: now_micros ( ) ;
537+ let t = timespec:: from_usec ( microseconds as i64 ) ;
538+
539+ // This is not perfectly memory-efficient, but we expect this
540+ // to be invoked usually once per kernel boot, so this cost should
541+ // be acceptable, given that it reduces code duplication and
542+ // makes implementation way easier.
543+ let thin_tree = ThinTree :: try_from_image ( image) . map_err ( |e| {
544+ error ! ( "unable to parse tar image: {:?}" , e) ;
545+ Errno :: Inval
546+ } ) ?;
547+
548+ let mut tree = match thin_tree {
549+ ThinTree :: Directory ( d) => d
550+ . into_iter ( )
551+ . map ( |( key, value) | Ok ( ( key. to_string ( ) , thin_tree_to_vfs_node ( value, t) ?) ) )
552+ . collect :: < io:: Result < _ > > ( ) ?,
553+ _ => {
554+ error ! ( "root of image isn't a directory" ) ;
555+ return Err ( Errno :: Inval ) ;
556+ }
557+ } ;
558+
559+ Self {
560+ inner : Arc :: new ( RwLock :: new ( tree) ) ,
561+ attr : FileAttr {
562+ st_mode : AccessPermission :: S_IRUSR | AccessPermission :: S_IFDIR ,
563+ st_atim : t,
564+ st_mtim : t,
565+ st_ctim : t,
566+ ..Default :: default ( )
567+ } ,
568+ }
569+ }
570+
497571 async fn async_traverse_open (
498572 & self ,
499573 components : & mut Vec < & str > ,
0 commit comments