1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-10 01:51:07 +09:00
anytype-heart/util/files/files.go
2021-08-16 18:13:44 +04:00

108 lines
2.1 KiB
Go

package files
import (
"bytes"
"io"
"os"
"path/filepath"
"strings"
)
// WriteReaderIntoFileReuseSameExistingFile has simple logic
// 1. if path not exists the reader(r) just copied to the file in the provided path
// 2. if path exists and the content is equals to reader(r) the existing path is returning
// 3. if path exists but the content is not equals reader(r), the path with random suffix is returning
func WriteReaderIntoFileReuseSameExistingFile(path string, r io.Reader) (string, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
f, err := os.Create(path)
if err != nil {
return "", err
}
_, err = io.Copy(f, r)
if err != nil {
return "", err
}
return path, f.Close()
}
var (
ext = filepath.Ext(path)
dir = filepath.Dir(path)
name = strings.TrimSuffix(filepath.Base(path), ext)
)
if name == "." {
name = "file"
}
tmp, err := os.CreateTemp(dir, name+"-*"+ext)
_, err = io.Copy(tmp, r)
if err != nil {
return "", err
}
if t, err := AreFilesEqual(tmp.Name(), path); err == nil && t {
tmpPath := tmp.Name()
_ = tmp.Truncate(0)
_ = tmp.Close()
_ = os.Remove(tmpPath)
// return path for existing file instead
return path, nil
}
return tmp.Name(), tmp.Close()
}
func AreFilesEqual(file1, file2 string) (bool, error) {
const chunkSize = 64000
f1s, err := os.Stat(file1)
if err != nil {
return false, err
}
f2s, err := os.Stat(file2)
if err != nil {
return false, err
}
/* may return false-positive on windows if size and name are the same
if os.SameFile(f1s, f2s) {
return true, nil
}*/
if f1s.Size() != f2s.Size() {
return false, nil
}
f1, err := os.Open(file1)
if err != nil {
return false, err
}
f2, err := os.Open(file2)
if err != nil {
return false, err
}
for {
b1 := make([]byte, chunkSize)
_, err1 := f1.Read(b1)
b2 := make([]byte, chunkSize)
_, err2 := f2.Read(b2)
if err1 != nil || err2 != nil {
if err1 == io.EOF && err2 == io.EOF {
return true, nil
} else if err1 == io.EOF && err2 == io.EOF {
return false, nil
} else {
return false, err
}
}
if !bytes.Equal(b1, b2) {
return false, nil
}
}
}