196 lines
3.1 KiB
Go
196 lines
3.1 KiB
Go
// 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 <base> [ <path> ]
|
|
|
|
ls file:///mnt/nfs /foo
|
|
|
|
copy file from/to directory:
|
|
cp <src base> <src> <dst base> <dst>
|
|
|
|
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 <base> <file>
|
|
|
|
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)
|
|
}
|