aboutsummaryrefslogtreecommitdiffstats
path: root/src/common.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/common.rs')
-rw-r--r--src/common.rs110
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();
}