Wow there's a lot of SFTP crap.

This commit is contained in:
Jeff Forcier 2014-02-21 19:15:36 -08:00
parent 6d9b28c56c
commit 9ae62eb47a
7 changed files with 87 additions and 73 deletions

View File

@ -28,12 +28,13 @@ class SFTPAttributes (object):
client or server mode. It attemps to mirror the object returned by client or server mode. It attemps to mirror the object returned by
`os.stat` as closely as possible, so it may have the following fields, `os.stat` as closely as possible, so it may have the following fields,
with the same meanings as those returned by an `os.stat` object: with the same meanings as those returned by an `os.stat` object:
- st_size
- st_uid - ``st_size``
- st_gid - ``st_uid``
- st_mode - ``st_gid``
- st_atime - ``st_mode``
- st_mtime - ``st_atime``
- ``st_mtime``
Because SFTP allows flags to have other arbitrary named attributes, these Because SFTP allows flags to have other arbitrary named attributes, these
are stored in a dict named ``attr``. Occasionally, the filename is also are stored in a dict named ``attr``. Occasionally, the filename is also
@ -61,10 +62,10 @@ class SFTPAttributes (object):
def from_stat(cls, obj, filename=None): def from_stat(cls, obj, filename=None):
""" """
Create an SFTPAttributes object from an existing ``stat`` object (an Create an `.SFTPAttributes` object from an existing ``stat`` object (an
object returned by ``os.stat``). object returned by `os.stat`).
:param obj: an object returned by ``os.stat`` (or equivalent). :param obj: an object returned by `os.stat` (or equivalent).
:type obj: object :type obj: object
:param filename: the filename associated with this file. :param filename: the filename associated with this file.
:type filename: str :type filename: str

View File

