Skip to content

Commit

Permalink
Implement SSH_FXP_OPENDIR and SSH_FXP_READDIR.
Browse files Browse the repository at this point in the history
  • Loading branch information
ggriffiniii committed Jun 23, 2015
1 parent 7cea9bc commit b782143
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ byteorder = "*"

[dev-dependencies]
tempfile = "*"
tempdir = "*"
52 changes: 52 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,17 @@ impl<W> Client<W> where W : 'static + io::Write + Send {
Client::<W>::expect_status_response(resp)
}

pub fn readdir(&mut self, path: String) -> Result<ReadDir<W>> {
let p = packets::FxpOpenDir{path: path.into_bytes()};
let resp = try!(self.sender.send_receive(&p));
match resp {
packets::SftpResponsePacket::Handle(handle) => {
Ok(ReadDir{client: self.sender.clone(), handle: handle.handle, names: Vec::new()})
},
x => Err(error::Error::UnexpectedResponse(Box::new(x))),
}
}

fn expect_status_response(resp : packets::SftpResponsePacket) -> Result<()> {
match resp {
packets::SftpResponsePacket::Status(packets::FxpStatus{code:
Expand Down Expand Up @@ -410,3 +421,44 @@ impl<W> io::Seek for File<W> where W : 'static + io::Write + Send {
Ok(self.offset)
}
}

pub struct ReadDir<W> where W : 'static + io::Write + Send {
client: Arc<ClientSender<W>>,
handle: Vec<u8>,
names: Vec<packets::Name>,
}

impl<W> Drop for ReadDir<W> where W : 'static + io::Write + Send {
fn drop(&mut self) {
let p = packets::FxpClose{handle: self.handle.clone()};
self.client.send_receive(&p);
}
}

impl<W> Iterator for ReadDir<W> where W : 'static + io::Write + Send {
type Item = Result<packets::Name>;

fn next(&mut self) -> Option<Result<packets::Name>> {
match self.names.pop() {
Some(name) => Some(Ok(name)),
None => {
let p = packets::FxpReadDir{handle: self.handle.clone()};
let resp = match self.client.send_receive(&p) {
Ok(x) => x,
Err(x) => return Some(Err(x)),
};
match resp {
packets::SftpResponsePacket::Status(packets::FxpStatus{code: packets::FxpStatusCode::EOF, msg: _}) => {
None
},
packets::SftpResponsePacket::Name(mut names) => {
names.names.reverse();
self.names = names.names;
self.next()
},
x => Some(Err(error::Error::UnexpectedResponse(Box::new(x)))),
}
},
}
}
}
34 changes: 32 additions & 2 deletions src/packets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ const SSH_FXP_LSTAT : u8 = 7;
const SSH_FXP_FSTAT : u8 = 8;
const SSH_FXP_SETSTAT : u8 = 9;
const SSH_FXP_FSETSTAT : u8 = 10;
//const SSH_FXP_OPENDIR : u8 = 11;
//const SSH_FXP_READDIR : u8 = 12;
const SSH_FXP_OPENDIR : u8 = 11;
const SSH_FXP_READDIR : u8 = 12;
const SSH_FXP_REMOVE : u8 = 13;
const SSH_FXP_MKDIR : u8 = 14;
const SSH_FXP_RMDIR : u8 = 15;
Expand Down Expand Up @@ -412,6 +412,36 @@ impl Sendable for FxpFSetStat {
}
}

#[derive(Debug)]
pub struct FxpOpenDir {
pub path : Vec<u8>,
}

impl Request for FxpOpenDir {
fn msg_type() -> u8 { SSH_FXP_OPENDIR }
}

impl Sendable for FxpOpenDir {
fn write_to<W : io::Write>(&self, w: &mut W) -> Result<usize> {
Ok(try!(self.path.write_to(w)))
}
}

#[derive(Debug)]
pub struct FxpReadDir {
pub handle : Vec<u8>,
}

impl Request for FxpReadDir {
fn msg_type() -> u8 { SSH_FXP_READDIR }
}

impl Sendable for FxpReadDir {
fn write_to<W : io::Write>(&self, w: &mut W) -> Result<usize> {
Ok(try!(self.handle.write_to(w)))
}
}

#[derive(Debug)]
pub struct FxpRemove {
pub filename : Vec<u8>
Expand Down
37 changes: 37 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

extern crate sftp;
extern crate tempfile;
extern crate tempdir;

use std::collections::HashMap;
use std::convert::From;
use std::process;
use std::thread;
use std::io;
use std::io::Read;
use std::io::Write;
use std::os::unix::fs::MetadataExt;
use std::fs::File;

struct TempFile {
file: tempfile::NamedTempFile,
Expand Down Expand Up @@ -366,3 +369,37 @@ fn can_readlink() {
//std::fs::remove_file(linkpath);
server.wait().unwrap();
}

#[test]
fn can_readdir() {
let tmp_dir = tempdir::TempDir::new("sftp_readdir").unwrap();
let mut files = HashMap::new();
let mut path = tmp_dir.path().to_path_buf();
path.push("filename");
for i in 0..100 {
let fname = format!("file-{}", i);
files.insert(fname.to_string(), ());
path.set_file_name(fname);
File::create(&path).unwrap();
}
let mut server = new_test_sftp_server().unwrap();
//let r = DebugReader{inner: server.stdout.take().unwrap()};
//let w = DebugWriter{inner: server.stdin.take().unwrap()};
let r = server.stdout.take().unwrap();
let w = server.stdin.take().unwrap();
{
let mut client = sftp::Client::new(r, w).unwrap();
for file in client.readdir(tmp_dir.path().to_str().unwrap().to_string()).unwrap().map(|x| x.unwrap()) {
let fname = String::from_utf8(file.filename).unwrap();
if fname == "." || fname == ".." {
continue;
}
match files.remove(&fname) {
None => panic!("unexpected file returned from readdir: {:?}", fname),
Some(_) => {},
}
}
assert_eq!(0, files.len());
}
server.wait().unwrap();
}

0 comments on commit b782143

Please sign in to comment.