def _open(self, path, mode): """Open the remote file with given path name and mode.""" # Check mode. if "a" in mode: raise ftp_error.FTPIOError("append mode not supported") if mode not in ("r", "rb", "w", "wb"): raise ftp_error.FTPIOError("invalid mode '%s'" % mode) # Remember convenience variables instead of the mode itself. self._bin_mode = "b" in mode self._read_mode = "r" in mode # Select ASCII or binary mode. transfer_type = ("A", "I")[self._bin_mode] command = "TYPE %s" % transfer_type ftp_error._try_with_ioerror(self._session.voidcmd, command) # Make transfer command. command_type = ("STOR", "RETR")[self._read_mode] command = "%s %s" % (command_type, path) # Ensure we can process the raw line separators. # Force to binary regardless of transfer type. if not "b" in mode: mode = mode + "b" # Get connection and file object. self._conn = ftp_error._try_with_ioerror(self._session.transfercmd, command) self._fo = self._conn.makefile(mode) # This comes last so that `close` won't try to close `_FTPFile` # objects without `_conn` and `_fo` attributes in case of an error. self.closed = False
def close(self): """Close the `FTPFile`.""" if self.closed: return # Timeout value to restore, see below. # Statement works only before the try/finally statement, # otherwise Python raises an `UnboundLocalError`. old_timeout = self._session.sock.gettimeout() try: self._fo.close() self._fo = None ftp_error._try_with_ioerror(self._conn.close) # Set a timeout to prevent waiting until server timeout # if we have a server blocking here like in ticket #51. self._session.sock.settimeout(self._close_timeout) try: ftp_error._try_with_ioerror(self._session.voidresp) except ftp_error.FTPIOError, exception: # Ignore some errors, see tickets #51 and #17 at # http://ftputil.sschwarzer.net/trac/ticket/51 and # http://ftputil.sschwarzer.net/trac/ticket/17, # respectively. exception = str(exception) error_code = exception[:3] if exception.splitlines()[0] != "timed out" and error_code not in ("150", "426", "450", "451"): raise finally: # Restore timeout for socket of `_FTPFile`'s `ftplib.FTP` # object in case the connection is reused later. self._session.sock.settimeout(old_timeout) # If something went wrong before, the file is probably # defunct and subsequent calls to `close` won't help # either, so we consider the file closed for practical # purposes. self.closed = True