@ -1,6 +1,6 @@
# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com> # Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
# #
# This file is part of paramiko. # This file is part of Paramiko.
# #
# Paramiko is free software; you can redistribute it and/or modify it under the # Paramiko is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free # terms of the GNU Lesser General Public License as published by the Free
@ -194,16 +194,17 @@ class SFTPClient(BaseSFTP):
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 Open a file on the remote server. The arguments are the same as for
Python's built-in ``file`` (aka ``open``). A file-like object is Python's built-in `python:file` (aka `python:open`). A file-like
returned, which closely mimics the behavior of a normal Python file object is returned, which closely mimics the behavior of a normal
object, including the ability to be used as a context manager. Python file object, including the ability to be used as a context
manager.
The mode indicates how the file is to be opened: ``'r'`` for reading, The mode indicates how the file is to be opened: ``'r'`` for reading,
``'w'`` for writing (truncating an existing file), ``'a'`` for appending, ``'w'`` for writing (truncating an existing file), ``'a'`` for
``'r+'`` for reading/writing, ``'w+'`` for reading/writing (truncating an appending, ``'r+'`` for reading/writing, ``'w+'`` for reading/writing
existing file), ``'a+'`` for reading/appending. The Python ``'b'`` flag (truncating an existing file), ``'a+'`` for reading/appending. The
is ignored, since SSH treats all files as binary. The ``'U'`` flag is Python ``'b'`` flag is ignored, since SSH treats all files as binary.
supported in a compatible way. The ``'U'`` flag is supported in a compatible way.
Since 1.5.2, an ``'x'`` flag indicates that the operation should only Since 1.5.2, an ``'x'`` flag indicates that the operation should only
succeed if the file was created and did not previously exist. This has succeed if the file was created and did not previously exist. This has
@ -222,7 +223,7 @@ class SFTPClient(BaseSFTP):
:param bufsize: desired buffering (-1 = default buffer size) :param bufsize: desired buffering (-1 = default buffer size)
:type bufsize: int :type bufsize: int
:return: a file object representing the open file :return: a file object representing the open file
:rtype: SFTPFile :rtype: `.SFTPFile`
:raises IOError: if the file could not be opened. :raises IOError: if the file could not be opened.
""" """
@ -319,16 +320,16 @@ class SFTPClient(BaseSFTP):
contains fewer fields. An SFTP server may return as much or as little contains fewer fields. An SFTP server may return as much or as little
info as it wants, so the results may vary from server to server. info as it wants, so the results may vary from server to server.
Unlike a Python ``stat`` object, the result may not be accessed as a Unlike a Python `python:stat` object, the result may not be accessed as
tuple. This is mostly due to the author's slack factor. a tuple. This is mostly due to the author's slack factor.
The fields supported are: ``st_mode``, ``st_size``, ``st_uid``, ``st_gid``, The fields supported are: ``st_mode``, ``st_size``, ``st_uid``,
``st_atime``, and ``st_mtime``. ``st_gid``, ``st_atime``, and ``st_mtime``.
:param path: the filename to stat :param path: the filename to stat
:type path: str :type path: str
:return: an object containing attributes about the given file :return: an object containing attributes about the given file
:rtype: SFTPAttributes :rtype: `.SFTPAttributes`
""" """
path = self._adjust_cwd(path) path = self._adjust_cwd(path)
self._log(DEBUG, 'stat(%r)' % path) self._log(DEBUG, 'stat(%r)' % path)
@ -346,7 +347,7 @@ class SFTPClient(BaseSFTP):
:param path: the filename to stat :param path: the filename to stat
:type path: str :type path: str
:return: an object containing attributes about the given file :return: an object containing attributes about the given file
:rtype: SFTPAttributes :rtype: `.SFTPAttributes`
""" """
path = self._adjust_cwd(path) path = self._adjust_cwd(path)
self._log(DEBUG, 'lstat(%r)' % path) self._log(DEBUG, 'lstat(%r)' % path)
@ -374,7 +375,7 @@ class SFTPClient(BaseSFTP):
def chmod(self, path, mode): def chmod(self, path, mode):
""" """
Change the mode (permissions) of a file. The permissions are Change the mode (permissions) of a file. The permissions are
unix-style and identical to those used by Python's ``os.chmod`` unix-style and identical to those used by Python's `os.chmod`
function. function.
:param path: path of the file to change the permissions of :param path: path of the file to change the permissions of
@ -391,7 +392,7 @@ class SFTPClient(BaseSFTP):
def chown(self, path, uid, gid): def chown(self, path, uid, gid):
""" """
Change the owner (``uid``) and group (``gid``) of a file. As with Change the owner (``uid``) and group (``gid``) of a file. As with
Python's ``os.chown`` function, you must pass both arguments, so if you Python's `os.chown` function, you must pass both arguments, so if you
only want to change one, use `stat` first to retrieve the current only want to change one, use `stat` first to retrieve the current
owner and group. owner and group.
@ -433,9 +434,9 @@ class SFTPClient(BaseSFTP):
def truncate(self, path, size): def truncate(self, path, size):
""" """
Change the size of the file specified by ``path``. This usually extends Change the size of the file specified by ``path``. This usually
or shrinks the size of the file, just like the ``truncate()`` method on extends or shrinks the size of the file, just like the `~file.truncate`
Python file objects. method on Python file objects.
:param path: path of the file to modify :param path: path of the file to modify
:type path: str :type path: str
@ -498,9 +499,9 @@ class SFTPClient(BaseSFTP):
def chdir(self, path): def chdir(self, path):
""" """
Change the "current directory" of this SFTP session. Since SFTP Change the "current directory" of this SFTP session. Since SFTP
doesn't really have the concept of a current working directory, this doesn't really have the concept of a current working directory, this is
is emulated by paramiko. Once you use this method to set a working emulated by Paramiko. Once you use this method to set a working
directory, all operations on this SFTPClient object will be relative directory, all operations on this `.SFTPClient` object will be relative
to that path. You can pass in ``None`` to stop using a current working to that path. You can pass in ``None`` to stop using a current working
directory. directory.
@ -521,7 +522,7 @@ class SFTPClient(BaseSFTP):
def getcwd(self): def getcwd(self):
""" """
Return the "current working directory" for this SFTP session, as Return the "current working directory" for this SFTP session, as
emulated by paramiko. If no directory has been set with `chdir`, emulated by Paramiko. If no directory has been set with `chdir`,
this method will return ``None``. this method will return ``None``.
:return: the current working directory on the server, or ``None`` :return: the current working directory on the server, or ``None``
@ -534,7 +535,8 @@ class SFTPClient(BaseSFTP):
def putfo(self, fl, remotepath, file_size=0, callback=None, confirm=True): def putfo(self, fl, remotepath, file_size=0, callback=None, confirm=True):
""" """
Copy the contents of an open file object (``fl``) to the SFTP server as Copy the contents of an open file object (``fl``) to the SFTP server as
``remotepath``. Any exception raised by operations will be passed through. ``remotepath``. Any exception raised by operations will be passed
through.
The SFTP operations use pipelining for speed. The SFTP operations use pipelining for speed.
@ -555,7 +557,7 @@ class SFTPClient(BaseSFTP):
:return: an object containing attributes about the given file :return: an object containing attributes about the given file
(since 1.7.4) (since 1.7.4)
:rtype: SFTPAttributes :rtype: `.SFTPAttributes`
.. versionadded:: 1.4 .. versionadded:: 1.4
""" """
@ -603,7 +605,7 @@ class SFTPClient(BaseSFTP):
:return: an object containing attributes about the given file :return: an object containing attributes about the given file
(since 1.7.4) (since 1.7.4)
:rtype: SFTPAttributes :rtype: `.SFTPAttributes`
.. versionadded:: 1.4 .. versionadded:: 1.4
""" """

