2016-07-19 03:58:57 +08:00
|
|
|
package sftp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2016-07-19 06:53:13 +08:00
|
|
|
"syscall"
|
2016-07-19 03:58:57 +08:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ = fmt.Println
|
|
|
|
|
|
|
|
func InMemHandler() Handlers {
|
2016-07-19 06:53:13 +08:00
|
|
|
root := &root{
|
|
|
|
files: make(map[string]*memFile),
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
root.memFile = newMemFile("/", true)
|
|
|
|
return Handlers{root, root, root, root}
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
|
|
|
|
2016-07-19 06:53:13 +08:00
|
|
|
//
|
|
|
|
type root struct {
|
|
|
|
*memFile
|
|
|
|
files map[string]*memFile
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
|
|
|
|
2016-07-19 06:53:13 +08:00
|
|
|
func (r *root) fetch(path string) (*memFile, error) {
|
|
|
|
fmt.Println("fetch", r.files)
|
|
|
|
if path == "/" {
|
|
|
|
return r.memFile, nil
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
if file, ok := r.files[path]; ok {
|
|
|
|
return file, nil
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
return nil, os.ErrNotExist
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handlers
|
2016-07-19 06:53:13 +08:00
|
|
|
func (fs *root) Fileread(r *Request) (io.Reader, error) {
|
|
|
|
file, err := fs.fetch(r.Filepath)
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if file.symlink != "" {
|
2016-07-19 06:53:13 +08:00
|
|
|
file, err = fs.fetch(file.symlink)
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return file.Reader()
|
|
|
|
}
|
|
|
|
|
2016-07-19 06:53:13 +08:00
|
|
|
func (fs *root) Filewrite(r *Request) (io.Writer, error) {
|
|
|
|
file, err := fs.fetch(r.Filepath)
|
2016-07-19 03:58:57 +08:00
|
|
|
if err == os.ErrNotExist {
|
2016-07-19 06:53:13 +08:00
|
|
|
dir, err := fs.fetch(filepath.Dir(r.Filepath))
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
if !dir.isdir {
|
|
|
|
return nil, os.ErrInvalid
|
|
|
|
}
|
|
|
|
file = newMemFile(r.Filepath, false)
|
|
|
|
fs.files[r.Filepath] = file
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
|
|
|
return file.Writer()
|
|
|
|
}
|
|
|
|
|
2016-07-19 06:53:13 +08:00
|
|
|
func (fs *root) Filecmd(r *Request) error {
|
2016-07-19 03:58:57 +08:00
|
|
|
switch r.Method {
|
|
|
|
case "SetStat":
|
|
|
|
return nil
|
|
|
|
case "Rename":
|
2016-07-19 06:53:13 +08:00
|
|
|
file, err := fs.fetch(r.Filepath)
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
fs.files[r.Target] = file
|
|
|
|
delete(fs.files, r.Filepath)
|
2016-07-19 03:58:57 +08:00
|
|
|
case "Rmdir", "Remove":
|
2016-07-19 06:53:13 +08:00
|
|
|
_, err := fs.fetch(filepath.Dir(r.Filepath))
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
delete(fs.files, r.Filepath)
|
2016-07-19 03:58:57 +08:00
|
|
|
case "Mkdir":
|
2016-07-19 06:53:13 +08:00
|
|
|
_, err := fs.fetch(filepath.Dir(r.Filepath))
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
fs.files[r.Filepath] = newMemFile(r.Filepath, true)
|
2016-07-19 03:58:57 +08:00
|
|
|
case "Symlink":
|
|
|
|
fmt.Println("ln -s", r.Filepath, r.Target)
|
2016-07-19 06:53:13 +08:00
|
|
|
_, err := fs.fetch(r.Filepath)
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
link := newMemFile(r.Target, false)
|
|
|
|
link.symlink = r.Filepath
|
|
|
|
fs.files[r.Target] = link
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-07-19 06:53:13 +08:00
|
|
|
func (fs *root) Fileinfo(r *Request) ([]os.FileInfo, error) {
|
2016-07-19 03:58:57 +08:00
|
|
|
switch r.Method {
|
|
|
|
case "List":
|
2016-07-19 06:53:13 +08:00
|
|
|
list := []os.FileInfo{}
|
|
|
|
fmt.Println("ls", r.Filepath)
|
|
|
|
for fn, fi := range fs.files {
|
|
|
|
if filepath.Dir(fn) == r.Filepath {
|
|
|
|
fmt.Println(fn, fi.Name())
|
|
|
|
list = append(list, fi)
|
2016-07-19 03:58:57 +08:00
|
|
|
}
|
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
return list, nil
|
2016-07-19 03:58:57 +08:00
|
|
|
case "Stat":
|
2016-07-19 06:53:13 +08:00
|
|
|
file, err := fs.fetch(r.Filepath)
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return []os.FileInfo{file}, nil
|
|
|
|
case "Readlink":
|
2016-07-19 06:53:13 +08:00
|
|
|
file, err := fs.fetch(r.Filepath)
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
if file.symlink != "" {
|
|
|
|
file, err = fs.fetch(file.symlink)
|
2016-07-19 03:58:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return []os.FileInfo{file}, nil
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
2016-07-19 06:53:13 +08:00
|
|
|
|
|
|
|
// Implements os.FileInfo interface
|
|
|
|
type memFile struct {
|
|
|
|
name string
|
|
|
|
content []byte
|
|
|
|
modtime time.Time
|
|
|
|
symlink string
|
|
|
|
isdir bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMemFile(name string, isdir bool) *memFile {
|
|
|
|
return &memFile{
|
|
|
|
name: name,
|
|
|
|
modtime: time.Now(),
|
|
|
|
isdir: isdir,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Have memFile fulfill os.FileInfo interface
|
|
|
|
func (f *memFile) Name() string {
|
|
|
|
return filepath.Base(f.name)
|
|
|
|
}
|
|
|
|
func (f *memFile) Size() int64 { return int64(len(f.content)) }
|
|
|
|
func (f *memFile) Mode() os.FileMode {
|
|
|
|
ret := os.FileMode(0644)
|
|
|
|
if f.isdir {
|
|
|
|
ret = os.FileMode(0755) | os.ModeDir
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
func (f *memFile) ModTime() time.Time { return time.Now() }
|
|
|
|
func (f *memFile) IsDir() bool { return f.isdir }
|
|
|
|
func (f *memFile) Sys() interface{} {
|
|
|
|
return syscall.Stat_t{Uid: 65534, Gid: 65534}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read/Write
|
|
|
|
func (f *memFile) Reader() (io.Reader, error) {
|
|
|
|
if f.isdir {
|
|
|
|
return nil, os.ErrInvalid
|
|
|
|
}
|
|
|
|
return bytes.NewReader(f.content), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *memFile) Writer() (io.Writer, error) {
|
|
|
|
if f.isdir {
|
|
|
|
return nil, os.ErrInvalid
|
|
|
|
}
|
|
|
|
return f, nil
|
|
|
|
}
|
|
|
|
func (f *memFile) Write(p []byte) (int, error) {
|
|
|
|
f.content = append(f.content, p...)
|
|
|
|
return len(p), nil
|
|
|
|
}
|