package Filesystem
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha1"
|
|
"encoding/gob"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"hash"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
var (
|
|
// TODO: Where do I put this
|
|
Data string
|
|
)
|
|
|
|
type Package struct {
|
|
Name string
|
|
Version string
|
|
}
|
|
|
|
type FileObject struct {
|
|
FileMode os.FileMode
|
|
Size int64
|
|
Package Package
|
|
Ref string
|
|
Sha1 []byte
|
|
}
|
|
|
|
type ByName []Package
|
|
|
|
func (f FileObject) IsLink() bool {
|
|
return f.FileMode&os.ModeSymlink != 0
|
|
}
|
|
|
|
func (f FileObject) objFile() string {
|
|
return filepath.Join(f.objDir(), hex.EncodeToString(f.Sha1))
|
|
}
|
|
|
|
func (f FileObject) objDir() string {
|
|
return filepath.Join(Data, hex.EncodeToString(f.Sha1[:2]))
|
|
}
|
|
|
|
func (f FileObject) Reset(dst string) error {
|
|
var err error
|
|
|
|
if f.IsLink() {
|
|
_, err = os.Lstat(dst)
|
|
if !os.IsNotExist(err) {
|
|
err = os.Remove(dst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = os.Symlink(f.Ref, dst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
f.cp(f.objFile(), dst)
|
|
err = os.Chmod(dst, f.FileMode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f FileObject) Stov(src string) error {
|
|
var err error
|
|
|
|
if f.IsLink() {
|
|
return nil
|
|
}
|
|
|
|
err = os.MkdirAll(f.objDir(), 0744)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
f.cp(src, f.objFile())
|
|
return nil
|
|
}
|
|
|
|
func (f FileObject) cp(src string, dst string) error {
|
|
var (
|
|
srcFile, dstFile *os.File
|
|
err error
|
|
)
|
|
|
|
fmt.Println("cp ", src, dst)
|
|
|
|
srcFile, err = os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer srcFile.Close()
|
|
|
|
dstFile, err = os.Create(dst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer dstFile.Close()
|
|
|
|
_, err = io.Copy(dstFile, srcFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return dstFile.Sync()
|
|
}
|
|
|
|
func (f FileObject) IsDifferent(fn FileObject) error {
|
|
if f.FileMode != fn.FileMode {
|
|
return errors.New("mode does not match")
|
|
}
|
|
|
|
if f.IsLink() {
|
|
if f.Ref != fn.Ref {
|
|
return errors.New("ref does not match")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if f.Size != fn.Size {
|
|
return errors.New("size does not match")
|
|
}
|
|
|
|
if !bytes.Equal(f.Sha1, fn.Sha1) {
|
|
return errors.New("sha1 does not match")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func CreateFileObject(f string) (FileObject, error) {
|
|
var (
|
|
sha1Hash hash.Hash = sha1.New()
|
|
fo FileObject
|
|
fi os.FileInfo
|
|
file *os.File
|
|
err error
|
|
)
|
|
|
|
fi, err = os.Lstat(f)
|
|
if err != nil {
|
|
return fo, err
|
|
}
|
|
|
|
fo = FileObject{
|
|
FileMode: fi.Mode(),
|
|
Size: fi.Size(),
|
|
}
|
|
|
|
if fo.IsLink() {
|
|
fo.Ref, err = os.Readlink(f)
|
|
if err != nil {
|
|
return fo, err
|
|
}
|
|
return fo, nil
|
|
|
|
}
|
|
|
|
file, err = os.Open(f)
|
|
if err != nil {
|
|
return fo, err
|
|
}
|
|
defer file.Close()
|
|
|
|
io.Copy(sha1Hash, file)
|
|
fo.Sha1 = sha1Hash.Sum(nil)
|
|
|
|
return fo, nil
|
|
}
|
|
|
|
func (f FileObject) ToBytes() ([]byte, error) {
|
|
var (
|
|
encoder *gob.Encoder
|
|
buf bytes.Buffer
|
|
err error
|
|
)
|
|
|
|
encoder = gob.NewEncoder(&buf)
|
|
err = encoder.Encode(f)
|
|
return buf.Bytes(), err
|
|
}
|
|
|
|
func FromBytes(v []byte) (FileObject, error) {
|
|
var (
|
|
buf *bytes.Buffer
|
|
decoder *gob.Decoder
|
|
fo FileObject
|
|
err error
|
|
)
|
|
|
|
buf = bytes.NewBuffer(v)
|
|
|
|
decoder = gob.NewDecoder(buf)
|
|
|
|
err = decoder.Decode(&fo)
|
|
if err != nil {
|
|
return fo, err
|
|
}
|
|
|
|
return fo, nil
|
|
}
|