View File

@ -17,7 +17,7 @@
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
""" """
`.SFTPFile` SFTP file object
""" """
from __future__ import with_statement from __future__ import with_statement
@ -64,6 +64,9 @@ class SFTPFile (BufferedFile):
self._close(async=True) self._close(async=True)
def close(self): def close(self):
"""
Close the file.
"""
self._close(async=False) self._close(async=False)
def _close(self, async=False): def _close(self, async=False):
@ -183,10 +186,11 @@ class SFTPFile (BufferedFile):
Set a timeout on read/write operations on the underlying socket or Set a timeout on read/write operations on the underlying socket or
ssh `.Channel`. ssh `.Channel`.
.. seealso:: `Channel.settimeout`
:param timeout: seconds to wait for a pending read/write operation :param timeout: seconds to wait for a pending read/write operation
before raising ``socket.timeout``, or ``None`` for no timeout before raising ``socket.timeout``, or ``None`` for no timeout
:type timeout: float :type timeout: float
.. seealso:: `.Channel.settimeout`
""" """
self.sftp.sock.settimeout(timeout) self.sftp.sock.settimeout(timeout)
@ -195,8 +199,9 @@ class SFTPFile (BufferedFile):
Returns the timeout in seconds (as a float) associated with the socket Returns the timeout in seconds (as a float) associated with the socket
or ssh `.Channel` used for this file. or ssh `.Channel` used for this file.
.. seealso:: `Channel.gettimeout`
:rtype: float :rtype: float
.. seealso:: `.Channel.gettimeout`
""" """
return self.sftp.sock.gettimeout() return self.sftp.sock.gettimeout()
@ -205,10 +210,11 @@ class SFTPFile (BufferedFile):
Set blocking or non-blocking mode on the underiying socket or ssh Set blocking or non-blocking mode on the underiying socket or ssh
`.Channel`. `.Channel`.
.. seealso:: `Channel.setblocking` :param blocking:
:param blocking: 0 to set non-blocking mode; non-0 to set blocking 0 to set non-blocking mode; non-0 to set blocking mode.
mode.
:type blocking: int :type blocking: int
.. seealso:: `.Channel.setblocking`
""" """
self.sftp.sock.setblocking(blocking) self.sftp.sock.setblocking(blocking)
@ -226,11 +232,11 @@ class SFTPFile (BufferedFile):
def stat(self): def stat(self):
""" """
Retrieve information about this file from the remote system. This is Retrieve information about this file from the remote system. This is
exactly like `SFTP.stat`, except that it operates on an already-open exactly like `.SFTPClient.stat`, except that it operates on an
file. already-open file.
:return: an object containing attributes about this file. :return: an object containing attributes about this file.
:rtype: SFTPAttributes :rtype: `.SFTPAttributes`
""" """
t, msg = self.sftp._request(CMD_FSTAT, self.handle) t, msg = self.sftp._request(CMD_FSTAT, self.handle)
if t != CMD_ATTRS: if t != CMD_ATTRS:
@ -240,7 +246,7 @@ class SFTPFile (BufferedFile):
def chmod(self, mode): def chmod(self, mode):
""" """
Change the mode (permissions) of this file. The permissions are Change the mode (permissions) of this file. The permissions are
unix-style and identical to those used by Python's ``os.chmod`` unix-style and identical to those used by Python's `os.chmod`
function. function.
:param mode: new permissions :param mode: new permissions
@ -254,7 +260,7 @@ class SFTPFile (BufferedFile):
def chown(self, uid, gid): def chown(self, uid, gid):
""" """
Change the owner (``uid``) and group (``gid``) of this file. As with Change the owner (``uid``) and group (``gid``) of this file. As with
Python's ``os.chown`` function, you must pass both arguments, so if you Python's `os.chown` function, you must pass both arguments, so if you
only want to change one, use `stat` first to retrieve the current only want to change one, use `stat` first to retrieve the current
owner and group. owner and group.
@ -341,12 +347,12 @@ class SFTPFile (BufferedFile):
concatenated together concatenated together
:rtype: str :rtype: str
.. note:: Many (most?) servers don't support this extension yet.
:raises IOError: if the server doesn't support the "check-file" :raises IOError: if the server doesn't support the "check-file"
extension, or possibly doesn't support the hash algorithm extension, or possibly doesn't support the hash algorithm
requested requested
.. note:: Many (most?) servers don't support this extension yet.
.. versionadded:: 1.4 .. versionadded:: 1.4
""" """
t, msg = self.sftp._request(CMD_EXTENDED, 'check-file', self.handle, t, msg = self.sftp._request(CMD_EXTENDED, 'check-file', self.handle,
@ -360,11 +366,11 @@ class SFTPFile (BufferedFile):
""" """
Turn on/off the pipelining of write operations to this file. When Turn on/off the pipelining of write operations to this file. When
pipelining is on, paramiko won't wait for the server response after pipelining is on, paramiko won't wait for the server response after
each write operation. Instead, they're collected as they come in. each write operation. Instead, they're collected as they come in. At
At the first non-write operation (including `close`), all remaining the first non-write operation (including `.close`), all remaining
server responses are collected. This means that if there was an error server responses are collected. This means that if there was an error
with one of your later writes, an exception might be thrown from with one of your later writes, an exception might be thrown from within
within `close` instead of `write`. `.close` instead of `.write`.
By default, files are not pipelined. By default, files are not pipelined.
@ -378,14 +384,14 @@ class SFTPFile (BufferedFile):
def prefetch(self): def prefetch(self):
""" """
Pre-fetch the remaining contents of this file in anticipation of Pre-fetch the remaining contents of this file in anticipation of future
future `read` calls. If reading the entire file, pre-fetching can `.read` calls. If reading the entire file, pre-fetching can
dramatically improve the download speed by avoiding roundtrip latency. dramatically improve the download speed by avoiding roundtrip latency.
The file's contents are incrementally buffered in a background thread. The file's contents are incrementally buffered in a background thread.
The prefetched data is stored in a buffer until read via the `read` The prefetched data is stored in a buffer until read via the `.read`
method. Once data has been read, it's removed from the buffer. The method. Once data has been read, it's removed from the buffer. The
data may be read in a random order (using `seek`); chunks of the data may be read in a random order (using `.seek`); chunks of the
buffer that haven't been read will continue to be buffered. buffer that haven't been read will continue to be buffered.
.. versionadded:: 1.5.1 .. versionadded:: 1.5.1
@ -404,7 +410,7 @@ class SFTPFile (BufferedFile):
def readv(self, chunks): def readv(self, chunks):
""" """
Read a set of blocks from the file by (offset, length). This is more Read a set of blocks from the file by (offset, length). This is more
efficient than doing a series of `seek` and `read` calls, since the efficient than doing a series of `.seek` and `.read` calls, since the
prefetch machinery is used to retrieve all the requested blocks at prefetch machinery is used to retrieve all the requested blocks at
once. once.

View File

@ -41,7 +41,7 @@ class SFTPHandle (object):
SFTP. If ``flags`` is passed in, it's used to determine if the file SFTP. If ``flags`` is passed in, it's used to determine if the file
is open in append mode. is open in append mode.
:param flags: optional flags as passed to `SFTPServerInterface.open` :param flags: optional flags as passed to `.SFTPServerInterface.open`
:type flags: int :type flags: int
""" """
self.__flags = flags self.__flags = flags
@ -149,7 +149,7 @@ class SFTPHandle (object):
def stat(self): def stat(self):
""" """
Return an `.SFTPAttributes` object referring to this open file, or an Return an `.SFTPAttributes` object referring to this open file, or an
error code. This is equivalent to `SFTPServerInterface.stat`, except error code. This is equivalent to `.SFTPServerInterface.stat`, except
it's called on an open file instead of a path. it's called on an open file instead of a path.
:return: an attributes object for the given file, or an SFTP error :return: an attributes object for the given file, or an SFTP error

View File

@ -42,7 +42,7 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
""" """
Server-side SFTP subsystem support. Since this is a `.SubsystemHandler`, Server-side SFTP subsystem support. Since this is a `.SubsystemHandler`,
it can be (and is meant to be) set as the handler for ``"sftp"`` requests. it can be (and is meant to be) set as the handler for ``"sftp"`` requests.
Use `Transport.set_subsystem_handler` to activate this class. Use `.Transport.set_subsystem_handler` to activate this class.
""" """
def __init__(self, channel, name, server, sftp_si=SFTPServerInterface, *largs, **kwargs): def __init__(self, channel, name, server, sftp_si=SFTPServerInterface, *largs, **kwargs):
@ -50,7 +50,7 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
The constructor for SFTPServer is meant to be called from within the The constructor for SFTPServer is meant to be called from within the
`.Transport` as a subsystem handler. ``server`` and any additional `.Transport` as a subsystem handler. ``server`` and any additional
parameters or keyword parameters are passed from the original call to parameters or keyword parameters are passed from the original call to
`Transport.set_subsystem_handler`. `.Transport.set_subsystem_handler`.
:param channel: channel passed from the `.Transport`. :param channel: channel passed from the `.Transport`.
:type channel: `.Channel` :type channel: `.Channel`
@ -128,7 +128,7 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
:param e: an errno code, as from ``OSError.errno``. :param e: an errno code, as from ``OSError.errno``.
:type e: int :type e: int
:return: an SFTP error code like `.SFTP_NO_SUCH_FILE`. :return: an SFTP error code like ``SFTP_NO_SUCH_FILE``.
:rtype: int :rtype: int
""" """
if e == errno.EACCES: if e == errno.EACCES:

View File

@ -17,7 +17,7 @@
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
""" """
`.SFTPServerInterface` is an interface to override for SFTP server support. An interface to override for SFTP server support.
""" """
import os import os
@ -64,7 +64,7 @@ class SFTPServerInterface (object):
""" """
The SFTP server session has just ended, either cleanly or via an The SFTP server session has just ended, either cleanly or via an
exception. This method is meant to be overridden to perform any exception. This method is meant to be overridden to perform any
necessary cleanup before this ``SFTPServerInterface`` object is necessary cleanup before this `.SFTPServerInterface` object is
destroyed. destroyed.
""" """
pass pass
@ -105,7 +105,7 @@ class SFTPServerInterface (object):
:param attr: requested attributes of the file if it is newly created. :param attr: requested attributes of the file if it is newly created.
:type attr: `.SFTPAttributes` :type attr: `.SFTPAttributes`
:return: a new `.SFTPHandle` or error code. :return: a new `.SFTPHandle` or error code.
:rtype `.SFTPHandle` :rtype: `.SFTPHandle`
""" """
return SFTP_OP_UNSUPPORTED return SFTP_OP_UNSUPPORTED
@ -120,7 +120,7 @@ class SFTPServerInterface (object):
``os.stat``. In addition, each object should have its ``filename`` ``os.stat``. In addition, each object should have its ``filename``
field filled in, since this is important to a directory listing and field filled in, since this is important to a directory listing and
not normally present in ``os.stat`` results. The method not normally present in ``os.stat`` results. The method
`SFTPAttributes.from_stat` will usually do what you want. `.SFTPAttributes.from_stat` will usually do what you want.
In case of an error, you should return one of the ``SFTP_*`` error In case of an error, you should return one of the ``SFTP_*`` error
codes, such as `.SFTP_PERMISSION_DENIED`. codes, such as `.SFTP_PERMISSION_DENIED`.
@ -131,11 +131,13 @@ class SFTPServerInterface (object):
`.SFTPAttributes` objects. `.SFTPAttributes` objects.
:rtype: list of `.SFTPAttributes` or error code :rtype: list of `.SFTPAttributes` or error code
.. note:: You should normalize the given ``path`` first (see the .. note::
``os.path`` module) and check appropriate permissions before returning You should normalize the given ``path`` first (see the `os.path`
the list of files. Be careful of malicious clients attempting to use module) and check appropriate permissions before returning the list
relative paths to escape restricted folders, if you're doing a direct of files. Be careful of malicious clients attempting to use
translation from the SFTP server path to your local filesystem. relative paths to escape restricted folders, if you're doing a
direct translation from the SFTP server path to your local
filesystem.
""" """
return SFTP_OP_UNSUPPORTED return SFTP_OP_UNSUPPORTED

View File

@ -6,5 +6,8 @@ SFTP
.. automodule:: paramiko.sftp_server .. automodule:: paramiko.sftp_server
.. automodule:: paramiko.sftp_attr .. automodule:: paramiko.sftp_attr
.. automodule:: paramiko.sftp_file .. automodule:: paramiko.sftp_file
:inherited-members:
:no-special-members:
:show-inheritance:
.. automodule:: paramiko.sftp_handle .. automodule:: paramiko.sftp_handle
.. automodule:: paramiko.sftp_si .. automodule:: paramiko.sftp_si