filebrowser/backend/fileutils/file.go

115 lines
2.2 KiB
Go
Raw Normal View History

package fileutils
import (
"io"
"os"
"path"
"path/filepath"
)
2024-08-24 22:02:33 +00:00
// MoveFile moves a file from src to dst.
// By default, the rename system call is used. If src and dst point to different volumes,
// the file copy is used as a fallback.
func MoveFile(src, dst string) error {
if os.Rename(src, dst) == nil {
return nil
}
// fallback
2024-08-24 22:02:33 +00:00
err := CopyFile(src, dst)
if err != nil {
2024-08-24 22:02:33 +00:00
_ = os.Remove(dst)
return err
}
2024-08-24 22:02:33 +00:00
if err := os.Remove(src); err != nil {
return err
}
return nil
}
// CopyFile copies a file from source to dest and returns
// an error if any.
2024-08-24 22:02:33 +00:00
func CopyFile(source, dest string) error {
// Open the source file.
2024-08-24 22:02:33 +00:00
src, err := os.Open(source)
if err != nil {
return err
}
defer src.Close()
2024-08-24 22:02:33 +00:00
// Makes the directory needed to create the dst file.
err = os.MkdirAll(filepath.Dir(dest), 0775) //nolint:gomnd
if err != nil {
return err
}
// Create the destination file.
2024-08-24 22:02:33 +00:00
dst, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) //nolint:gomnd
if err != nil {
return err
}
defer dst.Close()
// Copy the contents of the file.
_, err = io.Copy(dst, src)
if err != nil {
return err
}
2024-08-24 22:02:33 +00:00
// Copy the mode.
info, err := os.Stat(source)
if err != nil {
return err
}
2024-08-24 22:02:33 +00:00
err = os.Chmod(dest, info.Mode())
if err != nil {
return err
}
return nil
}
2024-08-24 22:02:33 +00:00
// CommonPrefix returns the common directory path of provided files.
func CommonPrefix(sep byte, paths ...string) string {
// Handle special cases.
switch len(paths) {
case 0:
return ""
case 1:
return path.Clean(paths[0])
}
2024-08-24 22:02:33 +00:00
// Treat string as []byte, not []rune as is often done in Go.
c := []byte(path.Clean(paths[0]))
2024-08-24 22:02:33 +00:00
// Add a trailing sep to handle the case where the common prefix directory
// is included in the path list.
c = append(c, sep)
2024-08-24 22:02:33 +00:00
// Ignore the first path since it's already in c.
for _, v := range paths[1:] {
2024-08-24 22:02:33 +00:00
// Clean up each path before testing it.
v = path.Clean(v) + string(sep)
2024-08-24 22:02:33 +00:00
// Find the first non-common byte and truncate c.
if len(v) < len(c) {
c = c[:len(v)]
}
for i := 0; i < len(c); i++ {
if v[i] != c[i] {
c = c[:i]
break
}
}
}
2024-08-24 22:02:33 +00:00
// Remove trailing non-separator characters and the final separator.
for i := len(c) - 1; i >= 0; i-- {
if c[i] == sep {
c = c[:i]
break
}
}
return string(c)
}