-
Notifications
You must be signed in to change notification settings - Fork 1k
internal/fs: handle symlinks in copyFile() #657
Changes from all commits
1dd2d58
b614fbf
e8fb51d
fc0c4b7
4af7780
f82ed6b
e568774
4d224bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -242,6 +242,13 @@ func CopyDir(src, dst string) error { | |
// of the source file. The file mode will be copied from the source and | ||
// the copied data is synced/flushed to stable storage. | ||
func copyFile(src, dst string) (err error) { | ||
if sym, err := IsSymlink(src); err != nil { | ||
return err | ||
} else if sym { | ||
err := copySymlink(src, dst) | ||
return err | ||
} | ||
|
||
in, err := os.Open(src) | ||
if err != nil { | ||
return | ||
|
@@ -280,6 +287,22 @@ func copyFile(src, dst string) (err error) { | |
return | ||
} | ||
|
||
// copySymlink will resolve the src symlink and create a new symlink in dst. | ||
// If src is a relative symlink, dst will also be a relative symlink. | ||
func copySymlink(src, dst string) error { | ||
resolved, err := os.Readlink(src) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to resolve symlink") | ||
} | ||
|
||
err = os.Symlink(resolved, dst) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to create symlink %s to %s", src, resolved) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// IsDir determines is the path given is a directory or not. | ||
func IsDir(name string) (bool, error) { | ||
// TODO: lstat? | ||
|
@@ -337,3 +360,13 @@ func IsRegular(name string) (bool, error) { | |
} | ||
return true, nil | ||
} | ||
|
||
// IsSymlink determines if the given path is a symbolic link. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a note to describe the behaviour of this function on Windows. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should behave in the same way. Unless I'm missing something else. 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason why they the tests for this function are skipped is that creating a symlink (using |
||
func IsSymlink(path string) (bool, error) { | ||
l, err := os.Lstat(path) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
return l.Mode()&os.ModeSymlink == os.ModeSymlink, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can write this
return errors.Wrapf(err, "...")
if err == nil, errors.Wrapf returns nil.
This might be too magical.