From f7b892905c62b94a6e54d115ee2d6d32d66af013 Mon Sep 17 00:00:00 2001 From: "Jeremy T. Bouse" Date: Fri, 27 Nov 2009 16:25:55 -0500 Subject: Imported Upstream version 1.7.6 Closes: #543784 --- docs/paramiko.sftp_client-pysrc.html | 1585 +++++++++++++++++----------------- 1 file changed, 809 insertions(+), 776 deletions(-) (limited to 'docs/paramiko.sftp_client-pysrc.html') diff --git a/docs/paramiko.sftp_client-pysrc.html b/docs/paramiko.sftp_client-pysrc.html index 0b17480..cb1c6ea 100644 --- a/docs/paramiko.sftp_client-pysrc.html +++ b/docs/paramiko.sftp_client-pysrc.html @@ -54,24 +54,24 @@

Source Code for Module paramiko.sftp_client

-  1  # Copyright (C) 2003-2007  Robey Pointer <robey@lag.net> 
-  2  # 
-  3  # This file is part of paramiko. 
-  4  # 
-  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
-  6  # terms of the GNU Lesser General Public License as published by the Free 
-  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
-  8  # any later version. 
-  9  # 
- 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
- 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
- 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
- 13  # details. 
- 14  # 
- 15  # You should have received a copy of the GNU Lesser General Public License 
- 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
- 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
- 18   
+  1  # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com> 
+  2  # 
+  3  # This file is part of paramiko. 
+  4  # 
+  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
+  6  # terms of the GNU Lesser General Public License as published by the Free 
+  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
+  8  # any later version. 
+  9  # 
+ 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
+ 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
+ 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
+ 13  # details. 
+ 14  # 
+ 15  # You should have received a copy of the GNU Lesser General Public License 
+ 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
+ 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
+ 18   
  19  """ 
  20  Client-mode SFTP support. 
  21  """ 
@@ -79,52 +79,56 @@
  23  from binascii import hexlify 
  24  import errno 
  25  import os 
- 26  import threading 
- 27  import time 
- 28  import weakref 
- 29   
- 30  from paramiko.sftp import * 
- 31  from paramiko.sftp_attr import SFTPAttributes 
- 32  from paramiko.ssh_exception import SSHException 
- 33  from paramiko.sftp_file import SFTPFile 
- 34   
+ 26  import stat 
+ 27  import threading 
+ 28  import time 
+ 29  import weakref 
+ 30   
+ 31  from paramiko.sftp import * 
+ 32  from paramiko.sftp_attr import SFTPAttributes 
+ 33  from paramiko.ssh_exception import SSHException 
+ 34  from paramiko.sftp_file import SFTPFile 
  35   
