gomi icon indicating copy to clipboard operation
gomi copied to clipboard

Gomi cannot remove broken symlinks

Open nsfisis opened this issue 11 months ago • 1 comments

Summary

gomi cannot remove symlinks that refer to non-existent files.

Version

Because I use a gomi binary built by Nix, gomi -V prints no version information.

$ gomi -V
gomi - a CLI trash manager
https://gomi.dev

version: (devel)
revision: unset
buildDate: unknown

According to the Nix metadata, it seems to be built with v1.6.0.

https://github.com/NixOS/nixpkgs/blob/46e634be05ce9dc6d4db8e664515ba10b78151ae/pkgs/by-name/go/gomi/package.nix#L14

EDIT: with the recent update of Nix, the version information is included in the gomi built by Nix.

$ gomi -V
gomi - a CLI trash manager
https://gomi.dev

version: v1.6.0
revision: da44e9f
buildDate: 2025-03-17T05:38:26Z

How to Reproduce

gomi can remove a symlink that points to a valid file.

$ mkdir -p ~/tmp/gomi
$ cd ~/tmp/gomi

$ touch a
$ ln -s a b

$ ls -l
total 0
-rw-rw-r-- 1 ken ken 0 Apr 30 18:59 a
lrwxrwxrwx 1 ken ken 1 Apr 30 18:59 b -> a

# Gomi successfully removes b.
$ gomi b

$ ls -l
total 0
-rw-rw-r-- 1 ken ken 0 Apr 30 18:59 a

However, it cannot remove a symlink that refers to an invalid file.

$ mkdir -p ~/tmp/gomi
$ cd ~/tmp/gomi

$ touch a
$ ln -s a b

$ ls -l
total 0
-rw-rw-r-- 1 ken ken 0 Apr 30 18:59 a
lrwxrwxrwx 1 ken ken 1 Apr 30 19:00 b -> a

# Remove a, which is referenced by b.
$ rm -f a
$ ls -l
total 0
lrwxrwxrwx 1 ken ken 1 Apr 30 19:00 b -> a

# Gomi failes to remove b.
$ gomi b
gomi: b: no such file or directory

Cause

internal/cli/put.go calls os.Stat() to check if the file to be removed exist:

	// Check if file exists
	if _, err := os.Stat(path); os.IsNotExist(err) {
		if !c.option.Rm.Force {
			failed.Append(arg)
			return fmt.Errorf("%s: no such file or directory", arg)
		}
		if c.option.Rm.Verbose {
			fmt.Fprintf(os.Stderr, "skipping %s: no such file or directory\n", arg)
		}
		return nil
	}

os.Stat(), however, follows symlinks. As a result, if the symlink points to a non-existent entry, os.Stat() returns a NotExist error.

os.Lstat() seems to be correct for this use case.

https://pkg.go.dev/os#Lstat

If the file is a symbolic link, the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.

nsfisis avatar Apr 30 '25 10:04 nsfisis

I ran into this today as well.

dsully avatar May 21 '25 17:05 dsully

I ran into this recently as well. lol

Lingshinx avatar Aug 19 '25 13:08 Lingshinx