diff options
Diffstat (limited to 'src/common.rs')
-rw-r--r-- | src/common.rs | 110 |
1 files changed, 99 insertions, 11 deletions
diff --git a/src/common.rs b/src/common.rs index 8183bbf..421f3a5 100644 --- a/src/common.rs +++ b/src/common.rs @@ -3,21 +3,109 @@ extern crate utp; use std::str; use std::env; -use std::fs::File; -use std::io::Read; +use std::path::Path; +use std::fs::{self, File}; +use std::os::unix::fs::PermissionsExt; +use std::io; +use std::io::{Read, Write, BufRead, BufReader}; use std::process::exit; -use utp::{UtpSocket}; +use utp::{UtpStream}; -pub fn send_files(socket: &mut UtpSocket, file_path: &str, recursive: bool) { - assert!(!recursive); - let f = File::open(file_path).unwrap(); - unimplemented!(); +pub fn source_files(stream: &mut UtpStream, file_path: &str, recursive: bool) { + if recursive { unimplemented!(); } + let mut f = File::open(file_path).unwrap(); + let metadata = f.metadata().unwrap(); + assert!(metadata.is_file()); + let fmode: u32 = metadata.permissions().mode(); + let flen: usize = metadata.len() as usize; + + // Format as 4 digits octal, left-padding with zero + let line = format!("C{:0<4o} {} {}\n", fmode, flen, file_path); + stream.write_all(line.as_bytes()).unwrap(); + + let mut byte_buf = [0; 1]; + stream.read_exact(&mut byte_buf).unwrap(); + let reply = byte_buf[0]; + match reply { + 0 => {}, // Success, pass + 1 | 2 => { // Warning + unimplemented!(); + }, + _ => { panic!("Unexpected status char!") }, + }; + + let mut buf = [0; 4096]; + let mut sent: usize = 0; + while sent < flen { + let rlen = f.read(&mut buf).unwrap(); + assert!(rlen > 0); + let mut wbuf = &mut buf[..rlen]; + stream.write_all(&wbuf).unwrap(); + sent += rlen; + } + // f.close(); XXX: + stream.read_exact(&mut byte_buf).unwrap(); + let reply = byte_buf[0]; + match reply { + 0 => {}, // Success, pass + 1 | 2 => { // Warning + unimplemented!(); + }, + _ => { panic!("Unexpected status char!") }, + }; +} + +fn raw_read_line(stream: &mut UtpStream) -> io::Result<String> { + + let mut s = String::new(); + let mut byte_buf = [0]; + loop { + stream.read_exact(&mut byte_buf).unwrap(); + if byte_buf[0] == '\n' as u8 { + return Ok(s); + } + s.push(byte_buf[0] as char); + } } -pub fn receive_files(socket: &mut UtpSocket, file_path: &str, recursive: bool) { - assert!(!recursive); - let f = File::create(file_path).unwrap(); +// TODO: it would be nice to be able to do BufReader/BufWriter on UtpStream. This would require +// implementations of Read and Write on immutable references to UtpStream (a la TcpStream, File, et +// al) +pub fn sink_files(stream: &mut UtpStream, file_path: &str, recursive: bool) { + if recursive { unimplemented!(); } + let mut f = File::create(file_path).unwrap(); + + let mut byte_buf = [0; 1]; + let mut buf = [0; 4096]; + stream.read_exact(&mut byte_buf).unwrap(); + let msg_type = byte_buf[0]; + match msg_type as char { + 'C' => {} // pass + 'D' => { unimplemented!(); }, + 'E' => { unimplemented!(); }, + 'T' => { unimplemented!(); }, + _ => { panic!(format!("Unexpected message type: {}", msg_type)); }, + }; + let line = raw_read_line(stream).unwrap(); + let line: Vec<&str> = line.split_whitespace().collect(); + assert!(line.len() == 3); + let fmode: u32 = u32::from_str_radix(line[0], 8).unwrap(); + let flen: usize = line[1].parse::<usize>().unwrap(); + let fpath = Path::new(line[2]); + + f.set_len(flen as u64).unwrap(); + fs::set_permissions(file_path, PermissionsExt::from_mode(fmode)).unwrap(); - //f.set_len(); + let mut received: usize = 0; + while received < flen { + let rlen = stream.read(&mut buf).unwrap(); + assert!(rlen > 0); + let mut wbuf = &mut buf[..rlen]; + f.write_all(&wbuf).unwrap(); + received += rlen; + } + f.sync_all().unwrap(); + // f.close(); XXX: closes automatically? + stream.write(&[0]).unwrap(); } |