github.com/gogf/gf@v1.16.9/os/gfile/gfile_copy.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gfile
     8  
     9  import (
    10  	"fmt"
    11  	"github.com/gogf/gf/errors/gcode"
    12  	"github.com/gogf/gf/errors/gerror"
    13  	"io"
    14  	"io/ioutil"
    15  	"os"
    16  	"path/filepath"
    17  )
    18  
    19  // Copy file/directory from <src> to <dst>.
    20  //
    21  // If <src> is file, it calls CopyFile to implements copy feature,
    22  // or else it calls CopyDir.
    23  func Copy(src string, dst string) error {
    24  	if src == "" {
    25  		return gerror.NewCode(gcode.CodeInvalidParameter, "source path cannot be empty")
    26  	}
    27  	if dst == "" {
    28  		return gerror.NewCode(gcode.CodeInvalidParameter, "destination path cannot be empty")
    29  	}
    30  	if IsFile(src) {
    31  		return CopyFile(src, dst)
    32  	}
    33  	return CopyDir(src, dst)
    34  }
    35  
    36  // CopyFile copies the contents of the file named <src> to the file named
    37  // by <dst>. The file will be created if it does not exist. If the
    38  // destination file exists, all it's contents will be replaced by the contents
    39  // of the source file. The file mode will be copied from the source and
    40  // the copied data is synced/flushed to stable storage.
    41  // Thanks: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04
    42  func CopyFile(src, dst string) (err error) {
    43  	if src == "" {
    44  		return gerror.NewCode(gcode.CodeInvalidParameter, "source file cannot be empty")
    45  	}
    46  	if dst == "" {
    47  		return gerror.NewCode(gcode.CodeInvalidParameter, "destination file cannot be empty")
    48  	}
    49  	// If src and dst are the same path, it does nothing.
    50  	if src == dst {
    51  		return nil
    52  	}
    53  	in, err := os.Open(src)
    54  	if err != nil {
    55  		return
    56  	}
    57  	defer func() {
    58  		if e := in.Close(); e != nil {
    59  			err = e
    60  		}
    61  	}()
    62  	out, err := os.Create(dst)
    63  	if err != nil {
    64  		return
    65  	}
    66  	defer func() {
    67  		if e := out.Close(); e != nil {
    68  			err = e
    69  		}
    70  	}()
    71  	_, err = io.Copy(out, in)
    72  	if err != nil {
    73  		return
    74  	}
    75  	err = out.Sync()
    76  	if err != nil {
    77  		return
    78  	}
    79  	err = os.Chmod(dst, DefaultPermCopy)
    80  	if err != nil {
    81  		return
    82  	}
    83  	return
    84  }
    85  
    86  // CopyDir recursively copies a directory tree, attempting to preserve permissions.
    87  //
    88  // Note that, the Source directory must exist and symlinks are ignored and skipped.
    89  func CopyDir(src string, dst string) (err error) {
    90  	if src == "" {
    91  		return gerror.NewCode(gcode.CodeInvalidParameter, "source directory cannot be empty")
    92  	}
    93  	if dst == "" {
    94  		return gerror.NewCode(gcode.CodeInvalidParameter, "destination directory cannot be empty")
    95  	}
    96  	// If src and dst are the same path, it does nothing.
    97  	if src == dst {
    98  		return nil
    99  	}
   100  	src = filepath.Clean(src)
   101  	dst = filepath.Clean(dst)
   102  	si, err := os.Stat(src)
   103  	if err != nil {
   104  		return err
   105  	}
   106  	if !si.IsDir() {
   107  		return fmt.Errorf("source is not a directory")
   108  	}
   109  	if !Exists(dst) {
   110  		err = os.MkdirAll(dst, DefaultPermCopy)
   111  		if err != nil {
   112  			return
   113  		}
   114  	}
   115  	entries, err := ioutil.ReadDir(src)
   116  	if err != nil {
   117  		return
   118  	}
   119  	for _, entry := range entries {
   120  		srcPath := filepath.Join(src, entry.Name())
   121  		dstPath := filepath.Join(dst, entry.Name())
   122  		if entry.IsDir() {
   123  			err = CopyDir(srcPath, dstPath)
   124  			if err != nil {
   125  				return
   126  			}
   127  		} else {
   128  			// Skip symlinks.
   129  			if entry.Mode()&os.ModeSymlink != 0 {
   130  				continue
   131  			}
   132  			err = CopyFile(srcPath, dstPath)
   133  			if err != nil {
   134  				return
   135  			}
   136  		}
   137  	}
   138  	return
   139  }