summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2017-11-16 08:46:16 -0800
committerChristopher Speller <crspeller@gmail.com>2017-11-16 08:46:16 -0800
commit95133098792e44d5c7fadb87f0199a0a8c2b7cee (patch)
tree96124b49d581d3a081723014ebaa4a003b98aac1 /utils
parentbf6bb9bce9723799991478e5aea745686045ad65 (diff)
parenta0017f184578d4d6250a9b54b50e656524078949 (diff)
downloadchat-95133098792e44d5c7fadb87f0199a0a8c2b7cee.tar.gz
chat-95133098792e44d5c7fadb87f0199a0a8c2b7cee.tar.bz2
chat-95133098792e44d5c7fadb87f0199a0a8c2b7cee.zip
Merge branch 'release-4.4'
Diffstat (limited to 'utils')
-rw-r--r--utils/file.go101
-rw-r--r--utils/file_test.go54
2 files changed, 155 insertions, 0 deletions
diff --git a/utils/file.go b/utils/file.go
index c7e092a20..6472770a0 100644
--- a/utils/file.go
+++ b/utils/file.go
@@ -5,6 +5,8 @@ package utils
import (
"bytes"
+ "fmt"
+ "io"
"io/ioutil"
"net/http"
"os"
@@ -367,3 +369,102 @@ func CopyMetadata(encrypt bool) map[string]string {
metaData["x-amz-server-side-encryption"] = "AES256"
return metaData
}
+
+// CopyFile will copy a file from src path to dst path.
+// Overwrites any existing files at dst.
+// Permissions are copied from file at src to the new file at dst.
+func CopyFile(src, dst string) (err error) {
+ in, err := os.Open(src)
+ if err != nil {
+ return
+ }
+ defer in.Close()
+
+ out, err := os.Create(dst)
+ if err != nil {
+ return
+ }
+ defer func() {
+ if e := out.Close(); e != nil {
+ err = e
+ }
+ }()
+
+ _, err = io.Copy(out, in)
+ if err != nil {
+ return
+ }
+
+ err = out.Sync()
+ if err != nil {
+ return
+ }
+
+ stat, err := os.Stat(src)
+ if err != nil {
+ return
+ }
+ err = os.Chmod(dst, stat.Mode())
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// CopyDir will copy a directory and all contained files and directories.
+// src must exist and dst must not exist.
+// Permissions are preserved when possible. Symlinks are skipped.
+func CopyDir(src string, dst string) (err error) {
+ src = filepath.Clean(src)
+ dst = filepath.Clean(dst)
+
+ stat, err := os.Stat(src)
+ if err != nil {
+ return
+ }
+ if !stat.IsDir() {
+ return fmt.Errorf("source must be a directory")
+ }
+
+ _, err = os.Stat(dst)
+ if err != nil && !os.IsNotExist(err) {
+ return
+ }
+ if err == nil {
+ return fmt.Errorf("destination already exists")
+ }
+
+ err = os.MkdirAll(dst, stat.Mode())
+ if err != nil {
+ return
+ }
+
+ items, err := ioutil.ReadDir(src)
+ if err != nil {
+ return
+ }
+
+ for _, item := range items {
+ srcPath := filepath.Join(src, item.Name())
+ dstPath := filepath.Join(dst, item.Name())
+
+ if item.IsDir() {
+ err = CopyDir(srcPath, dstPath)
+ if err != nil {
+ return
+ }
+ } else {
+ if item.Mode()&os.ModeSymlink != 0 {
+ continue
+ }
+
+ err = CopyFile(srcPath, dstPath)
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
diff --git a/utils/file_test.go b/utils/file_test.go
index 5c7162450..91e78f24e 100644
--- a/utils/file_test.go
+++ b/utils/file_test.go
@@ -5,9 +5,13 @@ package utils
import (
"fmt"
+ "io/ioutil"
"os"
+ "path/filepath"
"testing"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/mattermost/mattermost-server/model"
@@ -180,3 +184,53 @@ func (s *FileTestSuite) TestRemoveDirectory() {
_, err = ReadFile("tests2/asdf")
s.Error(err)
}
+
+func TestCopyDir(t *testing.T) {
+ srcDir, err := ioutil.TempDir("", "src")
+ require.NoError(t, err)
+ defer os.RemoveAll(srcDir)
+
+ dstParentDir, err := ioutil.TempDir("", "dstparent")
+ require.NoError(t, err)
+ defer os.RemoveAll(dstParentDir)
+
+ dstDir := filepath.Join(dstParentDir, "dst")
+
+ tempFile := "temp.txt"
+ err = ioutil.WriteFile(filepath.Join(srcDir, tempFile), []byte("test file"), 0655)
+ require.NoError(t, err)
+
+ childDir := "child"
+ err = os.Mkdir(filepath.Join(srcDir, childDir), 0777)
+ require.NoError(t, err)
+
+ childTempFile := "childtemp.txt"
+ err = ioutil.WriteFile(filepath.Join(srcDir, childDir, childTempFile), []byte("test file"), 0755)
+ require.NoError(t, err)
+
+ err = CopyDir(srcDir, dstDir)
+ assert.NoError(t, err)
+
+ stat, err := os.Stat(filepath.Join(dstDir, tempFile))
+ assert.NoError(t, err)
+ assert.Equal(t, uint32(0655), uint32(stat.Mode()))
+ assert.False(t, stat.IsDir())
+ data, err := ioutil.ReadFile(filepath.Join(dstDir, tempFile))
+ assert.NoError(t, err)
+ assert.Equal(t, "test file", string(data))
+
+ stat, err = os.Stat(filepath.Join(dstDir, childDir))
+ assert.NoError(t, err)
+ assert.True(t, stat.IsDir())
+
+ stat, err = os.Stat(filepath.Join(dstDir, childDir, childTempFile))
+ assert.NoError(t, err)
+ assert.Equal(t, uint32(0755), uint32(stat.Mode()))
+ assert.False(t, stat.IsDir())
+ data, err = ioutil.ReadFile(filepath.Join(dstDir, childDir, childTempFile))
+ assert.NoError(t, err)
+ assert.Equal(t, "test file", string(data))
+
+ err = CopyDir(srcDir, dstDir)
+ assert.Error(t, err)
+}