package storage
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
|
|
"cygnux.net/kepler/config"
|
|
)
|
|
|
|
type FileSystem struct {
|
|
cdn string
|
|
root string
|
|
prefix string
|
|
minFreeSize int64
|
|
allowZeroFile bool
|
|
autoCreateDirectory bool
|
|
removeEmptyDirectory bool
|
|
defaultFilePerm os.FileMode
|
|
defaultDirPerm os.FileMode
|
|
}
|
|
|
|
func NewFileSystem(cfg config.Config) (Storage, error) {
|
|
var fs FileSystem
|
|
if root := cfg.GetString("root"); root == "" {
|
|
return nil, fmt.Errorf("root can not be empty")
|
|
} else if !path.IsAbs(root) {
|
|
return nil, fmt.Errorf("root '%s' should be an albsolute path", root)
|
|
} else if rootInfo, e := os.Stat(root); nil != e {
|
|
return nil, e
|
|
} else if !rootInfo.IsDir() {
|
|
return nil, fmt.Errorf("root '%s' is not a directory", root)
|
|
} else {
|
|
fs.root = root
|
|
}
|
|
fs.cdn = cfg.GetString("cdn")
|
|
fs.prefix = cfg.GetString("prefix", "/")
|
|
fs.minFreeSize = cfg.GetInt64("min_free_size", 10*GB)
|
|
fs.allowZeroFile = cfg.GetBool("allow_zero_file", false)
|
|
fs.removeEmptyDirectory = cfg.GetBool("remove_empty_directory", false)
|
|
fs.autoCreateDirectory = cfg.GetBool("auto_create_directory", true)
|
|
fs.defaultDirPerm = os.FileMode(cfg.GetInt32("default_dir_perm", 0755))
|
|
fs.defaultFilePerm = os.FileMode(cfg.GetInt32("default_file_perm", 0644))
|
|
return fs, nil
|
|
}
|
|
|
|
func (fs FileSystem) CDN() string {
|
|
return fs.cdn
|
|
}
|
|
|
|
func (fs FileSystem) Root() string {
|
|
return fs.root
|
|
}
|
|
|
|
func (fs FileSystem) Prefix() string {
|
|
return fs.prefix
|
|
}
|
|
|
|
func (fs FileSystem) SaveFile(src interface{}, destination string) (FileObject, error) {
|
|
switch st := src.(type) {
|
|
case string:
|
|
return fs.copyFile(st, destination)
|
|
case io.Reader:
|
|
return fs.saveIOReader(st, destination)
|
|
case []byte:
|
|
return fs.saveBytes(st, destination)
|
|
default:
|
|
return nil, fmt.Errorf("unknow source type")
|
|
}
|
|
//return nil, fmt.Errorf("unknow source type")
|
|
}
|
|
|
|
func (fs FileSystem) copyFile(src string, destination string) (FileObject, error) {
|
|
log.Debugln("FileSystem.copyFile:>", src, destination)
|
|
if fp, e := os.Open(src); nil != e {
|
|
log.Errorln("FileSystem.copyFile:> open src file failed:", e)
|
|
return nil, e
|
|
} else if out, e := fs.createFile(destination); nil != e {
|
|
log.Errorln("FileSystem.copyFile:> create file failed:", e)
|
|
return nil, e
|
|
} else if n, e := io.Copy(out, fp); nil != e {
|
|
log.Errorln("FileSystem.copyFile:> Copy failed:", e)
|
|
return nil, e
|
|
} else {
|
|
return fsObject{
|
|
root: fs.root,
|
|
prefix: fs.prefix,
|
|
filename: destination,
|
|
size: n,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func (fs FileSystem) saveBytes(src []byte, destination string) (FileObject, error) {
|
|
log.Debugln("FileSystem.saveBytes:>", len(src), destination)
|
|
if len(src) < 1 && !fs.allowZeroFile {
|
|
log.Errorln("FileSystem.saveBytes:> not allow to create zero file")
|
|
return nil, fmt.Errorf("saving zero bytes file is not allowed")
|
|
}
|
|
if out, e := fs.createFile(destination); nil != e {
|
|
log.Errorln("FileSystem.saveBytes:> create file failed:", e)
|
|
return nil, e
|
|
} else if n, e := out.Write(src); nil != e {
|
|
log.Errorln("FileSystem.saveBytes:> write file failed:", e)
|
|
return nil, e
|
|
} else {
|
|
return fsObject{
|
|
root: fs.root,
|
|
prefix: fs.prefix,
|
|
filename: destination,
|
|
size: int64(n),
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func (fs FileSystem) saveIOReader(src io.Reader, destination string) (FileObject, error) {
|
|
log.Debugln("FileSystem.saveIOReader:> ", src, destination)
|
|
if out, e := fs.createFile(destination); nil != e {
|
|
log.Errorln("FileSystem.saveIOReader:> create file failed:", e)
|
|
return nil, e
|
|
} else if n, e := io.Copy(out, src); nil != e {
|
|
log.Errorln("FileSystem.saveIOReader:> copy file failed:", e)
|
|
return nil, e
|
|
} else {
|
|
return fsObject{
|
|
root: fs.root,
|
|
prefix: fs.prefix,
|
|
filename: destination,
|
|
size: n,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func (fs FileSystem) createFile(destination string) (*os.File, error) {
|
|
destination = path.Join(fs.root, destination)
|
|
if _, e := os.Stat(destination); nil == e {
|
|
log.Errorln("FileSystem.createFile:> target file already exists!", destination)
|
|
return nil, fmt.Errorf("target file '%s' already exists", destination)
|
|
}
|
|
dir := path.Dir(destination)
|
|
if dirInfo, e := os.Stat(dir); nil != e {
|
|
if fs.autoCreateDirectory {
|
|
if e := fs.createDirectory(dir); nil != e {
|
|
log.Errorln("FileSystem.createFile:> createDirector failed:", e)
|
|
return nil, e
|
|
}
|
|
} else {
|
|
log.Errorln("FileSystem.createFile:> target path is not exists:", dir)
|
|
return nil, fmt.Errorf("target path '%s' is not exists", dir)
|
|
}
|
|
} else if !dirInfo.IsDir() {
|
|
log.Errorln("FileSystem.createFile:> target path is not a dir:", dir)
|
|
return nil, fmt.Errorf("target path '%s' is already exists and it is not a directory", dir)
|
|
}
|
|
if fp, e := os.OpenFile(destination, os.O_CREATE|os.O_WRONLY, fs.defaultFilePerm); nil != e {
|
|
log.Errorln("FileSystem.createFile:> OpenFile failed:", e)
|
|
return nil, e
|
|
} else {
|
|
return fp, nil
|
|
}
|
|
}
|
|
|
|
func (fs FileSystem) createDirectory(path string) error {
|
|
if path == "" || path == "." || path == ".." {
|
|
return nil
|
|
}
|
|
return os.MkdirAll(path, fs.defaultDirPerm)
|
|
}
|
|
|
|
func (fs FileSystem) DeleteFile(root, filename string) error {
|
|
if e := os.Remove(path.Join(root, filename)); nil != e {
|
|
return e
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (fs FileSystem) OpenFile(root, filename string) (io.ReadSeeker, error) {
|
|
return os.Open(path.Join(root, filename))
|
|
}
|
|
|
|
func (fs FileSystem) Stat(root, filename string) (os.FileInfo, error) {
|
|
return os.Stat(path.Join(root, filename))
|
|
}
|
|
|
|
func init() {
|
|
Register("fs", NewFileSystem)
|
|
Register("filesystem", NewFileSystem)
|
|
}
|