@@ -10,9 +10,158 @@ use crate::linux::{Clock, LinuxBlockDevice};
10
10
11
11
mod linux;
12
12
13
- struct State {
13
+ struct VolumeState {
14
14
directory : Directory ,
15
15
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
+ }
16
165
}
17
166
18
167
fn main ( ) -> Result < ( ) , Error < std:: io:: Error > > {
@@ -22,29 +171,33 @@ fn main() -> Result<(), Error<std::io::Error>> {
22
171
let print_blocks = args. find ( |x| x == "-v" ) . map ( |_| true ) . unwrap_or ( false ) ;
23
172
println ! ( "Opening '{filename}'..." ) ;
24
173
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 ) ;
27
174
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
+ } ;
29
181
30
182
let mut current_volume = None ;
31
183
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) ) {
33
185
Ok ( volume) => {
34
186
println ! ( "Volume # {}: found" , volume_no, ) ;
35
- match volume_mgr. open_root_dir ( volume) {
187
+ match ctx . volume_mgr . open_root_dir ( volume) {
36
188
Ok ( root_dir) => {
37
- volumes[ volume_no] = Some ( State {
189
+ ctx . volumes [ volume_no] = Some ( VolumeState {
38
190
directory : root_dir,
39
191
volume,
192
+ path : vec ! [ ] ,
40
193
} ) ;
41
194
if current_volume. is_none ( ) {
42
195
current_volume = Some ( volume_no) ;
43
196
}
44
197
}
45
198
Err ( e) => {
46
199
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" ) ;
48
201
}
49
202
}
50
203
}
@@ -54,95 +207,51 @@ fn main() -> Result<(), Error<std::io::Error>> {
54
207
}
55
208
}
56
209
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
+ }
60
219
} ;
61
220
62
221
loop {
63
- print ! ( "{}:> " , current_volume) ;
222
+ print ! ( "{}:/" , ctx. current_volume) ;
223
+ print ! ( "{}" , ctx. current_path( ) . join( "/" ) ) ;
224
+ print ! ( "> " ) ;
64
225
std:: io:: stdout ( ) . flush ( ) . unwrap ( ) ;
65
226
let mut line = String :: new ( ) ;
66
227
stdin. read_line ( & mut line) ?;
67
228
let line = line. trim ( ) ;
68
229
if line == "quit" {
69
230
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) ;
122
233
}
123
234
}
124
235
125
- for ( idx, s) in volumes. into_iter ( ) . enumerate ( ) {
236
+ for ( idx, s) in ctx . volumes . into_iter ( ) . enumerate ( ) {
126
237
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
+ }
127
243
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
+ }
133
248
}
134
249
}
135
250
136
251
println ! ( "Bye!" ) ;
137
252
Ok ( ( ) )
138
253
}
139
254
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
-
146
255
// ****************************************************************************
147
256
//
148
257
// End Of File
0 commit comments