Bläddra i källkod

aufs compatibility

Signed-off-by: Viktor Stanchev <me@viktorstanchev.com>
Viktor Stanchev 9 år sedan
förälder
incheckning
b03d3232d1
1 ändrade filer med 80 tillägg och 5 borttagningar
  1. 80 5
      pkg/archive/archive.go

+ 80 - 5
pkg/archive/archive.go

@@ -47,6 +47,9 @@ type (
 		GIDMaps          []idtools.IDMap
 		GIDMaps          []idtools.IDMap
 		ChownOpts        *TarChownOptions
 		ChownOpts        *TarChownOptions
 		IncludeSourceDir bool
 		IncludeSourceDir bool
+		// When unpacking convert whiteouts and opaque dirs from aufs format to overlayfs format
+		// When packing convert whiteouts and opaque dirs from overlayfs format to aufs format
+		OverlayFormat bool
 		// When unpacking, specifies whether overwriting a directory with a
 		// When unpacking, specifies whether overwriting a directory with a
 		// non-directory is allowed and vice versa.
 		// non-directory is allowed and vice versa.
 		NoOverwriteDirNonDir bool
 		NoOverwriteDirNonDir bool
@@ -236,6 +239,11 @@ type tarAppender struct {
 	SeenFiles map[uint64]string
 	SeenFiles map[uint64]string
 	UIDMaps   []idtools.IDMap
 	UIDMaps   []idtools.IDMap
 	GIDMaps   []idtools.IDMap
 	GIDMaps   []idtools.IDMap
+
+	// `overlayFormat` controls whether to interpret character devices with numbers 0,0
+	// and directories with the attribute `trusted.overlay.opaque` using their overlayfs
+	// meanings and remap them to AUFS format
+	OverlayFormat bool
 }
 }
 
 
 // canonicalTarName provides a platform-independent and consistent posix-style
 // canonicalTarName provides a platform-independent and consistent posix-style
@@ -253,6 +261,7 @@ func canonicalTarName(name string, isDir bool) (string, error) {
 	return name, nil
 	return name, nil
 }
 }
 
 
+// addTarFile adds to the tar archive a file from `path` as `name`
 func (ta *tarAppender) addTarFile(path, name string) error {
 func (ta *tarAppender) addTarFile(path, name string) error {
 	fi, err := os.Lstat(path)
 	fi, err := os.Lstat(path)
 	if err != nil {
 	if err != nil {
@@ -323,6 +332,16 @@ func (ta *tarAppender) addTarFile(path, name string) error {
 		hdr.Gid = xGID
 		hdr.Gid = xGID
 	}
 	}
 
 
+	if ta.OverlayFormat {
+		// convert whiteouts to AUFS format
+		if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 {
+			// we just rename the file and make it normal
+			hdr.Name = WhiteoutPrefix + hdr.Name
+			hdr.Mode = 0600
+			hdr.Typeflag = tar.TypeReg
+		}
+	}
+
 	if err := ta.TarWriter.WriteHeader(hdr); err != nil {
 	if err := ta.TarWriter.WriteHeader(hdr); err != nil {
 		return err
 		return err
 	}
 	}
@@ -346,6 +365,30 @@ func (ta *tarAppender) addTarFile(path, name string) error {
 		}
 		}
 	}
 	}
 
 
+	if ta.OverlayFormat {
+		// convert opaque dirs to AUFS format by writing an empty file with the prefix
+		opaque, _ := system.Lgetxattr(path, "trusted.overlay.opaque")
+		if opaque != nil && len(opaque) == 1 && opaque[0] == 'y' {
+			// create a header for the whiteout file
+			// it should inherit some properties from the parent, but be a regular file
+			whHdr := &tar.Header{
+				Typeflag:   tar.TypeReg,
+				Mode:       hdr.Mode & int64(os.ModePerm),
+				Name:       filepath.Join(name, WhiteoutOpaqueDir),
+				Size:       0,
+				Uid:        hdr.Uid,
+				Uname:      hdr.Uname,
+				Gid:        hdr.Gid,
+				Gname:      hdr.Gname,
+				AccessTime: hdr.AccessTime,
+				ChangeTime: hdr.ChangeTime,
+			}
+			if err := ta.TarWriter.WriteHeader(whHdr); err != nil {
+				return err
+			}
+		}
+	}
+
 	return nil
 	return nil
 }
 }
 
 
@@ -501,11 +544,12 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
 
 
 	go func() {
 	go func() {
 		ta := &tarAppender{
 		ta := &tarAppender{
-			TarWriter: tar.NewWriter(compressWriter),
-			Buffer:    pools.BufioWriter32KPool.Get(nil),
-			SeenFiles: make(map[uint64]string),
-			UIDMaps:   options.UIDMaps,
-			GIDMaps:   options.GIDMaps,
+			TarWriter:     tar.NewWriter(compressWriter),
+			Buffer:        pools.BufioWriter32KPool.Get(nil),
+			SeenFiles:     make(map[uint64]string),
+			UIDMaps:       options.UIDMaps,
+			GIDMaps:       options.GIDMaps,
+			OverlayFormat: options.OverlayFormat,
 		}
 		}
 
 
 		defer func() {
 		defer func() {
@@ -766,6 +810,37 @@ loop:
 			hdr.Gid = xGID
 			hdr.Gid = xGID
 		}
 		}
 
 
+		base := filepath.Base(path)
+		dir := filepath.Dir(path)
+
+		if options.OverlayFormat {
+			// if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay
+			if base == WhiteoutOpaqueDir {
+				if err := syscall.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0); err != nil {
+					return err
+				}
+
+				// don't write the file itself
+				continue
+			}
+
+			// if a file was deleted and we are using overlay, we need to create a character device
+			if strings.HasPrefix(base, WhiteoutPrefix) {
+				originalBase := base[len(WhiteoutPrefix):]
+				originalPath := filepath.Join(dir, originalBase)
+
+				if err := syscall.Mknod(originalPath, syscall.S_IFCHR, 0); err != nil {
+					return err
+				}
+				if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil {
+					return err
+				}
+
+				// don't write the file itself
+				continue
+			}
+		}
+
 		if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown, options.ChownOpts); err != nil {
 		if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown, options.ChownOpts); err != nil {
 			return err
 			return err
 		}
 		}