making progress!
This commit is contained in:
parent
1e45ea3e24
commit
d4b3203f03
201
main.go
201
main.go
@ -63,6 +63,7 @@ func xsum() int {
|
|||||||
case "cron":
|
case "cron":
|
||||||
x := xsfCheckAndUpdate(paths)
|
x := xsfCheckAndUpdate(paths)
|
||||||
if x != nil {
|
if x != nil {
|
||||||
|
log.Error(x)
|
||||||
return -1
|
return -1
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0
|
||||||
@ -70,6 +71,7 @@ func xsum() int {
|
|||||||
case "check-and-update":
|
case "check-and-update":
|
||||||
x := xsfCheckAndUpdate(paths)
|
x := xsfCheckAndUpdate(paths)
|
||||||
if x != nil {
|
if x != nil {
|
||||||
|
log.Error(x)
|
||||||
return -1
|
return -1
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0
|
||||||
@ -77,6 +79,7 @@ func xsum() int {
|
|||||||
case "check":
|
case "check":
|
||||||
x := xsfCheck(paths)
|
x := xsfCheck(paths)
|
||||||
if x != nil {
|
if x != nil {
|
||||||
|
log.Error(x)
|
||||||
return -1
|
return -1
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0
|
||||||
@ -84,6 +87,7 @@ func xsum() int {
|
|||||||
case "update":
|
case "update":
|
||||||
x := xsfUpdate(paths)
|
x := xsfUpdate(paths)
|
||||||
if x != nil {
|
if x != nil {
|
||||||
|
log.Error(x)
|
||||||
return -1
|
return -1
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0
|
||||||
@ -101,7 +105,6 @@ func usage() {
|
|||||||
|
|
||||||
func xsfCheck(paths []string) error {
|
func xsfCheck(paths []string) error {
|
||||||
log.Debugf("check")
|
log.Debugf("check")
|
||||||
log.Fatalf("not implemented")
|
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
x := newXsf(path)
|
x := newXsf(path)
|
||||||
err := x.Check()
|
err := x.Check()
|
||||||
@ -154,6 +157,15 @@ func HashFile(fp *os.File) (string, error) {
|
|||||||
return base58.Encode(mHashBuf), nil
|
return base58.Encode(mHashBuf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stringInSlice(a string, list []string) bool {
|
||||||
|
for _, b := range list {
|
||||||
|
if b == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
// type xsf
|
// type xsf
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -180,21 +192,63 @@ func newXsf(path string) *xsf {
|
|||||||
return &x
|
return &x
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xsf) readXattrs(fp *os.File) error {
|
//FIXME calling .List() three times might be slow, memoize if necessary
|
||||||
log.Infof("reading xattrs")
|
|
||||||
var xn string
|
|
||||||
var err error
|
|
||||||
var v []byte
|
|
||||||
|
|
||||||
xn = fmt.Sprintf("%s.%s", namespacePrefix, "mtime")
|
func (x *xsf) hasMtimeXattr() bool {
|
||||||
v, err = xattr.FGet(x.fp, xn)
|
xn := fmt.Sprintf("%s.%s", namespacePrefix, "mtime")
|
||||||
|
l, err := xattr.FList(x.fp)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return stringInSlice(xn, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *xsf) readMtimeXattr() error {
|
||||||
|
log.Infof("reading mtime xattr")
|
||||||
|
xn := fmt.Sprintf("%s.%s", namespacePrefix, "mtime")
|
||||||
|
|
||||||
|
v, err := xattr.FGet(x.fp, xn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
x.xmtime = string(v)
|
x.xmtime = string(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
xn = fmt.Sprintf("%s.%s", namespacePrefix, "size")
|
func (x *xsf) hasMultihashXattr() bool {
|
||||||
v, err = xattr.FGet(x.fp, xn)
|
xn := fmt.Sprintf("%s.%s", namespacePrefix, "multihash")
|
||||||
|
l, err := xattr.FList(x.fp)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return stringInSlice(xn, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *xsf) readMultihashXattr() error {
|
||||||
|
log.Infof("reading multihash xattr")
|
||||||
|
xn := fmt.Sprintf("%s.%s", namespacePrefix, "multihash")
|
||||||
|
v, err := xattr.FGet(x.fp, xn)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
x.xmultihash = string(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *xsf) hasSizeXattr() bool {
|
||||||
|
xn := fmt.Sprintf("%s.%s", namespacePrefix, "size")
|
||||||
|
l, err := xattr.FList(x.fp)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return stringInSlice(xn, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *xsf) readSizeXattr() error {
|
||||||
|
log.Infof("reading size xattr")
|
||||||
|
xn := fmt.Sprintf("%s.%s", namespacePrefix, "size")
|
||||||
|
v, err := xattr.FGet(x.fp, xn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -205,19 +259,10 @@ func (x *xsf) readXattrs(fp *os.File) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
x.xsize = uint64(a)
|
x.xsize = uint64(a)
|
||||||
|
return nil
|
||||||
xn = fmt.Sprintf("%s.%s", namespacePrefix, "multihash")
|
|
||||||
v, err = xattr.FGet(x.fp, xn)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
x.xmultihash = string(v)
|
|
||||||
|
|
||||||
return nil //FIXME
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xsf) writeXattrs(fp *os.File) error {
|
func (x *xsf) writeXattrs() error {
|
||||||
log.Infof("writing xattrs")
|
log.Infof("writing xattrs")
|
||||||
|
|
||||||
var xn string
|
var xn string
|
||||||
@ -225,21 +270,21 @@ func (x *xsf) writeXattrs(fp *os.File) error {
|
|||||||
|
|
||||||
xn = fmt.Sprintf("%s.%s", namespacePrefix, "mtime")
|
xn = fmt.Sprintf("%s.%s", namespacePrefix, "mtime")
|
||||||
log.Infof("writing xattr %s=%s", xn, x.mtime)
|
log.Infof("writing xattr %s=%s", xn, x.mtime)
|
||||||
err = xattr.FSet(fp, xn, []byte(x.mtime))
|
err = xattr.FSet(x.fp, xn, []byte(x.mtime))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
xn = fmt.Sprintf("%s.%s", namespacePrefix, "size")
|
xn = fmt.Sprintf("%s.%s", namespacePrefix, "size")
|
||||||
log.Infof("writing xattr %s=%s", xn, fmt.Sprintf("%d", x.size))
|
log.Infof("writing xattr %s=%s", xn, fmt.Sprintf("%d", x.size))
|
||||||
err = xattr.FSet(fp, xn, []byte(fmt.Sprintf("%d", x.size)))
|
err = xattr.FSet(x.fp, xn, []byte(fmt.Sprintf("%d", x.size)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
xn = fmt.Sprintf("%s.%s", namespacePrefix, "multihash")
|
xn = fmt.Sprintf("%s.%s", namespacePrefix, "multihash")
|
||||||
log.Infof("writing xattr %s=%s", xn, x.multihash)
|
log.Infof("writing xattr %s=%s", xn, x.multihash)
|
||||||
err = xattr.FSet(fp, xn, []byte(x.multihash))
|
err = xattr.FSet(x.fp, xn, []byte(x.multihash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -247,8 +292,8 @@ func (x *xsf) writeXattrs(fp *os.File) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xsf) stat(fp *os.File) error {
|
func (x *xsf) stat() error {
|
||||||
fi, err := fp.Stat()
|
fi, err := x.fp.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -260,10 +305,10 @@ func (x *xsf) stat(fp *os.File) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xsf) hash(fp *os.File) error {
|
func (x *xsf) hash() error {
|
||||||
log.Debugf("hashing...")
|
log.Debugf("hashing...")
|
||||||
var err error
|
var err error
|
||||||
if x.multihash, err = HashFile(fp); err != nil {
|
if x.multihash, err = HashFile(x.fp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debugf("hash: %s", x.multihash)
|
log.Debugf("hash: %s", x.multihash)
|
||||||
@ -276,14 +321,100 @@ func (x *xsf) Check() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
x.stat(x.fp)
|
x.fp = fp
|
||||||
return nil
|
|
||||||
|
serr := x.stat()
|
||||||
|
if serr != nil {
|
||||||
|
log.Errorf("error stat(): %s", serr)
|
||||||
|
return serr
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.missingXattrs() == true {
|
||||||
|
log.Infof("can't check file %s, does not have appropriate xattrs", x.path)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//check to see if file needs update (wrong mtime, wrong size)
|
||||||
|
if x.needsUpdate() == true {
|
||||||
|
log.Infof("can't check file %s, needs update (xattrs not current)", x.path)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//finally hash the file
|
||||||
|
err2 := x.readMultihashXattr()
|
||||||
|
if err2 != nil {
|
||||||
|
log.Errorf("error reading file hash: %s", err2)
|
||||||
|
return err2
|
||||||
|
}
|
||||||
|
|
||||||
|
predictedHash := x.xmultihash
|
||||||
|
|
||||||
|
err3 := x.hash()
|
||||||
|
if err3 != nil {
|
||||||
|
log.Errorf("error hashing file: %s", err2)
|
||||||
|
return err3
|
||||||
|
}
|
||||||
|
|
||||||
|
actualHash := x.multihash
|
||||||
|
|
||||||
|
if predictedHash != actualHash {
|
||||||
|
log.Errorf("file corruption detected: expected=%s actual=%s", predictedHash, actualHash)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
log.Infof("file OK hash=%s", actualHash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *xsf) missingXattrs() bool {
|
||||||
|
if x.hasMtimeXattr() == false {
|
||||||
|
log.Debugf("file needs update, missing mtime xattr")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.hasMultihashXattr() == false {
|
||||||
|
log.Debugf("file needs update, missing multihash xattr")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.hasSizeXattr() == false {
|
||||||
|
log.Debugf("file needs update, missing size xattr")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *xsf) needsUpdate() bool {
|
||||||
|
// this expects stat() to have been called on the xsf
|
||||||
|
// by Update already, so we have x.mtime et al populated from the
|
||||||
|
// filesystem
|
||||||
|
|
||||||
|
// if the file doesn't have all 3 xattrs, it needs an update.
|
||||||
|
if x.missingXattrs() == false {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the size doesn't match, it needs an update
|
||||||
|
if x.size != x.xsize {
|
||||||
|
log.Debugf("file needs update, size is %s, xattr size is %s", x.size, x.xsize)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the mtime is not the same, it needs an update
|
||||||
|
if x.mtime != x.xmtime {
|
||||||
|
log.Debugf("file needs update, mtime is %s, xattr mtime is %s", x.mtime, x.xmtime)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xsf) Update() error {
|
func (x *xsf) Update() error {
|
||||||
fp, err := os.Open(x.path)
|
|
||||||
defer fp.Close()
|
|
||||||
log.Debugf("updating file (path: %s)", x.path)
|
log.Debugf("updating file (path: %s)", x.path)
|
||||||
|
fp, err := os.Open(x.path)
|
||||||
|
x.fp = fp
|
||||||
|
defer fp.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -291,15 +422,15 @@ func (x *xsf) Update() error {
|
|||||||
//FIXME check if size/mtime are defined first
|
//FIXME check if size/mtime are defined first
|
||||||
//and skip update if match (and key 'multihash' exists)
|
//and skip update if match (and key 'multihash' exists)
|
||||||
|
|
||||||
if err = x.stat(fp); err != nil {
|
if err = x.stat(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = x.hash(fp); err != nil {
|
if err = x.hash(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = x.writeXattrs(fp); err != nil {
|
if err = x.writeXattrs(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user