bugfix: allow hardlink to softlink file

With `fs.RootPath`, the target file will be the file which the softlink
points to, like:

  touch /tmp/zzz
  ln -s /tmp/zzz /tmp/xxx
  ln /tmp/xxx /tmp/yyy

The `/tmp/yyy` should be same with the `/tmp/xxx`, not `/tmp/zzz`. We
should allow hardlink to softlink file.

Signed-off-by: Wei Fu <fhfuwei@163.com>
This commit is contained in:
Wei Fu
2018-07-12 14:15:53 +08:00
parent fb1084d9cc
commit 3b1534c47a
2 changed files with 87 additions and 3 deletions

View File

@@ -196,6 +196,49 @@ func TestBreakouts(t *testing.T) {
return nil
}
errFileDiff := errors.New("files differ")
isSymlinkFile := func(f string) func(string) error {
return func(root string) error {
fi, err := os.Lstat(filepath.Join(root, f))
if err != nil {
return err
}
if got := fi.Mode() & os.ModeSymlink; got != os.ModeSymlink {
return errors.Errorf("%s should be symlink", fi.Name())
}
return nil
}
}
sameSymlinkFile := func(f1, f2 string) func(string) error {
checkF1, checkF2 := isSymlinkFile(f1), isSymlinkFile(f2)
return func(root string) error {
if err := checkF1(root); err != nil {
return err
}
if err := checkF2(root); err != nil {
return err
}
t1, err := os.Readlink(filepath.Join(root, f1))
if err != nil {
return err
}
t2, err := os.Readlink(filepath.Join(root, f2))
if err != nil {
return err
}
if t1 != t2 {
return errors.Wrapf(errFileDiff, "%#v and %#v", t1, t2)
}
return nil
}
}
sameFile := func(f1, f2 string) func(string) error {
return func(root string) error {
p1, err := fs.RootPath(root, f1)
@@ -406,6 +449,16 @@ func TestBreakouts(t *testing.T) {
),
validator: sameFile("localpasswd", "/etc/passwd"),
},
{
name: "HardlinkSymlinkBeforeCreateTarget",
w: TarAll(
tc.Dir("etc", 0770),
tc.Symlink("/etc/passwd", "localpasswd"),
tc.Link("localpasswd", "localpasswd-dup"),
tc.File("/etc/passwd", []byte("after"), 0644),
),
validator: sameFile("localpasswd-dup", "/etc/passwd"),
},
{
name: "HardlinkSymlinkRelative",
w: TarAll(
@@ -414,7 +467,10 @@ func TestBreakouts(t *testing.T) {
tc.Symlink("../../../../../etc/passwd", "passwdlink"),
tc.Link("/passwdlink", "localpasswd"),
),
validator: sameFile("/localpasswd", "/etc/passwd"),
validator: all(
sameSymlinkFile("/localpasswd", "/passwdlink"),
sameFile("/localpasswd", "/etc/passwd"),
),
},
{
name: "HardlinkSymlinkAbsolute",
@@ -424,7 +480,10 @@ func TestBreakouts(t *testing.T) {
tc.Symlink("/etc/passwd", "passwdlink"),
tc.Link("/passwdlink", "localpasswd"),
),
validator: sameFile("/localpasswd", "/etc/passwd"),
validator: all(
sameSymlinkFile("/localpasswd", "/passwdlink"),
sameFile("/localpasswd", "/etc/passwd"),
),
},
{
name: "SymlinkParentDirectory",