Nothing to see here, move along
at main 192 lines 5.4 kB view raw
1#![no_std] 2#![no_main] 3 4use lancer_user::fs::{self, FsClient, READDIR_ENTRY_SIZE, ReadDirEntry}; 5use lancer_user::net; 6use lancer_user::syscall; 7use lancer_user::{print, println}; 8 9struct SortEntry { 10 name: [u8; 48], 11 name_len: u16, 12 inode_type: u8, 13 size: u64, 14} 15 16const EMPTY_ENTRY: SortEntry = SortEntry { 17 name: [0; 48], 18 name_len: 0, 19 inode_type: 0, 20 size: 0, 21}; 22 23fn type_char(t: u8) -> u8 { 24 match t { 25 1 => b'd', 26 2 => b'l', 27 _ => b'f', 28 } 29} 30 31fn format_size(size: u64, buf: &mut [u8; 20]) -> usize { 32 match size { 33 0 => { 34 buf[0] = b'0'; 35 1 36 } 37 _ => { 38 let mut tmp = [0u8; 20]; 39 fn fill(v: u64, tmp: &mut [u8; 20], pos: usize) -> usize { 40 match v { 41 0 => pos, 42 _ => { 43 tmp[pos] = b'0' + (v % 10) as u8; 44 fill(v / 10, tmp, pos + 1) 45 } 46 } 47 } 48 let digits = fill(size, &mut tmp, 0); 49 (0..digits).for_each(|j| { 50 buf[j] = tmp[digits - 1 - j]; 51 }); 52 digits 53 } 54 } 55} 56 57fn insertion_sort(entries: &mut [SortEntry], count: usize) { 58 fn sink(entries: &mut [SortEntry], j: usize) { 59 if j > 0 && name_cmp(&entries[j], &entries[j - 1]) == core::cmp::Ordering::Less { 60 entries.swap(j, j - 1); 61 sink(entries, j - 1); 62 } 63 } 64 (1..count).for_each(|i| sink(entries, i)); 65} 66 67fn name_cmp(a: &SortEntry, b: &SortEntry) -> core::cmp::Ordering { 68 let a_name = &a.name[..a.name_len as usize]; 69 let b_name = &b.name[..b.name_len as usize]; 70 let min_len = a_name.len().min(b_name.len()); 71 (0..min_len) 72 .find_map(|i| match a_name[i].cmp(&b_name[i]) { 73 core::cmp::Ordering::Equal => None, 74 ord => Some(ord), 75 }) 76 .unwrap_or_else(|| a_name.len().cmp(&b_name.len())) 77} 78 79const MAX_DISPLAY_ENTRIES: usize = 128; 80 81struct CollectState { 82 total: usize, 83 overflow: bool, 84} 85 86fn collect_entries( 87 client: &mut FsClient, 88 handle: u8, 89 buf: &mut [u8], 90 entries: &mut [SortEntry; MAX_DISPLAY_ENTRIES], 91 state: &mut CollectState, 92 cursor: u64, 93) { 94 match client.readdir(handle, cursor, buf) { 95 Err(e) => { 96 println!("readdir error: {}", e.name()); 97 } 98 Ok((0, _)) => {} 99 Ok((count, next)) => { 100 (0..count).for_each(|i| match state.total < MAX_DISPLAY_ENTRIES { 101 true => { 102 let off = i * READDIR_ENTRY_SIZE; 103 if let Some(entry) = ReadDirEntry::from_bytes(&buf[off..]) { 104 let nlen = (entry.name_len as usize).min(48); 105 entries[state.total].name[..nlen].copy_from_slice(&entry.name[..nlen]); 106 entries[state.total].name_len = nlen as u16; 107 entries[state.total].inode_type = entry.inode_type; 108 entries[state.total].size = entry.size; 109 state.total += 1; 110 } 111 } 112 false => { 113 state.overflow = true; 114 } 115 }); 116 collect_entries(client, handle, buf, entries, state, next) 117 } 118 } 119} 120 121fn list_dir(client: &mut FsClient, handle: u8) { 122 let mut entries = [EMPTY_ENTRY; MAX_DISPLAY_ENTRIES]; 123 let mut state = CollectState { 124 total: 0, 125 overflow: false, 126 }; 127 let mut buf = [0u8; READDIR_ENTRY_SIZE * 16]; 128 129 collect_entries(client, handle, &mut buf, &mut entries, &mut state, 0); 130 131 insertion_sort(&mut entries, state.total); 132 133 (0..state.total).for_each(|i| { 134 let e = &entries[i]; 135 let tc = type_char(e.inode_type); 136 print!("{}", tc as char); 137 print!(" "); 138 if let Ok(name) = core::str::from_utf8(&e.name[..e.name_len as usize]) { 139 print!("{}", name); 140 } 141 let mut sbuf = [0u8; 20]; 142 let slen = format_size(e.size, &mut sbuf); 143 print!(" "); 144 if let Ok(s) = core::str::from_utf8(&sbuf[..slen]) { 145 print!("{}", s); 146 } 147 println!(); 148 }); 149 150 if state.overflow { 151 println!("(listing truncated at {} entries)", MAX_DISPLAY_ENTRIES); 152 } 153} 154 155#[unsafe(no_mangle)] 156pub extern "C" fn lancer_main() -> ! { 157 let (rx, _tx) = match net::init() { 158 Some(pair) => pair, 159 None => { 160 lancer_user::show!(net, error, "netsock init failed"); 161 syscall::exit(); 162 } 163 }; 164 165 let mut args_buf = [0u8; 256]; 166 let args_len = net::recv_args(&rx, &mut args_buf); 167 let args = &args_buf[..args_len]; 168 169 let (_cmd, rest) = net::next_token(args); 170 let (path_tok, _) = net::next_token(rest); 171 let path: &[u8] = match path_tok.is_empty() { 172 true => b"/", 173 false => path_tok, 174 }; 175 176 let mut client = unsafe { fs::init() }; 177 178 let list_rights = 179 fs::FsRights::from_raw(fs::FsRights::LIST.raw() | fs::FsRights::TRAVERSE.raw()); 180 let handle = match fs::open_path_with_rights(&mut client, 0, path, list_rights) { 181 Ok(h) => h, 182 Err(e) => { 183 println!("ls: {}", e.name()); 184 syscall::exit(); 185 } 186 }; 187 188 list_dir(&mut client, handle); 189 let _ = client.close(handle); 190 191 syscall::exit() 192}