// Copyright (C) 2022 Marius Schellenberger package main import ( "cachefs/pkg/provider/parse" "encoding/hex" "errors" "flag" "fmt" "io" "os" "path/filepath" "strings" ) var ( version string ) const gib = 1024 * 1024 * 1024 const ( srcKey = "SRC_KEY" dstKey = "DST_KEY" ) func fatal(err error) { fmt.Println(err) os.Exit(1) } func getKey(key string) (b []byte, err error) { k := os.Getenv(key) if k == "" { return } b, err = hex.DecodeString(k) if err != nil { err = fmt.Errorf("error decoding %s: %w", key, err) } return } func main() { flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0]) fmt.Fprintf(flag.CommandLine.Output(), ` optional environment variables: `+srcKey+` (source encryption key) `+dstKey+` (destination encryption key) list files and directories (uses `+srcKey+`): ls [ ] ls file:///mnt/nfs /foo copy file from/to directory: cp cp file:///mnt/nfs foo.txt file:///mnt/cache bar.txt cp file:///mnt/cache fizz.txt sftp:///home/user fizz.txt remove file (uses `+srcKey+`): rm rm file:///mnt/nfs /buzz.txt `) os.Exit(1) } flag.Parse() args := flag.Args() if len(args) < 2 { flag.Usage() } var err error switch args[0] { case "ls": err = ls(args[1:]) case "cp": if len(args) < 5 { flag.Usage() } err = cp(args[1:]) case "rm": if len(args) < 3 { flag.Usage() } err = rm(args[1:]) } if err != nil { fatal(err) } } func ls(args []string) (err error) { k, err := getKey(srcKey) if err != nil { return } fs, err := parse.FS(args[0], k, true) if err != nil { return } defer fs.Close() path := "" if len(args) == 2 { path = args[1] } f, err := fs.Open(path) if err != nil { return } defer f.Close() fis, err := f.Readdir(0) if err != nil { return } for _, fi := range fis { p := filepath.Join(fs.Root(), path, fi.Name()) if fi.IsDir() { fmt.Println(fi.Mode().String(), fi.Size(), p+"/") continue } fmt.Println(fi.Mode().String(), fi.Size(), p) } return } func cp(args []string) (err error) { src := args[0] sp := args[1] dst := args[2] dp := args[3] sk, err := getKey(srcKey) if err != nil { return } dk, err := getKey(dstKey) if err != nil { return } sfs, err := parse.FS(src, sk, true) if err != nil { return } defer sfs.Close() dfs, err := parse.FS(dst, dk, true) if err != nil { return } defer dfs.Close() sf, err := sfs.Open(sp) if err != nil { return } defer sf.Close() if i := strings.LastIndex(dp, "/"); i > 0 { dir := dp[:i] _, err = dfs.Stat(dir) if errors.Is(err, os.ErrNotExist) { err = dfs.MkdirAll(dir, 0o755) if err != nil { return } } } df, err := dfs.OpenFile(dp, os.O_RDWR|os.O_CREATE, 0o644) if err != nil { return } defer df.Close() _, err = io.Copy(df, sf) return } func rm(args []string) (err error) { src := args[0] path := args[1] k, err := getKey(srcKey) if err != nil { return } fs, err := parse.FS(src, k, true) if err != nil { return } defer fs.Close() return fs.Remove(path) }