Browse Source

Copy aufs hardlinks to top layer

Show warning if old method is used.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Tonis Tiigi 9 năm trước cách đây
mục cha
commit
ef05b83417
2 tập tin đã thay đổi với 95 bổ sung3 xóa
  1. 13 3
      daemon/graphdriver/aufs/aufs.go
  2. 82 0
      daemon/graphdriver/aufs/aufs_test.go

+ 13 - 3
daemon/graphdriver/aufs/aufs.go

@@ -360,10 +360,20 @@ func (a *Driver) Diff(id, parent string) (archive.Archive, error) {
 }
 
 func (a *Driver) applyDiff(id string, diff archive.Reader) error {
-	return chrootarchive.UntarUncompressed(diff, path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
+	dir := path.Join(a.rootPath(), "diff", id)
+	if err := chrootarchive.UntarUncompressed(diff, dir, &archive.TarOptions{
 		UIDMaps: a.uidMaps,
 		GIDMaps: a.gidMaps,
-	})
+	}); err != nil {
+		return err
+	}
+
+	// show invalid whiteouts warning.
+	files, err := ioutil.ReadDir(path.Join(dir, archive.WhiteoutLinkDir))
+	if err == nil && len(files) > 0 {
+		logrus.Warnf("Archive contains aufs hardlink references that are not supported.")
+	}
+	return nil
 }
 
 // DiffSize calculates the changes between the specified id
@@ -493,7 +503,7 @@ func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err erro
 		}
 
 		if firstMount {
-			opts := "dio,xino=/dev/shm/aufs.xino"
+			opts := "dio,noplink,xino=/dev/shm/aufs.xino"
 			if useDirperm() {
 				opts += ",dirperm1"
 			}

+ 82 - 0
daemon/graphdriver/aufs/aufs_test.go

@@ -638,6 +638,88 @@ func TestApplyDiff(t *testing.T) {
 	}
 }
 
+func TestHardlinks(t *testing.T) {
+	// Copy 2 layers that have linked files to new layers and check if hardlink are preserved
+	d := newDriver(t)
+	defer os.RemoveAll(tmp)
+	defer d.Cleanup()
+
+	origFile := "test_file"
+	linkedFile := "linked_file"
+
+	if err := d.Create("source-1", ""); err != nil {
+		t.Fatal(err)
+	}
+
+	mountPath, err := d.Get("source-1", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	f, err := os.Create(path.Join(mountPath, origFile))
+	if err != nil {
+		t.Fatal(err)
+	}
+	f.Close()
+
+	layerTar1, err := d.Diff("source-1", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := d.Create("source-2", "source-1"); err != nil {
+		t.Fatal(err)
+	}
+
+	mountPath, err = d.Get("source-2", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := os.Link(path.Join(mountPath, origFile), path.Join(mountPath, linkedFile)); err != nil {
+		t.Fatal(err)
+	}
+
+	layerTar2, err := d.Diff("source-2", "source-1")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := d.Create("target-1", ""); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := d.ApplyDiff("target-1", "", layerTar1); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := d.Create("target-2", "target-1"); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := d.ApplyDiff("target-2", "target-1", layerTar2); err != nil {
+		t.Fatal(err)
+	}
+
+	mountPath, err = d.Get("target-2", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	fi1, err := os.Lstat(path.Join(mountPath, origFile))
+	if err != nil {
+		t.Fatal(err)
+	}
+	fi2, err := os.Lstat(path.Join(mountPath, linkedFile))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !os.SameFile(fi1, fi2) {
+		t.Fatal("Target files are not linked")
+	}
+}
+
 func hash(c string) string {
 	h := sha256.New()
 	fmt.Fprint(h, c)