summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README1
-rw-r--r--paramiko/file.py3
-rw-r--r--paramiko/sftp_client.py57
-rw-r--r--paramiko/sftp_file.py9
-rwxr-xr-xtests/test_sftp.py29
5 files changed, 97 insertions, 2 deletions
diff --git a/README b/README
index 35f02251..033f4a5e 100644
--- a/README
+++ b/README
@@ -238,7 +238,6 @@ v0.9 FEAROW
* ctr forms of ciphers are missing (blowfish-ctr, aes128-ctr, aes256-ctr)
-* would be nice to have an ftp-like interface to sftp (put, get, chdir...)
* cool sftp extension: retreive MD5 or SHA1 of section of a file
* SFTPClient.from_url('sftp://robey@arch.lag.net/folder/filename', 'r+')
keep cache of opened sftp clients by (host, port, username)
diff --git a/paramiko/file.py b/paramiko/file.py
index c0601b0e..13d36ac8 100644
--- a/paramiko/file.py
+++ b/paramiko/file.py
@@ -56,6 +56,9 @@ class BufferedFile (object):
# (these may be different because we buffer for line reading)
self._pos = self._realpos = 0
+ def __del__(self):
+ self.close()
+
def __iter__(self):
"""
Returns an iterator that can be used to iterate over the lines in this
diff --git a/paramiko/sftp_client.py b/paramiko/sftp_client.py
index 488a4158..ab4f505c 100644
--- a/paramiko/sftp_client.py
+++ b/paramiko/sftp_client.py
@@ -20,6 +20,7 @@
Client-mode SFTP support.
"""
+import os
from sftp import *
from sftp_attr import SFTPAttributes
from sftp_file import SFTPFile
@@ -428,6 +429,62 @@ class SFTPClient (BaseSFTP):
@since: 1.4
"""
return self._cwd
+
+ def put(self, localpath, remotepath):
+ """
+ Copy a local file (C{localpath}) to the SFTP server as C{remotepath}.
+ Any exception raised by operations will be passed through. This
+ method is primarily provided as a convenience.
+
+ @param localpath: the local file to copy
+ @type localpath: str
+ @param remotepath: the destination path on the SFTP server
+ @type remotepath: str
+
+ @since: 1.4
+ """
+ fl = file(localpath, 'rb')
+ fr = self.file(remotepath, 'wb')
+ size = 0
+ while True:
+ data = fl.read(16384)
+ if len(data) == 0:
+ break
+ fr.write(data)
+ size += len(data)
+ fl.close()
+ fr.close()
+ s = self.stat(remotepath)
+ if s.st_size != size:
+ raise IOError('size mismatch in put! %d != %d' % (s.st_size, size))
+
+ def get(self, remotepath, localpath):
+ """
+ Copy a remote file (C{remotepath}) from the SFTP server to the local
+ host as C{localpath}. Any exception raised by operations will be
+ passed through. This method is primarily provided as a convenience.
+
+ @param remotepath: the remote file to copy
+ @type remotepath: str
+ @param localpath: the destination path on the local host
+ @type localpath: str
+
+ @since: 1.4
+ """
+ fr = self.file(remotepath, 'rb')
+ fl = file(localpath, 'wb')
+ size = 0
+ while True:
+ data = fr.read(16384)
+ if len(data) == 0:
+ break
+ fl.write(data)
+ size += len(data)
+ fl.close()
+ fr.close()
+ s = os.stat(localpath)
+ if s.st_size != size:
+ raise IOError('size mismatch in get! %d != %d' % (s.st_size, size))
### internals...
diff --git a/paramiko/sftp_file.py b/paramiko/sftp_file.py
index c173d1c8..36d6772f 100644
--- a/paramiko/sftp_file.py
+++ b/paramiko/sftp_file.py
@@ -43,7 +43,14 @@ class SFTPFile (BufferedFile):
def close(self):
BufferedFile.close(self)
- self.sftp._request(CMD_CLOSE, self.handle)
+ try:
+ self.sftp._request(CMD_CLOSE, self.handle)
+ except EOFError:
+ # may have outlived the Transport connection
+ pass
+ except IOError:
+ # may have outlived the Transport connection
+ pass
def _read(self, size):
size = min(size, self.MAX_REQUEST_SIZE)
diff --git a/tests/test_sftp.py b/tests/test_sftp.py
index f4b5fea2..992c9dc3 100755
--- a/tests/test_sftp.py
+++ b/tests/test_sftp.py
@@ -540,3 +540,32 @@ class SFTPTest (unittest.TestCase):
except:
pass
+ def test_J_get_put(self):
+ """
+ verify that get/put work.
+ """
+ import os, warnings
+ warnings.filterwarnings('ignore', 'tempnam.*')
+
+ localname = os.tempnam()
+ text = 'All I wanted was a plastic bunny rabbit.\n'
+ f = open(localname, 'w')
+ f.write(text)
+ f.close()
+ sftp.put(localname, FOLDER + '/bunny.txt')
+
+ f = sftp.open(FOLDER + '/bunny.txt', 'r')
+ self.assertEquals(text, f.read(128))
+ f.close()
+
+ os.unlink(localname)
+ localname = os.tempnam()
+ sftp.get(FOLDER + '/bunny.txt', localname)
+
+ f = open(localname, 'r')
+ self.assertEquals(text, f.read(128))
+ f.close()
+
+ os.unlink(localname)
+ sftp.unlink(FOLDER + '/bunny.txt')
+