Skip to content
This repository was archived by the owner on Oct 13, 2023. It is now read-only.

Commit 021a604

Browse files
authored
Merge pull request #2631 from cpuguy83/19.03_handle_close_error_on_save
[19.03] handle close error on save Upstream-commit: 5e05ef345905cecc0d42141608216e7c117462e4 Component: cli
2 parents f19d902 + 4e3a563 commit 021a604

3 files changed

Lines changed: 58 additions & 3 deletions

File tree

components/cli/cli/config/configfile/file.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/docker/cli/cli/config/credentials"
1414
"github.com/docker/cli/cli/config/types"
1515
"github.com/pkg/errors"
16+
"github.com/sirupsen/logrus"
1617
)
1718

1819
const (
@@ -177,7 +178,7 @@ func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
177178
}
178179

179180
// Save encodes and writes out all the authorization information
180-
func (configFile *ConfigFile) Save() error {
181+
func (configFile *ConfigFile) Save() (retErr error) {
181182
if configFile.Filename == "" {
182183
return errors.Errorf("Can't save config with empty filename")
183184
}
@@ -190,12 +191,26 @@ func (configFile *ConfigFile) Save() error {
190191
if err != nil {
191192
return err
192193
}
194+
defer func() {
195+
temp.Close()
196+
if retErr != nil {
197+
if err := os.Remove(temp.Name()); err != nil {
198+
logrus.WithError(err).WithField("file", temp.Name()).Debug("Error cleaning up temp file")
199+
}
200+
}
201+
}()
202+
193203
err = configFile.SaveToWriter(temp)
194-
temp.Close()
195204
if err != nil {
196-
os.Remove(temp.Name())
197205
return err
198206
}
207+
208+
if err := temp.Close(); err != nil {
209+
return errors.Wrap(err, "error closing temp file")
210+
}
211+
212+
// Try copying the current config file (if any) ownership and permissions
213+
copyFilePermissions(configFile.Filename, temp.Name())
199214
return os.Rename(temp.Name(), configFile.Filename)
200215
}
201216

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// +build !windows
2+
3+
package configfile
4+
5+
import (
6+
"os"
7+
"syscall"
8+
)
9+
10+
// copyFilePermissions copies file ownership and permissions from "src" to "dst",
11+
// ignoring any error during the process.
12+
func copyFilePermissions(src, dst string) {
13+
var (
14+
mode os.FileMode = 0600
15+
uid, gid int
16+
)
17+
18+
fi, err := os.Stat(src)
19+
if err != nil {
20+
return
21+
}
22+
if fi.Mode().IsRegular() {
23+
mode = fi.Mode()
24+
}
25+
if err := os.Chmod(dst, mode); err != nil {
26+
return
27+
}
28+
29+
uid = int(fi.Sys().(*syscall.Stat_t).Uid)
30+
gid = int(fi.Sys().(*syscall.Stat_t).Gid)
31+
32+
if uid > 0 && gid > 0 {
33+
_ = os.Chown(dst, uid, gid)
34+
}
35+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package configfile
2+
3+
func copyFilePermissions(src, dst string) {
4+
// TODO implement for Windows
5+
}

0 commit comments

Comments
 (0)