git » chasquid » commit cda11e0

safeio: Preserve file ownership

author Alberto Bertogli
2016-10-16 13:19:41 UTC
committer Alberto Bertogli
2016-10-21 21:18:53 UTC
parent ac7f32c2ced97915badb864bf7df69c539e5340e

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 +24 -1

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
+}