-
36 -def _to_unicode(s): -
37 """ - 38 decode a string as ascii or utf8 if possible (as required by the sftp - 39 protocol). if neither works, just return a byte string because the server - 40 probably doesn't know the filename's encoding. - 41 """ - 42 try: - 43 return s.encode('ascii') - 44 except UnicodeError: - 45 try: - 46 return s.decode('utf-8') - 47 except UnicodeError: - 48 return s -
49 - 50 -
51 -class SFTPClient (BaseSFTP): -
52 """ - 53 SFTP client object. C{SFTPClient} is used to open an sftp session across - 54 an open ssh L{Transport} and do remote file operations. - 55 """ - 56 -
57 - def __init__(self, sock): -
58 """ - 59 Create an SFTP client from an existing L{Channel}. The channel - 60 should already have requested the C{"sftp"} subsystem. - 61 - 62 An alternate way to create an SFTP client context is by using - 63 L{from_transport}. - 64 - 65 @param sock: an open L{Channel} using the C{"sftp"} subsystem - 66 @type sock: L{Channel} - 67 - 68 @raise SSHException: if there's an exception while negotiating - 69 sftp - 70 """ - 71 BaseSFTP. 36 +
37 -def _to_unicode(s): +
38 """ + 39 decode a string as ascii or utf8 if possible (as required by the sftp + 40 protocol). if neither works, just return a byte string because the server + 41 probably doesn't know the filename's encoding. + 42 """ + 43 try: + 44 return s.encode('ascii') + 45 except UnicodeError: + 46 try: + 47 return s.decode('utf-8') + 48 except UnicodeError: + 49 return s +
50 + 51 +
52 -class SFTPClient (BaseSFTP): +
53 """ + 54 SFTP client object. C{SFTPClient} is used to open an sftp session across + 55 an open ssh L{Transport} and do remote file operations. + 56 """ + 57 +
58 - def __init__(self, sock): +
59 """ + 60 Create an SFTP client from an existing L{Channel}. The channel + 61 should already have requested the C{"sftp"} subsystem. + 62 + 63 An alternate way to create an SFTP client context is by using + 64 L{from_transport}. + 65 + 66 @param sock: an open L{Channel} using the C{"sftp"} subsystem + 67 @type sock: L{Channel} + 68 + 69 @raise SSHException: if there's an exception while negotiating + 70 sftp + 71 """ + 72 BaseSFTP.__init__(self) - 72 self.sock = sock - 73 self.ultra_debug = False - 74 self.request_number = 1 - 75 # lock for request_number - 76 self._lock = threading.Lock() - 77 self._cwd = None - 78 # request # -> SFTPFile - 79 self._expecting = weakref.WeakValueDictionary() - 80 if type(sock) is Channel: - 81 # override default logger - 82 transport = self.sock.get_transport() - 83 self.logger = util.get_logger(transport.get_log_channel() + '.sftp') - 84 self.ultra_debug = transport.get_hexdump() - 85 try: - 86 server_version = self._send_version() - 87 except EOFError, x: - 88 raise SSHException('EOF during negotiation') - 89 self._log(__init__(self) + 73 self.sock = sock + 74 self.ultra_debug = False + 75 self.request_number = 1 + 76 # lock for request_number + 77 self._lock = threading.Lock() + 78 self._cwd = None + 79 # request # -> SFTPFile + 80 self._expecting = weakref.WeakValueDictionary() + 81 if type(sock) is Channel: + 82 # override default logger + 83 transport = self.sock.get_transport() + 84 self.logger = util.get_logger(transport.get_log_channel() + '.sftp') + 85 self.ultra_debug = transport.get_hexdump() + 86 try: + 87 server_version = self._send_version() + 88 except EOFError, x: + 89 raise SSHException('EOF during negotiation') + 90 self._log(INFO, 'Opened sftp connection (server version %d)' % server_version) -
90 -
91 - def from_transport(cls, t): -
92 """ - 93 Create an SFTP client channel from an open L{Transport}. - 94 - 95 @param t: an open L{Transport} which is already authenticated - 96 @type t: L{Transport} - 97 @return: a new L{SFTPClient} object, referring to an sftp session - 98 (channel) across the transport - 99 @rtype: L{SFTPClient} -100 """ -101 chan = t.open_session() -102 if chan is None: -103 return None -104 chan.invoke_subsystem('sftp') -105 return cls(chan) -
106 from_transport = classmethod(from_transport) -107 -
108 - def _log(self, level, msg, *args): -
109 super(SFTPClient, self)._log(level, "[chan %s] " + msg, *([ self.sock.INFO, 'Opened sftp connection (server version %d)' % server_version) +
91 +
92 - def from_transport(cls, t): +
93 """ + 94 Create an SFTP client channel from an open L{Transport}. + 95 + 96 @param t: an open L{Transport} which is already authenticated + 97 @type t: L{Transport} + 98 @return: a new L{SFTPClient} object, referring to an sftp session + 99 (channel) across the transport +100 @rtype: L{SFTPClient} +101 """ +102 chan = t.open_session() +103 if chan is None: +104 return None +105 chan.invoke_subsystem('sftp') +106 return cls(chan) +
107 from_transport = classmethod(from_transport) +108 +
109 - def _log(self, level, msg, *args): +
110 if isinstance(msg, list): +111 for m in msg: +112 super(SFTPClient, self)._log(level, "[chan %s] " + m, *([ self.sock.get_name() ] + list(args))) +113 else: +114 super(SFTPClient, self)._log(level, "[chan %s] " + msg, *([ self.sock.get_name() ] + list(args))) -
110 -
111 - def close(self): -
112 """ -113 Close the SFTP session and its underlying channel. -114 -115 @since: 1.4 -116 """ -117 self._log(get_name() ] + list(args))) +
115 +
116 - def close(self): +
117 """ +118 Close the SFTP session and its underlying channel. +119 +120 @since: 1.4 +121 """ +122 self._log(INFO, 'sftp session closed.') -118 self.sock.INFO, 'sftp session closed.') +123 self.sock.close() -
119 -
120 - def get_channel(self): -
121 """ -122 Return the underlying L{Channel} object for this SFTP session. This -123 might be useful for doing things like setting a timeout on the channel. -124 -125 @return: the SSH channel -126 @rtype: L{Channel} -127 -128 @since: 1.7.1 -129 """ -130 return self.sock -
131 -
132 - def listdir(self, path='.'): -
133 """ -134 Return a list containing the names of the entries in the given C{path}. -135 The list is in arbitrary order. It does not include the special -136 entries C{'.'} and C{'..'} even if they are present in the folder. -137 This method is meant to mirror C{os.listdir} as closely as possible. -138 For a list of full L{SFTPAttributes} objects, see L{listdir_attr}. -139 -140 @param path: path to list (defaults to C{'.'}) -141 @type path: str -142 @return: list of filenames -143 @rtype: list of str -144 """ -145 return [f.filename for f in self.listdir_attr(path)] -
146 -
147 - def listdir_attr(self, path='.'): -
148 """ -149 Return a list containing L{SFTPAttributes} objects corresponding to -150 files in the given C{path}. The list is in arbitrary order. It does -151 not include the special entries C{'.'} and C{'..'} even if they are -152 present in the folder. -153 -154 The returned L{SFTPAttributes} objects will each have an additional -155 field: C{longname}, which may contain a formatted string of the file's -156 attributes, in unix format. The content of this string will probably -157 depend on the SFTP server implementation. +paramiko.win_pageant.PageantConnection.close" class="py-name" href="#" onclick="return doclink('link-36', 'close', 'link-36');">close() +
124 +
125 - def get_channel(self): +
126 """ +127 Return the underlying L{Channel} object for this SFTP session. This +128 might be useful for doing things like setting a timeout on the channel. +129 +130 @return: the SSH channel +131 @rtype: L{Channel} +132 +133 @since: 1.7.1 +134 """ +135 return self.sock +
136 +
137 - def listdir(self, path='.'): +
138 """ +139 Return a list containing the names of the entries in the given C{path}. +140 The list is in arbitrary order. It does not include the special +141 entries C{'.'} and C{'..'} even if they are present in the folder. +142 This method is meant to mirror C{os.listdir} as closely as possible. +143 For a list of full L{SFTPAttributes} objects, see L{listdir_attr}. +144 +145 @param path: path to list (defaults to C{'.'}) +146 @type path: str +147 @return: list of filenames +148 @rtype: list of str +149 """ +150 return [f.filename for f in self.listdir_attr(path)] +
151 +
152 - def listdir_attr(self, path='.'): +
153 """ +154 Return a list containing L{SFTPAttributes} objects corresponding to +155 files in the given C{path}. The list is in arbitrary order. It does +156 not include the special entries C{'.'} and C{'..'} even if they are +157 present in the folder. 158 -159 @param path: path to list (defaults to C{'.'}) -160 @type path: str -161 @return: list of attributes -162 @rtype: list of L{SFTPAttributes} -163 -164 @since: 1.2 -165 """ -166 path = self._adjust_cwd(path) -167 self._log(159 The returned L{SFTPAttributes} objects will each have an additional +160 field: C{longname}, which may contain a formatted string of the file's +161 attributes, in unix format. The content of this string will probably +162 depend on the SFTP server implementation. +163 +164 @param path: path to list (defaults to C{'.'}) +165 @type path: str +166 @return: list of attributes +167 @rtype: list of L{SFTPAttributes} +168 +169 @since: 1.2 +170 """ +171 path = self._adjust_cwd(path) +172 self._log(DEBUG, 'listdir(%r)' % path) -168 t, msg = self._request(DEBUG, 'listdir(%r)' % path) +173 t, msg = self._request(CMD_OPENDIR, path) -169 if t != CMD_OPENDIR, path) +174 if t != CMD_HANDLE: -170 raise SFTPError('Expected handle') -171 handle = msg.get_string() -172 filelist = [] -173 while True: -174 try: -175 t, msg = self._request(CMD_HANDLE: +175 raise SFTPError('Expected handle') +176 handle = msg.get_string() +177 filelist = [] +178 while True: +179 try: +180 t, msg = self._request(CMD_READDIR, handle) -176 except EOFError, e: -177 # done with handle -178 break -179 if t != CMD_READDIR, handle) +181 except EOFError, e: +182 # done with handle +183 break +184 if t != CMD_NAME: -180 raise SFTPError('Expected name response') -181 count = msg.get_int() -182 for i in range(count): -183 filename = _to_unicode(msg.get_string()) -184 longname = _to_unicode(msg.get_string()) -185 attr = SFTPAttributes._from_msg(msg, filename, longname) -186 if (filename != '.') and (filename != '..'): -187 filelist.append(attr) -188 self._request(CMD_NAME: +185 raise SFTPError('Expected name response') +186 count = msg.get_int() +187 for i in range(count): +188 filename = _to_unicode(msg.get_string()) +189 longname = _to_unicode(msg.get_string()) +190 attr = SFTPAttributes._from_msg(msg, filename, longname) +191 if (filename != '.') and (filename != '..'): +192 filelist.append(attr) +193 self._request(CMD_CLOSE, handle) -189 return filelist -
190 -
191 - def open(self, filename, mode='r', bufsize=-1): -
192 """ -193 Open a file on the remote server. The arguments are the same as for -194 python's built-in C{file} (aka C{open}). A file-like object is -195 returned, which closely mimics the behavior of a normal python file -196 object. -197 -198 The mode indicates how the file is to be opened: C{'r'} for reading, -199 C{'w'} for writing (truncating an existing file), C{'a'} for appending, -200 C{'r+'} for reading/writing, C{'w+'} for reading/writing (truncating an -201 existing file), C{'a+'} for reading/appending. The python C{'b'} flag -202 is ignored, since SSH treats all files as binary. The C{'U'} flag is -203 supported in a compatible way. -204 -205 Since 1.5.2, an C{'x'} flag indicates that the operation should only -206 succeed if the file was created and did not previously exist. This has -207 no direct mapping to python's file flags, but is commonly known as the -208 C{O_EXCL} flag in posix. +paramiko.sftp_si.CMD_CLOSE" class="py-name" href="#" onclick="return doclink('link-50', 'CMD_CLOSE', 'link-50');">CMD_CLOSE, handle) +194 return filelist +
195 +
196 - def open(self, filename, mode='r', bufsize=-1): +
197 """ +198 Open a file on the remote server. The arguments are the same as for +199 python's built-in C{file} (aka C{open}). A file-like object is +200 returned, which closely mimics the behavior of a normal python file +201 object. +202 +203 The mode indicates how the file is to be opened: C{'r'} for reading, +204 C{'w'} for writing (truncating an existing file), C{'a'} for appending, +205 C{'r+'} for reading/writing, C{'w+'} for reading/writing (truncating an +206 existing file), C{'a+'} for reading/appending. The python C{'b'} flag +207 is ignored, since SSH treats all files as binary. The C{'U'} flag is +208 supported in a compatible way. 209 -210 The file will be buffered in standard python style by default, but -211 can be altered with the C{bufsize} parameter. C{0} turns off -212 buffering, C{1} uses line buffering, and any number greater than 1 -213 (C{>1}) uses that specific buffer size. +210 Since 1.5.2, an C{'x'} flag indicates that the operation should only +211 succeed if the file was created and did not previously exist. This has +212 no direct mapping to python's file flags, but is commonly known as the +213 C{O_EXCL} flag in posix. 214 -215 @param filename: name of the file to open -216 @type filename: str -217 @param mode: mode (python-style) to open in -218 @type mode: str -219 @param bufsize: desired buffering (-1 = default buffer size) -220 @type bufsize: int -221 @return: a file object representing the open file -222 @rtype: SFTPFile -223 -224 @raise IOError: if the file could not be opened. -225 """ -226 filename = self._adjust_cwd(filename) -227 self._log(215 The file will be buffered in standard python style by default, but +216 can be altered with the C{bufsize} parameter. C{0} turns off +217 buffering, C{1} uses line buffering, and any number greater than 1 +218 (C{>1}) uses that specific buffer size. +219 +220 @param filename: name of the file to open +221 @type filename: str +222 @param mode: mode (python-style) to open in +223 @type mode: str +224 @param bufsize: desired buffering (-1 = default buffer size) +225 @type bufsize: int +226 @return: a file object representing the open file +227 @rtype: SFTPFile +228 +229 @raise IOError: if the file could not be opened. +230 """ +231 filename = self._adjust_cwd(filename) +232 self._log(DEBUG, 'open(%r, %r)' % (filename, mode)) -228 imode = 0 -229 if ('r' in mode) or ('+' in mode): -230 imode |= DEBUG, 'open(%r, %r)' % (filename, mode)) +233 imode = 0 +234 if ('r' in mode) or ('+' in mode): +235 imode |= SFTP_FLAG_READ -231 if ('w' in mode) or ('+' in mode) or ('a' in mode): -232 imode |= SFTP_FLAG_READ +236 if ('w' in mode) or ('+' in mode) or ('a' in mode): +237 imode |= SFTP_FLAG_WRITE -233 if ('w' in mode): -234 imode |= SFTP_FLAG_WRITE +238 if ('w' in mode): +239 imode |= SFTP_FLAG_CREATE | SFTP_FLAG_CREATE | SFTP_FLAG_TRUNC -235 if ('a' in mode): -236 imode |= SFTP_FLAG_TRUNC +240 if ('a' in mode): +241 imode |= SFTP_FLAG_CREATE | SFTP_FLAG_CREATE | SFTP_FLAG_APPEND -237 if ('x' in mode): -238 imode |= SFTP_FLAG_APPEND +242 if ('x' in mode): +243 imode |= SFTP_FLAG_CREATE | SFTP_FLAG_CREATE | SFTP_FLAG_EXCL -239 attrblock = SFTPAttributes() -240 t, msg = self._request(SFTP_FLAG_EXCL +244 attrblock = SFTPAttributes() +245 t, msg = self._request(CMD_OPEN, filename, imode, attrblock) -241 if t != CMD_OPEN, filename, imode, attrblock) +246 if t != CMD_HANDLE: -242 raise SFTPError('Expected handle') -243 handle = msg.get_string() -244 self._log(CMD_HANDLE: +247 raise SFTPError('Expected handle') +248 handle = msg.get_string() +249 self._log(DEBUG, 'open(%r, %r) -> %s' % (filename, mode, hexlify(handle))) -245 return SFTPFile(self, handle, mode, bufsize) -
246 -247 # python continues to vacillate about "open" vs "file"... -248 file = open -249 -
250 - def remove(self, path): -
251 """ -252 Remove the file at the given path. This only works on files; for -253 removing folders (directories), use L{rmdir}. -254 -255 @param path: path (absolute or relative) of the file to remove -256 @type path: str -257 -258 @raise IOError: if the path refers to a folder (directory) -259 """ -260 path = self._adjust_cwd(path) -261 self._log(DEBUG, 'open(%r, %r) -> %s' % (filename, mode, hexlify(handle))) +250 return SFTPFile(self, handle, mode, bufsize) +
251 +252 # python continues to vacillate about "open" vs "file"... +253 file = open +254 +
255 - def remove(self, path): +
256 """ +257 Remove the file at the given path. This only works on files; for +258 removing folders (directories), use L{rmdir}. +259 +260 @param path: path (absolute or relative) of the file to remove +261 @type path: str +262 +263 @raise IOError: if the path refers to a folder (directory) +264 """ +265 path = self._adjust_cwd(path) +266 self._log(DEBUG, 'remove(%r)' % path) -262 self._request(DEBUG, 'remove(%r)' % path) +267 self._request(CMD_REMOVE, path) -
263 -264 unlink = remove -265 -
266 - def rename(self, oldpath, newpath): -
267 """ -268 Rename a file or folder from C{oldpath} to C{newpath}. -269 -270 @param oldpath: existing name of the file or folder -271 @type oldpath: str -272 @param newpath: new name for the file or folder -273 @type newpath: str -274 -275 @raise IOError: if C{newpath} is a folder, or something else goes -276 wrong -277 """ -278 oldpath = self._adjust_cwd(oldpath) -279 newpath = self._adjust_cwd(newpath) -280 self._log(CMD_REMOVE, path) +
268 +269 unlink = remove +270 +
271 - def rename(self, oldpath, newpath): +
272 """ +273 Rename a file or folder from C{oldpath} to C{newpath}. +274 +275 @param oldpath: existing name of the file or folder +276 @type oldpath: str +277 @param newpath: new name for the file or folder +278 @type newpath: str +279 +280 @raise IOError: if C{newpath} is a folder, or something else goes +281 wrong +282 """ +283 oldpath = self._adjust_cwd(oldpath) +284 newpath = self._adjust_cwd(newpath) +285 self._log(DEBUG, 'rename(%r, %r)' % (oldpath, newpath)) -281 self._request(DEBUG, 'rename(%r, %r)' % (oldpath, newpath)) +286 self._request(CMD_RENAME, oldpath, newpath) -
282 -
283 - def mkdir(self, path, mode=0777): -
284 """ -285 Create a folder (directory) named C{path} with numeric mode C{mode}. -286 The default mode is 0777 (octal). On some systems, mode is ignored. -287 Where it is used, the current umask value is first masked out. -288 -289 @param path: name of the folder to create -290 @type path: str -291 @param mode: permissions (posix-style) for the newly-created folder -292 @type mode: int -293 """ -294 path = self._adjust_cwd(path) -295 self._log(CMD_RENAME, oldpath, newpath) +
287 +
288 - def mkdir(self, path, mode=0777): +
289 """ +290 Create a folder (directory) named C{path} with numeric mode C{mode}. +291 The default mode is 0777 (octal). On some systems, mode is ignored. +292 Where it is used, the current umask value is first masked out. +293 +294 @param path: name of the folder to create +295 @type path: str +296 @param mode: permissions (posix-style) for the newly-created folder +297 @type mode: int +298 """ +299 path = self._adjust_cwd(path) +300 self._log(DEBUG, 'mkdir(%r, %r)' % (path, mode)) -296 attr = SFTPAttributes() -297 attr.st_mode = mode -298 self._request(DEBUG, 'mkdir(%r, %r)' % (path, mode)) +301 attr = SFTPAttributes() +302 attr.st_mode = mode +303 self._request(CMD_MKDIR, path, attr) -
299 -
300 - def rmdir(self, path): -
301 """ -302 Remove the folder named C{path}. -303 -304 @param path: name of the folder to remove -305 @type path: str -306 """ -307 path = self._adjust_cwd(path) -308 self._log(CMD_MKDIR, path, attr) +
304 +
305 - def rmdir(self, path): +
306 """ +307 Remove the folder named C{path}. +308 +309 @param path: name of the folder to remove +310 @type path: str +311 """ +312 path = self._adjust_cwd(path) +313 self._log(DEBUG, 'rmdir(%r)' % path) -309 self._request(DEBUG, 'rmdir(%r)' % path) +314 self._request(CMD_RMDIR, path) -
310 -
311 - def stat(self, path): -
312 """ -313 Retrieve information about a file on the remote system. The return -314 value is an object whose attributes correspond to the attributes of -315 python's C{stat} structure as returned by C{os.stat}, except that it -316 contains fewer fields. An SFTP server may return as much or as little -317 info as it wants, so the results may vary from server to server. -318 -319 Unlike a python C{stat} object, the result may not be accessed as a -320 tuple. This is mostly due to the author's slack factor. -321 -322 The fields supported are: C{st_mode}, C{st_size}, C{st_uid}, C{st_gid}, -323 C{st_atime}, and C{st_mtime}. -324 -325 @param path: the filename to stat -326 @type path: str -327 @return: an object containing attributes about the given file -328 @rtype: SFTPAttributes -329 """ -330 path = self._adjust_cwd(path) -331 self._log(CMD_RMDIR, path) +
315 +
316 - def stat(self, path): +
317 """ +318 Retrieve information about a file on the remote system. The return +319 value is an object whose attributes correspond to the attributes of +320 python's C{stat} structure as returned by C{os.stat}, except that it +321 contains fewer fields. An SFTP server may return as much or as little +322 info as it wants, so the results may vary from server to server. +323 +324 Unlike a python C{stat} object, the result may not be accessed as a +325 tuple. This is mostly due to the author's slack factor. +326 +327 The fields supported are: C{st_mode}, C{st_size}, C{st_uid}, C{st_gid}, +328 C{st_atime}, and C{st_mtime}. +329 +330 @param path: the filename to stat +331 @type path: str +332 @return: an object containing attributes about the given file +333 @rtype: SFTPAttributes +334 """ +335 path = self._adjust_cwd(path) +336 self._log(DEBUG, 'stat(%r)' % path) -332 t, msg = self._request(DEBUG, 'stat(%r)' % path) +337 t, msg = self._request(CMD_STAT, path) -333 if t != CMD_STAT, path) +338 if t != CMD_ATTRS: -334 raise SFTPError('Expected attributes') -335 return SFTPAttributes._from_msg(msg) -
336 -
337 - def lstat(self, path): -
338 """ -339 Retrieve information about a file on the remote system, without -340 following symbolic links (shortcuts). This otherwise behaves exactly -341 the same as L{stat}. -342 -343 @param path: the filename to stat -344 @type path: str -345 @return: an object containing attributes about the given file -346 @rtype: SFTPAttributes -347 """ -348 path = self._adjust_cwd(path) -349 self._log(CMD_ATTRS: +339 raise SFTPError('Expected attributes') +340 return SFTPAttributes._from_msg(msg) +
341 +
342 - def lstat(self, path): +
343 """ +344 Retrieve information about a file on the remote system, without +345 following symbolic links (shortcuts). This otherwise behaves exactly +346 the same as L{stat}. +347 +348 @param path: the filename to stat +349 @type path: str +350 @return: an object containing attributes about the given file +351 @rtype: SFTPAttributes +352 """ +353 path = self._adjust_cwd(path) +354 self._log(DEBUG, 'lstat(%r)' % path) -350 t, msg = self._request(DEBUG, 'lstat(%r)' % path) +355 t, msg = self._request(CMD_LSTAT, path) -351 if t != CMD_LSTAT, path) +356 if t != CMD_ATTRS: -352 raise SFTPError('Expected attributes') -353 return SFTPAttributes._from_msg(msg) -
354 -359 +370 -
371 - def chmod(self, path, mode): -
372 """ -373 Change the mode (permissions) of a file. The permissions are -374 unix-style and identical to those used by python's C{os.chmod} -375 function. -376 -377 @param path: path of the file to change the permissions of -378 @type path: str -379 @param mode: new permissions -380 @type mode: int -381 """ -382 path = self._adjust_cwd(path) -383 self._log(CMD_SYMLINK, source, dest) +
375 +
376 - def chmod(self, path, mode): +
377 """ +378 Change the mode (permissions) of a file. The permissions are +379 unix-style and identical to those used by python's C{os.chmod} +380 function. +381 +382 @param path: path of the file to change the permissions of +383 @type path: str +384 @param mode: new permissions +385 @type mode: int +386 """ +387 path = self._adjust_cwd(path) +388 self._log(DEBUG, 'chmod(%r, %r)' % (path, mode)) -384 attr = SFTPAttributes() -385 attr.st_mode = mode -386 self._request(DEBUG, 'chmod(%r, %r)' % (path, mode)) +389 attr = SFTPAttributes() +390 attr.st_mode = mode +391 self._request(CMD_SETSTAT, path, attr) -
387 -
388 - def chown(self, path, uid, gid): -
389 """ -390 Change the owner (C{uid}) and group (C{gid}) of a file. As with -391 python's C{os.chown} function, you must pass both arguments, so if you -392 only want to change one, use L{stat} first to retrieve the current -393 owner and group. -394 -395 @param path: path of the file to change the owner and group of -396 @type path: str -397 @param uid: new owner's uid -398 @type uid: int -399 @param gid: new group id -400 @type gid: int -401 """ -402 path = self._adjust_cwd(path) -403 self._log(CMD_SETSTAT, path, attr) +
392 +
393 - def chown(self, path, uid, gid): +
394 """ +395 Change the owner (C{uid}) and group (C{gid}) of a file. As with +396 python's C{os.chown} function, you must pass both arguments, so if you +397 only want to change one, use L{stat} first to retrieve the current +398 owner and group. +399 +400 @param path: path of the file to change the owner and group of +401 @type path: str +402 @param uid: new owner's uid +403 @type uid: int +404 @param gid: new group id +405 @type gid: int +406 """ +407 path = self._adjust_cwd(path) +408 self._log(DEBUG, 'chown(%r, %r, %r)' % (path, uid, gid)) -404 attr = SFTPAttributes() -405 attr.st_uid, attr.st_gid = uid, gid -406 self._request(DEBUG, 'chown(%r, %r, %r)' % (path, uid, gid)) +409 attr = SFTPAttributes() +410 attr.st_uid, attr.st_gid = uid, gid +411 self._request(CMD_SETSTAT, path, attr) -
407 -
408 - def utime(self, path, times): -
409 """ -410 Set the access and modified times of the file specified by C{path}. If -411 C{times} is C{None}, then the file's access and modified times are set -412 to the current time. Otherwise, C{times} must be a 2-tuple of numbers, -413 of the form C{(atime, mtime)}, which is used to set the access and -414 modified times, respectively. This bizarre API is mimicked from python -415 for the sake of consistency -- I apologize. -416 -417 @param path: path of the file to modify -418 @type path: str -419 @param times: C{None} or a tuple of (access time, modified time) in -420 standard internet epoch time (seconds since 01 January 1970 GMT) -421 @type times: tuple(int) -422 """ -423 path = self._adjust_cwd(path) -424 if times is None: -425 times = (time.time(), time.time()) -426 self._log(CMD_SETSTAT, path, attr) +
412 +
413 - def utime(self, path, times): +
414 """ +415 Set the access and modified times of the file specified by C{path}. If +416 C{times} is C{None}, then the file's access and modified times are set +417 to the current time. Otherwise, C{times} must be a 2-tuple of numbers, +418 of the form C{(atime, mtime)}, which is used to set the access and +419 modified times, respectively. This bizarre API is mimicked from python +420 for the sake of consistency -- I apologize. +421 +422 @param path: path of the file to modify +423 @type path: str +424 @param times: C{None} or a tuple of (access time, modified time) in +425 standard internet epoch time (seconds since 01 January 1970 GMT) +426 @type times: tuple(int) +427 """ +428 path = self._adjust_cwd(path) +429 if times is None: +430 times = (time.time(), time.time()) +431 self._log(DEBUG, 'utime(%r, %r)' % (path, times)) -427 attr = SFTPAttributes() -428 attr.st_atime, attr.st_mtime = times -429 self._request(DEBUG, 'utime(%r, %r)' % (path, times)) +432 attr = SFTPAttributes() +433 attr.st_atime, attr.st_mtime = times +434 self._request(CMD_SETSTAT, path, attr) -
430 -
431 - def truncate(self, path, size): -
432 """ -433 Change the size of the file specified by C{path}. This usually extends -434 or shrinks the size of the file, just like the C{truncate()} method on -435 python file objects. -436 -437 @param path: path of the file to modify -438 @type path: str -439 @param size: the new size of the file -440 @type size: int or long -441 """ -442 path = self._adjust_cwd(path) -443 self._log(CMD_SETSTAT, path, attr) +
435 +
436 - def truncate(self, path, size): +
437 """ +438 Change the size of the file specified by C{path}. This usually extends +439 or shrinks the size of the file, just like the C{truncate()} method on +440 python file objects. +441 +442 @param path: path of the file to modify +443 @type path: str +444 @param size: the new size of the file +445 @type size: int or long +446 """ +447 path = self._adjust_cwd(path) +448 self._log(DEBUG, 'truncate(%r, %r)' % (path, size)) -444 attr = SFTPAttributes() -445 attr.st_size = size -446 self._request(DEBUG, 'truncate(%r, %r)' % (path, size)) +449 attr = SFTPAttributes() +450 attr.st_size = size +451 self._request(CMD_SETSTAT, path, attr) -
447 -452 +470 -
471 - def normalize(self, path): -
472 """ -473 Return the normalized path (on the server) of a given path. This -474 can be used to quickly resolve symbolic links or determine what the -475 server is considering to be the "current folder" (by passing C{'.'} -476 as C{path}). -477 -478 @param path: path to be normalized -479 @type path: str -480 @return: normalized form of the given path -481 @rtype: str -482 -483 @raise IOError: if the path can't be resolved on the server -484 """ -485 path = self._adjust_cwd(path) -486 self._log(CMD_NAME: +468 raise SFTPError('Expected name response') +469 count = msg.get_int() +470 if count == 0: +471 return None +472 if count != 1: +473 raise SFTPError('Readlink returned %d results' % count) +474 return _to_unicode(msg.get_string()) +
475 +
476 - def normalize(self, path): +
477 """ +478 Return the normalized path (on the server) of a given path. This +479 can be used to quickly resolve symbolic links or determine what the +480 server is considering to be the "current folder" (by passing C{'.'} +481 as C{path}). +482 +483 @param path: path to be normalized +484 @type path: str +485 @return: normalized form of the given path +486 @rtype: str +487 +488 @raise IOError: if the path can't be resolved on the server +489 """ +490 path = self._adjust_cwd(path) +491 self._log(DEBUG, 'normalize(%r)' % path) -487 t, msg = self._request(DEBUG, 'normalize(%r)' % path) +492 t, msg = self._request(CMD_REALPATH, path) -488 if t != CMD_REALPATH, path) +493 if t != CMD_NAME: -489 raise SFTPError('Expected name response') -490 count = msg.get_int() -491 if count != 1: -492 raise SFTPError('Realpath returned %d results' % count) -493 return _to_unicode(msg.get_string()) -
494 -
495 - def chdir(self, path): -
496 """ -497 Change the "current directory" of this SFTP session. Since SFTP -498 doesn't really have the concept of a current working directory, this -499 is emulated by paramiko. Once you use this method to set a working -500 directory, all operations on this SFTPClient object will be relative -501 to that path. -502 -503 @param path: new current working directory -504 @type path: str -505 -506 @raise IOError: if the requested path doesn't exist on the server -507 -508 @since: 1.4 -509 """ -510 self._cwd = self.normalize(path) -
511 -
512 - def getcwd(self): -
513 """ -514 Return the "current working directory" for this SFTP session, as -515 emulated by paramiko. If no directory has been set with L{chdir}, -516 this method will return C{None}. -517 -518 @return: the current working directory on the server, or C{None} -519 @rtype: str -520 -521 @since: 1.4 -522 """ -523 return self._cwd -
524 -
525 - def put(self, localpath, remotepath, callback=None): -
526 """ -527 Copy a local file (C{localpath}) to the SFTP server as C{remotepath}. -528 Any exception raised by operations will be passed through. This -529 method is primarily provided as a convenience. -530 -531 The SFTP operations use pipelining for speed. -532 -533 @param localpath: the local file to copy -534 @type localpath: str -535 @param remotepath: the destination path on the SFTP server -536 @type remotepath: str -537 @param callback: optional callback function that accepts the bytes -538 transferred so far and the total bytes to be transferred -539 (since 1.7.4) -540 @type callback: function(int, int) -541 @return: an object containing attributes about the given file -542 (since 1.7.4) -543 @rtype: SFTPAttributes -544 -545 @since: 1.4 -546 """ -547 file_size = os.CMD_NAME: +494 raise SFTPError('Expected name response') +495 count = msg.get_int() +496 if count != 1: +497 raise SFTPError('Realpath returned %d results' % count) +498 return _to_unicode(msg.get_string()) +
499 +
500 - def chdir(self, path): +
501 """ +502 Change the "current directory" of this SFTP session. Since SFTP +503 doesn't really have the concept of a current working directory, this +504 is emulated by paramiko. Once you use this method to set a working +505 directory, all operations on this SFTPClient object will be relative +506 to that path. You can pass in C{None} to stop using a current working +507 directory. +508 +509 @param path: new current working directory +510 @type path: str +511 +512 @raise IOError: if the requested path doesn't exist on the server +513 +514 @since: 1.4 +515 """ +516 if path is None: +517 self._cwd = None +518 return +519 if not stat(localpath).st_size -548 fl = file(localpath, 'rb') -549 fr = self.file(remotepath, 'wb') -550 fr.set_pipelined(True) -551 size = 0 -552 while True: -553 data = fl.stat.S_ISDIR(self.stat(path).st_mode): +520 raise SFTPError(errno.ENOTDIR, "%s: %s" % (os.strerror(errno.ENOTDIR), path)) +521 self._cwd = self.normalize(path).encode('utf-8') +
522 +
523 - def getcwd(self): +
524 """ +525 Return the "current working directory" for this SFTP session, as +526 emulated by paramiko. If no directory has been set with L{chdir}, +527 this method will return C{None}. +528 +529 @return: the current working directory on the server, or C{None} +530 @rtype: str +531 +532 @since: 1.4 +533 """ +534 return self._cwd +
535 +
536 - def put(self, localpath, remotepath, callback=None): +
537 """ +538 Copy a local file (C{localpath}) to the SFTP server as C{remotepath}. +539 Any exception raised by operations will be passed through. This +540 method is primarily provided as a convenience. +541 +542 The SFTP operations use pipelining for speed. +543 +544 @param localpath: the local file to copy +545 @type localpath: str +546 @param remotepath: the destination path on the SFTP server +547 @type remotepath: str +548 @param callback: optional callback function that accepts the bytes +549 transferred so far and the total bytes to be transferred +550 (since 1.7.4) +551 @type callback: function(int, int) +552 @return: an object containing attributes about the given file +553 (since 1.7.4) +554 @rtype: SFTPAttributes +555 +556 @since: 1.4 +557 """ +558 file_size = os.stat(localpath).st_size +559 fl = file(localpath, 'rb') +560 try: +561 fr = self.file(remotepath, 'wb') +562 fr.set_pipelined(True) +563 size = 0 +564 try: +565 while True: +566 data = fl.read(32768) -554 if len(data) == 0: -555 break -556 fr.write(data) -557 size += len(data) -558 if callback is not None: -559 callback(size, file_size) -560 fl.read(32768) +567 if len(data) == 0: +568 break +569 fr.write(data) +570 size += len(data) +571 if callback is not None: +572 callback(size, file_size) +573 finally: +574 fr.close() -561 fr.close() +575 finally: +576 fl.close() -562 s = self.close() +577 s = self.stat(remotepath) -563 if s.st_size != size: -564 raise IOError('size mismatch in put! %d != %d' % (s.st_size, size)) -565 return s -
566 -
567 - def get(self, remotepath, localpath, callback=None): -
568 """ -569 Copy a remote file (C{remotepath}) from the SFTP server to the local -570 host as C{localpath}. Any exception raised by operations will be -571 passed through. This method is primarily provided as a convenience. -572 -573 @param remotepath: the remote file to copy -574 @type remotepath: str -575 @param localpath: the destination path on the local host -576 @type localpath: str -577 @param callback: optional callback function that accepts the bytes -578 transferred so far and the total bytes to be transferred -579 (since 1.7.4) -580 @type callback: function(int, int) -581 -582 @since: 1.4 -583 """ -584 fr = self.file(remotepath, 'rb') -585 file_size = self.stat(remotepath) +578 if s.st_size != size: +579 raise IOError('size mismatch in put! %d != %d' % (s.st_size, size)) +580 return s +
581 +
582 - def get(self, remotepath, localpath, callback=None): +
583 """ +584 Copy a remote file (C{remotepath}) from the SFTP server to the local +585 host as C{localpath}. Any exception raised by operations will be +586 passed through. This method is primarily provided as a convenience. +587 +588 @param remotepath: the remote file to copy +589 @type remotepath: str +590 @param localpath: the destination path on the local host +591 @type localpath: str +592 @param callback: optional callback function that accepts the bytes +593 transferred so far and the total bytes to be transferred +594 (since 1.7.4) +595 @type callback: function(int, int) +596 +597 @since: 1.4 +598 """ +599 fr = self.file(remotepath, 'rb') +600 file_size = self.stat(remotepath).st_size -586 fr.prefetch() -587 fl = file(localpath, 'wb') -588 size = 0 -589 while True: -590 data = fr.stat(remotepath).st_size +601 fr.prefetch() +602 try: +603 fl = file(localpath, 'wb') +604 try: +605 size = 0 +606 while True: +607 data = fr.read(32768) -591 if len(data) == 0: -592 break -593 fl.write(data) -594 size += len(data) -595 if callback is not None: -596 callback(size, file_size) -597 fl.read(32768) +608 if len(data) == 0: +609 break +610 fl.write(data) +611 size += len(data) +612 if callback is not None: +613 callback(size, file_size) +614 finally: +615 fl.close() -598 fr.close() +616 finally: +617 fr.close() -599 s = os.close() +618 s = os.stat(localpath) -600 if s.st_size != size: -601 raise IOError('size mismatch in get! %d != %d' % (s.st_size, size)) -
602 -603 -604 ### internals... -605 -606 -
607 - def _request(self, t, *arg): -
608 num = self._async_request(type(None), t, *arg) -609 return self._read_response(num) -
610 -
611 - def _async_request(self, fileobj, t, *arg): -
612 # this method may be called from other threads (prefetch) -613 self._lock.acquire() -614 try: -615 msg = Message() -616 msg.add_int(self.request_number) -617 for item in arg: -618 if type(item) is int: -619 msg.add_int(item) -620 elif type(item) is long: -621 msg.add_int64(item) -622 elif type(item) is str: -623 msg.add_string(item) -624 elif type(item) is SFTPAttributes: -625 item._pack(msg) -626 else: -627 raise Exception('unknown type for %r type %r' % (item, type(item))) -628 num = self.request_number -629 self._expecting[num] = fileobj -630 self._send_packet(t, str(msg)) -631 self.request_number += 1 -632 finally: -633 self._lock.release() -634 return num -
635 -
636 - def _read_response(self, waitfor=None): -
637 while True: -638 try: -639 t, data = self._read_packet() -640 except EOFError, e: -641 raise SSHException('Server connection dropped: %s' % (str(e),)) -642 msg = Message(data) -643 num = msg.get_int() -644 if num not in self._expecting: -645 # might be response for a file that was closed before responses came back -646 self._log(stat(localpath) +619 if s.st_size != size: +620 raise IOError('size mismatch in get! %d != %d' % (s.st_size, size)) +
621 +622 +623 ### internals... +624 +625 +
626 - def _request(self, t, *arg): +
627 num = self._async_request(type(None), t, *arg) +628 return self._read_response(num) +
629 +
630 - def _async_request(self, fileobj, t, *arg): +
631 # this method may be called from other threads (prefetch) +632 self._lock.acquire() +633 try: +634 msg = Message() +635 msg.add_int(self.request_number) +636 for item in arg: +637 if type(item) is int: +638 msg.add_int(item) +639 elif type(item) is long: +640 msg.add_int64(item) +641 elif type(item) is str: +642 msg.add_string(item) +643 elif type(item) is SFTPAttributes: +644 item._pack(msg) +645 else: +646 raise Exception('unknown type for %r type %r' % (item, type(item))) +647 num = self.request_number +648 self._expecting[num] = fileobj +649 self._send_packet(t, str(msg)) +650 self.request_number += 1 +651 finally: +652 self._lock.release() +653 return num +
654 +
655 - def _read_response(self, waitfor=None): +
656 while True: +657 try: +658 t, data = self._read_packet() +659 except EOFError, e: +660 raise SSHException('Server connection dropped: %s' % (str(e),)) +661 msg = Message(data) +662 num = msg.get_int() +663 if num not in self._expecting: +664 # might be response for a file that was closed before responses came back +665 self._log(DEBUG, 'Unexpected response #%d' % (num,)) -647 if waitfor is None: -648 # just doing a single check -649 break -650 continue -651 fileobj = self._expecting[num] -652 del self._expecting[num] -653 if num == waitfor: -654 # synchronous -655 if t == DEBUG, 'Unexpected response #%d' % (num,)) +666 if waitfor is None: +667 # just doing a single check +668 break +669 continue +670 fileobj = self._expecting[num] +671 del self._expecting[num] +672 if num == waitfor: +673 # synchronous +674 if t == CMD_STATUS: -656 self._convert_status(msg) -657 return t, msg -658 if fileobj is not type(None): -659 fileobj._async_response(t, msg) -660 if waitfor is None: -661 # just doing a single check -662 break -663 return (None, None) -
664 -
665 - def _finish_responses(self, fileobj): -
666 while fileobj in self._expecting.values(): -667 self._read_response() -668 fileobj._check_exception() -
669 -
670 - def _convert_status(self, msg): -
671 """ -672 Raises EOFError or IOError on error status; otherwise does nothing. -673 """ -674 code = msg.get_int() -675 text = msg.get_string() -676 if code == CMD_STATUS: +675 self._convert_status(msg) +676 return t, msg +677 if fileobj is not type(None): +678 fileobj._async_response(t, msg) +679 if waitfor is None: +680 # just doing a single check +681 break +682 return (None, None) +
683 +
684 - def _finish_responses(self, fileobj): +
685 while fileobj in self._expecting.values(): +686 self._read_response() +687 fileobj._check_exception() +
688 +
689 - def _convert_status(self, msg): +
690 """ +691 Raises EOFError or IOError on error status; otherwise does nothing. +692 """ +693 code = msg.get_int() +694 text = msg.get_string() +695 if code == SFTP_OK: -677 return -678 elif code == SFTP_OK: +696 return +697 elif code == SFTP_EOF: -679 raise EOFError(text) -680 elif code == SFTP_EOF: +698 raise EOFError(text) +699 elif code == SFTP_NO_SUCH_FILE: -681 # clever idea from john a. meinel: map the error codes to errno -682 raise IOError(errno.ENOENT, text) -683 elif code == SFTP_NO_SUCH_FILE: +700 # clever idea from john a. meinel: map the error codes to errno +701 raise IOError(errno.ENOENT, text) +702 elif code == SFTP_PERMISSION_DENIED: -684 raise IOError(errno.EACCES, text) -685 else: -686 raise IOError(text) -
687 -
688 - def _adjust_cwd(self, path): -
689 """ -690 Return an adjusted path if we're emulating a "current working -691 directory" for the server. -692 """ -693 if type(path) is unicode: -694 path = path.encode('utf-8') -695 if self._cwd is None: -696 return path -697 if (len(path) > 0) and (path[0] == '/'): -698 # absolute path -699 return path -700 if self._cwd == '/': -701 return self._cwd + path -702 return self._cwd + '/' + path -
703 -704 -
705 -class SFTP (SFTPClient): -
706 "an alias for L{SFTPClient} for backwards compatability" -707 pass -
708