package Filesystem
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/gob"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"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 (
|
|
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
|
|
}
|