From cda11e03a5c1b1cab6a6e628807462feb1f24cb7 Mon Sep 17 00:00:00 2001 From: Alberto Bertogli Date: Sun, 16 Oct 2016 14:19:41 +0100 Subject: [PATCH] safeio: Preserve file ownership This patch makes safeio preserve file ownership. This is specially useful when using command-line utilities as root, but the files they change are owned by a different user. --- internal/safeio/safeio.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/internal/safeio/safeio.go b/internal/safeio/safeio.go index e8cce16..8eba2a6 100644 --- a/internal/safeio/safeio.go +++ b/internal/safeio/safeio.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" "path" + "syscall" ) // WriteFile writes data to a file named by filename, atomically. @@ -24,12 +25,20 @@ func WriteFile(filename string, data []byte, perm os.FileMode) error { return err } - if err = os.Chmod(tmpf.Name(), perm); err != nil { + if err = tmpf.Chmod(perm); err != nil { tmpf.Close() os.Remove(tmpf.Name()) return err } + if uid, gid := getOwner(filename); uid >= 0 { + if err = tmpf.Chown(uid, gid); err != nil { + tmpf.Close() + os.Remove(tmpf.Name()) + return err + } + } + if _, err = tmpf.Write(data); err != nil { tmpf.Close() os.Remove(tmpf.Name()) @@ -43,3 +52,17 @@ func WriteFile(filename string, data []byte, perm os.FileMode) error { return os.Rename(tmpf.Name(), filename) } + +func getOwner(fname string) (uid, gid int) { + uid = -1 + gid = -1 + stat, err := os.Stat(fname) + if err == nil { + if sysstat, ok := stat.Sys().(*syscall.Stat_t); ok { + uid = int(sysstat.Uid) + gid = int(sysstat.Gid) + } + } + + return +}