diff options
Diffstat (limited to 'paramiko/sftp_file.py')
-rw-r--r-- | paramiko/sftp_file.py | 115 |
1 files changed, 76 insertions, 39 deletions
diff --git a/paramiko/sftp_file.py b/paramiko/sftp_file.py index fdf667cd..337cdbeb 100644 --- a/paramiko/sftp_file.py +++ b/paramiko/sftp_file.py @@ -31,8 +31,10 @@ from paramiko.common import DEBUG from paramiko.file import BufferedFile from paramiko.py3compat import long -from paramiko.sftp import CMD_CLOSE, CMD_READ, CMD_DATA, SFTPError, CMD_WRITE, \ - CMD_STATUS, CMD_FSTAT, CMD_ATTRS, CMD_FSETSTAT, CMD_EXTENDED +from paramiko.sftp import ( + CMD_CLOSE, CMD_READ, CMD_DATA, SFTPError, CMD_WRITE, CMD_STATUS, CMD_FSTAT, + CMD_ATTRS, CMD_FSETSTAT, CMD_EXTENDED, +) from paramiko.sftp_attr import SFTPAttributes @@ -87,7 +89,8 @@ class SFTPFile (BufferedFile): BufferedFile.close(self) try: if async: - # GC'd file handle could be called from an arbitrary thread -- don't wait for a response + # GC'd file handle could be called from an arbitrary thread + # -- don't wait for a response self.sftp._async_request(type(None), CMD_CLOSE, self.handle) else: self.sftp._request(CMD_CLOSE, self.handle) @@ -99,7 +102,8 @@ class SFTPFile (BufferedFile): pass def _data_in_prefetch_requests(self, offset, size): - k = [x for x in list(self._prefetch_extents.values()) if x[0] <= offset] + k = [x for x in list(self._prefetch_extents.values()) + if x[0] <= offset] if len(k) == 0: return False k.sort(key=lambda x: x[0]) @@ -110,8 +114,11 @@ class SFTPFile (BufferedFile): if buf_offset + buf_size >= offset + size: # inclusive return True - # well, we have part of the request. see if another chunk has the rest. - return self._data_in_prefetch_requests(buf_offset + buf_size, offset + size - buf_offset - buf_size) + # well, we have part of the request. see if another chunk has + # the rest. + return self._data_in_prefetch_requests( + buf_offset + buf_size, + offset + size - buf_offset - buf_size) def _data_in_prefetch_buffers(self, offset): """ @@ -135,7 +142,8 @@ class SFTPFile (BufferedFile): read data out of the prefetch buffer, if possible. if the data isn't in the buffer, return None. otherwise, behaves like a normal read. """ - # while not closed, and haven't fetched past the current position, and haven't reached EOF... + # while not closed, and haven't fetched past the current position, + # and haven't reached EOF... while True: offset = self._data_in_prefetch_buffers(self._realpos) if offset is not None: @@ -165,7 +173,12 @@ class SFTPFile (BufferedFile): data = self._read_prefetch(size) if data is not None: return data - t, msg = self.sftp._request(CMD_READ, self.handle, long(self._realpos), int(size)) + t, msg = self.sftp._request( + CMD_READ, + self.handle, + long(self._realpos), + int(size) + ) if t != CMD_DATA: raise SFTPError('Expected data') return msg.get_string() @@ -173,8 +186,18 @@ class SFTPFile (BufferedFile): def _write(self, data): # may write less than requested if it would exceed max packet size chunk = min(len(data), self.MAX_REQUEST_SIZE) - self._reqs.append(self.sftp._async_request(type(None), CMD_WRITE, self.handle, long(self._realpos), data[:chunk])) - if not self.pipelined or (len(self._reqs) > 100 and self.sftp.sock.recv_ready()): + sftp_async_request = self.sftp._async_request( + type(None), + CMD_WRITE, + self.handle, + long(self._realpos), + data[:chunk] + ) + self._reqs.append(sftp_async_request) + if ( + not self.pipelined or + (len(self._reqs) > 100 and self.sftp.sock.recv_ready()) + ): while len(self._reqs): req = self._reqs.popleft() t, msg = self.sftp._read_response(req) @@ -228,6 +251,11 @@ class SFTPFile (BufferedFile): return True def seek(self, offset, whence=0): + """ + Set the file's current position. + + See `file.seek` for details. + """ self.flush() if whence == self.SEEK_SET: self._realpos = self._pos = offset @@ -244,7 +272,8 @@ class SFTPFile (BufferedFile): exactly like `.SFTPClient.stat`, except that it operates on an already-open file. - :return: an `.SFTPAttributes` object containing attributes about this file. + :returns: + an `.SFTPAttributes` object containing attributes about this file. """ t, msg = self.sftp._request(CMD_FSTAT, self.handle) if t != CMD_ATTRS: @@ -274,7 +303,9 @@ class SFTPFile (BufferedFile): :param int uid: new owner's uid :param int gid: new group id """ - self.sftp._log(DEBUG, 'chown(%s, %r, %r)' % (hexlify(self.handle), uid, gid)) + self.sftp._log( + DEBUG, + 'chown(%s, %r, %r)' % (hexlify(self.handle), uid, gid)) attr = SFTPAttributes() attr.st_uid, attr.st_gid = uid, gid self.sftp._request(CMD_FSETSTAT, self.handle, attr) @@ -282,11 +313,11 @@ class SFTPFile (BufferedFile): def utime(self, times): """ Set the access and modified times of this file. If - ``times`` is ``None``, then the file's access and modified times are set - to the current time. Otherwise, ``times`` must be a 2-tuple of numbers, - of the form ``(atime, mtime)``, which is used to set the access and - modified times, respectively. This bizarre API is mimicked from Python - for the sake of consistency -- I apologize. + ``times`` is ``None``, then the file's access and modified times are + set to the current time. Otherwise, ``times`` must be a 2-tuple of + numbers, of the form ``(atime, mtime)``, which is used to set the + access and modified times, respectively. This bizarre API is mimicked + from Python for the sake of consistency -- I apologize. :param tuple times: ``None`` or a tuple of (access time, modified time) in standard @@ -306,9 +337,10 @@ class SFTPFile (BufferedFile): Python file objects. :param size: the new size of the file - :type size: int or long """ - self.sftp._log(DEBUG, 'truncate(%s, %r)' % (hexlify(self.handle), size)) + self.sftp._log( + DEBUG, + 'truncate(%s, %r)' % (hexlify(self.handle), size)) attr = SFTPAttributes() attr.st_size = size self.sftp._request(CMD_FSETSTAT, self.handle, attr) @@ -319,9 +351,9 @@ class SFTPFile (BufferedFile): to verify a successful upload or download, or for various rsync-like operations. - The file is hashed from ``offset``, for ``length`` bytes. If ``length`` - is 0, the remainder of the file is hashed. Thus, if both ``offset`` - and ``length`` are zero, the entire file is hashed. + The file is hashed from ``offset``, for ``length`` bytes. + If ``length`` is 0, the remainder of the file is hashed. Thus, if both + ``offset`` and ``length`` are zero, the entire file is hashed. Normally, ``block_size`` will be 0 (the default), and this method will return a byte string representing the requested hash (for example, a @@ -342,30 +374,28 @@ class SFTPFile (BufferedFile): :param offset: offset into the file to begin hashing (0 means to start from the beginning) - :type offset: int or long :param length: number of bytes to hash (0 means continue to the end of the file) - :type length: int or long :param int block_size: number of bytes to hash per result (must not be less than 256; 0 means to compute only one hash of the entire segment) - :type block_size: int :return: `str` of bytes representing the hash of each block, concatenated together - :raises IOError: if the server doesn't support the "check-file" - extension, or possibly doesn't support the hash algorithm - requested + :raises: + ``IOError`` -- if the server doesn't support the "check-file" + extension, or possibly doesn't support the hash algorithm requested .. note:: Many (most?) servers don't support this extension yet. .. versionadded:: 1.4 """ - t, msg = self.sftp._request(CMD_EXTENDED, 'check-file', self.handle, - hash_algorithm, long(offset), long(length), block_size) - ext = msg.get_text() - alg = msg.get_text() + t, msg = self.sftp._request( + CMD_EXTENDED, 'check-file', self.handle, + hash_algorithm, long(offset), long(length), block_size) + msg.get_text() # ext + msg.get_text() # alg data = msg.get_remainder() return data @@ -417,7 +447,7 @@ class SFTPFile (BufferedFile): compatibility. """ if file_size is None: - file_size = self.stat().st_size; + file_size = self.stat().st_size # queue up async reads for the rest of the file chunks = [] @@ -437,9 +467,8 @@ class SFTPFile (BufferedFile): once. :param chunks: - a list of (offset, length) tuples indicating which sections of the - file to read - :type chunks: list(tuple(long, int)) + a list of ``(offset, length)`` tuples indicating which sections of + the file to read :return: a list of blocks read, in the same order as in ``chunks`` .. versionadded:: 1.5.4 @@ -449,7 +478,10 @@ class SFTPFile (BufferedFile): read_chunks = [] for offset, size in chunks: # don't fetch data that's already in the prefetch buffer - if self._data_in_prefetch_buffers(offset) or self._data_in_prefetch_requests(offset, size): + if ( + self._data_in_prefetch_buffers(offset) or + self._data_in_prefetch_requests(offset, size) + ): continue # break up anything larger than the max read size @@ -465,7 +497,7 @@ class SFTPFile (BufferedFile): self.seek(x[0]) yield self.read(x[1]) - ### internals... + # ...internals... def _get_size(self): try: @@ -485,7 +517,12 @@ class SFTPFile (BufferedFile): # do these read requests in a temporary thread because there may be # a lot of them, so it may block. for offset, length in chunks: - num = self.sftp._async_request(self, CMD_READ, self.handle, long(offset), int(length)) + num = self.sftp._async_request( + self, + CMD_READ, + self.handle, + long(offset), + int(length)) with self._prefetch_lock: self._prefetch_extents[num] = (offset, length) |