aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--trash.go60
1 files changed, 59 insertions, 1 deletions
diff --git a/trash.go b/trash.go
index eb9e5f6..cf92cfe 100644
--- a/trash.go
+++ b/trash.go
@@ -3,6 +3,8 @@ package main
import (
"flag"
"fmt"
+ "io"
+ "io/fs"
"net/url"
"os"
"path/filepath"
@@ -10,6 +12,62 @@ import (
"time"
)
+func mv(src, dst string) error {
+ if err := os.Rename(src, dst); err == nil {
+ return nil
+ }
+ src = filepath.Clean(src)
+ if err := filepath.WalkDir(src, func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ relPath := strings.TrimPrefix(path, src)
+ dstPath := filepath.Join(dst, relPath)
+ switch d.Type() {
+ case fs.ModeDir:
+ stat, err := d.Info()
+ if err != nil {
+ return err
+ }
+ return os.Mkdir(dstPath, stat.Mode().Perm())
+ case fs.ModeSymlink:
+ linkTarget, err := os.Readlink(path)
+ if err != nil {
+ return err
+ }
+ return os.Symlink(linkTarget, dstPath)
+ case 0:
+ srcF, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer srcF.Close()
+ stat, err := srcF.Stat()
+ if err != nil {
+ return err
+ }
+ dstF, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE, stat.Mode().Perm())
+ if err != nil {
+ return err
+ }
+ defer dstF.Close()
+ if _, err := io.Copy(dstF, srcF); err != nil {
+ return err
+ }
+ if err := dstF.Close(); err != nil {
+ return err
+ }
+ return nil
+ default:
+ return fmt.Errorf("unknown file type %s", d.Type())
+ }
+ }); err != nil {
+ os.RemoveAll(dst)
+ return err
+ }
+ return os.RemoveAll(src)
+}
+
func trashFile(fileName, trash, now string) error {
absPath, err := filepath.Abs(fileName)
if err != nil {
@@ -38,7 +96,7 @@ DeletionDate=%s
os.Remove(info.Name())
return fmt.Errorf("%s: write trashinfo: %s", fileName, err)
}
- if err := os.Rename(fileName, trash+"/files/"+strings.TrimSuffix(filepath.Base(info.Name()), ".trashinfo")); err != nil {
+ if err := mv(fileName, trash+"/files/"+strings.TrimSuffix(filepath.Base(info.Name()), ".trashinfo")); err != nil {
os.Remove(info.Name())
return fmt.Errorf("%s: %s", fileName, err)
}