add changes to maintain perms and owner of logfile
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package lumberjack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func chown(_ string, _ os.FileInfo) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package lumberjack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// os_Chown is a var so we can mock it out during tests.
|
||||||
|
var os_Chown = os.Chown
|
||||||
|
|
||||||
|
func chown(name string, info os.FileInfo) error {
|
||||||
|
f, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, info.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
stat := info.Sys().(*syscall.Stat_t)
|
||||||
|
return os_Chown(name, int(stat.Uid), int(stat.Gid))
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package lumberjack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMaintainOwner(t *testing.T) {
|
||||||
|
fakeC := fakeChown{}
|
||||||
|
os_Chown = fakeC.Set
|
||||||
|
os_Stat = fakeStat
|
||||||
|
defer func() {
|
||||||
|
os_Chown = os.Chown
|
||||||
|
os_Stat = os.Stat
|
||||||
|
}()
|
||||||
|
currentTime = fakeTime
|
||||||
|
dir := makeTempDir("TestMaintainOwner", t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
filename := logFile(dir)
|
||||||
|
|
||||||
|
l := &Logger{
|
||||||
|
Filename: filename,
|
||||||
|
MaxBackups: 1,
|
||||||
|
MaxSize: 100, // megabytes
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
b := []byte("boo!")
|
||||||
|
n, err := l.Write(b)
|
||||||
|
isNil(err, t)
|
||||||
|
equals(len(b), n, t)
|
||||||
|
|
||||||
|
newFakeTime()
|
||||||
|
|
||||||
|
err = l.Rotate()
|
||||||
|
isNil(err, t)
|
||||||
|
|
||||||
|
equals(555, fakeC.uid, t)
|
||||||
|
equals(666, fakeC.gid, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeChown struct {
|
||||||
|
name string
|
||||||
|
uid int
|
||||||
|
gid int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeChown) Set(name string, uid, gid int) error {
|
||||||
|
f.name = name
|
||||||
|
f.uid = uid
|
||||||
|
f.gid = gid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fakeStat(name string) (os.FileInfo, error) {
|
||||||
|
info, err := os.Stat(name)
|
||||||
|
if err != nil {
|
||||||
|
return info, err
|
||||||
|
}
|
||||||
|
stat := info.Sys().(*syscall.Stat_t)
|
||||||
|
stat.Uid = 555
|
||||||
|
stat.Gid = 666
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
+14
-3
@@ -101,6 +101,9 @@ var (
|
|||||||
// currentTime exists so it can be mocked out by tests.
|
// currentTime exists so it can be mocked out by tests.
|
||||||
currentTime = time.Now
|
currentTime = time.Now
|
||||||
|
|
||||||
|
// os_Stat exists so it can be mocked out by tests.
|
||||||
|
os_Stat = os.Stat
|
||||||
|
|
||||||
// megabyte is the conversion factor between MaxSize and bytes. It is a
|
// megabyte is the conversion factor between MaxSize and bytes. It is a
|
||||||
// variable so tests can mock it out and not need to write megabytes of data
|
// variable so tests can mock it out and not need to write megabytes of data
|
||||||
// to disk.
|
// to disk.
|
||||||
@@ -191,19 +194,27 @@ func (l *Logger) openNew() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
name := l.filename()
|
name := l.filename()
|
||||||
_, err = os.Stat(name)
|
mode := os.FileMode(0644)
|
||||||
|
info, err := os_Stat(name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
// Copy the mode off the old logfile.
|
||||||
|
mode = info.Mode()
|
||||||
// move the existing file
|
// move the existing file
|
||||||
newname := backupName(name, l.LocalTime)
|
newname := backupName(name, l.LocalTime)
|
||||||
if err := os.Rename(name, newname); err != nil {
|
if err := os.Rename(name, newname); err != nil {
|
||||||
return fmt.Errorf("can't rename log file: %s", err)
|
return fmt.Errorf("can't rename log file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is a no-op anywhere but linux
|
||||||
|
if err := chown(name, info); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use truncate here because this should only get called when we've moved
|
// we use truncate here because this should only get called when we've moved
|
||||||
// the file ourselves. if someone else creates the file in the meantime,
|
// the file ourselves. if someone else creates the file in the meantime,
|
||||||
// just wipe out the contents.
|
// just wipe out the contents.
|
||||||
f, err := os.OpenFile(l.filename(), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
|
f, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't open new logfile: %s", err)
|
return fmt.Errorf("can't open new logfile: %s", err)
|
||||||
}
|
}
|
||||||
@@ -234,7 +245,7 @@ func backupName(name string, local bool) string {
|
|||||||
// put it over the MaxSize, a new file is created.
|
// put it over the MaxSize, a new file is created.
|
||||||
func (l *Logger) openExistingOrNew(writeLen int) error {
|
func (l *Logger) openExistingOrNew(writeLen int) error {
|
||||||
filename := l.filename()
|
filename := l.filename()
|
||||||
info, err := os.Stat(filename)
|
info, err := os_Stat(filename)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return l.openNew()
|
return l.openNew()
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-1
@@ -493,7 +493,6 @@ func TestRotate(t *testing.T) {
|
|||||||
existsWithLen(filename2, n, t)
|
existsWithLen(filename2, n, t)
|
||||||
existsWithLen(filename, 0, t)
|
existsWithLen(filename, 0, t)
|
||||||
fileCount(dir, 2, t)
|
fileCount(dir, 2, t)
|
||||||
|
|
||||||
newFakeTime()
|
newFakeTime()
|
||||||
|
|
||||||
err = l.Rotate()
|
err = l.Rotate()
|
||||||
@@ -574,6 +573,43 @@ localtime = true`[1:]
|
|||||||
equals(0, len(md.Undecoded()), t)
|
equals(0, len(md.Undecoded()), t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMaintainMode(t *testing.T) {
|
||||||
|
currentTime = fakeTime
|
||||||
|
dir := makeTempDir("TestMaintainMode", t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
filename := logFile(dir)
|
||||||
|
|
||||||
|
mode := os.FileMode(0770)
|
||||||
|
f, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, mode)
|
||||||
|
isNil(err, t)
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
l := &Logger{
|
||||||
|
Filename: filename,
|
||||||
|
MaxBackups: 1,
|
||||||
|
MaxSize: 100, // megabytes
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
b := []byte("boo!")
|
||||||
|
n, err := l.Write(b)
|
||||||
|
isNil(err, t)
|
||||||
|
equals(len(b), n, t)
|
||||||
|
|
||||||
|
newFakeTime()
|
||||||
|
|
||||||
|
err = l.Rotate()
|
||||||
|
isNil(err, t)
|
||||||
|
|
||||||
|
filename2 := backupFile(dir)
|
||||||
|
info, err := os.Stat(filename)
|
||||||
|
isNil(err, t)
|
||||||
|
info2, err := os.Stat(filename2)
|
||||||
|
isNil(err, t)
|
||||||
|
equals(mode, info.Mode(), t)
|
||||||
|
equals(mode, info2.Mode(), t)
|
||||||
|
}
|
||||||
|
|
||||||
// makeTempDir creates a file with a semi-unique name in the OS temp directory.
|
// makeTempDir creates a file with a semi-unique name in the OS temp directory.
|
||||||
// It should be based on the name of the test, to keep parallel tests from
|
// It should be based on the name of the test, to keep parallel tests from
|
||||||
// colliding, and must be cleaned up after the test is finished.
|
// colliding, and must be cleaned up after the test is finished.
|
||||||
|
|||||||
Reference in New Issue
Block a user