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 e error if f.IsLink() { _, e = os.Lstat(dst) if !os.IsNotExist(e) { e = os.Remove(dst) if e != nil { return e } } e = os.Symlink(f.Ref, dst) if e != nil { return e } return nil } f.cp(f.objFile(), dst) e = os.Chmod(dst, f.FileMode) if e != nil { return e } return nil } func (f FileObject) Stov(src string) error { var e error if f.IsLink() { return nil } e = os.MkdirAll(f.objDir(), 0744) if e != nil { return e } f.cp(src, f.objFile()) return nil } func (f FileObject) cp(src string, dst string) error { var ( srcFile, dstFile *os.File e error ) fmt.Println("cp ", src, dst) srcFile, e = os.Open(src) if e != nil { return e } defer srcFile.Close() dstFile, e = os.Create(dst) if e != nil { return e } defer dstFile.Close() _, e = io.Copy(dstFile, srcFile) if e != nil { return e } 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.Compare(f.Sha1, fn.Sha1) != 0 { 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 e error ) fi, e = os.Lstat(f) if e != nil { return fo, e } fo = FileObject{ FileMode: fi.Mode(), Size: fi.Size(), } if fo.IsLink() { fo.Ref, e = os.Readlink(f) if e != nil { return fo, e } return fo, nil } file, e = os.Open(f) if e != nil { return fo, e } 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 e error ) encoder = gob.NewEncoder(&buf) e = encoder.Encode(f) return buf.Bytes(), e } func FromBytes(v []byte) (FileObject, error) { var ( buf *bytes.Buffer decoder *gob.Decoder fo FileObject e error ) buf = bytes.NewBuffer(v) decoder = gob.NewDecoder(buf) e = decoder.Decode(&fo) if e != nil { return fo, e } return fo, nil }