def _close(self, async_=False): # We allow double-close without signaling an error, because real # Python file objects do. However, we must protect against actually # sending multiple CMD_CLOSE packets, because after we close our # handle, the same handle may be re-allocated by the server, and we # may end up mysteriously closing some random other file. (This is # especially important because we unconditionally call close() from # __del__.) if self._closed: return self.sftp._log(DEBUG, 'close({})'.format(u(hexlify(self.handle)))) if self.pipelined: self.sftp._finish_responses(self) BufferedFile.close(self) try: if async_: # 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) except EOFError: # may have outlived the Transport connection pass except (IOError, socket.error): # may have outlived the Transport connection pass
def get_base64(self): """ Return a base64 string containing the public part of this key. Nothing secret is revealed. This format is compatible with that used to store public key files or recognized host keys. :return: a base64 `string <str>` containing the public part of the key. """ return u(encodebytes(self.asbytes())).replace('\n', '')
def getcwd(self): """ Return the "current working directory" for this SFTP session, as emulated by Paramiko. If no directory has been set with `chdir`, this method will return ``None``. .. versionadded:: 1.4 """ # TODO: make class initialize with self._cwd set to self.normalize('.') return self._cwd and u(self._cwd)
def open(self, filename, mode='r', bufsize=-1): """ Open a file on the remote server. The arguments are the same as for Python's built-in `python:file` (aka `python:open`). A file-like object is returned, which closely mimics the behavior of a normal 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, ``'w'`` for writing (truncating an existing file), ``'a'`` for appending, ``'r+'`` for reading/writing, ``'w+'`` for reading/writing (truncating an existing file), ``'a+'`` for reading/appending. The Python ``'b'`` flag is ignored, since SSH treats all files as binary. The ``'U'`` flag is supported in a compatible way. 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 no direct mapping to Python's file flags, but is commonly known as the ``O_EXCL`` flag in posix. The file will be buffered in standard Python style by default, but can be altered with the ``bufsize`` parameter. ``0`` turns off buffering, ``1`` uses line buffering, and any number greater than 1 (``>1``) uses that specific buffer size. :param str filename: name of the file to open :param str mode: mode (Python-style) to open in :param int bufsize: desired buffering (-1 = default buffer size) :return: an `.SFTPFile` object representing the open file :raises: ``IOError`` -- if the file could not be opened. """ filename = self._adjust_cwd(filename) self._log(DEBUG, 'open({!r}, {!r})'.format(filename, mode)) imode = 0 if ('r' in mode) or ('+' in mode): imode |= SFTP_FLAG_READ if ('w' in mode) or ('+' in mode) or ('a' in mode): imode |= SFTP_FLAG_WRITE if 'w' in mode: imode |= SFTP_FLAG_CREATE | SFTP_FLAG_TRUNC if 'a' in mode: imode |= SFTP_FLAG_CREATE | SFTP_FLAG_APPEND if 'x' in mode: imode |= SFTP_FLAG_CREATE | SFTP_FLAG_EXCL attrblock = SFTPAttributes() t, msg = self._request(CMD_OPEN, filename, imode, attrblock) if t != CMD_HANDLE: raise SFTPError('Expected handle') handle = msg.get_binary() self._log( DEBUG, 'open({!r}, {!r}) -> {}'.format(filename, mode, u(hexlify(handle))) ) return SFTPFile(self, handle, mode, bufsize)
def readline(self, timeout): """ Read a line from the socket. We assume no data is pending after the line, so it's okay to attempt large reads. """ buf = self.__remainder while linefeed_byte not in buf: buf += self._read_timeout(timeout) n = buf.index(linefeed_byte) self.__remainder = buf[n + 1:] buf = buf[:n] if (len(buf) > 0) and (buf[-1] == cr_byte_value): buf = buf[:-1] return u(buf)
def __enter__(self): p_SA = (ctypes.byref(self.security_attributes) if self.security_attributes else None) INVALID_HANDLE_VALUE = -1 PAGE_READWRITE = 0x4 FILE_MAP_WRITE = 0x2 filemap = ctypes.windll.kernel32.CreateFileMappingW( INVALID_HANDLE_VALUE, p_SA, PAGE_READWRITE, 0, self.length, u(self.name)) handle_nonzero_success(filemap) if filemap == INVALID_HANDLE_VALUE: raise Exception("Failed to create file mapping") self.filemap = filemap self.view = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0) return self
def readline(self, size=None): """ Read one entire line from the file. A trailing newline character is kept in the string (but may be absent when a file ends with an incomplete line). If the size argument is present and non-negative, it is a maximum byte count (including the trailing newline) and an incomplete line may be returned. An empty string is returned only when EOF is encountered immediately. .. note:: Unlike stdio's ``fgets``, the returned string contains null characters (``'\\0'``) if they occurred in the input. :param int size: maximum length of returned string. :returns: next line of the file, or an empty string if the end of the file has been reached. If the file was opened in binary (``'b'``) mode: bytes are returned Else: the encoding of the file is assumed to be UTF-8 and character strings (`str`) are returned """ # it's almost silly how complex this function is. if self._closed: raise IOError('File is closed') if not (self._flags & self.FLAG_READ): raise IOError('File not open for reading') line = self._rbuffer truncated = False while True: if (self._at_trailing_cr and self._flags & self.FLAG_UNIVERSAL_NEWLINE and len(line) > 0): # edge case: the newline may be '\r\n' and we may have read # only the first '\r' last time. if line[0] == linefeed_byte_value: line = line[1:] self._record_newline(crlf) else: self._record_newline(cr_byte) self._at_trailing_cr = False # check size before looking for a linefeed, in case we already have # enough. if (size is not None) and (size >= 0): if len(line) >= size: # truncate line self._rbuffer = line[size:] line = line[:size] truncated = True break n = size - len(line) else: n = self._bufsize if (linefeed_byte in line or (self._flags & self.FLAG_UNIVERSAL_NEWLINE and cr_byte in line)): break try: new_data = self._read(n) except EOFError: new_data = None if (new_data is None) or (len(new_data) == 0): self._rbuffer = bytes() self._pos += len(line) return line if self._flags & self.FLAG_BINARY else u(line) line += new_data self._realpos += len(new_data) # find the newline pos = line.find(linefeed_byte) if self._flags & self.FLAG_UNIVERSAL_NEWLINE: rpos = line.find(cr_byte) if (rpos >= 0) and (rpos < pos or pos < 0): pos = rpos if pos == -1: # we couldn't find a newline in the truncated string, return it self._pos += len(line) return line if self._flags & self.FLAG_BINARY else u(line) xpos = pos + 1 if (line[pos] == cr_byte_value and xpos < len(line) and line[xpos] == linefeed_byte_value): xpos += 1 # if the string was truncated, _rbuffer needs to have the string after # the newline character plus the truncated part of the line we stored # earlier in _rbuffer if truncated: self._rbuffer = line[xpos:] + self._rbuffer else: self._rbuffer = line[xpos:] lf = line[pos:xpos] line = line[:pos] + linefeed_byte if (len(self._rbuffer) == 0) and (lf == cr_byte): # we could read the line up to a '\r' and there could still be a # '\n' following that we read next time. note that and eat it. self._at_trailing_cr = True else: self._record_newline(lf) self._pos += len(line) return line if self._flags & self.FLAG_BINARY else u(line)
def get_text(self): """ Fetch a Unicode string from the stream. """ return u(self.get_string())