Selaa lähdekoodia

Merge pull request #3845 from alexlarsson/tar-caps

Implement capabilitiy bit storage in layers
Victor Vieux 11 vuotta sitten
vanhempi
commit
a6909084e9
4 muutettua tiedostoa jossa 84 lisäystä ja 5 poistoa
  1. 13 0
      archive/archive.go
  2. 10 5
      archive/changes.go
  3. 53 0
      archive/stat_linux.go
  4. 8 0
      archive/stat_unsupported.go

+ 13 - 0
archive/archive.go

@@ -165,6 +165,13 @@ func addTarFile(path, name string, tw *tar.Writer) error {
 			hdr.Devmajor = int64(major(uint64(stat.Rdev)))
 			hdr.Devmajor = int64(major(uint64(stat.Rdev)))
 			hdr.Devminor = int64(minor(uint64(stat.Rdev)))
 			hdr.Devminor = int64(minor(uint64(stat.Rdev)))
 		}
 		}
+
+	}
+
+	capability, _ := Lgetxattr(path, "security.capability")
+	if capability != nil {
+		hdr.Xattrs = make(map[string]string)
+		hdr.Xattrs["security.capability"] = string(capability)
 	}
 	}
 
 
 	if err := tw.WriteHeader(hdr); err != nil {
 	if err := tw.WriteHeader(hdr); err != nil {
@@ -251,6 +258,12 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader) e
 		return err
 		return err
 	}
 	}
 
 
+	for key, value := range hdr.Xattrs {
+		if err := Lsetxattr(path, key, []byte(value), 0); err != nil {
+			return err
+		}
+	}
+
 	// There is no LChmod, so ignore mode for symlink. Also, this
 	// There is no LChmod, so ignore mode for symlink. Also, this
 	// must happen after chown, as that can modify the file mode
 	// must happen after chown, as that can modify the file mode
 	if hdr.Typeflag != tar.TypeSymlink {
 	if hdr.Typeflag != tar.TypeSymlink {

+ 10 - 5
archive/changes.go

@@ -1,6 +1,7 @@
 package archive
 package archive
 
 
 import (
 import (
+	"bytes"
 	"code.google.com/p/go/src/pkg/archive/tar"
 	"code.google.com/p/go/src/pkg/archive/tar"
 	"fmt"
 	"fmt"
 	"github.com/dotcloud/docker/utils"
 	"github.com/dotcloud/docker/utils"
@@ -126,10 +127,11 @@ func Changes(layers []string, rw string) ([]Change, error) {
 }
 }
 
 
 type FileInfo struct {
 type FileInfo struct {
-	parent   *FileInfo
-	name     string
-	stat     syscall.Stat_t
-	children map[string]*FileInfo
+	parent     *FileInfo
+	name       string
+	stat       syscall.Stat_t
+	children   map[string]*FileInfo
+	capability []byte
 }
 }
 
 
 func (root *FileInfo) LookUp(path string) *FileInfo {
 func (root *FileInfo) LookUp(path string) *FileInfo {
@@ -200,7 +202,8 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
 				oldStat.Rdev != newStat.Rdev ||
 				oldStat.Rdev != newStat.Rdev ||
 				// Don't look at size for dirs, its not a good measure of change
 				// 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) ||
 				(oldStat.Size != newStat.Size && oldStat.Mode&syscall.S_IFDIR != syscall.S_IFDIR) ||
-				!sameFsTimeSpec(getLastModification(oldStat), getLastModification(newStat)) {
+				!sameFsTimeSpec(getLastModification(oldStat), getLastModification(newStat)) ||
+				bytes.Compare(oldChild.capability, newChild.capability) != 0 {
 				change := Change{
 				change := Change{
 					Path: newChild.path(),
 					Path: newChild.path(),
 					Kind: ChangeModify,
 					Kind: ChangeModify,
@@ -275,6 +278,8 @@ func collectFileInfo(sourceDir string) (*FileInfo, error) {
 			return err
 			return err
 		}
 		}
 
 
+		info.capability, _ = Lgetxattr(path, "security.capability")
+
 		parent.children[info.name] = info
 		parent.children[info.name] = info
 
 
 		return nil
 		return nil

+ 53 - 0
archive/stat_linux.go

@@ -37,3 +37,56 @@ func UtimesNano(path string, ts []syscall.Timespec) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+// Returns a nil slice and nil error if the xattr is not set
+func Lgetxattr(path string, attr string) ([]byte, error) {
+	pathBytes, err := syscall.BytePtrFromString(path)
+	if err != nil {
+		return nil, err
+	}
+	attrBytes, err := syscall.BytePtrFromString(attr)
+	if err != nil {
+		return nil, err
+	}
+
+	dest := make([]byte, 128)
+	destBytes := unsafe.Pointer(&dest[0])
+	sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
+	if errno == syscall.ENODATA {
+		return nil, nil
+	}
+	if errno == syscall.ERANGE {
+		dest = make([]byte, sz)
+		destBytes := unsafe.Pointer(&dest[0])
+		sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
+	}
+	if errno != 0 {
+		return nil, errno
+	}
+
+	return dest[:sz], nil
+}
+
+var _zero uintptr
+
+func Lsetxattr(path string, attr string, data []byte, flags int) error {
+	pathBytes, err := syscall.BytePtrFromString(path)
+	if err != nil {
+		return err
+	}
+	attrBytes, err := syscall.BytePtrFromString(attr)
+	if err != nil {
+		return err
+	}
+	var dataBytes unsafe.Pointer
+	if len(data) > 0 {
+		dataBytes = unsafe.Pointer(&data[0])
+	} else {
+		dataBytes = unsafe.Pointer(&_zero)
+	}
+	_, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0)
+	if errno != 0 {
+		return errno
+	}
+	return nil
+}

+ 8 - 0
archive/stat_unsupported.go

@@ -19,3 +19,11 @@ func LUtimesNano(path string, ts []syscall.Timespec) error {
 func UtimesNano(path string, ts []syscall.Timespec) error {
 func UtimesNano(path string, ts []syscall.Timespec) error {
 	return ErrNotImplemented
 	return ErrNotImplemented
 }
 }
+
+func Lgetxattr(path string, attr string) ([]byte, error) {
+	return nil, ErrNotImplemented
+}
+
+func Lsetxattr(path string, attr string, data []byte, flags int) error {
+	return ErrNotImplemented
+}