diff --git a/daemon/volumes.go b/daemon/volumes.go index 16d00dd945..b389ad0b86 100644 --- a/daemon/volumes.go +++ b/daemon/volumes.go @@ -8,12 +8,12 @@ import ( "path/filepath" "sort" "strings" - "syscall" log "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/pkg/chrootarchive" "github.com/docker/docker/pkg/symlink" + "github.com/docker/docker/pkg/system" "github.com/docker/docker/volumes" ) @@ -385,15 +385,14 @@ func copyExistingContents(source, destination string) error { // copyOwnership copies the permissions and uid:gid of the source file // into the destination file func copyOwnership(source, destination string) error { - var stat syscall.Stat_t - - if err := syscall.Stat(source, &stat); err != nil { + stat, err := system.Stat(source) + if err != nil { return err } - if err := os.Chown(destination, int(stat.Uid), int(stat.Gid)); err != nil { + if err := os.Chown(destination, int(stat.Uid()), int(stat.Gid())); err != nil { return err } - return os.Chmod(destination, os.FileMode(stat.Mode)) + return os.Chmod(destination, os.FileMode(stat.Mode())) } diff --git a/pkg/archive/changes.go b/pkg/archive/changes.go index 9f16b76f16..f2ac2a3561 100644 --- a/pkg/archive/changes.go +++ b/pkg/archive/changes.go @@ -143,7 +143,7 @@ func Changes(layers []string, rw string) ([]Change, error) { type FileInfo struct { parent *FileInfo name string - stat *system.Stat + stat *system.Stat_t children map[string]*FileInfo capability []byte added bool diff --git a/pkg/system/lstat.go b/pkg/system/lstat.go index 9ef82d5523..6c1ed2e386 100644 --- a/pkg/system/lstat.go +++ b/pkg/system/lstat.go @@ -6,7 +6,7 @@ import ( "syscall" ) -func Lstat(path string) (*Stat, error) { +func Lstat(path string) (*Stat_t, error) { s := &syscall.Stat_t{} err := syscall.Lstat(path, s) if err != nil { diff --git a/pkg/system/lstat_windows.go b/pkg/system/lstat_windows.go index 213a7c7ade..801e756d8b 100644 --- a/pkg/system/lstat_windows.go +++ b/pkg/system/lstat_windows.go @@ -2,7 +2,7 @@ package system -func Lstat(path string) (*Stat, error) { +func Lstat(path string) (*Stat_t, error) { // should not be called on cli code path return nil, ErrNotSupportedPlatform } diff --git a/pkg/system/stat.go b/pkg/system/stat.go index 5d47494d21..186e85287d 100644 --- a/pkg/system/stat.go +++ b/pkg/system/stat.go @@ -4,7 +4,7 @@ import ( "syscall" ) -type Stat struct { +type Stat_t struct { mode uint32 uid uint32 gid uint32 @@ -13,30 +13,30 @@ type Stat struct { mtim syscall.Timespec } -func (s Stat) Mode() uint32 { +func (s Stat_t) Mode() uint32 { return s.mode } -func (s Stat) Uid() uint32 { +func (s Stat_t) Uid() uint32 { return s.uid } -func (s Stat) Gid() uint32 { +func (s Stat_t) Gid() uint32 { return s.gid } -func (s Stat) Rdev() uint64 { +func (s Stat_t) Rdev() uint64 { return s.rdev } -func (s Stat) Size() int64 { +func (s Stat_t) Size() int64 { return s.size } -func (s Stat) Mtim() syscall.Timespec { +func (s Stat_t) Mtim() syscall.Timespec { return s.mtim } -func (s Stat) GetLastModification() syscall.Timespec { +func (s Stat_t) GetLastModification() syscall.Timespec { return s.Mtim() } diff --git a/pkg/system/stat_linux.go b/pkg/system/stat_linux.go index 47cebef5cf..072728d0a1 100644 --- a/pkg/system/stat_linux.go +++ b/pkg/system/stat_linux.go @@ -4,11 +4,20 @@ import ( "syscall" ) -func fromStatT(s *syscall.Stat_t) (*Stat, error) { - return &Stat{size: s.Size, +func fromStatT(s *syscall.Stat_t) (*Stat_t, error) { + return &Stat_t{size: s.Size, mode: s.Mode, uid: s.Uid, gid: s.Gid, rdev: s.Rdev, mtim: s.Mtim}, nil } + +func Stat(path string) (*Stat_t, error) { + s := &syscall.Stat_t{} + err := syscall.Stat(path, s) + if err != nil { + return nil, err + } + return fromStatT(s) +} diff --git a/pkg/system/stat_unsupported.go b/pkg/system/stat_unsupported.go index c4d53e6cd6..66323eee21 100644 --- a/pkg/system/stat_unsupported.go +++ b/pkg/system/stat_unsupported.go @@ -6,8 +6,8 @@ import ( "syscall" ) -func fromStatT(s *syscall.Stat_t) (*Stat, error) { - return &Stat{size: s.Size, +func fromStatT(s *syscall.Stat_t) (*Stat_t, error) { + return &Stat_t{size: s.Size, mode: uint32(s.Mode), uid: s.Uid, gid: s.Gid, diff --git a/pkg/system/stat_windows.go b/pkg/system/stat_windows.go index 584e8940cc..42d29d6cca 100644 --- a/pkg/system/stat_windows.go +++ b/pkg/system/stat_windows.go @@ -7,6 +7,11 @@ import ( "syscall" ) -func fromStatT(s *syscall.Win32FileAttributeData) (*Stat, error) { +func fromStatT(s *syscall.Win32FileAttributeData) (*Stat_t, error) { return nil, errors.New("fromStatT should not be called on windows path") } + +func Stat(path string) (*Stat_t, error) { + // should not be called on cli code path + return nil, ErrNotSupportedPlatform +} diff --git a/utils/utils_daemon.go b/utils/utils_daemon.go index 9aee485fef..3f8f4d569f 100644 --- a/utils/utils_daemon.go +++ b/utils/utils_daemon.go @@ -3,14 +3,14 @@ package utils import ( + "github.com/docker/docker/pkg/system" "os" - "syscall" ) // IsFileOwner checks whether the current user is the owner of the given file. func IsFileOwner(f string) bool { - if fileInfo, err := os.Stat(f); err == nil && fileInfo != nil { - if stat, ok := fileInfo.Sys().(*syscall.Stat_t); ok && int(stat.Uid) == os.Getuid() { + if fileInfo, err := system.Stat(f); err == nil && fileInfo != nil { + if int(fileInfo.Uid()) == os.Getuid() { return true } } diff --git a/utils/utils_daemon_test.go b/utils/utils_daemon_test.go new file mode 100644 index 0000000000..e8361489b7 --- /dev/null +++ b/utils/utils_daemon_test.go @@ -0,0 +1,26 @@ +package utils + +import ( + "os" + "path" + "testing" +) + +func TestIsFileOwner(t *testing.T) { + var err error + var file *os.File + + if file, err = os.Create(path.Join(os.TempDir(), "testIsFileOwner")); err != nil { + t.Fatalf("failed to create file: %s", err) + } + file.Close() + + if ok := IsFileOwner(path.Join(os.TempDir(), "testIsFileOwner")); !ok { + t.Fatalf("User should be owner of file") + } + + if err = os.Remove(path.Join(os.TempDir(), "testIsFileOwner")); err != nil { + t.Fatalf("failed to remove file: %s", err) + } + +}