Repository: otiai10/copy (go)

Issue:
Option to preserve special files
Similar to `rsync --specials` an option to handle special files as special is required: Currently the code tries to always copy the *content* of such files, e.g. `/dev/console`, pipes, sockets, … instead of copying it as a special files.
This is causing `kaniko` to stall when building base images: https://github.com/GoogleContainerTools/kaniko/issues/960

Pull request description:
Skip device files by default: Use opt.Specials
Fix #78

Patch:
diff --git a/copy.go b/copy.go
index 81e1ecc..7ec6394 100644
--- a/copy.go
+++ b/copy.go
@@ -26,6 +26,11 @@ func Copy(src, dest string, opt ...Options) error {
 // switchboard switches proper copy functions regarding file type, etc...
 // If there would be anything else here, add a case to this switchboard.
 func switchboard(src, dest string, info os.FileInfo, opt Options) (err error) {
+
+	if info.Mode()&os.ModeDevice != 0 && !opt.Specials {
+		return err
+	}
+
 	switch {
 	case info.Mode()&os.ModeSymlink != 0:
 		err = onsymlink(src, dest, opt)
diff --git a/options.go b/options.go
index 0045813..22cd958 100644
--- a/options.go
+++ b/options.go
@@ -14,6 +14,9 @@ type Options struct {
 	// Skip can specify which files should be skipped
 	Skip func(src string) (bool, error)
 
+	// Specials includes special files to be copied. default false.
+	Specials bool
+
 	// AddPermission to every entities,
 	// NO MORE THAN 0777
 	// @OBSOLETE
@@ -90,6 +93,7 @@ func getDefaultOptions(src, dest string) Options {
 		AddPermission:     0,                  // Add nothing
 		PermissionControl: PerservePermission, // Just preserve permission
 		Sync:              false,              // Do not sync
+		Specials:          false,              // Do not copy special files
 		PreserveTimes:     false,              // Do not preserve the modification time
 		CopyBufferSize:    0,                  // Do not specify, use default bufsize (32*1024)
 		intent: struct {


Test patch:
diff --git a/all_test.go b/all_test.go
index b77a182..47896ec 100644
--- a/all_test.go
+++ b/all_test.go
@@ -195,6 +195,13 @@ func TestOptions_Skip(t *testing.T) {
 	})
 }
 
+func TestOptions_Specials(t *testing.T) {
+	if runtime.GOOS == "linux" || runtime.GOOS == "darwin" {
+		err := Copy("/dev/null", "test/data.copy/dev-null", Options{Specials: false})
+		Expect(t, err).ToBe(nil)
+	}
+}
+
 func TestOptions_PermissionControl(t *testing.T) {
 	info, err := os.Stat("test/data/case07/dir_0555")
 	Expect(t, err).ToBe(nil)