Refactor pkg/archive with a platform-independent stat struct

pkg/archive contains code both invoked from cli (cross platform) and
daemon (linux only) and Unix-specific dependencies break compilation on
Windows. We extracted those stat-related funcs into platform specific
implementations at pkg/system and added unit tests.

Signed-off-by: Ahmet Alp Balkan <ahmetb@microsoft.com>
This commit is contained in:
Ahmet Alp Balkan 2014-11-13 12:36:05 -08:00
parent 515e7481de
commit 718066ad61
13 changed files with 209 additions and 65 deletions

View file

@ -135,7 +135,7 @@ func Changes(layers []string, rw string) ([]Change, error) {
type FileInfo struct {
parent *FileInfo
name string
stat syscall.Stat_t
stat *system.Stat
children map[string]*FileInfo
capability []byte
added bool
@ -168,7 +168,7 @@ func (info *FileInfo) path() string {
}
func (info *FileInfo) isDir() bool {
return info.parent == nil || info.stat.Mode&syscall.S_IFDIR == syscall.S_IFDIR
return info.parent == nil || info.stat.Mode()&syscall.S_IFDIR == syscall.S_IFDIR
}
func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
@ -199,21 +199,21 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
oldChild, _ := oldChildren[name]
if oldChild != nil {
// change?
oldStat := &oldChild.stat
newStat := &newChild.stat
oldStat := oldChild.stat
newStat := newChild.stat
// Note: We can't compare inode or ctime or blocksize here, because these change
// when copying a file into a container. However, that is not generally a problem
// because any content change will change mtime, and any status change should
// be visible when actually comparing the stat fields. The only time this
// breaks down is if some code intentionally hides a change by setting
// back mtime
if oldStat.Mode != newStat.Mode ||
oldStat.Uid != newStat.Uid ||
oldStat.Gid != newStat.Gid ||
oldStat.Rdev != newStat.Rdev ||
if oldStat.Mode() != newStat.Mode() ||
oldStat.Uid() != newStat.Uid() ||
oldStat.Gid() != newStat.Gid() ||
oldStat.Rdev() != newStat.Rdev() ||
// Don't look at size for dirs, its not a good measure of change
(oldStat.Size != newStat.Size && oldStat.Mode&syscall.S_IFDIR != syscall.S_IFDIR) ||
!sameFsTimeSpec(system.GetLastModification(oldStat), system.GetLastModification(newStat)) ||
(oldStat.Size() != newStat.Size() && oldStat.Mode()&syscall.S_IFDIR != syscall.S_IFDIR) ||
!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) ||
bytes.Compare(oldChild.capability, newChild.capability) != 0 {
change := Change{
Path: newChild.path(),
@ -269,14 +269,6 @@ func newRootFileInfo() *FileInfo {
return root
}
func lstat(path string) (*stat, error) {
s, err := system.Lstat(path)
if err != nil {
return nil, err
}
return fromStatT(s), nil
}
func collectFileInfo(sourceDir string) (*FileInfo, error) {
root := newRootFileInfo()
@ -307,7 +299,7 @@ func collectFileInfo(sourceDir string) (*FileInfo, error) {
parent: parent,
}
s, err := lstat(path)
s, err := system.Lstat(path)
if err != nil {
return err
}
@ -369,14 +361,6 @@ func ChangesSize(newDir string, changes []Change) int64 {
return size
}
func major(device uint64) uint64 {
return (device >> 8) & 0xfff
}
func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00)
}
// ExportChanges produces an Archive from the provided changes, relative to dir.
func ExportChanges(dir string, changes []Change) (Archive, error) {
reader, writer := io.Pipe()