From 6cb584f4556a41e94c874dbeabef926e321f8e1f Mon Sep 17 00:00:00 2001 From: albertony <12441419+albertony@users.noreply.github.com> Date: Tue, 4 Apr 2023 14:35:53 +0200 Subject: [PATCH] config: do not overwrite config file symbolic link - fixes #6754 --- docs/content/docs.md | 8 ++++++++ fs/config/configfile/configfile.go | 28 +++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/docs/content/docs.md b/docs/content/docs.md index 3b836490c..941c9c842 100644 --- a/docs/content/docs.md +++ b/docs/content/docs.md @@ -956,6 +956,14 @@ the new file. Then it will rename the existing file to a temporary name as backup. Next, rclone will rename the new file to the correct name, before finally cleaning up by deleting the backup file. +If the configuration file path used by rclone is a symbolic link, then +this will be evaluated and rclone will write to the resolved path, instead +of overwriting the symbolic link. Temporary files used in the process +(described above) will be written to the same parent directory as that +of the resolved configuration file, but if this directory is also a +symbolic link it will not be resolved and the temporary files will be +written to the location of the directory symbolic link. + ### --contimeout=TIME ### Set the connection timeout. This should be in go time format which diff --git a/fs/config/configfile/configfile.go b/fs/config/configfile/configfile.go index 30aa8227c..659df705d 100644 --- a/fs/config/configfile/configfile.go +++ b/fs/config/configfile/configfile.go @@ -106,12 +106,30 @@ func (s *Storage) Save() error { if configPath == "" { return fmt.Errorf("failed to save config file, path is empty") } - dir, name := filepath.Split(configPath) - err := file.MkdirAll(dir, os.ModePerm) + configDir, configName := filepath.Split(configPath) + + info, err := os.Lstat(configPath) + if err != nil { + if !os.IsNotExist(err) { + return fmt.Errorf("failed to resolve config file path: %w", err) + } + } else { + if info.Mode()&os.ModeSymlink != 0 { + configPath, err = os.Readlink(configPath) + if err != nil { + return fmt.Errorf("failed to resolve config file symbolic link: %w", err) + } + if !filepath.IsAbs(configPath) { + configPath = filepath.Join(configDir, configPath) + } + configDir = filepath.Dir(configPath) + } + } + err = file.MkdirAll(configDir, os.ModePerm) if err != nil { return fmt.Errorf("failed to create config directory: %w", err) } - f, err := os.CreateTemp(dir, name) + f, err := os.CreateTemp(configDir, configName) if err != nil { return fmt.Errorf("failed to create temp file for new config: %w", err) } @@ -138,7 +156,7 @@ func (s *Storage) Save() error { } var fileMode os.FileMode = 0600 - info, err := os.Stat(configPath) + info, err = os.Stat(configPath) if err != nil { fs.Debugf(nil, "Using default permissions for config file: %v", fileMode) } else if info.Mode() != fileMode { @@ -153,7 +171,7 @@ func (s *Storage) Save() error { fs.Errorf(nil, "Failed to set permissions on config file: %v", err) } - fbackup, err := os.CreateTemp(dir, name+".old") + fbackup, err := os.CreateTemp(configDir, configName+".old") if err != nil { return fmt.Errorf("failed to create temp file for old config backup: %w", err) }