mirror of https://github.com/schollz/croc.git
102 lines
2.2 KiB
Go
102 lines
2.2 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"crypto/md5"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"os"
|
||
|
)
|
||
|
|
||
|
// CopyFile copies a file from src to dst. If src and dst files exist, and are
|
||
|
// the same, then return success. Otherise, attempt to create a hard link
|
||
|
// between the two files. If that fail, copy the file contents from src to dst.
|
||
|
func CopyFile(src, dst string) (err error) {
|
||
|
sfi, err := os.Stat(src)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
if !sfi.Mode().IsRegular() {
|
||
|
// cannot copy non-regular files (e.g., directories,
|
||
|
// symlinks, devices, etc.)
|
||
|
return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
|
||
|
}
|
||
|
dfi, err := os.Stat(dst)
|
||
|
if err != nil {
|
||
|
if !os.IsNotExist(err) {
|
||
|
return
|
||
|
}
|
||
|
} else {
|
||
|
if !(dfi.Mode().IsRegular()) {
|
||
|
return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
|
||
|
}
|
||
|
if os.SameFile(sfi, dfi) {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
if err = os.Link(src, dst); err == nil {
|
||
|
return
|
||
|
}
|
||
|
err = copyFileContents(src, dst)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// copyFileContents copies the contents of the file named src to the file named
|
||
|
// by dst. The file will be created if it does not already exist. If the
|
||
|
// destination file exists, all it's contents will be replaced by the contents
|
||
|
// of the source file.
|
||
|
func copyFileContents(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() {
|
||
|
cerr := out.Close()
|
||
|
if err == nil {
|
||
|
err = cerr
|
||
|
}
|
||
|
}()
|
||
|
if _, err = io.Copy(out, in); err != nil {
|
||
|
return
|
||
|
}
|
||
|
err = out.Sync()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// HashFile does a md5 hash on the file
|
||
|
// from https://golang.org/pkg/crypto/md5/#example_New_file
|
||
|
func HashFile(filename string) (hash string, err error) {
|
||
|
f, err := os.Open(filename)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
defer f.Close()
|
||
|
|
||
|
h := md5.New()
|
||
|
if _, err = io.Copy(h, f); err != nil {
|
||
|
return
|
||
|
}
|
||
|
hash = fmt.Sprintf("%x", h.Sum(nil))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// FileSize returns the size of a file
|
||
|
func FileSize(filename string) (int, error) {
|
||
|
f, err := os.Open(filename)
|
||
|
if err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
defer f.Close()
|
||
|
|
||
|
fi, err := f.Stat()
|
||
|
if err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
size := int(fi.Size())
|
||
|
return size, nil
|
||
|
}
|