xsum/main.go

285 lines
5.3 KiB
Go
Raw Normal View History

2019-09-05 15:38:43 +00:00
//3456789112345676892123456789312345678941234567895123456789612345678971234567898
2019-09-05 12:14:53 +00:00
package main
2019-09-05 15:38:43 +00:00
import "crypto/sha256"
2019-09-05 12:14:53 +00:00
import "fmt"
import "github.com/sirupsen/logrus"
2019-09-05 15:38:43 +00:00
import "github.com/multiformats/go-multihash"
import "github.com/mr-tron/base58"
import "github.com/pkg/xattr"
2019-09-24 20:08:08 +00:00
//import "errors"
2019-09-05 12:14:53 +00:00
import "os"
2019-09-05 15:38:43 +00:00
import "io"
2019-09-05 12:14:53 +00:00
import "flag"
import "time"
var Version string
var Buildtime string
var Builduser string
var Buildarch string
var log *logrus.Logger
2019-09-05 15:38:43 +00:00
const namespacePrefix = "berlin.sneak.xsum"
//FIXME(sneak) make this parallelize to NUM_CPUS when processing multiple
//args
//FIXME(sneak) add a -r (recursive) flag for directories
//FIXME(sneak) make checking support reading hash algo type from multihash
//instead of assumming sha256
2019-09-05 12:14:53 +00:00
func main() {
os.Exit(xsum())
}
func xsum() int {
log = logrus.New()
log.SetLevel(logrus.ErrorLevel)
log.SetReportCaller(false)
debugPtr := flag.Bool("d", false, "debug mode")
flag.Parse()
if *debugPtr == true {
log.SetReportCaller(true)
log.SetLevel(logrus.DebugLevel)
}
log.Debugf(
"xsum version %s (%s) built %s by %s",
Version,
Buildarch,
Buildtime,
Builduser,
)
paths := flag.Args()
if len(paths) > 1 {
paths = paths[1:]
}
switch flag.Arg(0) {
case "cron":
2019-09-24 20:08:08 +00:00
x := xsfCheckAndUpdate(paths)
if x != nil {
return -1
} else {
return 0
}
2019-09-05 12:14:53 +00:00
case "check-and-update":
2019-09-24 20:08:08 +00:00
x := xsfCheckAndUpdate(paths)
if x != nil {
return -1
} else {
return 0
}
2019-09-05 12:14:53 +00:00
case "check":
2019-09-24 20:08:08 +00:00
x := xsfCheck(paths)
if x != nil {
return -1
} else {
return 0
}
2019-09-05 12:14:53 +00:00
case "update":
2019-09-24 20:08:08 +00:00
x := xsfUpdate(paths)
if x != nil {
return -1
} else {
return 0
}
2019-09-05 12:14:53 +00:00
default:
usage()
return -1
}
}
func usage() {
fmt.Fprintf(os.Stderr, "usage: %s [-d] <update|check|check-and-update|cron> <path> [path2] [...]\n", os.Args[0])
flag.PrintDefaults()
}
2019-09-24 20:08:08 +00:00
func xsfCheck(paths []string) error {
2019-09-05 12:14:53 +00:00
log.Debugf("check")
2019-09-05 15:38:43 +00:00
log.Fatalf("not implemented")
2019-09-24 20:08:08 +00:00
for _, path := range paths {
x := newXsf(path)
err := x.Check()
if err != nil {
return err
}
}
return nil
2019-09-05 12:14:53 +00:00
}
2019-09-05 15:38:43 +00:00
func showError(e error) {
2019-09-05 12:14:53 +00:00
fmt.Fprintf(os.Stderr, "error: %s\n", e)
}
2019-09-24 20:08:08 +00:00
func xsfUpdate(paths []string) error {
2019-09-05 12:14:53 +00:00
log.Debugf("update")
for _, path := range paths {
2019-09-05 15:38:43 +00:00
x := newXsf(path)
2019-09-05 12:14:53 +00:00
err := x.Update()
if err != nil {
2019-09-05 15:38:43 +00:00
showError(err)
2019-09-24 20:08:08 +00:00
return err
2019-09-05 12:14:53 +00:00
}
}
2019-09-24 20:08:08 +00:00
return nil
2019-09-05 12:14:53 +00:00
}
2019-09-24 20:08:08 +00:00
func xsfCheckAndUpdate(paths []string) error {
2019-09-05 12:14:53 +00:00
log.Debugf("check-and-update")
r := xsfCheck(paths)
2019-09-24 20:08:08 +00:00
if r != nil {
2019-09-05 12:14:53 +00:00
return r
}
return xsfUpdate(paths)
}
2019-09-05 15:38:43 +00:00
func HashFile(fp *os.File) (string, error) {
h := sha256.New()
if _, err := io.Copy(h, fp); err != nil {
return "", err
}
mHashBuf, err := multihash.EncodeName(h.Sum(nil), "sha1")
if err != nil {
return "", err
}
return base58.Encode(mHashBuf), nil
}
/////////////////////////////////////////////////////////////////////////////////
// type xsf
/////////////////////////////////////////////////////////////////////////////////
2019-09-05 12:14:53 +00:00
type xsf struct {
2019-09-24 20:08:08 +00:00
fi *os.FileInfo
fp *os.File
multihash string
mtime string
path string
size int64
2019-09-05 15:38:43 +00:00
}
/////////////////////////////////////////////////////////////////////////////////
// constructor
/////////////////////////////////////////////////////////////////////////////////
func newXsf(path string) *xsf {
x := xsf{}
x.path = path
return &x
}
2019-09-24 20:08:08 +00:00
func (x *xsf) readXattrs(fp *os.File) error {
log.Infof("reading xattrs")
var xn string
var err error
var v []byte
xn = fmt.Sprintf("%s.%s", namespacePrefix, "mtime")
v, err = xattr.FGet(x.fp, xn)
xn = fmt.Sprintf("%s.%s", namespacePrefix, "size")
v, err = xattr.FGet(x.fp, xn)
xn = fmt.Sprintf("%s.%s", namespacePrefix, "multihash")
v, err = xattr.FGet(x.fp, xn)
return nil //FIXME
}
2019-09-05 15:38:43 +00:00
func (x *xsf) writeXattrs(fp *os.File) error {
log.Infof("writing xattrs")
var xn string
var err error
xn = fmt.Sprintf("%s.%s", namespacePrefix, "mtime")
log.Infof("writing xattr %s=%s", xn, x.mtime)
err = xattr.FSet(fp, xn, []byte(x.mtime))
if err != nil {
return err
}
xn = fmt.Sprintf("%s.%s", namespacePrefix, "size")
log.Infof("writing xattr %s=%s", xn, fmt.Sprintf("%d", x.size))
err = xattr.FSet(fp, xn, []byte(fmt.Sprintf("%d", x.size)))
if err != nil {
return err
}
xn = fmt.Sprintf("%s.%s", namespacePrefix, "multihash")
2019-09-24 20:08:08 +00:00
log.Infof("writing xattr %s=%s", xn, x.multihash)
err = xattr.FSet(fp, xn, []byte(x.multihash))
2019-09-05 15:38:43 +00:00
if err != nil {
return err
}
return nil
2019-09-05 12:14:53 +00:00
}
2019-09-24 20:08:08 +00:00
func (x *xsf) stat(fp *os.File) error {
fi, err := fp.Stat()
if err != nil {
return err
2019-09-05 12:14:53 +00:00
}
x.size = fi.Size()
2019-09-05 15:38:43 +00:00
log.Debugf("size: %d", x.size)
t := fi.ModTime().UTC().Format(time.RFC3339)
log.Debugf("modtime: %s", t)
x.mtime = t
2019-09-24 20:08:08 +00:00
return nil
}
2019-09-05 15:38:43 +00:00
2019-09-24 20:08:08 +00:00
func (x *xsf) hash(fp *os.File) error {
2019-09-05 15:38:43 +00:00
log.Debugf("hashing...")
2019-09-24 20:08:08 +00:00
var err error
if x.multihash, err = HashFile(fp); err != nil {
return err
2019-09-05 15:38:43 +00:00
}
2019-09-24 20:08:08 +00:00
log.Debugf("hash: %s", x.multihash)
return nil
}
2019-09-05 12:14:53 +00:00
2019-09-24 20:08:08 +00:00
func (x *xsf) Check() error {
fp, err := os.Open(x.path)
defer fp.Close()
if err != nil {
return err
}
x.stat(x.fp)
return nil
}
func (x *xsf) Update() error {
fp, err := os.Open(x.path)
defer fp.Close()
log.Debugf("updating file (path: %s)", x.path)
if err != nil {
return err
}
//FIXME check if size/mtime are defined first
//and skip update if match (and key 'multihash' exists)
2019-09-05 15:38:43 +00:00
2019-09-24 20:08:08 +00:00
if err = x.stat(fp); err != nil {
return err
}
if err = x.hash(fp); err != nil {
return err
}
if err = x.writeXattrs(fp); err != nil {
return err
2019-09-05 15:38:43 +00:00
}
return nil
2019-09-05 12:14:53 +00:00
}