Skip to content

Commit 6a89348

Browse files
committed
configFile: directly write changes to configFile
In some situations, the config.json is volumed from somewhere else and the file is busy, move can't be performed on this file and configFile.Save() will be failed because it's trying to move another file to this file. This will write changes directly to the file. For concurrency issues, it will lock the file using flock and release after write. Signed-off-by: Seena Fallah <seenafallah@gmail.com>
1 parent 2291f61 commit 6a89348

2 files changed

Lines changed: 19 additions & 53 deletions

File tree

cli/config/configfile/file.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os"
1010
"path/filepath"
1111
"strings"
12+
"syscall"
1213

1314
"github.com/docker/cli/cli/config/credentials"
1415
"github.com/docker/cli/cli/config/types"
@@ -194,37 +195,37 @@ func (configFile *ConfigFile) Save() (retErr error) {
194195
if err := os.MkdirAll(dir, 0700); err != nil {
195196
return err
196197
}
197-
temp, err := ioutil.TempFile(dir, filepath.Base(configFile.Filename))
198+
199+
// Handle situation where the configfile is a symlink
200+
cfgFile := configFile.Filename
201+
if f, err := os.Readlink(cfgFile); err == nil {
202+
cfgFile = f
203+
}
204+
205+
f, err := os.OpenFile(cfgFile, os.O_CREATE|os.O_WRONLY, 0600)
198206
if err != nil {
199207
return err
200208
}
201209
defer func() {
202-
temp.Close()
203-
if retErr != nil {
204-
if err := os.Remove(temp.Name()); err != nil {
205-
logrus.WithError(err).WithField("file", temp.Name()).Debug("Error cleaning up temp file")
206-
}
210+
err = syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
211+
if err != nil {
212+
logrus.WithError(err).WithField("file", cfgFile).Error("Unable to unlock config file")
207213
}
214+
f.Close()
208215
}()
209216

210-
err = configFile.SaveToWriter(temp)
217+
err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX)
211218
if err != nil {
219+
logrus.WithError(err).WithField("file", cfgFile).Error("Unable to lock config file")
212220
return err
213221
}
214222

215-
if err := temp.Close(); err != nil {
216-
return errors.Wrap(err, "error closing temp file")
217-
}
218-
219-
// Handle situation where the configfile is a symlink
220-
cfgFile := configFile.Filename
221-
if f, err := os.Readlink(cfgFile); err == nil {
222-
cfgFile = f
223+
err = f.Truncate(0)
224+
if err != nil {
225+
return err
223226
}
224227

225-
// Try copying the current config file (if any) ownership and permissions
226-
copyFilePermissions(cfgFile, temp.Name())
227-
return os.Rename(temp.Name(), cfgFile)
228+
return configFile.SaveToWriter(f)
228229
}
229230

230231
// ParseProxyConfig computes proxy configuration by retrieving the config for the provided host and

cli/config/configfile/file_unix.go

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)