1use core::panic;
2use std::env::Args;
3use std::fmt::format;
4use std::fs::{self, metadata, read, DirEntry, File};
5use std::io::{BufReader, BufWriter, Read, Write};
6use std::net::IpAddr;
7use std::path::Path;
8use std::process::Command;
9use std::sync::{Arc, Mutex};
10use std::thread::{sleep, JoinHandle};
11use std::time::{Duration, UNIX_EPOCH};
12use std::{
13 collections::HashMap,
14 net::{SocketAddr, TcpListener, TcpStream},
15 thread::Thread,
16};
17use std::{path, thread};
18
19type ArcClient = Arc<Client>;
20pub struct RustTP {
21 server_con: TcpListener,
22
23 directories: Arc<Vec<String>>,
25 client_addrs: Mutex<HashMap<SocketAddr, ArcClient>>,
26 add: Arc<String>,
27 root_store: Arc<String>,
28}
29
30struct Client {
31 addr: SocketAddr,
32 stream: Mutex<TcpStream>,
33 datastream: Mutex<Option<TcpStream>>,
34 stream_type: StreamType,
35 current_path: Arc<Mutex<String>>,
36 real_path: Arc<Mutex<String>>,
37 base_directories: Arc<Vec<String>>,
38 add: Arc<String>,
39 root_store: Arc<String>,
40}
41
42enum StreamType {
43 ASCII,
44 BINARY,
45 EBCDIC,
46}
47
48static DIRECTORYMODE: i32 = 1;
49
50#[allow(dead_code)]
51trait SendResponse {
52 fn send110(stream: &mut TcpStream) {
54 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
55 }
56
57 fn send125(stream: &mut TcpStream) {
58 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
59 }
60
61 fn send150(stream: &mut TcpStream) {
62 stream
63 .write(b"150 Opening data connection for file list.\r\n")
64 .unwrap();
65 stream.flush().unwrap();
66 ;
67 }
68
69 fn send200(stream: &mut TcpStream) {
71
72 stream.write_all(b"200 command ok\r\n").unwrap();
73 stream.flush().unwrap();
74 }
75 fn send202(stream: &mut TcpStream) {
76 stream.write_all(b"202 no action needed\r\n").unwrap();
77 }
78
79 fn send211(stream: &mut TcpStream) {
80 stream.write_all(b"211-Features:\r\nEPSV\r\n211 End\r\n").unwrap();
81 stream.flush().unwrap();
82 }
83
84 fn send212(stream: &mut TcpStream) {
85 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
86 }
87
88 fn send213(stream: &mut TcpStream) {
89 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
90 }
91
92 fn send214(stream: &mut TcpStream) {
93 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
94 }
95
96 fn send215(stream: &mut TcpStream) {
97 stream.write_all(b"215 UNIX Type: L8\r\n").unwrap();
98 stream.flush().unwrap();
99 }
100
101 fn send220(stream: &mut TcpStream) {
102 stream.write_all(b"220 FTP Server ready\r\n").unwrap();
103 stream.flush().unwrap();
104 }
105
106 fn send221(stream: &mut TcpStream) {
107 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
108 }
109
110 fn send225(stream: &mut TcpStream) {
111 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
112 }
113
114 fn send226(stream: &mut TcpStream) {
115 stream.write_all(b"226 Transfer complete\r\n").unwrap();
116 stream.flush().unwrap();
117 }
118
119 fn send227(stream: &mut TcpStream, addr: String) -> TcpListener {
120 let listener = TcpListener::bind("0.0.0.0:0").unwrap(); let port = listener.local_addr().unwrap().port(); let p1 = port / 256;
126 let p2 = port % 256;
127 println!("ad {addr}");
128 let ad: Vec<String> = addr.clone().split(".").map(|e| e.to_string()).collect();
129
130 let binding = listener.local_addr().unwrap().ip().to_string();
131 let vec: Vec<&str> = binding.split(".").collect();
132
133 let str = format!("227 Entering Passive Mode ({},{},{},{},{},{})\r\n", ad[0],ad[1],ad[2],ad[3],p1, p2);
134 println!("port is {port}");
136
137 stream.write_all(str.as_bytes()).unwrap();
138 stream.flush().unwrap();
139 listener
140 }
141
142 fn send228(stream: &mut TcpStream) {
143 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
144 }
145
146 fn send229(stream: &mut TcpStream) -> TcpListener {
147 let listener = TcpListener::bind("0.0.0.0:0").unwrap();
148 let port = listener.local_addr().unwrap().port();
149 println!("{}", format!("229 (|||{port}|)\r\n"));
150 stream.write_all(format!("229 Entering Extended Passive Mode (|||{port}|)\r\n").as_bytes()).unwrap();
151 stream.flush().unwrap();
152 listener
153 }
154
155 fn send230(stream: &mut TcpStream) {
156 stream.write_all(b"230 User logged in\r\n").unwrap();
157 stream.flush().unwrap();
158 }
159
160 fn send232(stream: &mut TcpStream) {
161 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
162 }
163
164 fn send234(stream: &mut TcpStream) {
165 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
166 }
167
168 fn send235(stream: &mut TcpStream) {
169 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
170 }
171
172 fn send250(stream: &mut TcpStream) {
173 stream.write_all(b"250 DIRSTYLE set to WINDOWS\r\n").unwrap();
174 }
175
176 fn send257(stream: &mut TcpStream, path: String) {
177 print!("path is {path}");
178 stream
179 .write(format!("257 \"{path}\" is directory\r\n").as_bytes())
180 .unwrap();
181 stream.flush().unwrap();
182 ;
183 }
184
185 fn send300(stream: &mut TcpStream) {
188 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
189 }
190
191 fn send331(stream: &mut TcpStream) {
192 stream.write_all(b"331 Guest login okay, send your complete email address as your password.\r\n").unwrap();
193 stream.flush().unwrap();
194 }
195
196 fn send332(stream: &mut TcpStream) {
197 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
198 }
199
200 fn send334(stream: &mut TcpStream) {
201 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
202 }
203
204 fn send336(stream: &mut TcpStream) {
205 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
206 }
207
208 fn send421(stream: &mut TcpStream) {
210 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
211 }
212
213 fn send425(stream: &mut TcpStream) {
214 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
215 }
216
217 fn send426(stream: &mut TcpStream) {
218 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
219 }
220
221 fn send430(stream: &mut TcpStream) {
222 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
223 }
224
225 fn send431(stream: &mut TcpStream) {
226 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
227 }
228
229 fn send434(stream: &mut TcpStream) {
230 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
231 }
232
233 fn send450(stream: &mut TcpStream) {
234 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
235 }
236
237 fn send451(stream: &mut TcpStream) {
238 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
239 }
240
241 fn send452(stream: &mut TcpStream) {
242 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
243 }
244
245 fn send500(stream: &mut TcpStream){
247 stream.write_all(b"500 do not try again fucker\r\n").unwrap();
248 }
249
250 fn send501(stream: &mut TcpStream) {
251 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
252 }
253
254 fn send502(stream: &mut TcpStream) {
255 stream.write_all(b"502 Command not implemented.\r\n").unwrap();
256 }
257
258 fn send503(stream: &mut TcpStream) {
259 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
260 }
261
262 fn send504(stream: &mut TcpStream) {
263 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
264 }
265
266 fn send530(stream: &mut TcpStream) {
267 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
268 }
269
270 fn send532(stream: &mut TcpStream) {
271 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
272 }
273
274 fn send533(stream: &mut TcpStream) {
275 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
276 }
277
278 fn send534(stream: &mut TcpStream) {
279 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
280 }
281
282 fn send535(stream: &mut TcpStream) {
283 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
284 }
285
286 fn send536(stream: &mut TcpStream) {
287 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
288 }
289
290 fn send537(stream: &mut TcpStream) {
291 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
292 }
293
294 fn send550(stream: &mut TcpStream) {
295 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
296 }
297
298 fn send551(stream: &mut TcpStream) {
299 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
300 }
301
302 fn send552(stream: &mut TcpStream) {
303 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
304 }
305
306 fn send553(stream: &mut TcpStream) {
307 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
308 }
309
310 fn send600(stream: &mut TcpStream) {
313 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
314 }
315
316 fn send631(stream: &mut TcpStream) {
317 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
318 }
319
320 fn send632(stream: &mut TcpStream) {
321 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
322 }
323
324 fn send633(stream: &mut TcpStream) {
325 stream.write_all(b"110 MARK yyyy = mmmm\r\n").unwrap();
326 }
327
328 }
330
331trait SendData {}
332
333impl RustTP {
341 pub fn new_with_paths(path_list: Vec<String>,address: &str, root_store: &str) ->(Arc<Self>, JoinHandle<()>) {
342 let toc = TcpListener::bind("0.0.0.0:21").unwrap();
343 let rs = Arc::new(RustTP {
344 server_con: toc,
345 client_addrs: Mutex::new(HashMap::new()),
346 directories: Arc::new(path_list),
347 add: Arc::new(address.to_owned()),
348 root_store: Arc::new(root_store.to_owned()),
349 });
350 let t= rs.clone().start_event_loop();
351 (rs,t)
352 }
353
354 pub fn new(address: &str,root_store: &str) -> (Arc<Self>, JoinHandle<()>) {
355 let toc = TcpListener::bind(address.to_owned() + ":21").unwrap();
356 let rs = Arc::new(RustTP {
357 server_con: toc,
358 client_addrs: Mutex::new(HashMap::new()),
359 directories: Arc::new(Vec::new()),
360 add: Arc::new(address.to_owned()),
361 root_store: Arc::new(root_store.to_owned()),
362 });
363 let t = rs.clone().start_event_loop();
364 (rs,t)
365 }
366
367 fn start_event_loop(self: Arc<Self>) -> JoinHandle<()> {
368 thread::spawn(move || {
369 while let Ok(t) = self.server_con.accept() {
370 let stream = t.0;
371 let addr = t.1;
372 println!("new client connected with {:?}", addr);
373 let client = Client::new(addr, stream, self.directories.clone(), self.add.clone(), self.root_store.clone());
374 let mut lock = self.client_addrs.lock().unwrap();
375 lock.insert(addr, client);
376 drop(lock);
377 }
378 })
379 }
380
381
382}
383
384impl SendResponse for Client {}
385
386impl Client {
387 fn new(addr: SocketAddr, stream: TcpStream, dir: Arc<Vec<String>>, ad: Arc<String>, root_store: Arc<String>) -> ArcClient {
388 println!("ad: {ad}");
390 let s = Arc::new(Client {
391 addr,
392 stream: Mutex::new(stream),
393 datastream: Mutex::new(None),
394 stream_type: StreamType::ASCII,
395 current_path: Arc::new(Mutex::new(String::from("/"))),
396 base_directories: dir,
397 real_path: Arc::new(Mutex::new("/".to_string())),
398 add: ad,
399 root_store
400 });
401 s.clone().start_event_loop();
402 return s;
403 }
404
405 fn start_event_loop(self: Arc<Self>) {
406 thread::spawn(move || {
407 let mut buf: [u8; 1000] = [0; 1000];
408 let mut stream = self.stream.lock().unwrap();
409 Client::send220(&mut stream);
410 stream.flush().unwrap();
411 let stream = &mut stream;
412 stream.set_read_timeout(Some(Duration::new(200, 0))).unwrap();
413 stream.set_nonblocking(false).unwrap();
414 while let Ok(size) = stream.read(&mut buf) {
415 let data = &buf[..size];
416
417 if size == 0 {
418 println!("connection closed");
419 return;
420 }
421
422 let comm = String::from_utf8_lossy(data);
423
424 println!("command received from {:?}: {:?}", self.addr, comm);
425 let word = &comm[..4].to_uppercase();
426
427 match word.as_str() {
428 "USER" => {
429 Client::send331(stream);
430 }
431 "PASS" => {
432 Client::send230(stream);
433 }
434 "ACCT" => {}
435 "CWD " => {
436 let s = comm[4..].trim().to_string();
437 let mut iter = s.split("/");
438 let firstDir = iter.next().unwrap();
439 if let Some(found) = self.base_directories.iter().find(|string| {
440 string.split("/").last().unwrap() == firstDir
441 }){
442 let mut l2k = self.real_path.lock().unwrap();
443 *l2k = found.to_owned().to_owned() + "/" + &iter.map(|d| d.to_owned() + "/").collect::<String>();
444 println!("real path is {l2k}");
445 } else {
446 let mut l2k = self.real_path.lock().unwrap();
447 *l2k = "/".to_string();
448 println!("real path is /");
449 }
450
451 let mut lock = self.current_path.lock().unwrap();
452 let mut clone = s.clone();
453 if !clone.starts_with("/"){
454 clone.insert(0, '/');
455 }
456 println!("{clone} : os the new directory");
457 *lock = clone;
458 Client::send200(stream);
459 }
460 "CDUP" => {}
461 "SMNT" => {}
462 "QUIT" => {
463 panic!();
464 }
465 "REIN" => {}
466 "PORT" => {
467 let args = comm[4..].trim();
468 self.clone().handle_active(args);
469 Client::send226(stream);
470 }
471 "PASV" => {
472 self.clone().handle_pasv(stream);
473 }
474 "TYPE" => {
475 Client::send200(stream);
476 }
477 "STRU" => {}
478 "MODE" => {}
479 "RETR" => {
480 Client::send150(stream);
481 let args = comm[4..].trim();
482 self.clone().send_from_buffered(args);
483 Client::send226(stream);
484 }
485 "STOR" => {
486 Client::send150(stream);
487 let args = comm[4..].trim();
488 self.clone().receive_file(args);
489 Client::send226(stream);
490 }
491 "STOU" => {}
492 "APPE" => {}
493 "ALLO" => {}
494 "REST" => {}
495 "RNFR" => {}
496 "RNTO" => {}
497 "ABOR" => {}
498 "DELE" => {}
499 "RMD " => {}
500 "MKD " => {
501 let args = comm[4..].trim();
502 self.clone().create_dir(args);
503 Client::send200(stream);
504 }
505 "PWD\r" => {
506 let path = self.current_path.lock().unwrap();
507 Client::send257(stream, path.clone());
508 }
509 "LIST" => {
510 Client::send150(stream);
511 self.clone().sendDirectoryInfo();
513 Client::send226(stream);
514 }
515 "NLST" => {}
516 "SITE" => {
517 Client::send502(stream);
518 }
519 "SYST" => {
520 Client::send215(stream);
521
522 }
523 "STAT" => {
524 Client::send502(stream);
525 }
526 "HELP" => {}
527 "NOOP" => {
528 Client::send200(stream);
529 }
530 "OPTS" => {
531 Client::send200(stream);
532 }
533 "FEAT" => {
534 Client::send211(stream);
535 },
536 "EPSV" => {
537 if size > 6{
538 Client::send200(stream);
539 } else {
540 self.clone().handle_epsv(stream);
541 }
542 }
543 _ => {
544 println!("command was not parsed: {comm}");
545 Client::send500(stream)
546 },
547 }
548 }
549 println!("erorred out");
550 });
551
552 }
553
554 fn top_dir_to_real_path(self: Arc<Self>, name: &str) -> Option<String>{
555 return self.base_directories.iter().find(|dir| {
556 dir.split("/").last().unwrap() == name
557 }).cloned();
558 }
559
560 fn create_dir(self: Arc<Self>, name: &str){
561 let parsedpath = if name.contains("/") {
562 let mut liter = name.split("/");
563 let top_most = liter.next().unwrap();
564 let path = self.clone().top_dir_to_real_path(top_most).unwrap();
565 let total_path = path + "/" + liter.map(|pat| pat.to_owned() + "/").collect::<String>().as_str();
566 total_path
567 } else {
568 self.root_store.clone().to_string() + "/" + name
569 };
570 fs::create_dir(parsedpath).unwrap();
571 }
572
573
574 fn receive_file(self: Arc<Self>,name: &str){
575 let parsedpath = if name.contains("/") {
576 let mut liter = name.split("/");
577 let top_most = liter.next().unwrap();
578 let path = self.clone().top_dir_to_real_path(top_most).unwrap();
579 let total_path = path + "/" + liter.map(|pat| pat.to_owned() + "/").collect::<String>().as_str();
580 total_path
581 } else {
582 self.root_store.clone().to_string() + "/" + name
583 };
584
585 let parsedpath = if parsedpath.ends_with("/") {parsedpath.strip_suffix("/").unwrap().to_string()} else {parsedpath};
586
587 println!("path to store file is {}",parsedpath);
588 let mut file = File::create(parsedpath).unwrap();
589 let mut reader = self.datastream.lock().unwrap();
590 let mut buffer = [0u8;32000];
591
592 println!("startng reading process");
593 if let Some(mut reeder) = reader.take() {
594 reeder.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
595 println!("set timeout");
596 while let Ok(size) = reeder.read(&mut buffer) {
597 if size == 0{
598 println!("file contents finished.");
599 break;
600 }
601 let data = &buffer[..size];
602 println!("buffer ereceievedf");
603 file.write(data).unwrap();
604 }
605 }else {
606 println!("reader was empty?");
607 }
608
609 }
610
611 fn sendDirectoryInfo(self: Arc<Self>) {
612 let mut lock = self.datastream.lock().unwrap();
613 let curr = self.current_path.lock().unwrap().clone();
614 let mut ls_list: String = String::new();
615 if curr == "/" {
616 ls_list = self.base_directories.iter().map(|dir| {
618 let metadata = metadata(dir).unwrap();
619 let filetype = if metadata.is_dir() {'d'} else {'-'};
620 let file_size = metadata.len();
621 let name = Path::file_name(Path::new(dir)).unwrap().to_str().unwrap();
622 let links = if metadata.is_dir() {2} else {1};
623 format!("{filetype}rw-r--r-- {links} user group {file_size} Oct 1 10:00 {name}\r\n")
625 }).collect::<String>();
626 } else {
627 let realpath = self.real_path.lock().unwrap().clone();
628 println!("path given is {realpath}");
629 let entries = fs::read_dir(realpath).unwrap();
630 ls_list = entries.map(|entry| {
631 get_file_info(&entry.unwrap())
632 }).collect::<String>();
633
634 }
635
636 if let Some(mut stream) = lock.take() {
639 stream.write_all(ls_list.as_bytes()).unwrap();
640 stream.flush().unwrap();
641 } else {
642 }
643 drop(lock);
644 self.clone().close_data_stream();
645 }
646 fn handle_epsv(self: Arc<Self>, stream: &mut TcpStream){
647 let list = Client::send229(stream);
648 println!("stream: started waiting onconnection {:?}",list);
649 let clie = list.accept().unwrap();
650 println!("stream: accepted connection at {:?}", clie.1);
651 self.datastream.lock().unwrap().replace(clie.0);
652 }
653 fn close_data_stream(self: Arc<Self>) {
654 let mut lock = self.datastream.lock().unwrap();
655 if lock.is_some() {
656 drop(lock.take());
657 }
658 }
659
660 fn send_rudimentary_data(self: Arc<Self>, data: &[u8]) {
661 let mut lock = self.datastream.lock().unwrap();
662 if let Some(mut stream) = lock.take() {
663 stream.write_all(&data).unwrap();
664 }
665 drop(lock);
666
667 self.clone().close_data_stream();
668 }
669
670 fn send_from_buffered(self: Arc<Self>, file_name: &str) {
671
672 let currdir = self.real_path.lock().unwrap().clone();
673
674 let top_most = file_name.split("/").next().unwrap();
675
676 let real = self.base_directories.iter().find(|e| {
677 let bot_most = e.split("/").last().unwrap();
678 bot_most.trim() == top_most
679 });
680
681
682 let mut ite = file_name.split("/").into_iter();
683 ite.next();
684 let relpath = real.unwrap().to_owned() + "/" + &ite.map(|e| e.to_owned() + "/").collect::<String>();
685 let s = real.unwrap();
686 println!("path foudn now :{} given {s}", relpath);
687 let relpath = if relpath.ends_with("/") {relpath.strip_suffix("/").unwrap().to_string()} else {relpath};
688 let file = File::open(relpath).unwrap();
689 let mut buffer = vec![0u8; 32000];
690 let mut reader = BufReader::new(file);
691 let mut lock = self.datastream.lock().unwrap();
692 if let Some(mut stream) = lock.take() {
693 stream.set_nodelay(true).unwrap();
694 loop {
695 match reader.read(&mut buffer) {
696 Ok(0) => break, Ok(bytes_read) => {
698 stream.write_all(&buffer[..bytes_read]).unwrap();
699 }
700 Err(e) => {
701 eprintln!("Error reading file: {}", e);
702 break;
703 }
704 }
705 }
706 }
707 }
708
709 fn handle_pasv(self: Arc<Self>, stream: &mut TcpStream) {
710 let list = Client::send227(stream, self.add.clone().to_string());
711 println!("stream: started waiting onconnection {:?}",list);
712 let clie = list.accept().unwrap();
713 println!("stream: accepted connection at {:?}", clie.1);
714 self.datastream.lock().unwrap().replace(clie.0);
715 }
717
718 fn handle_active(self: Arc<Self>, addrstr: &str) {
719 let numbers: Vec<&str> = addrstr.split(",").collect();
720 let port = numbers[4].parse::<i32>().unwrap() * 256 + numbers[5].parse::<i32>().unwrap();
721 let ip = numbers[..4].join(".");
722 println!("active add given: {}:{}", ip, port);
723 let stream = TcpStream::connect(format!("{}:{}", ip, port)).unwrap();
724 self.datastream.lock().unwrap().replace(stream);
725 }
726}
727
728
729impl Drop for Client {
730 fn drop(&mut self) {
731 println!("client dropped");
732 }
733}
734
735fn get_file_info(entry: &DirEntry) -> String {
736 let metadata = entry.metadata().unwrap();
737
738 let permissions = metadata.permissions();
740 let links = if metadata.is_dir() {2} else {1};
741 let filetype = if (metadata.is_dir()) {'d'} else {'-'};
742 let file_size = metadata.len();
744 let binding = entry.path().display().to_string();
745 let name = binding.split("/").last().unwrap();
746 let name = name.split("\\").last().unwrap();
747 println!("{} interpreted",name);
748
749
750 let modified_time = metadata.modified().unwrap_or(UNIX_EPOCH)
752 .duration_since(UNIX_EPOCH).unwrap()
753 .as_secs();
754 let s = format!(
755 "{filetype}rw-r--r-- {links} user group {file_size} Oct 1 10:00 {name}\r\n"
756 );
757 s
758}
759
760