~howeyc/util-windows

e3bc2660949e4901af1e9e9ca0c30b2e11084d60 — Chris Howey 10 months ago b9ee22d v0.2.0
rm command
2 files changed, 106 insertions(+), 0 deletions(-)

M README.md
A cmd/rm/main.go
M README.md => README.md +1 -0
@@ 9,3 9,4 @@ All implemented arguments/flags follow the util-linux equivalent.

- cal
- touch
- rm

A cmd/rm/main.go => cmd/rm/main.go +105 -0
@@ 0,0 1,105 @@
package main

import (
	"errors"
	"flag"
	"fmt"
	"io/fs"
	"os"
)

const ModeUserWrite = 0o200

func main() {
	var recursive bool
	var force bool
	var rmdir bool
	var help bool

	flag.BoolVar(&recursive, "r", false, "recursive")
	flag.BoolVar(&recursive, "recursive", false, "recursive")
	flag.BoolVar(&force, "f", false, "force")
	flag.BoolVar(&force, "force", false, "force")
	flag.BoolVar(&rmdir, "d", false, "rmdir")
	flag.BoolVar(&rmdir, "dir", false, "rmdir")
	flag.BoolVar(&help, "h", false, "help")
	flag.BoolVar(&help, "help", false, "help")
	flag.Parse()

	if help {
		fmt.Println(`Usage: rm [OPTION]... [FILE]...
Remove (unlink) the FILE(s).

  -f, --force           ignore nonexistent files and arguments, never prompt
  -r, --recursive       remove directories and their contents recursively
  -d, --dir             remove empty directories
      --help            display this help and exit

By default, rm does not remove directories.  Use the --recursive (-r)
option to remove each listed directory, too, along with all of its contents.`)
		os.Exit(0)
	}

	if flag.NArg() < 1 {
		fmt.Println("rm: missing operand")
		fmt.Println("Try \"rm --help\" for more information.")
		os.Exit(1)
	}

	for _, f := range flag.Args() {
		fi, serr := os.Stat(f)
		if serr != nil {
			if errors.Is(serr, fs.ErrNotExist) {
				fmt.Fprintf(os.Stderr, "rm: cannot remove %q: no such file or directory\n", f)
			} else {
				fmt.Fprintf(os.Stderr, "rm: cannot remove %q: %w\n", f, serr)
			}
			os.Exit(1)
		}

		// write-protected
		if fi.Mode().Perm()&ModeUserWrite == 0 {
			var propstring string
			if fi.Mode().IsRegular() {
				propstring += "regular "
			}
			if fi.Size() == 0 {
				propstring += "empty "
			}

			fmt.Fprintf(os.Stderr, "rm: remove write-protected %sfile %q? ", propstring, f)
			var response string
			fmt.Scanln(&response)
			if response != "y" {
				os.Exit(0)
			}
		}

		if fi.IsDir() {
			if rmdir {
				if err := os.Remove(f); err != nil {
					if pe, ok := err.(*fs.PathError); ok {
						fmt.Fprintf(os.Stderr, "rm: cannot remove %q: %s\n", f, pe.Err.Error())
					} else {
						fmt.Fprintf(os.Stderr, "rm: cannot remove %q: %s\n", f, err.Error())
					}
					os.Exit(1)
				}
			}
			if !recursive {
				fmt.Fprintf(os.Stderr, "rm: cannot remove %q: is a directory\n", f)
				os.Exit(1)
			} else {
				if rerr := os.RemoveAll(f); rerr != nil {
					fmt.Fprintln(os.Stderr, rerr.Error())
					os.Exit(1)
				}
			}
		} else {
			if err := os.Remove(f); err != nil {
				fmt.Fprintln(os.Stderr, err.Error())
				os.Exit(1)
			}
		}
	}
}