def _process_fsetstat(self, request_number, msg): handle = msg.get_binary() attr = SFTPAttributes._from_msg(msg) if handle not in self.file_table: self._response(request_number, SFTP_BAD_MESSAGE, 'Invalid handle') return self._send_status(request_number, self.file_table[handle].chattr(attr))
def listdir_ex(self, path): path = self._adjust_cwd(path) basename = os.path.basename(path) dir = os.path.dirname(path) t, msg = self._request(CMD_OPENDIR, dir) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_string() filelist = [] while True: try: t, msg = self._request(CMD_READDIR, handle) except EOFError: # done with handle break if t != CMD_NAME: raise SFTPError('Expected name response') count = msg.get_int() for i in range(count): filename = _to_unicode(msg.get_string()) longname = _to_unicode(msg.get_string()) attr = SFTPAttributes._from_msg(msg, filename, longname) if (filename != '.') and ( filename != '..') and filename.startswith(basename): filelist.append(filename) self._request(CMD_CLOSE, handle) return filelist
def stat(self, path): """ Retrieve information about a file on the remote system. The return value is an object whose attributes correspond to the attributes of Python's ``stat`` structure as returned by ``os.stat``, except that it 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. Unlike a Python `python:stat` object, the result may not be accessed as a tuple. This is mostly due to the author's slack factor. The fields supported are: ``st_mode``, ``st_size``, ``st_uid``, ``st_gid``, ``st_atime``, and ``st_mtime``. :param str path: the filename to stat :return: an `.SFTPAttributes` object containing attributes about the given file """ path = self._adjust_cwd(path) self._log(DEBUG, 'stat({!r})'.format(path)) t, msg = self._request(CMD_STAT, path) if t != CMD_ATTRS: raise SFTPError('Expected attributes') return SFTPAttributes._from_msg(msg)
def stat(self, path): """ Retrieve information about a file on the remote system. The return value is an object whose attributes correspond to the attributes of python's C{stat} structure as returned by C{os.stat}, except that it 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. Unlike a python C{stat} object, the result may not be accessed as a tuple. This is mostly due to the author's slack factor. The fields supported are: C{st_mode}, C{st_size}, C{st_uid}, C{st_gid}, C{st_atime}, and C{st_mtime}. @param path: the filename to stat @type path: str @return: an object containing attributes about the given file @rtype: SFTPAttributes """ path = self._adjust_cwd(path) self._log(DEBUG, 'stat(%r)' % path) t, msg = self._request(CMD_STAT, path) if t != CMD_ATTRS: raise SFTPError('Expected attributes') return SFTPAttributes._from_msg(msg)
def stat(self, path): """ Retrieve information about a file on the remote system. The return value is an object whose attributes correspond to the attributes of Python's ``stat`` structure as returned by ``os.stat``, except that it 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. Unlike a Python `python:stat` object, the result may not be accessed as a tuple. This is mostly due to the author's slack factor. The fields supported are: ``st_mode``, ``st_size``, ``st_uid``, ``st_gid``, ``st_atime``, and ``st_mtime``. :param str path: the filename to stat :return: an `.SFTPAttributes` object containing attributes about the given file """ path = self._adjust_cwd(path) self._log(DEBUG, 'stat(%r)' % path) t, msg = self._request(CMD_STAT, path) if t != CMD_ATTRS: raise SFTPError('Expected attributes') return SFTPAttributes._from_msg(msg)
def listdir_attr(self, path='.'): """ Return a list containing L{SFTPAttributes} objects corresponding to files in the given C{path}. The list is in arbitrary order. It does not include the special entries C{'.'} and C{'..'} even if they are present in the folder. @param path: path to list (defaults to C{'.'}) @type path: str @return: list of attributes @rtype: list of L{SFTPAttributes} @since: 1.2 """ path = self._adjust_cwd(path) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_string() filelist = [] while True: try: t, msg = self._request(CMD_READDIR, handle) except EOFError, e: # done with handle break if t != CMD_NAME: raise SFTPError('Expected name response') count = msg.get_int() for i in range(count): filename = _to_unicode(msg.get_string()) longname = _to_unicode(msg.get_string()) attr = SFTPAttributes._from_msg(msg, filename) if (filename != '.') and (filename != '..'): filelist.append(attr)
def fstat(self, handle): """ Get stats about a file on the remote server via it's handle """ log.debug(f"stat request: [{handle}]") resp_type, msg = self._blocking_request(CMD_FSTAT, handle) if resp_type != CMD_ATTRS: raise SFTPError("Expected back attributes") return SFTPAttributes._from_msg(msg)
def listdir_iter(self, path='.', read_aheads=10): """ Generator version of `.listdir_attr`. See the API docs for `.listdir_attr` for overall details. This function adds one more kwarg on top of `.listdir_attr`: ``read_aheads``, an integer controlling how many ``SSH_FXP_READDIR`` requests are made to the server. The default should suffice for most file listings as each request/response cycle may contain multiple files (dependent on server implementation.) .. versionadded:: 1.15 """ path = self._adjust_cwd(path) self._log(DEBUG, "listdir(%r)", path) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_string() while True: nums = list() results = list() try: # Send out a bunch of readdir requests so that we can read the responses later # Section 6.7 of the SSH file transfer RFC explains this # http://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt for i in range(read_aheads): num = self._async_request(type(None), CMD_READDIR, handle) nums.append(num) # need to read whole batch before yielding any for num in nums: t, msg = self._read_response(num) count = msg.get_int() for i in range(count): filename = msg.get_text() longname = msg.get_text() attr = SFTPAttributes._from_msg( msg, filename, longname) if (filename != '.') and (filename != '..'): results.append(attr) for a in results: yield a except EOFError: self._request(CMD_CLOSE, handle) for a in results: yield a return
def stat(self): """ Retrieve information about this file from the remote system. This is exactly like `.SFTPClient.stat`, except that it operates on an already-open file. :return: an `.SFTPAttributes` object containing attributes about this file. """ t, msg = self.sftp._request(CMD_FSTAT, self.handle) if t != CMD_ATTRS: raise SFTPError('Expected attributes') return SFTPAttributes._from_msg(msg)
def lstat(self, path): """ Retrieve information about a file on the remote system, without following symbolic links (shortcuts). This otherwise behaves exactly the same as L{stat}. @param path: the filename to stat. @type path: string @return: an object containing attributes about the given file. @rtype: SFTPAttributes """ path = self._adjust_cwd(path) t, msg = self._request(CMD_LSTAT, path) if t != CMD_ATTRS: raise SFTPError('Expected attributes') return SFTPAttributes._from_msg(msg)
def listdir_attr(self, path=".", encoding="utf-8", path_encoding='utf-8'): """ Return a list containing `.SFTPAttributes` objects corresponding to files in the given ``path``. The list is in arbitrary order. It does not include the special entries ``'.'`` and ``'..'`` even if they are present in the folder. The returned `.SFTPAttributes` objects will each have an additional field: ``longname``, which may contain a formatted string of the file's attributes, in unix format. The content of this string will probably depend on the SFTP server implementation. :param str encoding: the byte decode format (defauls to ```'utf-8'```),used to decode filename(under the path) byte ,eg: ```'中文目录'``` :param str encoding: 设置服务器中返回byte的解码格式,当服务器返回内容中有使用其他格式编码的内容时(如目录下包含有中文)需要设置此参数,参数值建议为服务器使用的编码格式,如: 'GB180303'编码的中文,此时建议使用方式: listdir_attr(path='/test', encoding='GB18030') :param str path: path to list (defaults to ``'.'``) :param str path_encoding: the path parameter encode format (defauls to ```'utf-8'```),eg: listdir_attr(path='中文目录'.encode('GB18030'), path_encoding='GB18030') :param str path_encoding: 当需要查看的路径path在服务器上的编码格式不是utf-8时需要设置此参数,参数值为服务器所使用的编码格式,如需要查看的路径是'/test/中文路径',而服务器使用的编码格式是GB18030, 此时就建议如下使用方式: listdir_attr(path="/test/中文路径".encode("GB18030"), path_encoding='GB18030') :return: list of `.SFTPAttributes` objects .. versionadded:: 1.2 """ if path == '.' and self.getcwd() is not None: path = self.getcwd().encode(path_encoding) path = self._adjust_cwd(path) self._log(DEBUG, "listdir({!r})".format(path)) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError("Expected handle") handle = msg.get_binary() filelist = [] while True: try: t, msg = self._request(CMD_READDIR, handle) except EOFError: # done with handle break if t != CMD_NAME: raise SFTPError("Expected name response") count = msg.get_int() for i in range(count): filename = msg.get_text(encoding) longname = msg.get_text(encoding) attr = SFTPAttributes._from_msg(msg, filename, longname) if (filename != ".") and (filename != ".."): filelist.append(attr) self._request(CMD_CLOSE, handle) return filelist
def lstat(self, path): """ Retrieve information about a file on the remote system, without following symbolic links (shortcuts). This otherwise behaves exactly the same as `stat`. :param str path: the filename to stat :return: an `.SFTPAttributes` object containing attributes about the given file """ path = self._adjust_cwd(path) self._log(DEBUG, 'lstat(%r)' % path) t, msg = self._request(CMD_LSTAT, path) if t != CMD_ATTRS: raise SFTPError('Expected attributes') return SFTPAttributes._from_msg(msg)
def listdir_attr(self, path='.'): """ Return a list containing L{SFTPAttributes} objects corresponding to files in the given C{path}. The list is in arbitrary order. It does not include the special entries C{'.'} and C{'..'} even if they are present in the folder. The returned L{SFTPAttributes} objects will each have an additional field: C{longname}, which may contain a formatted string of the file's attributes, in unix format. The content of this string will probably depend on the SFTP server implementation. @param path: path to list (defaults to C{'.'}) @type path: str @return: list of attributes @rtype: list of L{SFTPAttributes} @since: 1.2 """ path = self._adjust_cwd(path) self._log(DEBUG, 'listdir(%r)' % path) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_binary() filelist = [] while True: try: t, msg = self._request(CMD_READDIR, handle) except EOFError: # done with handle break if t != CMD_NAME: raise SFTPError('Expected name response') count = msg.get_int() for i in range(count): filename = msg.get_text() longname = msg.get_text() attr = SFTPAttributes._from_msg(msg, filename, longname) if (filename != '.') and (filename != '..'): filelist.append(attr) self._request(CMD_CLOSE, handle) return filelist
def listdir_attr(self, path="."): """ Return a list containing `.SFTPAttributes` objects corresponding to files in the given ``path``. The list is in arbitrary order. It does not include the special entries ``'.'`` and ``'..'`` even if they are present in the folder. The returned `.SFTPAttributes` objects will each have an additional field: ``longname``, which may contain a formatted string of the file's attributes, in unix format. The content of this string will probably depend on the SFTP server implementation. :param str path: path to list (defaults to ``'.'``) :return: list of `.SFTPAttributes` objects .. versionadded:: 1.2 """ path = self._adjust_cwd(path) self._log(DEBUG, "listdir({!r})".format(path)) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError("Expected handle") handle = msg.get_binary() filelist = [] while True: try: t, msg = self._request(CMD_READDIR, handle) except EOFError: # done with handle break if t != CMD_NAME: raise SFTPError("Expected name response") count = msg.get_int() for i in range(count): filename = msg.get_text() longname = msg.get_text() attr = SFTPAttributes._from_msg(msg, filename, longname) if (filename != ".") and (filename != ".."): filelist.append(attr) self._request(CMD_CLOSE, handle) return filelist
def listdir_attr(self, path='.'): """ Return a list containing `.SFTPAttributes` objects corresponding to files in the given ``path``. The list is in arbitrary order. It does not include the special entries ``'.'`` and ``'..'`` even if they are present in the folder. The returned `.SFTPAttributes` objects will each have an additional field: ``longname``, which may contain a formatted string of the file's attributes, in unix format. The content of this string will probably depend on the SFTP server implementation. :param str path: path to list (defaults to ``'.'``) :return: list of `.SFTPAttributes` objects .. versionadded:: 1.2 """ path = self._adjust_cwd(path) self._log(DEBUG, 'listdir({!r})'.format(path)) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_binary() filelist = [] while True: try: t, msg = self._request(CMD_READDIR, handle) except EOFError: # done with handle break if t != CMD_NAME: raise SFTPError('Expected name response') count = msg.get_int() for i in range(count): filename = msg.get_text() longname = msg.get_text() attr = SFTPAttributes._from_msg(msg, filename, longname) if (filename != '.') and (filename != '..'): filelist.append(attr) self._request(CMD_CLOSE, handle) return filelist
def stat(self, path): """ Retrieve information about a file on the remote system. The return value is an object whose attributes correspond to the attributes of python's C{stat} structure as returned by C{os.stat}, except that it 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. Unlike a python C{stat} object, the result may not be accessed as a tuple. This is mostly due to the author's slack factor. The fields supported are: C{st_mode}, C{st_size}, C{st_uid}, C{st_gid}, C{st_atime}, and C{st_mtime}. @param path: the filename to stat. @type path: string @return: an object containing attributes about the given file. @rtype: SFTPAttributes """ path = self._adjust_cwd(path) t, msg = self._request(CMD_STAT, path) if t != CMD_ATTRS: raise SFTPError('Expected attributes') return SFTPAttributes._from_msg(msg)
def _process(self, t, request_number, msg): self._log(DEBUG, 'Request: %s' % CMD_NAMES[t]) if t == CMD_OPEN: path = msg.get_text() flags = self._convert_pflags(msg.get_int()) attr = SFTPAttributes._from_msg(msg) self._send_handle_response(request_number, self.server.open(path, flags, attr)) elif t == CMD_CLOSE: handle = msg.get_binary() if handle in self.folder_table: del self.folder_table[handle] self._send_status(request_number, SFTP_OK) return if handle in self.file_table: self.file_table[handle].close() del self.file_table[handle] self._send_status(request_number, SFTP_OK) return self._send_status(request_number, SFTP_BAD_MESSAGE, 'Invalid handle') elif t == CMD_READ: handle = msg.get_binary() offset = msg.get_int64() length = msg.get_int() if handle not in self.file_table: self._send_status(request_number, SFTP_BAD_MESSAGE, 'Invalid handle') return data = self.file_table[handle].read(offset, length) if isinstance(data, (bytes_types, string_types)): if len(data) == 0: self._send_status(request_number, SFTP_EOF) else: self._response(request_number, CMD_DATA, data) else: self._send_status(request_number, data) elif t == CMD_WRITE: handle = msg.get_binary() offset = msg.get_int64() data = msg.get_binary() if handle not in self.file_table: self._send_status(request_number, SFTP_BAD_MESSAGE, 'Invalid handle') return self._send_status(request_number, self.file_table[handle].write(offset, data)) elif t == CMD_REMOVE: path = msg.get_text() self._send_status(request_number, self.server.remove(path)) elif t == CMD_RENAME: oldpath = msg.get_text() newpath = msg.get_text() self._send_status(request_number, self.server.rename(oldpath, newpath)) elif t == CMD_MKDIR: path = msg.get_text() attr = SFTPAttributes._from_msg(msg) self._send_status(request_number, self.server.mkdir(path, attr)) elif t == CMD_RMDIR: path = msg.get_text() self._send_status(request_number, self.server.rmdir(path)) elif t == CMD_OPENDIR: path = msg.get_text() self._open_folder(request_number, path) return elif t == CMD_READDIR: handle = msg.get_binary() if handle not in self.folder_table: self._send_status(request_number, SFTP_BAD_MESSAGE, 'Invalid handle') return folder = self.folder_table[handle] self._read_folder(request_number, folder) elif t == CMD_STAT: path = msg.get_text() resp = self.server.stat(path) if issubclass(type(resp), SFTPAttributes): self._response(request_number, CMD_ATTRS, resp) else: self._send_status(request_number, resp) elif t == CMD_LSTAT: path = msg.get_text() resp = self.server.lstat(path) if issubclass(type(resp), SFTPAttributes): self._response(request_number, CMD_ATTRS, resp) else: self._send_status(request_number, resp) elif t == CMD_FSTAT: handle = msg.get_binary() if handle not in self.file_table: self._send_status(request_number, SFTP_BAD_MESSAGE, 'Invalid handle') return resp = self.file_table[handle].stat() if issubclass(type(resp), SFTPAttributes): self._response(request_number, CMD_ATTRS, resp) else: self._send_status(request_number, resp) elif t == CMD_SETSTAT: path = msg.get_text() attr = SFTPAttributes._from_msg(msg) self._send_status(request_number, self.server.chattr(path, attr)) elif t == CMD_FSETSTAT: handle = msg.get_binary() attr = SFTPAttributes._from_msg(msg) if handle not in self.file_table: self._response(request_number, SFTP_BAD_MESSAGE, 'Invalid handle') return self._send_status(request_number, self.file_table[handle].chattr(attr)) elif t == CMD_READLINK: path = msg.get_text() resp = self.server.readlink(path) if isinstance(resp, (bytes_types, string_types)): self._response(request_number, CMD_NAME, 1, resp, '', SFTPAttributes()) else: self._send_status(request_number, resp) elif t == CMD_SYMLINK: # the sftp 2 draft is incorrect here! path always follows target_path target_path = msg.get_text() path = msg.get_text() self._send_status(request_number, self.server.symlink(target_path, path)) elif t == CMD_REALPATH: path = msg.get_text() rpath = self.server.canonicalize(path) self._response(request_number, CMD_NAME, 1, rpath, '', SFTPAttributes()) elif t == CMD_EXTENDED: tag = msg.get_text() if tag == 'check-file': self._check_file(request_number, msg) else: self._send_status(request_number, SFTP_OP_UNSUPPORTED) else: self._send_status(request_number, SFTP_OP_UNSUPPORTED)
def _process_open(self, request_number, msg): path = msg.get_text() flags = self._convert_pflags(msg.get_int()) attr = SFTPAttributes._from_msg(msg) self._send_handle_response(request_number, self.server.open(path, flags, attr))
def _process_setstat(self, request_number, msg): path = msg.get_text() attr = SFTPAttributes._from_msg(msg) self._send_status(request_number, self.server.chattr(path, attr))
def listdir_iter(self, path='.', read_aheads=50): """ Generator version of `.listdir_attr`. See the API docs for `.listdir_attr` for overall details. This function adds one more kwarg on top of `.listdir_attr`: ``read_aheads``, an integer controlling how many ``SSH_FXP_READDIR`` requests are made to the server. The default of 50 should suffice for most file listings as each request/response cycle may contain multiple files (dependent on server implementation.) .. versionadded:: 1.15 """ path = self._adjust_cwd(path) self._log(DEBUG, 'listdir(%r)' % path) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_string() nums = list() while True: try: # Send out a bunch of readdir requests so that we can read the # responses later on Section 6.7 of the SSH file transfer RFC # explains this # http://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt for i in range(read_aheads): num = self._async_request(type(None), CMD_READDIR, handle) nums.append(num) # For each of our sent requests # Read and parse the corresponding packets # If we're at the end of our queued requests, then fire off # some more requests # Exit the loop when we've reached the end of the directory # handle for num in nums: t, pkt_data = self._read_packet() msg = Message(pkt_data) new_num = msg.get_int() if num == new_num: if t == CMD_STATUS: self._convert_status(msg) count = msg.get_int() for i in range(count): filename = msg.get_text() longname = msg.get_text() attr = SFTPAttributes._from_msg( msg, filename, longname) if (filename != '.') and (filename != '..'): yield attr # If we've hit the end of our queued requests, reset nums. nums = list() except EOFError: self._request(CMD_CLOSE, handle) return
def listdir_iter(self, path='.', read_ahead_requests=50): """ Generator yielding L{SFTPAttributes} objects corresponding to files in the given C{path}. Files are yielded in arbitrary order. It does not include the special entries C{'.'} and C{'..'} even if they are present in the folder. The returned L{SFTPAttributes} objects will each have an additional field: C{longname}, which may contain a formatted string of the file's attributes, in unix format. The content of this string will probably depend on the SFTP server implementation. @param path: path to list (defaults to C{'.'}) @type path: str @return: Yields L{SFTPAttributes} @rtype: L{SFTPAttributes} @since: 1.9 """ path = self._adjust_cwd(path) self._log(DEBUG, 'listdir(%r)' % path) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_string() nums = list() while True: try: # Send out a bunch of readdir requests so that we can read the responses later on # Section 6.7 of the SSH file transfer RFC explains this # http://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt for i in range(read_ahead_requests): num = self._async_request(type(None), CMD_READDIR, handle) nums.append(num) # For each of our sent requests # Read and parse the corresponding packets # If we're at the end of our queued requests, then fire off some more requests # Exit the loop when we've reached the end of the directory handle for num in nums: t, pkt_data = self._read_packet() msg = Message(pkt_data) new_num = msg.get_int() if num == new_num: if t == CMD_STATUS: self._convert_status(msg) count = msg.get_int() for i in range(count): filename = msg.get_string() longname = msg.get_string() attr = SFTPAttributes._from_msg(msg, filename, longname) if (filename != '.') and (filename != '..'): yield attr # If we've hit the end of our queued requests, reset nums. nums = list() except EOFError: self._request(CMD_CLOSE, handle) return
def listdir_iter(self, path='.', read_aheads=50): """ Generator version of `.listdir_attr`. See the API docs for `.listdir_attr` for overall details. This function adds one more kwarg on top of `.listdir_attr`: ``read_aheads``, an integer controlling how many ``SSH_FXP_READDIR`` requests are made to the server. The default of 50 should suffice for most file listings as each request/response cycle may contain multiple files (dependant on server implementation.) .. versionadded:: 1.15 """ path = self._adjust_cwd(path) self._log(DEBUG, 'listdir(%r)' % path) t, msg = self._request(CMD_OPENDIR, path) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_string() nums = list() while True: try: # Send out a bunch of readdir requests so that we can read the # responses later on Section 6.7 of the SSH file transfer RFC # explains this # http://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt for i in range(read_aheads): num = self._async_request(type(None), CMD_READDIR, handle) nums.append(num) # For each of our sent requests # Read and parse the corresponding packets # If we're at the end of our queued requests, then fire off # some more requests # Exit the loop when we've reached the end of the directory # handle for num in nums: t, pkt_data = self._read_packet() msg = Message(pkt_data) new_num = msg.get_int() if num == new_num: if t == CMD_STATUS: self._convert_status(msg) count = msg.get_int() for i in range(count): filename = msg.get_text() longname = msg.get_text() attr = SFTPAttributes._from_msg( msg, filename, longname) if (filename != '.') and (filename != '..'): yield attr # If we've hit the end of our queued requests, reset nums. nums = list() except EOFError: self._request(CMD_CLOSE, handle) return