@@ -10,9 +10,158 @@ use crate::linux::{Clock, LinuxBlockDevice};
1010
1111mod linux;
1212
13- struct State {
13+ struct VolumeState {
1414 directory : Directory ,
1515 volume : Volume ,
16+ path : Vec < String > ,
17+ }
18+
19+ struct Context {
20+ volume_mgr : VolumeManager < LinuxBlockDevice , Clock , 8 , 8 , 4 > ,
21+ volumes : [ Option < VolumeState > ; 4 ] ,
22+ current_volume : usize ,
23+ }
24+
25+ impl Context {
26+ fn current_path ( & self ) -> Vec < String > {
27+ let Some ( s) = & self . volumes [ self . current_volume ] else {
28+ return vec ! [ ] ;
29+ } ;
30+ s. path . clone ( )
31+ }
32+
33+ fn process_line ( & mut self , line : & str ) -> Result < ( ) , Error < std:: io:: Error > > {
34+ if line == "help" {
35+ println ! ( "Commands:" ) ;
36+ println ! ( "\t help -> this help text" ) ;
37+ println ! ( "\t <volume>: -> change volume/partition" ) ;
38+ println ! ( "\t dir -> do a directory listing" ) ;
39+ println ! ( "\t stat -> print volume manager status" ) ;
40+ println ! ( "\t cat <file> -> print a text file" ) ;
41+ println ! ( "\t hexdump <file> -> print a binary file" ) ;
42+ println ! ( "\t cd .. -> go up a level" ) ;
43+ println ! ( "\t cd <dir> -> change into <dir>" ) ;
44+ println ! ( "\t quit -> exits the program" ) ;
45+ } else if line == "0:" {
46+ self . current_volume = 0 ;
47+ } else if line == "1:" {
48+ self . current_volume = 1 ;
49+ } else if line == "2:" {
50+ self . current_volume = 2 ;
51+ } else if line == "3:" {
52+ self . current_volume = 3 ;
53+ } else if line == "stat" {
54+ println ! ( "Status:\n {:#?}" , self . volume_mgr) ;
55+ } else if line == "dir" {
56+ let Some ( s) = & self . volumes [ self . current_volume ] else {
57+ println ! ( "That volume isn't available" ) ;
58+ return Ok ( ( ) ) ;
59+ } ;
60+ self . volume_mgr . iterate_dir ( s. directory , |entry| {
61+ println ! (
62+ "{:12} {:9} {} {}" ,
63+ entry. name,
64+ entry. size,
65+ entry. mtime,
66+ if entry. attributes. is_directory( ) {
67+ "<DIR>"
68+ } else {
69+ ""
70+ }
71+ ) ;
72+ } ) ?;
73+ } else if let Some ( arg) = line. strip_prefix ( "cd " ) {
74+ let Some ( s) = & mut self . volumes [ self . current_volume ] else {
75+ println ! ( "This volume isn't available" ) ;
76+ return Ok ( ( ) ) ;
77+ } ;
78+ let d = self . volume_mgr . open_dir ( s. directory , arg) ?;
79+ self . volume_mgr . close_dir ( s. directory ) ?;
80+ s. directory = d;
81+ if arg == ".." {
82+ s. path . pop ( ) ;
83+ } else {
84+ s. path . push ( arg. to_owned ( ) ) ;
85+ }
86+ } else if let Some ( arg) = line. strip_prefix ( "cat " ) {
87+ let Some ( s) = & mut self . volumes [ self . current_volume ] else {
88+ println ! ( "This volume isn't available" ) ;
89+ return Ok ( ( ) ) ;
90+ } ;
91+ let f = self . volume_mgr . open_file_in_dir (
92+ s. directory ,
93+ arg,
94+ embedded_sdmmc:: Mode :: ReadOnly ,
95+ ) ?;
96+ let mut inner = || -> Result < ( ) , Error < std:: io:: Error > > {
97+ let mut data = Vec :: new ( ) ;
98+ while !self . volume_mgr . file_eof ( f) ? {
99+ let mut buffer = vec ! [ 0u8 ; 65536 ] ;
100+ let n = self . volume_mgr . read ( f, & mut buffer) ?;
101+ // read n bytes
102+ data. extend_from_slice ( & buffer[ 0 ..n] ) ;
103+ println ! ( "Read {} bytes, making {} total" , n, data. len( ) ) ;
104+ }
105+ if let Ok ( s) = std:: str:: from_utf8 ( & data) {
106+ println ! ( "{}" , s) ;
107+ } else {
108+ println ! ( "I'm afraid that file isn't UTF-8 encoded" ) ;
109+ }
110+ Ok ( ( ) )
111+ } ;
112+ let r = inner ( ) ;
113+ self . volume_mgr . close_file ( f) ?;
114+ r?;
115+ } else if let Some ( arg) = line. strip_prefix ( "hexdump " ) {
116+ let Some ( s) = & mut self . volumes [ self . current_volume ] else {
117+ println ! ( "This volume isn't available" ) ;
118+ return Ok ( ( ) ) ;
119+ } ;
120+ let f = self . volume_mgr . open_file_in_dir (
121+ s. directory ,
122+ arg,
123+ embedded_sdmmc:: Mode :: ReadOnly ,
124+ ) ?;
125+ let mut inner = || -> Result < ( ) , Error < std:: io:: Error > > {
126+ let mut data = Vec :: new ( ) ;
127+ while !self . volume_mgr . file_eof ( f) ? {
128+ let mut buffer = vec ! [ 0u8 ; 65536 ] ;
129+ let n = self . volume_mgr . read ( f, & mut buffer) ?;
130+ // read n bytes
131+ data. extend_from_slice ( & buffer[ 0 ..n] ) ;
132+ println ! ( "Read {} bytes, making {} total" , n, data. len( ) ) ;
133+ }
134+ for ( idx, chunk) in data. chunks ( 16 ) . enumerate ( ) {
135+ print ! ( "{:08x} | " , idx * 16 ) ;
136+ for b in chunk {
137+ print ! ( "{:02x} " , b) ;
138+ }
139+ for _padding in 0 ..( 16 - chunk. len ( ) ) {
140+ print ! ( " " ) ;
141+ }
142+ print ! ( "| " ) ;
143+ for b in chunk {
144+ print ! (
145+ "{}" ,
146+ if b. is_ascii_graphic( ) {
147+ * b as char
148+ } else {
149+ '.'
150+ }
151+ ) ;
152+ }
153+ println ! ( ) ;
154+ }
155+ Ok ( ( ) )
156+ } ;
157+ let r = inner ( ) ;
158+ self . volume_mgr . close_file ( f) ?;
159+ r?;
160+ } else {
161+ println ! ( "Unknown command {line:?} - try 'help' for help" ) ;
162+ }
163+ Ok ( ( ) )
164+ }
16165}
17166
18167fn main ( ) -> Result < ( ) , Error < std:: io:: Error > > {
@@ -22,29 +171,33 @@ fn main() -> Result<(), Error<std::io::Error>> {
22171 let print_blocks = args. find ( |x| x == "-v" ) . map ( |_| true ) . unwrap_or ( false ) ;
23172 println ! ( "Opening '{filename}'..." ) ;
24173 let lbd = LinuxBlockDevice :: new ( filename, print_blocks) . map_err ( Error :: DeviceError ) ?;
25- let mut volume_mgr: VolumeManager < LinuxBlockDevice , Clock , 8 , 8 , 4 > =
26- VolumeManager :: new_with_limits ( lbd, Clock , 100 ) ;
27174 let stdin = std:: io:: stdin ( ) ;
28- let mut volumes: [ Option < State > ; 4 ] = [ None , None , None , None ] ;
175+
176+ let mut ctx = Context {
177+ volume_mgr : VolumeManager :: new_with_limits ( lbd, Clock , 100 ) ,
178+ volumes : [ None , None , None , None ] ,
179+ current_volume : 0 ,
180+ } ;
29181
30182 let mut current_volume = None ;
31183 for volume_no in 0 ..4 {
32- match volume_mgr. open_volume ( VolumeIdx ( volume_no) ) {
184+ match ctx . volume_mgr . open_volume ( VolumeIdx ( volume_no) ) {
33185 Ok ( volume) => {
34186 println ! ( "Volume # {}: found" , volume_no, ) ;
35- match volume_mgr. open_root_dir ( volume) {
187+ match ctx . volume_mgr . open_root_dir ( volume) {
36188 Ok ( root_dir) => {
37- volumes[ volume_no] = Some ( State {
189+ ctx . volumes [ volume_no] = Some ( VolumeState {
38190 directory : root_dir,
39191 volume,
192+ path : vec ! [ ] ,
40193 } ) ;
41194 if current_volume. is_none ( ) {
42195 current_volume = Some ( volume_no) ;
43196 }
44197 }
45198 Err ( e) => {
46199 println ! ( "Failed to open root directory: {e:?}" ) ;
47- volume_mgr. close_volume ( volume) . expect ( "close volume" ) ;
200+ ctx . volume_mgr . close_volume ( volume) . expect ( "close volume" ) ;
48201 }
49202 }
50203 }
@@ -54,95 +207,51 @@ fn main() -> Result<(), Error<std::io::Error>> {
54207 }
55208 }
56209
57- let Some ( mut current_volume) = current_volume else {
58- println ! ( "No volumes found in file. Sorry." ) ;
59- return Ok ( ( ) ) ;
210+ match current_volume {
211+ Some ( n) => {
212+ // Default to the first valid partition
213+ ctx. current_volume = n;
214+ }
215+ None => {
216+ println ! ( "No volumes found in file. Sorry." ) ;
217+ return Ok ( ( ) ) ;
218+ }
60219 } ;
61220
62221 loop {
63- print ! ( "{}:> " , current_volume) ;
222+ print ! ( "{}:/" , ctx. current_volume) ;
223+ print ! ( "{}" , ctx. current_path( ) . join( "/" ) ) ;
224+ print ! ( "> " ) ;
64225 std:: io:: stdout ( ) . flush ( ) . unwrap ( ) ;
65226 let mut line = String :: new ( ) ;
66227 stdin. read_line ( & mut line) ?;
67228 let line = line. trim ( ) ;
68229 if line == "quit" {
69230 break ;
70- } else if line == "help" {
71- println ! ( "Commands:" ) ;
72- println ! ( "\t help -> this help text" ) ;
73- println ! ( "\t <volume>: -> change volume/partition" ) ;
74- println ! ( "\t dir -> do a directory listing" ) ;
75- println ! ( "\t quit -> exits the program" ) ;
76- } else if line == "0:" {
77- current_volume = 0 ;
78- } else if line == "1:" {
79- current_volume = 1 ;
80- } else if line == "2:" {
81- current_volume = 2 ;
82- } else if line == "3:" {
83- current_volume = 3 ;
84- } else if line == "stat" {
85- println ! ( "Status:\n {volume_mgr:#?}" ) ;
86- } else if line == "dir" {
87- let Some ( s) = & volumes[ current_volume] else {
88- println ! ( "That volume isn't available" ) ;
89- continue ;
90- } ;
91- let r = volume_mgr. iterate_dir ( s. directory , |entry| {
92- println ! (
93- "{:12} {:9} {} {}" ,
94- entry. name,
95- entry. size,
96- entry. mtime,
97- if entry. attributes. is_directory( ) {
98- "<DIR>"
99- } else {
100- ""
101- }
102- ) ;
103- } ) ;
104- handle ( "iterating directory" , r) ;
105- } else if let Some ( arg) = line. strip_prefix ( "cd " ) {
106- let Some ( s) = & mut volumes[ current_volume] else {
107- println ! ( "This volume isn't available" ) ;
108- continue ;
109- } ;
110- match volume_mgr. open_dir ( s. directory , arg) {
111- Ok ( d) => {
112- let r = volume_mgr. close_dir ( s. directory ) ;
113- handle ( "closing old directory" , r) ;
114- s. directory = d;
115- }
116- Err ( e) => {
117- handle ( "changing directory" , Err ( e) ) ;
118- }
119- }
120- } else {
121- println ! ( "Unknown command {line:?} - try 'help' for help" ) ;
231+ } else if let Err ( e) = ctx. process_line ( line) {
232+ println ! ( "Error: {:?}" , e) ;
122233 }
123234 }
124235
125- for ( idx, s) in volumes. into_iter ( ) . enumerate ( ) {
236+ for ( idx, s) in ctx . volumes . into_iter ( ) . enumerate ( ) {
126237 if let Some ( state) = s {
238+ println ! ( "Closing current dir for {idx}..." ) ;
239+ let r = ctx. volume_mgr . close_dir ( state. directory ) ;
240+ if let Err ( e) = r {
241+ println ! ( "Error closing directory: {e:?}" ) ;
242+ }
127243 println ! ( "Unmounting {idx}..." ) ;
128- let r = volume_mgr. close_dir ( state. directory ) ;
129- handle ( "closing directory" , r) ;
130- let r = volume_mgr. close_volume ( state. volume ) ;
131- handle ( "closing volume" , r) ;
132- println ! ( "Unmounted {idx}!" ) ;
244+ let r = ctx. volume_mgr . close_volume ( state. volume ) ;
245+ if let Err ( e) = r {
246+ println ! ( "Error closing volume: {e:?}" ) ;
247+ }
133248 }
134249 }
135250
136251 println ! ( "Bye!" ) ;
137252 Ok ( ( ) )
138253}
139254
140- fn handle ( operation : & str , r : Result < ( ) , Error < std:: io:: Error > > ) {
141- if let Err ( e) = r {
142- println ! ( "Error {operation}: {e:?}" ) ;
143- }
144- }
145-
146255// ****************************************************************************
147256//
148257// End Of File
0 commit comments