Merge pull request #2627 from thaJeztah/dont_overwrite_symlinks

Fix ConfigFile.Save() replacing symlink with file
This commit is contained in:
Tibor Vass 2020-07-16 12:06:34 +02:00 committed by GitHub
commit 8ff4f034aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 2 deletions

View File

@ -209,9 +209,15 @@ func (configFile *ConfigFile) Save() (retErr error) {
return errors.Wrap(err, "error closing temp file") return errors.Wrap(err, "error closing temp file")
} }
// Handle situation where the configfile is a symlink
cfgFile := configFile.Filename
if f, err := os.Readlink(cfgFile); err == nil {
cfgFile = f
}
// Try copying the current config file (if any) ownership and permissions // Try copying the current config file (if any) ownership and permissions
copyFilePermissions(configFile.Filename, temp.Name()) copyFilePermissions(cfgFile, temp.Name())
return os.Rename(temp.Name(), configFile.Filename) return os.Rename(temp.Name(), cfgFile)
} }
// ParseProxyConfig computes proxy configuration by retrieving the config for the provided host and // ParseProxyConfig computes proxy configuration by retrieving the config for the provided host and

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/cli/cli/config/types" "github.com/docker/cli/cli/config/types"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp" is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/fs"
"gotest.tools/v3/golden" "gotest.tools/v3/golden"
) )
@ -468,6 +469,33 @@ func TestSave(t *testing.T) {
assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}")) assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}"))
} }
func TestSaveWithSymlink(t *testing.T) {
dir := fs.NewDir(t, t.Name(), fs.WithFile("real-config.json", `{}`))
defer dir.Remove()
symLink := dir.Join("config.json")
realFile := dir.Join("real-config.json")
err := os.Symlink(realFile, symLink)
assert.NilError(t, err)
configFile := New(symLink)
err = configFile.Save()
assert.NilError(t, err)
fi, err := os.Lstat(symLink)
assert.NilError(t, err)
assert.Assert(t, fi.Mode()&os.ModeSymlink != 0, "expected %s to be a symlink", symLink)
cfg, err := ioutil.ReadFile(symLink)
assert.NilError(t, err)
assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}"))
cfg, err = ioutil.ReadFile(realFile)
assert.NilError(t, err)
assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}"))
}
func TestPluginConfig(t *testing.T) { func TestPluginConfig(t *testing.T) {
configFile := New("test-plugin") configFile := New("test-plugin")
defer os.Remove("test-plugin") defer os.Remove("test-plugin")