aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2025-01-21 22:31:29 -0800
committerRose Hogenson <rosehogenson@posteo.net>2025-01-21 22:31:29 -0800
commitb876c33587ce3a2e7305c912ef816b6f2058dc5f (patch)
treebf892a0a0b21cbbf662f6ab31d24e6fd2cc7e822
downloadtrash-b876c33587ce3a2e7305c912ef816b6f2058dc5f.tar.zst
Initial commit.
-rw-r--r--.gitignore1
-rw-r--r--go.mod3
-rw-r--r--trash.go72
3 files changed, 76 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..500a66a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/trash
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..8ee3af0
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module gitlab.com/rhogenson/trash
+
+go 1.23.4
diff --git a/trash.go b/trash.go
new file mode 100644
index 0000000..6a3e024
--- /dev/null
+++ b/trash.go
@@ -0,0 +1,72 @@
+package main
+
+import (
+ "fmt"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+)
+
+func trashFile(fileName, trash, now string) error {
+ absPath, err := filepath.Abs(fileName)
+ if err != nil {
+ return fmt.Errorf("%s: find absolute path: %s", fileName, err)
+ }
+ info, err := os.CreateTemp(trash+"/info", filepath.Base(fileName)+"."+now+".*.trashinfo")
+ if err != nil {
+ return fmt.Errorf("%s: create trashinfo: %s", fileName, err)
+ }
+ escapedPath := strings.Split(absPath, "/")
+ for i, pathSegment := range escapedPath {
+ escapedPath[i] = url.QueryEscape(pathSegment)
+ }
+ _, err = fmt.Fprintf(info, `[Trash Info]
+Path=%s
+DeletionDate=%s
+`,
+ strings.Join(escapedPath, "/"),
+ now)
+ if err != nil {
+ info.Close()
+ os.Remove(info.Name())
+ return fmt.Errorf("%s: write trashinfo: %s", fileName, err)
+ }
+ if err := info.Close(); err != nil {
+ 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 {
+ os.Remove(info.Name())
+ return fmt.Errorf("%s: trash: %s", fileName, err)
+ }
+ return nil
+}
+
+func main() {
+ trash := os.Getenv("HOME") + "/.local/share/Trash"
+ if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
+ trash = xdgDataHome + "/Trash"
+ }
+ if err := os.MkdirAll(trash+"/files", 0755); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+ if err := os.MkdirAll(trash+"/info", 0755); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+
+ now := time.Now().Format("2006-01-02T15:04:05")
+ success := true
+ for _, fileName := range os.Args[1:] {
+ if err := trashFile(fileName, trash, now); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ success = false
+ }
+ }
+ if !success {
+ os.Exit(1)
+ }
+}