Remove unnecessary interface methods and implement cur direcoty #95
15
cmd.go
15
cmd.go
|
@ -225,9 +225,18 @@ func (cmd commandCwd) RequireAuth() bool {
|
|||
|
||||
func (cmd commandCwd) Execute(conn *Conn, param string) {
|
||||
path := conn.buildPath(param)
|
||||
err := conn.driver.ChangeDir(path)
|
||||
info, err := conn.driver.Stat(path)
|
||||
if err != nil {
|
||||
conn.writeMessage(550, fmt.Sprint("Directory change to ", path, " failed: ", err))
|
||||
return
|
||||
}
|
||||
if !info.IsDir() {
|
||||
conn.writeMessage(550, fmt.Sprint("Directory change to ", path, " is a file"))
|
||||
return
|
||||
}
|
||||
|
||||
err = conn.changeCurDir(path)
|
||||
if err == nil {
|
||||
conn.namePrefix = path
|
||||
conn.writeMessage(250, "Directory changed to "+path)
|
||||
} else {
|
||||
conn.writeMessage(550, fmt.Sprint("Directory change to ", path, " failed: ", err))
|
||||
|
@ -713,7 +722,7 @@ func (cmd commandPwd) RequireAuth() bool {
|
|||
}
|
||||
|
||||
func (cmd commandPwd) Execute(conn *Conn, param string) {
|
||||
conn.writeMessage(257, "\""+conn.namePrefix+"\" is the current directory")
|
||||
conn.writeMessage(257, "\""+conn.curDir+"\" is the current directory")
|
||||
}
|
||||
|
||||
// CommandQuit responds to the QUIT FTP command. The client has requested the
|
||||
|
|
11
conn.go
11
conn.go
|
@ -37,7 +37,7 @@ type Conn struct {
|
|||
server *Server
|
||||
tlsConfig *tls.Config
|
||||
sessionID string
|
||||
namePrefix string
|
||||
curDir string
|
||||
reqUser string
|
||||
user string
|
||||
renameFrom string
|
||||
|
@ -242,9 +242,9 @@ func (conn *Conn) buildPath(filename string) (fullPath string) {
|
|||
if len(filename) > 0 && filename[0:1] == "/" {
|
||||
fullPath = filepath.Clean(filename)
|
||||
} else if len(filename) > 0 && filename != "-a" {
|
||||
fullPath = filepath.Clean(conn.namePrefix + "/" + filename)
|
||||
fullPath = filepath.Clean(conn.curDir + "/" + filename)
|
||||
} else {
|
||||
fullPath = filepath.Clean(conn.namePrefix)
|
||||
fullPath = filepath.Clean(conn.curDir)
|
||||
}
|
||||
fullPath = strings.Replace(fullPath, "//", "/", -1)
|
||||
fullPath = strings.Replace(fullPath, string(filepath.Separator), "/", -1)
|
||||
|
@ -279,3 +279,8 @@ func (conn *Conn) sendOutofBandDataWriter(data io.ReadCloser) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (conn *Conn) changeCurDir(path string) error {
|
||||
conn.curDir = path
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
func TestConnBuildPath(t *testing.T) {
|
||||
c := &Conn{
|
||||
namePrefix: "",
|
||||
curDir: "",
|
||||
}
|
||||
var pathtests = []struct {
|
||||
in string
|
||||
|
|
21
driver.go
21
driver.go
|
@ -20,20 +20,12 @@ type DriverFactory interface {
|
|||
// chosen persistence layer. graval will create a new instance of your
|
||||
// driver for each client that connects and delegate to it as required.
|
||||
type Driver interface {
|
||||
// Init init
|
||||
Init(*Conn)
|
||||
|
||||
// params - a file path
|
||||
// returns - a time indicating when the requested path was last modified
|
||||
// - an error if the file doesn't exist or the user lacks
|
||||
// permissions
|
||||
Stat(string) (FileInfo, error)
|
||||
|
||||
// params - path
|
||||
// returns - true if the current user is permitted to change to the
|
||||
// requested path
|
||||
ChangeDir(string) error
|
||||
|
||||
// params - path, function on file or subdir found
|
||||
// returns - error
|
||||
// path
|
||||
|
@ -71,19 +63,6 @@ type MultipleDriver struct {
|
|||
drivers map[string]Driver
|
||||
}
|
||||
|
||||
// Init init
|
||||
func (driver *MultipleDriver) Init(conn *Conn) {
|
||||
}
|
||||
|
||||
func (driver *MultipleDriver) ChangeDir(path string) error {
|
||||
for prefix, driver := range driver.drivers {
|
||||
if strings.HasPrefix(path, prefix) {
|
||||
return driver.ChangeDir(strings.TrimPrefix(path, prefix))
|
||||
}
|
||||
}
|
||||
return errors.New("Not a directory")
|
||||
}
|
||||
|
||||
func (driver *MultipleDriver) Stat(path string) (FileInfo, error) {
|
||||
for prefix, driver := range driver.drivers {
|
||||
if strings.HasPrefix(path, prefix) {
|
||||
|
|
|
@ -23,22 +23,6 @@ func (driver *FileDriver) realPath(path string) string {
|
|||
return filepath.Join(append([]string{driver.RootPath}, paths...)...)
|
||||
}
|
||||
|
||||
func (driver *FileDriver) Init(conn *Conn) {
|
||||
//driver.conn = conn
|
||||
}
|
||||
|
||||
func (driver *FileDriver) ChangeDir(path string) error {
|
||||
rPath := driver.realPath(path)
|
||||
f, err := os.Lstat(rPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.IsDir() {
|
||||
return nil
|
||||
}
|
||||
return errors.New("Not a directory")
|
||||
}
|
||||
|
||||
func (driver *FileDriver) Stat(path string) (FileInfo, error) {
|
||||
basepath := driver.realPath(path)
|
||||
rPath, err := filepath.Abs(basepath)
|
||||
|
@ -149,9 +133,9 @@ func (driver *FileDriver) GetFile(path string, offset int64) (int64, io.ReadClos
|
|||
return 0, nil, err
|
||||
}
|
||||
|
||||
f.Seek(offset, os.SEEK_SET)
|
||||
f.Seek(offset, io.SeekStart)
|
||||
|
||||
return info.Size(), f, nil
|
||||
return info.Size() - offset, f, nil
|
||||
}
|
||||
|
||||
func (driver *FileDriver) PutFile(destPath string, data io.Reader, appendData bool) (int64, error) {
|
||||
|
|
|
@ -7,6 +7,7 @@ package server
|
|||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -15,7 +16,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
_ Driver = &MinioDriver{}
|
||||
)
|
||||
|
||||
type MinioDriver struct {
|
||||
|
@ -24,17 +25,18 @@ type MinioDriver struct {
|
|||
bucket string
|
||||
}
|
||||
|
||||
func (driver *MinioDriver) Init(conn *Conn) {
|
||||
}
|
||||
|
||||
func (driver *MinioDriver) ChangeDir(path string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func buildMinioPath(p string) string {
|
||||
return strings.TrimPrefix(p, "/")
|
||||
}
|
||||
|
||||
func buildMinioDir(p string) string {
|
||||
v := buildMinioPath(p)
|
||||
if !strings.HasSuffix(v, "/") {
|
||||
return v + "/"
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
type minioFileInfo struct {
|
||||
p string
|
||||
info minio.ObjectInfo
|
||||
|
@ -80,15 +82,16 @@ func (m *minioFileInfo) Group() string {
|
|||
func (driver *MinioDriver) isDir(path string) (bool, error) {
|
||||
doneCh := make(chan struct{})
|
||||
defer close(doneCh)
|
||||
p := buildMinioPath(path)
|
||||
objectCh := driver.client.ListObjects(driver.bucket, p, false, doneCh)
|
||||
for object := range objectCh {
|
||||
if object.Err != nil {
|
||||
return false, object.Err
|
||||
}
|
||||
return true, nil
|
||||
p := buildMinioDir(path)
|
||||
info, err := driver.client.StatObject(driver.bucket, p, minio.StatObjectOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
|
||||
if info.Err != nil {
|
||||
return false, info.Err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (driver *MinioDriver) Stat(path string) (FileInfo, error) {
|
||||
|
@ -103,7 +106,7 @@ func (driver *MinioDriver) Stat(path string) (FileInfo, error) {
|
|||
p := buildMinioPath(path)
|
||||
objInfo, err := driver.client.StatObject(driver.bucket, p, minio.StatObjectOptions{})
|
||||
if err != nil {
|
||||
if isDir, err := driver.isDir(path); err != nil {
|
||||
if isDir, err := driver.isDir(p); err != nil {
|
||||
return nil, err
|
||||
} else if isDir {
|
||||
return &minioFileInfo{
|
||||
|
@ -132,6 +135,11 @@ func (driver *MinioDriver) ListDir(path string, callback func(FileInfo) error) e
|
|||
return object.Err
|
||||
}
|
||||
|
||||
// ignore itself
|
||||
if object.Key == p {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := callback(&minioFileInfo{
|
||||
p: object.Key,
|
||||
info: object,
|
||||
|
@ -149,7 +157,7 @@ func (driver *MinioDriver) DeleteDir(path string) error {
|
|||
defer close(doneCh)
|
||||
|
||||
p := buildMinioPath(path)
|
||||
objectCh := driver.client.ListObjects(driver.bucket, p, false, doneCh)
|
||||
objectCh := driver.client.ListObjects(driver.bucket, p, true, doneCh)
|
||||
for object := range objectCh {
|
||||
if object.Err != nil {
|
||||
return object.Err
|
||||
|
@ -181,32 +189,59 @@ func (driver *MinioDriver) Rename(fromPath string, toPath string) error {
|
|||
}
|
||||
|
||||
func (driver *MinioDriver) MakeDir(path string) error {
|
||||
return nil
|
||||
dirPath := buildMinioDir(path)
|
||||
_, err := driver.client.PutObject(driver.bucket, dirPath, nil, 0, minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
return err
|
||||
}
|
||||
|
||||
func (driver *MinioDriver) GetFile(path string, offset int64) (int64, io.ReadCloser, error) {
|
||||
if offset > 0 {
|
||||
return 0, nil, ErrNotImplemented
|
||||
}
|
||||
object, err := driver.client.GetObject(driver.bucket, buildMinioPath(path), minio.GetObjectOptions{})
|
||||
var opts = minio.GetObjectOptions{}
|
||||
object, err := driver.client.GetObject(driver.bucket, buildMinioPath(path), opts)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
object.Seek(offset, io.SeekStart)
|
||||
|
||||
info, err := object.Stat()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return info.Size, object, nil
|
||||
return info.Size - offset, object, nil
|
||||
}
|
||||
|
||||
func (driver *MinioDriver) PutFile(destPath string, data io.Reader, appendData bool) (int64, error) {
|
||||
p := buildMinioPath(destPath)
|
||||
if !appendData {
|
||||
return driver.client.PutObject(driver.bucket, buildMinioPath(destPath), data, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
return driver.client.PutObject(driver.bucket, p, data, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
}
|
||||
|
||||
return 0, ErrNotImplemented
|
||||
tempFile := p + ".tmp"
|
||||
//tempDstFile := p + ".dst"
|
||||
defer func() {
|
||||
if err := driver.DeleteFile(tempFile); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
/*if err := driver.DeleteFile(tempDstFile); err != nil {
|
||||
log.Println(err)
|
||||
}*/
|
||||
}()
|
||||
|
||||
size, err := driver.client.PutObject(driver.bucket, tempFile, data, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
var srcs = []minio.SourceInfo{
|
||||
minio.NewSourceInfo(driver.bucket, tempFile, nil),
|
||||
minio.NewSourceInfo(driver.bucket, p, nil),
|
||||
}
|
||||
dst, err := minio.NewDestinationInfo(driver.bucket, p, nil, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return size, driver.client.ComposeObject(dst, srcs)
|
||||
}
|
||||
|
||||
type MinioDriverFactory struct {
|
||||
|
|
|
@ -54,6 +54,10 @@ func TestMinioDriver(t *testing.T) {
|
|||
assert.NoError(t, f.Login("admin", "admin"))
|
||||
assert.Error(t, f.Login("admin", ""))
|
||||
|
||||
curDir, err := f.CurrentDir()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "/", curDir)
|
||||
|
||||
err = f.RemoveDir("/")
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
@ -73,8 +77,8 @@ func TestMinioDriver(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, len(entries))
|
||||
assert.EqualValues(t, "server_test.go", entries[0].Name)
|
||||
assert.EqualValues(t, 4, entries[0].Size)
|
||||
assert.EqualValues(t, ftp.EntryTypeFile, entries[0].Type)
|
||||
assert.EqualValues(t, len(buf), entries[0].Size)
|
||||
|
||||
size, err := f.FileSize("/server_test.go")
|
||||
assert.NoError(t, err)
|
||||
|
@ -107,6 +111,27 @@ func TestMinioDriver(t *testing.T) {
|
|||
assert.EqualValues(t, 4, entries[0].Size)
|
||||
assert.EqualValues(t, ftp.EntryTypeFile, entries[0].Type)
|
||||
|
||||
err = f.MakeDir("/src")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = f.ChangeDir("/src")
|
||||
assert.NoError(t, err)
|
||||
|
||||
curDir, err = f.CurrentDir()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "/src", curDir)
|
||||
|
||||
err = f.MakeDir("/new/1/2")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.NoError(t, f.Stor("/test/1/2/server_test3.go", strings.NewReader(content)))
|
||||
|
||||
r, err = f.RetrFrom("/test/1/2/server_test3.go", 2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
buf, err = ioutil.ReadAll(r)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "st", string(buf))
|
||||
break
|
||||
}
|
||||
})
|
||||
|
|
|
@ -163,7 +163,7 @@ func NewServer(opts *ServerOpts) *Server {
|
|||
// will handle all auth and persistence details.
|
||||
func (server *Server) newConn(tcpConn net.Conn, driver Driver) *Conn {
|
||||
c := new(Conn)
|
||||
c.namePrefix = "/"
|
||||
c.curDir = "/"
|
||||
c.conn = tcpConn
|
||||
c.controlReader = bufio.NewReader(tcpConn)
|
||||
c.controlWriter = bufio.NewWriter(tcpConn)
|
||||
|
@ -173,8 +173,6 @@ func (server *Server) newConn(tcpConn net.Conn, driver Driver) *Conn {
|
|||
c.sessionID = newSessionID()
|
||||
c.logger = server.logger
|
||||
c.tlsConfig = server.tlsConfig
|
||||
|
||||
driver.Init(c)
|
||||
return c
|
||||
}
|
||||
|
||||
|
|
|
@ -87,14 +87,13 @@ func TestFileDriver(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 4, size)
|
||||
|
||||
/*resp, err := f.RetrFrom("/server_test.go", 0)
|
||||
r, err := f.RetrFrom("/server_test.go", 2)
|
||||
assert.NoError(t, err)
|
||||
var buf []byte
|
||||
l, err := resp.Read(buf)
|
||||
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
r.Close()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 4, l)
|
||||
assert.EqualValues(t, 4, len(buf))
|
||||
assert.EqualValues(t, content, string(buf))*/
|
||||
assert.EqualValues(t, "st", string(buf))
|
||||
|
||||
err = f.Rename("/server_test.go", "/test.go")
|
||||
assert.NoError(t, err)
|
||||
|
@ -105,6 +104,13 @@ func TestFileDriver(t *testing.T) {
|
|||
err = f.Delete("/test.go")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = f.ChangeDir("/src")
|
||||
assert.NoError(t, err)
|
||||
|
||||
curDir, err = f.CurrentDir()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "/src", curDir)
|
||||
|
||||
err = f.RemoveDir("/src")
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user