From c01679de1f24ea114d4ce11e8ad8ab4adc3d6fd2 Mon Sep 17 00:00:00 2001 From: Phil Hudson Date: Thu, 11 Oct 2018 21:58:08 +0000 Subject: [PATCH] [Config] Prevent symlinked config files being overwritten If a user keeps the deluge config file under source control and symlinks to the config files in deluge config dir then when deluge saves config files it will replace the symlink with actual file. Using realpath will resolve these symlinks and file will be updated in the correct location. Use a temporary file for new config new before moving it to the resolved location. Co-authored-by: Calum Lind --- deluge/config.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/deluge/config.py b/deluge/config.py index 3061bf947..29f28e479 100644 --- a/deluge/config.py +++ b/deluge/config.py @@ -47,6 +47,7 @@ import os import shutil from codecs import getwriter from io import open +from tempfile import NamedTemporaryFile import six.moves.cPickle as pickle @@ -475,8 +476,11 @@ class Config(object): # Save the new config and make sure it's written to disk try: - log.debug('Saving new config file %s', filename + '.new') - with open(filename + '.new', 'wb') as _file: + with NamedTemporaryFile( + prefix=os.path.basename(filename) + '.', delete=False + ) as _file: + filename_tmp = _file.name + log.debug('Saving new config file %s', filename_tmp) json.dump(self.__version, getwriter('utf8')(_file), **JSON_FORMAT) json.dump(self.__config, getwriter('utf8')(_file), **JSON_FORMAT) _file.flush() @@ -485,6 +489,9 @@ class Config(object): log.error('Error writing new config file: %s', ex) return False + # Resolve symlinked config files before backing up and saving. + filename = os.path.realpath(filename) + # Make a backup of the old config try: log.debug('Backing up old config file to %s.bak', filename) @@ -495,8 +502,8 @@ class Config(object): # The new config file has been written successfully, so let's move it over # the existing one. try: - log.debug('Moving new config file %s to %s..', filename + '.new', filename) - shutil.move(filename + '.new', filename) + log.debug('Moving new config file %s to %s', filename_tmp, filename) + shutil.move(filename_tmp, filename) except IOError as ex: log.error('Error moving new config file: %s', ex) return False