sftp_handle.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. """
  19. Abstraction of an SFTP file handle (for server mode).
  20. """
  21. import os
  22. from paramiko.sftp import SFTP_OP_UNSUPPORTED, SFTP_OK
  23. from paramiko.util import ClosingContextManager
  24. class SFTPHandle(ClosingContextManager):
  25. """
  26. Abstract object representing a handle to an open file (or folder) in an
  27. SFTP server implementation. Each handle has a string representation used
  28. by the client to refer to the underlying file.
  29. Server implementations can (and should) subclass SFTPHandle to implement
  30. features of a file handle, like `stat` or `chattr`.
  31. Instances of this class may be used as context managers.
  32. """
  33. def __init__(self, flags=0):
  34. """
  35. Create a new file handle representing a local file being served over
  36. SFTP. If ``flags`` is passed in, it's used to determine if the file
  37. is open in append mode.
  38. :param int flags: optional flags as passed to
  39. `.SFTPServerInterface.open`
  40. """
  41. self.__flags = flags
  42. self.__name = None
  43. # only for handles to folders:
  44. self.__files = {}
  45. self.__tell = None
  46. def close(self):
  47. """
  48. When a client closes a file, this method is called on the handle.
  49. Normally you would use this method to close the underlying OS level
  50. file object(s).
  51. The default implementation checks for attributes on ``self`` named
  52. ``readfile`` and/or ``writefile``, and if either or both are present,
  53. their ``close()`` methods are called. This means that if you are
  54. using the default implementations of `read` and `write`, this
  55. method's default implementation should be fine also.
  56. """
  57. readfile = getattr(self, "readfile", None)
  58. if readfile is not None:
  59. readfile.close()
  60. writefile = getattr(self, "writefile", None)
  61. if writefile is not None:
  62. writefile.close()
  63. def read(self, offset, length):
  64. """
  65. Read up to ``length`` bytes from this file, starting at position
  66. ``offset``. The offset may be a Python long, since SFTP allows it
  67. to be 64 bits.
  68. If the end of the file has been reached, this method may return an
  69. empty string to signify EOF, or it may also return ``SFTP_EOF``.
  70. The default implementation checks for an attribute on ``self`` named
  71. ``readfile``, and if present, performs the read operation on the Python
  72. file-like object found there. (This is meant as a time saver for the
  73. common case where you are wrapping a Python file object.)
  74. :param offset: position in the file to start reading from.
  75. :param int length: number of bytes to attempt to read.
  76. :return: data read from the file, or an SFTP error code, as a `str`.
  77. """
  78. readfile = getattr(self, "readfile", None)
  79. if readfile is None:
  80. return SFTP_OP_UNSUPPORTED
  81. try:
  82. if self.__tell is None:
  83. self.__tell = readfile.tell()
  84. if offset != self.__tell:
  85. readfile.seek(offset)
  86. self.__tell = offset
  87. data = readfile.read(length)
  88. except IOError as e:
  89. self.__tell = None
  90. return SFTPServer.convert_errno(e.errno)
  91. self.__tell += len(data)
  92. return data
  93. def write(self, offset, data):
  94. """
  95. Write ``data`` into this file at position ``offset``. Extending the
  96. file past its original end is expected. Unlike Python's normal
  97. ``write()`` methods, this method cannot do a partial write: it must
  98. write all of ``data`` or else return an error.
  99. The default implementation checks for an attribute on ``self`` named
  100. ``writefile``, and if present, performs the write operation on the
  101. Python file-like object found there. The attribute is named
  102. differently from ``readfile`` to make it easy to implement read-only
  103. (or write-only) files, but if both attributes are present, they should
  104. refer to the same file.
  105. :param offset: position in the file to start reading from.
  106. :param str data: data to write into the file.
  107. :return: an SFTP error code like ``SFTP_OK``.
  108. """
  109. writefile = getattr(self, "writefile", None)
  110. if writefile is None:
  111. return SFTP_OP_UNSUPPORTED
  112. try:
  113. # in append mode, don't care about seeking
  114. if (self.__flags & os.O_APPEND) == 0:
  115. if self.__tell is None:
  116. self.__tell = writefile.tell()
  117. if offset != self.__tell:
  118. writefile.seek(offset)
  119. self.__tell = offset
  120. writefile.write(data)
  121. writefile.flush()
  122. except IOError as e:
  123. self.__tell = None
  124. return SFTPServer.convert_errno(e.errno)
  125. if self.__tell is not None:
  126. self.__tell += len(data)
  127. return SFTP_OK
  128. def stat(self):
  129. """
  130. Return an `.SFTPAttributes` object referring to this open file, or an
  131. error code. This is equivalent to `.SFTPServerInterface.stat`, except
  132. it's called on an open file instead of a path.
  133. :return:
  134. an attributes object for the given file, or an SFTP error code
  135. (like ``SFTP_PERMISSION_DENIED``).
  136. :rtype: `.SFTPAttributes` or error code
  137. """
  138. return SFTP_OP_UNSUPPORTED
  139. def chattr(self, attr):
  140. """
  141. Change the attributes of this file. The ``attr`` object will contain
  142. only those fields provided by the client in its request, so you should
  143. check for the presence of fields before using them.
  144. :param .SFTPAttributes attr: the attributes to change on this file.
  145. :return: an `int` error code like ``SFTP_OK``.
  146. """
  147. return SFTP_OP_UNSUPPORTED
  148. # ...internals...
  149. def _set_files(self, files):
  150. """
  151. Used by the SFTP server code to cache a directory listing. (In
  152. the SFTP protocol, listing a directory is a multi-stage process
  153. requiring a temporary handle.)
  154. """
  155. self.__files = files
  156. def _get_next_files(self):
  157. """
  158. Used by the SFTP server code to retrieve a cached directory
  159. listing.
  160. """
  161. fnlist = self.__files[:16]
  162. self.__files = self.__files[16:]
  163. return fnlist
  164. def _get_name(self):
  165. return self.__name
  166. def _set_name(self, name):
  167. self.__name = name
  168. from paramiko.sftp_server import SFTPServer