Package paramiko :: Module sftp_client
[frames] | no frames]

Source Code for Module paramiko.sftp_client

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