@@ -122,15 +122,6 @@ pub(crate) struct RamFileInner {
122122 pub attr : FileAttr ,
123123}
124124
125- impl RamFileInner {
126- pub fn new ( attr : FileAttr ) -> Self {
127- Self {
128- data : Vec :: new ( ) ,
129- attr,
130- }
131- }
132- }
133-
134125pub struct RamFileInterface {
135126 /// Position within the file
136127 pos : Mutex < usize > ,
@@ -354,6 +345,10 @@ impl VfsNode for RamFile {
354345
355346impl RamFile {
356347 pub fn new ( mode : AccessPermission ) -> Self {
348+ Self :: new_with_data ( Vec :: new ( ) , mode)
349+ }
350+
351+ fn new_with_data ( data : Vec < u8 > , mode : AccessPermission ) -> Self {
357352 let microseconds = arch:: kernel:: systemtime:: now_micros ( ) ;
358353 let t = timespec:: from_usec ( microseconds as i64 ) ;
359354 let attr = FileAttr {
@@ -365,7 +360,7 @@ impl RamFile {
365360 } ;
366361
367362 Self {
368- data : Arc :: new ( RwLock :: new ( RamFileInner :: new ( attr) ) ) ,
363+ data : Arc :: new ( RwLock :: new ( RamFileInner { data , attr } ) ) ,
369364 }
370365 }
371366}
@@ -464,6 +459,63 @@ impl MemDirectory {
464459 }
465460 }
466461
462+ pub fn try_from_image ( image : & ' static [ u8 ] ) -> io:: Result < Self > {
463+ let this = Self :: new ( AccessPermission :: S_IRUSR ) ;
464+
465+ let taref = tar_no_std:: TarArchiveRef :: new ( image) . map_err ( |e| {
466+ error ! ( "[Hermit image] Tar file has invalid format: {e:?}" ) ;
467+ Errno :: Inval
468+ } ) ?;
469+
470+ for i in taref. entries ( ) {
471+ let filename = i. filename ( ) ;
472+ let filename = filename. as_str ( ) . map_err ( |e| {
473+ error ! (
474+ "[Hermit image] Tar entry has not supported filename (non UTF-8): {filename:?}; {e}" ,
475+ ) ;
476+ Errno :: Inval
477+ } ) ?;
478+ if filename. is_empty ( ) {
479+ continue ;
480+ }
481+ debug ! ( "[Hermit image] Processing tar entry: {}" , filename) ;
482+
483+ let mode = i. posix_header ( ) . mode . to_flags ( ) . map_err ( |e| {
484+ error ! (
485+ "[Hermit image] Tar entry {filename:?} has invalid mode: {:?}; {e}" ,
486+ i. posix_header( ) . mode,
487+ ) ;
488+ Errno :: Inval
489+ } ) ?;
490+ let mode = AccessPermission :: from_bits ( mode. bits ( ) as u32 ) . ok_or_else ( || {
491+ error ! ( "[Hermit image] Tar entry {filename:?} has invalid mode: {mode:?}" ) ;
492+ Errno :: Inval
493+ } ) ?;
494+
495+ for ( i, _) in filename. match_indices ( "/" ) {
496+ let part = & filename[ ..i] ;
497+ if this. traverse_lstat ( part) . is_err ( ) {
498+ this. traverse_mkdir (
499+ part,
500+ AccessPermission :: S_IRUSR
501+ | AccessPermission :: S_IWUSR
502+ | AccessPermission :: S_IRGRP ,
503+ )
504+ . inspect_err ( |e| {
505+ error ! ( "[Hermit image] Unable to mkdir {part:?}: {e}" ) ;
506+ } ) ?;
507+ }
508+ }
509+
510+ this. traverse_create_file ( filename, i. data ( ) , mode)
511+ . inspect_err ( |e| {
512+ error ! ( "[Hermit image] Unable to write entry {filename:?}: {e}" ) ;
513+ } ) ?;
514+ }
515+
516+ Ok ( this)
517+ }
518+
467519 async fn async_traverse_open (
468520 & self ,
469521 path : & str ,
@@ -693,11 +745,16 @@ impl VfsNode for MemDirectory {
693745 return directory. traverse_create_file ( rest, data, mode) ;
694746 }
695747
696- let file = RomFile :: new ( data, mode) ;
697- self . inner
698- . write ( )
699- . await
700- . insert ( component. to_owned ( ) , Box :: new ( file) ) ;
748+ let file: Box < dyn VfsNode > = if mode. contains ( AccessPermission :: S_IWUSR )
749+ || mode. contains ( AccessPermission :: S_IWGRP )
750+ || mode. contains ( AccessPermission :: S_IWOTH )
751+ {
752+ Box :: new ( RamFile :: new_with_data ( data. to_vec ( ) , mode) )
753+ } else {
754+ Box :: new ( RomFile :: new ( data, mode) )
755+ } ;
756+
757+ self . inner . write ( ) . await . insert ( component. to_owned ( ) , file) ;
701758 Ok ( ( ) )
702759 } ,
703760 None ,
0 commit comments