diff --git a/paramiko/sftp_client.py b/paramiko/sftp_client.py index ce6fbec..1caaf16 100644 --- a/paramiko/sftp_client.py +++ b/paramiko/sftp_client.py @@ -117,8 +117,10 @@ class SFTPClient(BaseSFTP): def _log(self, level, msg, *args): if isinstance(msg, list): for m in msg: - super(SFTPClient, self)._log(level, "[chan %s] " + m, *([self.sock.get_name()] + list(args))) + self._log(level, m, *args) else: + # escape '%' in msg (they could come from file or directory names) before logging + msg = msg.replace('%','%%') super(SFTPClient, self)._log(level, "[chan %s] " + msg, *([self.sock.get_name()] + list(args))) def close(self): diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst index cedc44f..16f3bb1 100644 --- a/sites/www/changelog.rst +++ b/sites/www/changelog.rst @@ -2,6 +2,8 @@ Changelog ========= +* :bug:`-` Fix logging error in sftp_client for filenames containing the '%' + character. Thanks to Antoine Brenner. * :bug:`308` Fix regression in dsskey.py that caused sporadic signature verification failures. Thanks to Chris Rose. * :support:`299` Use deterministic signatures for ECDSA keys for improved diff --git a/tests/test_sftp.py b/tests/test_sftp.py index 6417ac9..e0534eb 100755 --- a/tests/test_sftp.py +++ b/tests/test_sftp.py @@ -37,6 +37,7 @@ from paramiko.common import o777, o600, o666, o644 from tests.stub_sftp import StubServer, StubSFTPServer from tests.loop import LoopSocket from tests.util import test_path +import paramiko.util from paramiko.sftp_attr import SFTPAttributes ARTICLE = ''' @@ -732,7 +733,23 @@ class SFTPTest (unittest.TestCase): sftp.remove(target) + def test_N_file_with_percent(self): + """ + verify that we can create a file with a '%' in the filename. + ( it needs to be properly escaped by _log() ) + """ + self.assertTrue( paramiko.util.get_logger("paramiko").handlers, "This unit test requires logging to be enabled" ) + f = sftp.open(FOLDER + '/test%file', 'w') + try: + self.assertEqual(f.stat().st_size, 0) + finally: + f.close() + sftp.remove(FOLDER + '/test%file') + + if __name__ == '__main__': SFTPTest.init_loopback() + # logging is required by test_N_file_with_percent + paramiko.util.log_to_file('test_sftp.log') from unittest import main main()