Skip to content

Commit

Permalink
Merge pull request #98 from samuel-phan/main
Browse files Browse the repository at this point in the history
fix: symlink deep copy with relative path
  • Loading branch information
otiai10 authored Jan 9, 2024
2 parents 3969df7 + be46744 commit 83d4daf
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 35 deletions.
36 changes: 1 addition & 35 deletions all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func TestMain(m *testing.M) {

func teardown(m *testing.M) {
os.RemoveAll("test/data/case03/case01")
os.RemoveAll("test/data/case03/relative_case01")
os.RemoveAll("test/data.copy")
os.RemoveAll("test/data.copyTime")
os.RemoveAll("test/owned-by-root") // Do not check the error ;)
Expand Down Expand Up @@ -165,41 +166,6 @@ func TestCopy_NamedPipe(t *testing.T) {
})
}

func TestOptions_OnSymlink(t *testing.T) {
opt := Options{OnSymlink: func(string) SymlinkAction { return Deep }}
err := Copy("test/data/case03", "test/data.copy/case03.deep", opt)
Expect(t, err).ToBe(nil)
info, err := os.Lstat("test/data.copy/case03.deep/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).ToBe(os.FileMode(0))

opt = Options{OnSymlink: func(string) SymlinkAction { return Shallow }}
err = Copy("test/data/case03", "test/data.copy/case03.shallow", opt)
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.shallow/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))

opt = Options{OnSymlink: func(string) SymlinkAction { return Skip }}
err = Copy("test/data/case03", "test/data.copy/case03.skip", opt)
Expect(t, err).ToBe(nil)
_, err = os.Stat("test/data.copy/case03.skip/case01")
Expect(t, os.IsNotExist(err)).ToBe(true)

err = Copy("test/data/case03", "test/data.copy/case03.default")
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.default/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))

opt = Options{OnSymlink: nil}
err = Copy("test/data/case03", "test/data.copy/case03.not-specified", opt)
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.not-specified/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))
}

func TestOptions_Skip(t *testing.T) {
opt := Options{Skip: func(info os.FileInfo, src, dest string) (bool, error) {
switch {
Expand Down
5 changes: 5 additions & 0 deletions copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io/fs"
"os"
"path/filepath"
"strings"
"time"

"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -286,6 +287,10 @@ func onsymlink(src, dest string, opt Options) error {
if err != nil {
return err
}
if strings.HasPrefix(orig, ".") {
// orig is a relative link: need to add src dir to orig
orig = filepath.Join(filepath.Dir(src), orig)
}
info, err := os.Lstat(orig)
if err != nil {
return err
Expand Down
49 changes: 49 additions & 0 deletions symlink_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//go:build !windows && !plan9 && !netbsd && !aix && !illumos && !solaris && !js
// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris,!js

package copy

import (
"os"
"testing"

. "github.com/otiai10/mint"
)

func TestOptions_OnSymlink(t *testing.T) {
opt := Options{OnSymlink: func(string) SymlinkAction { return Deep }}
err := Copy("test/data/case03", "test/data.copy/case03.deep", opt)
Expect(t, err).ToBe(nil)
info, err := os.Lstat("test/data.copy/case03.deep/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).ToBe(os.FileMode(0))
info, err = os.Lstat("test/data.copy/case03.deep/relative_case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).ToBe(os.FileMode(0))

opt = Options{OnSymlink: func(string) SymlinkAction { return Shallow }}
err = Copy("test/data/case03", "test/data.copy/case03.shallow", opt)
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.shallow/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))

opt = Options{OnSymlink: func(string) SymlinkAction { return Skip }}
err = Copy("test/data/case03", "test/data.copy/case03.skip", opt)
Expect(t, err).ToBe(nil)
_, err = os.Stat("test/data.copy/case03.skip/case01")
Expect(t, os.IsNotExist(err)).ToBe(true)

err = Copy("test/data/case03", "test/data.copy/case03.default")
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.default/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))

opt = Options{OnSymlink: nil}
err = Copy("test/data/case03", "test/data.copy/case03.not-specified", opt)
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.not-specified/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))
}
46 changes: 46 additions & 0 deletions symlink_test_x.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//go:build windows || plan9 || netbsd || aix || illumos || solaris || js
// +build windows plan9 netbsd aix illumos solaris js

package copy

import (
"os"
"testing"

. "github.com/otiai10/mint"
)

func TestOptions_OnSymlink(t *testing.T) {
opt := Options{OnSymlink: func(string) SymlinkAction { return Deep }}
err := Copy("test/data/case03", "test/data.copy/case03.deep", opt)
Expect(t, err).ToBe(nil)
info, err := os.Lstat("test/data.copy/case03.deep/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).ToBe(os.FileMode(0))

opt = Options{OnSymlink: func(string) SymlinkAction { return Shallow }}
err = Copy("test/data/case03", "test/data.copy/case03.shallow", opt)
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.shallow/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))

opt = Options{OnSymlink: func(string) SymlinkAction { return Skip }}
err = Copy("test/data/case03", "test/data.copy/case03.skip", opt)
Expect(t, err).ToBe(nil)
_, err = os.Stat("test/data.copy/case03.skip/case01")
Expect(t, os.IsNotExist(err)).ToBe(true)

err = Copy("test/data/case03", "test/data.copy/case03.default")
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.default/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))

opt = Options{OnSymlink: nil}
err = Copy("test/data/case03", "test/data.copy/case03.not-specified", opt)
Expect(t, err).ToBe(nil)
info, err = os.Lstat("test/data.copy/case03.not-specified/case01")
Expect(t, err).ToBe(nil)
Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0))
}
1 change: 1 addition & 0 deletions test_setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func setup(m *testing.M) {
os.RemoveAll("test/data.copy")
os.MkdirAll("test/data.copy", os.ModePerm)
os.Symlink("test/data/case01", "test/data/case03/case01")
os.Symlink("../case01", "test/data/case03/relative_case01")
os.Chmod("test/data/case07/dir_0555", 0o555)
os.Chmod("test/data/case07/file_0444", 0o444)
syscall.Mkfifo("test/data/case11/foo/bar", 0o555)
Expand Down

0 comments on commit 83d4daf

Please sign in to comment.