diff options
Diffstat (limited to 'src/sftp.rs')
-rw-r--r-- | src/sftp.rs | 304 |
1 files changed, 175 insertions, 129 deletions
diff --git a/src/sftp.rs b/src/sftp.rs index 4e1eb56..a02c4db 100644 --- a/src/sftp.rs +++ b/src/sftp.rs @@ -1,12 +1,12 @@ +use libc::{c_int, c_long, c_uint, c_ulong, size_t}; use std::io::prelude::*; use std::io::{self, ErrorKind, SeekFrom}; use std::marker; use std::mem; use std::path::{Path, PathBuf}; -use libc::{c_int, c_ulong, c_long, c_uint, size_t}; -use {raw, Session, Error, Channel}; use util::{self, SessionBinding}; +use {raw, Channel, Error, Session}; /// A handle to a remote filesystem over SFTP. /// @@ -104,16 +104,23 @@ pub enum OpenType { impl<'sess> Sftp<'sess> { /// Open a handle to a file. - pub fn open_mode(&self, filename: &Path, flags: OpenFlags, - mode: i32, open_type: OpenType) -> Result<File, Error> { + pub fn open_mode( + &self, + filename: &Path, + flags: OpenFlags, + mode: i32, + open_type: OpenType, + ) -> Result<File, Error> { let filename = try!(util::path2bytes(filename)); unsafe { - let ret = raw::libssh2_sftp_open_ex(self.raw, - filename.as_ptr() as *const _, - filename.len() as c_uint, - flags.bits() as c_ulong, - mode as c_long, - open_type as c_int); + let ret = raw::libssh2_sftp_open_ex( + self.raw, + filename.as_ptr() as *const _, + filename.len() as c_uint, + flags.bits() as c_ulong, + mode as c_long, + open_type as c_int, + ); if ret.is_null() { Err(self.last_error()) } else { @@ -129,7 +136,12 @@ impl<'sess> Sftp<'sess> { /// Helper to create a file in write-only mode with truncation. pub fn create(&self, filename: &Path) -> Result<File, Error> { - self.open_mode(filename, OpenFlags::WRITE | OpenFlags::TRUNCATE, 0o644, OpenType::File) + self.open_mode( + filename, + OpenFlags::WRITE | OpenFlags::TRUNCATE, + 0o644, + OpenType::File, + ) } /// Helper to open a directory for reading its contents. @@ -141,15 +153,15 @@ impl<'sess> Sftp<'sess> { /// /// The returned paths are all joined with `dirname` when returned, and the /// paths `.` and `..` are filtered out of the returned list. - pub fn readdir(&self, dirname: &Path) - -> Result<Vec<(PathBuf, FileStat)>, Error> { + pub fn readdir(&self, dirname: &Path) -> Result<Vec<(PathBuf, FileStat)>, Error> { let mut dir = try!(self.opendir(dirname)); let mut ret = Vec::new(); loop { match dir.readdir() { Ok((filename, stat)) => { - if &*filename == Path::new(".") || - &*filename == Path::new("..") { continue } + if &*filename == Path::new(".") || &*filename == Path::new("..") { + continue; + } ret.push((dirname.join(&filename), stat)) } @@ -161,14 +173,15 @@ impl<'sess> Sftp<'sess> { } /// Create a directory on the remote file system. - pub fn mkdir(&self, filename: &Path, mode: i32) - -> Result<(), Error> { + pub fn mkdir(&self, filename: &Path, mode: i32) -> Result<(), Error> { let filename = try!(util::path2bytes(filename)); self.rc(unsafe { - raw::libssh2_sftp_mkdir_ex(self.raw, - filename.as_ptr() as *const _, - filename.len() as c_uint, - mode as c_long) + raw::libssh2_sftp_mkdir_ex( + self.raw, + filename.as_ptr() as *const _, + filename.len() as c_uint, + mode as c_long, + ) }) } @@ -176,9 +189,11 @@ impl<'sess> Sftp<'sess> { pub fn rmdir(&self, filename: &Path) -> Result<(), Error> { let filename = try!(util::path2bytes(filename)); self.rc(unsafe { - raw::libssh2_sftp_rmdir_ex(self.raw, - filename.as_ptr() as *const _, - filename.len() as c_uint) + raw::libssh2_sftp_rmdir_ex( + self.raw, + filename.as_ptr() as *const _, + filename.len() as c_uint, + ) }) } @@ -187,11 +202,13 @@ impl<'sess> Sftp<'sess> { let filename = try!(util::path2bytes(filename)); unsafe { let mut ret = mem::zeroed(); - let rc = raw::libssh2_sftp_stat_ex(self.raw, - filename.as_ptr() as *const _, - filename.len() as c_uint, - raw::LIBSSH2_SFTP_STAT, - &mut ret); + let rc = raw::libssh2_sftp_stat_ex( + self.raw, + filename.as_ptr() as *const _, + filename.len() as c_uint, + raw::LIBSSH2_SFTP_STAT, + &mut ret, + ); try!(self.rc(rc)); Ok(FileStat::from_raw(&ret)) } @@ -202,11 +219,13 @@ impl<'sess> Sftp<'sess> { let filename = try!(util::path2bytes(filename)); unsafe { let mut ret = mem::zeroed(); - let rc = raw::libssh2_sftp_stat_ex(self.raw, - filename.as_ptr() as *const _, - filename.len() as c_uint, - raw::LIBSSH2_SFTP_LSTAT, - &mut ret); + let rc = raw::libssh2_sftp_stat_ex( + self.raw, + filename.as_ptr() as *const _, + filename.len() as c_uint, + raw::LIBSSH2_SFTP_LSTAT, + &mut ret, + ); try!(self.rc(rc)); Ok(FileStat::from_raw(&ret)) } @@ -217,11 +236,13 @@ impl<'sess> Sftp<'sess> { let filename = try!(util::path2bytes(filename)); self.rc(unsafe { let mut raw = stat.raw(); - raw::libssh2_sftp_stat_ex(self.raw, - filename.as_ptr() as *const _, - filename.len() as c_uint, - raw::LIBSSH2_SFTP_SETSTAT, - &mut raw) + raw::libssh2_sftp_stat_ex( + self.raw, + filename.as_ptr() as *const _, + filename.len() as c_uint, + raw::LIBSSH2_SFTP_SETSTAT, + &mut raw, + ) }) } @@ -230,12 +251,14 @@ impl<'sess> Sftp<'sess> { let path = try!(util::path2bytes(path)); let target = try!(util::path2bytes(target)); self.rc(unsafe { - raw::libssh2_sftp_symlink_ex(self.raw, - path.as_ptr() as *const _, - path.len() as c_uint, - target.as_ptr() as *mut _, - target.len() as c_uint, - raw::LIBSSH2_SFTP_SYMLINK) + raw::libssh2_sftp_symlink_ex( + self.raw, + path.as_ptr() as *const _, + path.len() as c_uint, + target.as_ptr() as *mut _, + target.len() as c_uint, + raw::LIBSSH2_SFTP_SYMLINK, + ) }) } @@ -255,18 +278,20 @@ impl<'sess> Sftp<'sess> { let mut rc; loop { rc = unsafe { - raw::libssh2_sftp_symlink_ex(self.raw, - path.as_ptr() as *const _, - path.len() as c_uint, - ret.as_ptr() as *mut _, - ret.capacity() as c_uint, - op) + raw::libssh2_sftp_symlink_ex( + self.raw, + path.as_ptr() as *const _, + path.len() as c_uint, + ret.as_ptr() as *mut _, + ret.capacity() as c_uint, + op, + ) }; if rc == raw::LIBSSH2_ERROR_BUFFER_TOO_SMALL { let cap = ret.capacity(); ret.reserve(cap); } else { - break + break; } } if rc < 0 { @@ -289,20 +314,20 @@ impl<'sess> Sftp<'sess> { /// operation and/or using native system calls when possible. /// /// If no flags are specified then all flags are used. - pub fn rename(&self, src: &Path, dst: &Path, flags: Option<RenameFlags>) - -> Result<(), Error> { - let flags = flags.unwrap_or( - RenameFlags::ATOMIC | RenameFlags::OVERWRITE | RenameFlags::NATIVE - ); + pub fn rename(&self, src: &Path, dst: &Path, flags: Option<RenameFlags>) -> Result<(), Error> { + let flags = + flags.unwrap_or(RenameFlags::ATOMIC | RenameFlags::OVERWRITE | RenameFlags::NATIVE); let src = try!(util::path2bytes(src)); let dst = try!(util::path2bytes(dst)); self.rc(unsafe { - raw::libssh2_sftp_rename_ex(self.raw, - src.as_ptr() as *const _, - src.len() as c_uint, - dst.as_ptr() as *const _, - dst.len() as c_uint, - flags.bits()) + raw::libssh2_sftp_rename_ex( + self.raw, + src.as_ptr() as *const _, + src.len() as c_uint, + dst.as_ptr() as *const _, + dst.len() as c_uint, + flags.bits(), + ) }) } @@ -310,9 +335,7 @@ impl<'sess> Sftp<'sess> { pub fn unlink(&self, file: &Path) -> Result<(), Error> { let file = try!(util::path2bytes(file)); self.rc(unsafe { - raw::libssh2_sftp_unlink_ex(self.raw, - file.as_ptr() as *const _, - file.len() as c_uint) + raw::libssh2_sftp_unlink_ex(self.raw, file.as_ptr() as *const _, file.len() as c_uint) }) } @@ -324,21 +347,28 @@ impl<'sess> Sftp<'sess> { /// Translates a return code into a Rust-`Result` pub fn rc(&self, rc: c_int) -> Result<(), Error> { - if rc == 0 {Ok(())} else {Err(self.last_error())} + if rc == 0 { + Ok(()) + } else { + Err(self.last_error()) + } } } impl<'sess> SessionBinding<'sess> for Sftp<'sess> { type Raw = raw::LIBSSH2_SFTP; - unsafe fn from_raw(_sess: &'sess Session, - raw: *mut raw::LIBSSH2_SFTP) -> Sftp<'sess> { - Sftp { raw: raw, _marker: marker::PhantomData } + unsafe fn from_raw(_sess: &'sess Session, raw: *mut raw::LIBSSH2_SFTP) -> Sftp<'sess> { + Sftp { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::LIBSSH2_SFTP { + self.raw } - fn raw(&self) -> *mut raw::LIBSSH2_SFTP { self.raw } } - impl<'sess> Drop for Sftp<'sess> { fn drop(&mut self) { unsafe { assert_eq!(raw::libssh2_sftp_shutdown(self.raw), 0) } @@ -350,8 +380,10 @@ impl<'sftp> File<'sftp> { /// given session. /// /// This consumes ownership of `raw`. - unsafe fn from_raw(sftp: &'sftp Sftp<'sftp>, - raw: *mut raw::LIBSSH2_SFTP_HANDLE) -> File<'sftp> { + unsafe fn from_raw( + sftp: &'sftp Sftp<'sftp>, + raw: *mut raw::LIBSSH2_SFTP_HANDLE, + ) -> File<'sftp> { File { raw: raw, sftp: sftp, @@ -370,7 +402,9 @@ impl<'sftp> File<'sftp> { pub fn stat(&mut self) -> Result<FileStat, Error> { unsafe { let mut ret = mem::zeroed(); - try!(self.sftp.rc(raw::libssh2_sftp_fstat_ex(self.raw, &mut ret, 0))); + try!(self + .sftp + .rc(raw::libssh2_sftp_fstat_ex(self.raw, &mut ret, 0))); Ok(FileStat::from_raw(&ret)) } } @@ -400,25 +434,30 @@ impl<'sftp> File<'sftp> { let mut rc; loop { rc = unsafe { - raw::libssh2_sftp_readdir_ex(self.raw, - buf.as_mut_ptr() as *mut _, - buf.capacity() as size_t, - 0 as *mut _, 0, - &mut stat) + raw::libssh2_sftp_readdir_ex( + self.raw, + buf.as_mut_ptr() as *mut _, + buf.capacity() as size_t, + 0 as *mut _, + 0, + &mut stat, + ) }; if rc == raw::LIBSSH2_ERROR_BUFFER_TOO_SMALL { let cap = buf.capacity(); buf.reserve(cap); } else { - break + break; } } if rc < 0 { - return Err(self.sftp.last_error()) + return Err(self.sftp.last_error()); } else if rc == 0 { - return Err(Error::new(raw::LIBSSH2_ERROR_FILE, "no more files")) + return Err(Error::new(raw::LIBSSH2_ERROR_FILE, "no more files")); } else { - unsafe { buf.set_len(rc as usize); } + unsafe { + buf.set_len(rc as usize); + } } Ok((mkpath(buf), FileStat::from_raw(&stat))) } @@ -435,13 +474,11 @@ impl<'sftp> File<'sftp> { impl<'sftp> Read for File<'sftp> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { unsafe { - let rc = raw::libssh2_sftp_read(self.raw, - buf.as_mut_ptr() as *mut _, - buf.len() as size_t); + let rc = + raw::libssh2_sftp_read(self.raw, buf.as_mut_ptr() as *mut _, buf.len() as size_t); match rc { - n if n < 0 => Err(io::Error::new(ErrorKind::Other, - self.sftp.last_error())), - n => Ok(n as usize) + n if n < 0 => Err(io::Error::new(ErrorKind::Other, self.sftp.last_error())), + n => Ok(n as usize), } } } @@ -450,9 +487,7 @@ impl<'sftp> Read for File<'sftp> { impl<'sftp> Write for File<'sftp> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { let rc = unsafe { - raw::libssh2_sftp_write(self.raw, - buf.as_ptr() as *const _, - buf.len() as size_t) + raw::libssh2_sftp_write(self.raw, buf.as_ptr() as *const _, buf.len() as size_t) }; if rc < 0 { Err(io::Error::new(ErrorKind::Other, self.sftp.last_error())) @@ -460,7 +495,9 @@ impl<'sftp> Write for File<'sftp> { Ok(rc as usize) } } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } } impl<'sftp> Seek for File<'sftp> { @@ -484,15 +521,10 @@ impl<'sftp> Seek for File<'sftp> { SeekFrom::End(offset) => match self.stat() { Ok(s) => match s.size { Some(size) => (size as i64 + offset) as u64, - None => { - return Err(io::Error::new(ErrorKind::Other, - "no file size available")) - } + None => return Err(io::Error::new(ErrorKind::Other, "no file size available")), }, - Err(e) => { - return Err(io::Error::new(ErrorKind::Other, e)) - } - } + Err(e) => return Err(io::Error::new(ErrorKind::Other, e)), + }, }; unsafe { raw::libssh2_sftp_seek64(self.raw, next) } Ok(next) @@ -508,50 +540,58 @@ impl<'sftp> Drop for File<'sftp> { impl FileStat { /// Returns the file type for this filestat. pub fn file_type(&self) -> FileType { - FileType { perm: self.perm.unwrap_or(0) as c_ulong } + FileType { + perm: self.perm.unwrap_or(0) as c_ulong, + } } /// Returns whether this metadata is for a directory. - pub fn is_dir(&self) -> bool { self.file_type().is_dir() } + pub fn is_dir(&self) -> bool { + self.file_type().is_dir() + } /// Returns whether this metadata is for a regular file. - pub fn is_file(&self) -> bool { self.file_type().is_file() } + pub fn is_file(&self) -> bool { + self.file_type().is_file() + } /// Creates a new instance of a stat from a raw instance. pub fn from_raw(raw: &raw::LIBSSH2_SFTP_ATTRIBUTES) -> FileStat { - fn val<T: Copy>(raw: &raw::LIBSSH2_SFTP_ATTRIBUTES, t: &T, - flag: c_ulong) -> Option<T> { - if raw.flags & flag != 0 {Some(*t)} else {None} + fn val<T: Copy>(raw: &raw::LIBSSH2_SFTP_ATTRIBUTES, t: &T, flag: c_ulong) -> Option<T> { + if raw.flags & flag != 0 { + Some(*t) + } else { + None + } } FileStat { size: val(raw, &raw.filesize, raw::LIBSSH2_SFTP_ATTR_SIZE), - uid: val(raw, &raw.uid, raw::LIBSSH2_SFTP_ATTR_UIDGID) - .map(|s| s as u32), - gid: val(raw, &raw.gid, raw::LIBSSH2_SFTP_ATTR_UIDGID) - .map(|s| s as u32), - perm: val(raw, &raw.permissions, raw::LIBSSH2_SFTP_ATTR_PERMISSIONS) - .map(|s| s as u32), - mtime: val(raw, &raw.mtime, raw::LIBSSH2_SFTP_ATTR_ACMODTIME) - .map(|s| s as u64), - atime: val(raw, &raw.atime, raw::LIBSSH2_SFTP_ATTR_ACMODTIME) - .map(|s| s as u64), + uid: val(raw, &raw.uid, raw::LIBSSH2_SFTP_ATTR_UIDGID).map(|s| s as u32), + gid: val(raw, &raw.gid, raw::LIBSSH2_SFTP_ATTR_UIDGID).map(|s| s as u32), + perm: val(raw, &raw.permissions, raw::LIBSSH2_SFTP_ATTR_PERMISSIONS).map(|s| s as u32), + mtime: val(raw, &raw.mtime, raw::LIBSSH2_SFTP_ATTR_ACMODTIME).map(|s| s as u64), + atime: val(raw, &raw.atime, raw::LIBSSH2_SFTP_ATTR_ACMODTIME).map(|s| s as u64), } } /// Convert this stat structure to its raw representation. pub fn raw(&self) -> raw::LIBSSH2_SFTP_ATTRIBUTES { fn flag<T>(o: &Option<T>, flag: c_ulong) -> c_ulong { - if o.is_some() {flag} else {0} + if o.is_some() { + flag + } else { + 0 + } } raw::LIBSSH2_SFTP_ATTRIBUTES { - flags: flag(&self.size, raw::LIBSSH2_SFTP_ATTR_SIZE) | - flag(&self.uid, raw::LIBSSH2_SFTP_ATTR_UIDGID) | - flag(&self.gid, raw::LIBSSH2_SFTP_ATTR_UIDGID) | - flag(&self.perm, raw::LIBSSH2_SFTP_ATTR_PERMISSIONS) | - flag(&self.atime, raw::LIBSSH2_SFTP_ATTR_ACMODTIME) | - flag(&self.mtime, raw::LIBSSH2_SFTP_ATTR_ACMODTIME), + flags: flag(&self.size, raw::LIBSSH2_SFTP_ATTR_SIZE) + | flag(&self.uid, raw::LIBSSH2_SFTP_ATTR_UIDGID) + | flag(&self.gid, raw::LIBSSH2_SFTP_ATTR_UIDGID) + | flag(&self.perm, raw::LIBSSH2_SFTP_ATTR_PERMISSIONS) + | flag(&self.atime, raw::LIBSSH2_SFTP_ATTR_ACMODTIME) + | flag(&self.mtime, raw::LIBSSH2_SFTP_ATTR_ACMODTIME), filesize: self.size.unwrap_or(0), uid: self.uid.unwrap_or(0) as c_ulong, gid: self.gid.unwrap_or(0) as c_ulong, @@ -564,13 +604,19 @@ impl FileStat { impl FileType { /// Test whether this file type represents a directory. - pub fn is_dir(&self) -> bool { self.is(raw::LIBSSH2_SFTP_S_IFDIR) } + pub fn is_dir(&self) -> bool { + self.is(raw::LIBSSH2_SFTP_S_IFDIR) + } /// Test whether this file type represents a regular file. - pub fn is_file(&self) -> bool { self.is(raw::LIBSSH2_SFTP_S_IFREG) } + pub fn is_file(&self) -> bool { + self.is(raw::LIBSSH2_SFTP_S_IFREG) + } /// Test whether this file type represents a symbolic link. - pub fn is_symlink(&self) -> bool { self.is(raw::LIBSSH2_SFTP_S_IFLNK) } + pub fn is_symlink(&self) -> bool { + self.is(raw::LIBSSH2_SFTP_S_IFLNK) + } fn is(&self, perm: c_ulong) -> bool { (self.perm & raw::LIBSSH2_SFTP_S_IFMT) == perm @@ -579,8 +625,8 @@ impl FileType { #[cfg(unix)] fn mkpath(v: Vec<u8>) -> PathBuf { - use std::os::unix::prelude::*; use std::ffi::OsStr; + use std::os::unix::prelude::*; PathBuf::from(OsStr::from_bytes(&v)) } #[cfg(windows)] |