diff options
author | Jeff Forcier <jeff@bitprophet.org> | 2018-05-29 15:26:48 -0700 |
---|---|---|
committer | Jeff Forcier <jeff@bitprophet.org> | 2018-05-29 15:26:48 -0700 |
commit | 3c90e2cd52f7b956671db944061dc5b6cc7872d1 (patch) | |
tree | 1f03c2065463d2c7c71181c3a766593b4ed04f9d /paramiko/sftp_client.py | |
parent | 2b40bf14493245ef4112128a66b3f347c6f7b746 (diff) | |
parent | f2ab9241daa49be4a7293b903eac34188d3a74d8 (diff) | |
download | paramiko-3c90e2cd52f7b956671db944061dc5b6cc7872d1.tar.gz |
Merge branch '2.4'
Diffstat (limited to 'paramiko/sftp_client.py')
-rw-r--r-- | paramiko/sftp_client.py | 175 |
1 files changed, 104 insertions, 71 deletions
diff --git a/paramiko/sftp_client.py b/paramiko/sftp_client.py index 31dc234c..de3f9f58 100644 --- a/paramiko/sftp_client.py +++ b/paramiko/sftp_client.py @@ -30,12 +30,37 @@ from paramiko.message import Message from paramiko.common import INFO, DEBUG, o777 from paramiko.py3compat import b, u, long from paramiko.sftp import ( - BaseSFTP, CMD_OPENDIR, CMD_HANDLE, SFTPError, CMD_READDIR, CMD_NAME, - CMD_CLOSE, SFTP_FLAG_READ, SFTP_FLAG_WRITE, SFTP_FLAG_CREATE, - SFTP_FLAG_TRUNC, SFTP_FLAG_APPEND, SFTP_FLAG_EXCL, CMD_OPEN, CMD_REMOVE, - CMD_RENAME, CMD_MKDIR, CMD_RMDIR, CMD_STAT, CMD_ATTRS, CMD_LSTAT, - CMD_SYMLINK, CMD_SETSTAT, CMD_READLINK, CMD_REALPATH, CMD_STATUS, - CMD_EXTENDED, SFTP_OK, SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED, + BaseSFTP, + CMD_OPENDIR, + CMD_HANDLE, + SFTPError, + CMD_READDIR, + CMD_NAME, + CMD_CLOSE, + SFTP_FLAG_READ, + SFTP_FLAG_WRITE, + SFTP_FLAG_CREATE, + SFTP_FLAG_TRUNC, + SFTP_FLAG_APPEND, + SFTP_FLAG_EXCL, + CMD_OPEN, + CMD_REMOVE, + CMD_RENAME, + CMD_MKDIR, + CMD_RMDIR, + CMD_STAT, + CMD_ATTRS, + CMD_LSTAT, + CMD_SYMLINK, + CMD_SETSTAT, + CMD_READLINK, + CMD_REALPATH, + CMD_STATUS, + CMD_EXTENDED, + SFTP_OK, + SFTP_EOF, + SFTP_NO_SUCH_FILE, + SFTP_PERMISSION_DENIED, ) from paramiko.sftp_attr import SFTPAttributes @@ -51,15 +76,15 @@ def _to_unicode(s): probably doesn't know the filename's encoding. """ try: - return s.encode('ascii') + return s.encode("ascii") except (UnicodeError, AttributeError): try: - return s.decode('utf-8') + return s.decode("utf-8") except UnicodeError: return s -b_slash = b'/' +b_slash = b"/" class SFTPClient(BaseSFTP, ClosingContextManager): @@ -71,6 +96,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): Instances of this class may be used as context managers. """ + def __init__(self, sock): """ Create an SFTP client from an existing `.Channel`. The channel @@ -97,15 +123,18 @@ class SFTPClient(BaseSFTP, ClosingContextManager): # override default logger transport = self.sock.get_transport() self.logger = util.get_logger( - transport.get_log_channel() + '.sftp') + transport.get_log_channel() + ".sftp" + ) self.ultra_debug = transport.get_hexdump() try: server_version = self._send_version() except EOFError: - raise SSHException('EOF during negotiation') + raise SSHException("EOF during negotiation") self._log( INFO, - 'Opened sftp connection (server version {})'.format(server_version) + "Opened sftp connection (server version {})".format( + server_version + ), ) @classmethod @@ -132,11 +161,12 @@ class SFTPClient(BaseSFTP, ClosingContextManager): .. versionchanged:: 1.15 Added the ``window_size`` and ``max_packet_size`` arguments. """ - chan = t.open_session(window_size=window_size, - max_packet_size=max_packet_size) + chan = t.open_session( + window_size=window_size, max_packet_size=max_packet_size + ) if chan is None: return None - chan.invoke_subsystem('sftp') + chan.invoke_subsystem("sftp") return cls(chan) def _log(self, level, msg, *args): @@ -148,10 +178,12 @@ class SFTPClient(BaseSFTP, ClosingContextManager): # logging.Logger.log() explicitly requires it. Grump. # escape '%' in msg (they could come from file or directory names) # before logging - msg = msg.replace('%', '%%') + msg = msg.replace("%", "%%") super(SFTPClient, self)._log( level, - "[chan %s] " + msg, *([self.sock.get_name()] + list(args))) + "[chan %s] " + msg, + *([self.sock.get_name()] + list(args)) + ) def close(self): """ @@ -159,7 +191,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): .. versionadded:: 1.4 """ - self._log(INFO, 'sftp session closed.') + self._log(INFO, "sftp session closed.") self.sock.close() def get_channel(self): @@ -171,7 +203,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): """ return self.sock - def listdir(self, path='.'): + def listdir(self, path="."): """ Return a list containing the names of the entries in the given ``path``. @@ -185,7 +217,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): """ return [f.filename for f in self.listdir_attr(path)] - def listdir_attr(self, path='.'): + def listdir_attr(self, path="."): """ Return a list containing `.SFTPAttributes` objects corresponding to files in the given ``path``. The list is in arbitrary order. It does @@ -203,10 +235,10 @@ class SFTPClient(BaseSFTP, ClosingContextManager): .. versionadded:: 1.2 """ path = self._adjust_cwd(path) - self._log(DEBUG, 'listdir({!r})'.format(path)) + self._log(DEBUG, "listdir({!r})".format(path)) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: - raise SFTPError('Expected handle') + raise SFTPError("Expected handle") handle = msg.get_binary() filelist = [] while True: @@ -216,18 +248,18 @@ class SFTPClient(BaseSFTP, ClosingContextManager): # done with handle break if t != CMD_NAME: - raise SFTPError('Expected name response') + raise SFTPError("Expected name response") count = msg.get_int() for i in range(count): filename = msg.get_text() longname = msg.get_text() attr = SFTPAttributes._from_msg(msg, filename, longname) - if (filename != '.') and (filename != '..'): + if (filename != ".") and (filename != ".."): filelist.append(attr) self._request(CMD_CLOSE, handle) return filelist - def listdir_iter(self, path='.', read_aheads=50): + def listdir_iter(self, path=".", read_aheads=50): """ Generator version of `.listdir_attr`. @@ -242,11 +274,11 @@ class SFTPClient(BaseSFTP, ClosingContextManager): .. versionadded:: 1.15 """ path = self._adjust_cwd(path) - self._log(DEBUG, 'listdir({!r})'.format(path)) + self._log(DEBUG, "listdir({!r})".format(path)) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: - raise SFTPError('Expected handle') + raise SFTPError("Expected handle") handle = msg.get_string() @@ -261,7 +293,6 @@ class SFTPClient(BaseSFTP, ClosingContextManager): num = self._async_request(type(None), CMD_READDIR, handle) nums.append(num) - # For each of our sent requests # Read and parse the corresponding packets # If we're at the end of our queued requests, then fire off @@ -280,8 +311,9 @@ class SFTPClient(BaseSFTP, ClosingContextManager): filename = msg.get_text() longname = msg.get_text() attr = SFTPAttributes._from_msg( - msg, filename, longname) - if (filename != '.') and (filename != '..'): + msg, filename, longname + ) + if (filename != ".") and (filename != ".."): yield attr # If we've hit the end of our queued requests, reset nums. @@ -291,8 +323,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): self._request(CMD_CLOSE, handle) return - - def open(self, filename, mode='r', bufsize=-1): + def open(self, filename, mode="r", bufsize=-1): """ Open a file on the remote server. The arguments are the same as for Python's built-in `python:file` (aka `python:open`). A file-like @@ -325,26 +356,28 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :raises: ``IOError`` -- if the file could not be opened. """ filename = self._adjust_cwd(filename) - self._log(DEBUG, 'open({!r}, {!r})'.format(filename, mode)) + self._log(DEBUG, "open({!r}, {!r})".format(filename, mode)) imode = 0 - if ('r' in mode) or ('+' in mode): + if ("r" in mode) or ("+" in mode): imode |= SFTP_FLAG_READ - if ('w' in mode) or ('+' in mode) or ('a' in mode): + if ("w" in mode) or ("+" in mode) or ("a" in mode): imode |= SFTP_FLAG_WRITE - if 'w' in mode: + if "w" in mode: imode |= SFTP_FLAG_CREATE | SFTP_FLAG_TRUNC - if 'a' in mode: + if "a" in mode: imode |= SFTP_FLAG_CREATE | SFTP_FLAG_APPEND - if 'x' in mode: + if "x" in mode: imode |= SFTP_FLAG_CREATE | SFTP_FLAG_EXCL attrblock = SFTPAttributes() t, msg = self._request(CMD_OPEN, filename, imode, attrblock) if t != CMD_HANDLE: - raise SFTPError('Expected handle') + raise SFTPError("Expected handle") handle = msg.get_binary() self._log( DEBUG, - 'open({!r}, {!r}) -> {}'.format(filename, mode, u(hexlify(handle))) + "open({!r}, {!r}) -> {}".format( + filename, mode, u(hexlify(handle)) + ), ) return SFTPFile(self, handle, mode, bufsize) @@ -361,7 +394,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :raises: ``IOError`` -- if the path refers to a folder (directory) """ path = self._adjust_cwd(path) - self._log(DEBUG, 'remove({!r})'.format(path)) + self._log(DEBUG, "remove({!r})".format(path)) self._request(CMD_REMOVE, path) unlink = remove @@ -386,7 +419,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): """ oldpath = self._adjust_cwd(oldpath) newpath = self._adjust_cwd(newpath) - self._log(DEBUG, 'rename({!r}, {!r})'.format(oldpath, newpath)) + self._log(DEBUG, "rename({!r}, {!r})".format(oldpath, newpath)) self._request(CMD_RENAME, oldpath, newpath) def posix_rename(self, oldpath, newpath): @@ -406,7 +439,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): """ oldpath = self._adjust_cwd(oldpath) newpath = self._adjust_cwd(newpath) - self._log(DEBUG, 'posix_rename({!r}, {!r})'.format(oldpath, newpath)) + self._log(DEBUG, "posix_rename({!r}, {!r})".format(oldpath, newpath)) self._request( CMD_EXTENDED, "posix-rename@openssh.com", oldpath, newpath ) @@ -421,7 +454,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :param int mode: permissions (posix-style) for the newly-created folder """ path = self._adjust_cwd(path) - self._log(DEBUG, 'mkdir({!r}, {!r})'.format(path, mode)) + self._log(DEBUG, "mkdir({!r}, {!r})".format(path, mode)) attr = SFTPAttributes() attr.st_mode = mode self._request(CMD_MKDIR, path, attr) @@ -433,7 +466,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :param str path: name of the folder to remove """ path = self._adjust_cwd(path) - self._log(DEBUG, 'rmdir({!r})'.format(path)) + self._log(DEBUG, "rmdir({!r})".format(path)) self._request(CMD_RMDIR, path) def stat(self, path): @@ -456,10 +489,10 @@ class SFTPClient(BaseSFTP, ClosingContextManager): file """ path = self._adjust_cwd(path) - self._log(DEBUG, 'stat({!r})'.format(path)) + self._log(DEBUG, "stat({!r})".format(path)) t, msg = self._request(CMD_STAT, path) if t != CMD_ATTRS: - raise SFTPError('Expected attributes') + raise SFTPError("Expected attributes") return SFTPAttributes._from_msg(msg) def lstat(self, path): @@ -474,10 +507,10 @@ class SFTPClient(BaseSFTP, ClosingContextManager): file """ path = self._adjust_cwd(path) - self._log(DEBUG, 'lstat({!r})'.format(path)) + self._log(DEBUG, "lstat({!r})".format(path)) t, msg = self._request(CMD_LSTAT, path) if t != CMD_ATTRS: - raise SFTPError('Expected attributes') + raise SFTPError("Expected attributes") return SFTPAttributes._from_msg(msg) def symlink(self, source, dest): @@ -488,7 +521,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :param str dest: path of the newly created symlink """ dest = self._adjust_cwd(dest) - self._log(DEBUG, 'symlink({!r}, {!r})'.format(source, dest)) + self._log(DEBUG, "symlink({!r}, {!r})".format(source, dest)) source = b(source) self._request(CMD_SYMLINK, source, dest) @@ -502,7 +535,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :param int mode: new permissions """ path = self._adjust_cwd(path) - self._log(DEBUG, 'chmod({!r}, {!r})'.format(path, mode)) + self._log(DEBUG, "chmod({!r}, {!r})".format(path, mode)) attr = SFTPAttributes() attr.st_mode = mode self._request(CMD_SETSTAT, path, attr) @@ -519,7 +552,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :param int gid: new group id """ path = self._adjust_cwd(path) - self._log(DEBUG, 'chown({!r}, {!r}, {!r})'.format(path, uid, gid)) + self._log(DEBUG, "chown({!r}, {!r}, {!r})".format(path, uid, gid)) attr = SFTPAttributes() attr.st_uid, attr.st_gid = uid, gid self._request(CMD_SETSTAT, path, attr) @@ -541,7 +574,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): path = self._adjust_cwd(path) if times is None: times = (time.time(), time.time()) - self._log(DEBUG, 'utime({!r}, {!r})'.format(path, times)) + self._log(DEBUG, "utime({!r}, {!r})".format(path, times)) attr = SFTPAttributes() attr.st_atime, attr.st_mtime = times self._request(CMD_SETSTAT, path, attr) @@ -556,7 +589,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :param int size: the new size of the file """ path = self._adjust_cwd(path) - self._log(DEBUG, 'truncate({!r}, {!r})'.format(path, size)) + self._log(DEBUG, "truncate({!r}, {!r})".format(path, size)) attr = SFTPAttributes() attr.st_size = size self._request(CMD_SETSTAT, path, attr) @@ -571,15 +604,15 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :return: target path, as a `str` """ path = self._adjust_cwd(path) - self._log(DEBUG, 'readlink({!r})'.format(path)) + self._log(DEBUG, "readlink({!r})".format(path)) t, msg = self._request(CMD_READLINK, path) if t != CMD_NAME: - raise SFTPError('Expected name response') + raise SFTPError("Expected name response") count = msg.get_int() if count == 0: return None if count != 1: - raise SFTPError('Readlink returned {} results'.format(count)) + raise SFTPError("Readlink returned {} results".format(count)) return _to_unicode(msg.get_string()) def normalize(self, path): @@ -595,13 +628,13 @@ class SFTPClient(BaseSFTP, ClosingContextManager): :raises: ``IOError`` -- if the path can't be resolved on the server """ path = self._adjust_cwd(path) - self._log(DEBUG, 'normalize({!r})'.format(path)) + self._log(DEBUG, "normalize({!r})".format(path)) t, msg = self._request(CMD_REALPATH, path) if t != CMD_NAME: - raise SFTPError('Expected name response') + raise SFTPError("Expected name response") count = msg.get_int() if count != 1: - raise SFTPError('Realpath returned {} results'.format(count)) + raise SFTPError("Realpath returned {} results".format(count)) return msg.get_text() def chdir(self, path=None): @@ -625,9 +658,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): return if not stat.S_ISDIR(self.stat(path).st_mode): code = errno.ENOTDIR - raise SFTPError( - code, "{}: {}".format(os.strerror(code), path) - ) + raise SFTPError(code, "{}: {}".format(os.strerror(code), path)) self._cwd = b(self.normalize(path)) def getcwd(self): @@ -680,7 +711,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): .. versionadded:: 1.10 """ - with self.file(remotepath, 'wb') as fr: + with self.file(remotepath, "wb") as fr: fr.set_pipelined(True) size = self._transfer_with_callback( reader=fl, writer=fr, file_size=file_size, callback=callback @@ -689,7 +720,8 @@ class SFTPClient(BaseSFTP, ClosingContextManager): s = self.stat(remotepath) if s.st_size != size: raise IOError( - 'size mismatch in put! {} != {}'.format(s.st_size, size)) + "size mismatch in put! {} != {}".format(s.st_size, size) + ) else: s = SFTPAttributes() return s @@ -723,7 +755,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): ``confirm`` param added. """ file_size = os.stat(localpath).st_size - with open(localpath, 'rb') as fl: + with open(localpath, "rb") as fl: return self.putfo(fl, remotepath, file_size, callback, confirm) def getfo(self, remotepath, fl, callback=None): @@ -744,7 +776,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): .. versionadded:: 1.10 """ file_size = self.stat(remotepath).st_size - with self.open(remotepath, 'rb') as fr: + with self.open(remotepath, "rb") as fr: fr.prefetch(file_size) return self._transfer_with_callback( reader=fr, writer=fl, file_size=file_size, callback=callback @@ -766,12 +798,13 @@ class SFTPClient(BaseSFTP, ClosingContextManager): .. versionchanged:: 1.7.4 Added the ``callback`` param """ - with open(localpath, 'wb') as fl: + with open(localpath, "wb") as fl: size = self.getfo(remotepath, fl, callback) s = os.stat(localpath) if s.st_size != size: raise IOError( - 'size mismatch in get! {} != {}'.format(s.st_size, size)) + "size mismatch in get! {} != {}".format(s.st_size, size) + ) # ...internals... @@ -809,7 +842,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): try: t, data = self._read_packet() except EOFError as e: - raise SSHException('Server connection dropped: {}'.format(e)) + raise SSHException("Server connection dropped: {}".format(e)) msg = Message(data) num = msg.get_int() self._lock.acquire() @@ -817,7 +850,7 @@ class SFTPClient(BaseSFTP, ClosingContextManager): if num not in self._expecting: # might be response for a file that was closed before # responses came back - self._log(DEBUG, 'Unexpected response #{}'.format(num)) + self._log(DEBUG, "Unexpected response #{}".format(num)) if waitfor is None: # just doing a single check break |