mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-02 20:23:32 +08:00
227 lines
4.1 KiB
Go
227 lines
4.1 KiB
Go
package plg_backend_samba
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hirochachacha/go-smb2"
|
|
. "github.com/mickael-kerjean/filestash/server/common"
|
|
)
|
|
|
|
var SambaCache AppCache
|
|
|
|
func init() {
|
|
Backend.Register("samba", Samba{})
|
|
|
|
SambaCache = NewAppCache()
|
|
SambaCache.OnEvict(func(key string, value interface{}) {
|
|
smb := value.(*Samba)
|
|
err := smb.share.Umount()
|
|
if err != nil {
|
|
Log.Warning("samba: error unmounting share: %v", err)
|
|
}
|
|
err = smb.session.Logoff()
|
|
if err != nil {
|
|
Log.Warning("samba: error logging out: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
type Samba struct {
|
|
session *smb2.Session
|
|
share *smb2.Share
|
|
}
|
|
|
|
func (smb Samba) Init(params map[string]string, app *App) (IBackend, error) {
|
|
c := SambaCache.Get(params)
|
|
if c != nil {
|
|
return c.(*Samba), nil
|
|
}
|
|
|
|
conn, err := net.DialTimeout("tcp", params["host"]+":"+params["port"], 10*time.Second)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := &smb2.Dialer{
|
|
Initiator: &smb2.NTLMInitiator{
|
|
User: params["username"],
|
|
Password: params["password"],
|
|
Domain: params["domain"],
|
|
},
|
|
}
|
|
|
|
s := &Samba{}
|
|
s.session, err = d.Dial(conn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
s.share, err = s.session.Mount(params["share"])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
SambaCache.Set(params, s)
|
|
return s, nil
|
|
}
|
|
|
|
func (smb Samba) LoginForm() Form {
|
|
return Form{
|
|
Elmnts: []FormElement{
|
|
{
|
|
Name: "type",
|
|
Type: "hidden",
|
|
Value: "samba",
|
|
},
|
|
{
|
|
Name: "username",
|
|
Type: "text",
|
|
Placeholder: "Username",
|
|
},
|
|
{
|
|
Name: "domain",
|
|
Type: "text",
|
|
Placeholder: "Domain",
|
|
},
|
|
{
|
|
Name: "password",
|
|
Type: "long_password",
|
|
Placeholder: "Password",
|
|
},
|
|
{
|
|
Name: "host",
|
|
Type: "text",
|
|
Placeholder: "example.com",
|
|
Required: true,
|
|
},
|
|
{
|
|
Name: "port",
|
|
Type: "number",
|
|
Placeholder: "Default: 445",
|
|
Default: 445,
|
|
},
|
|
{
|
|
Name: "share",
|
|
Type: "text",
|
|
Placeholder: `sharename`,
|
|
Required: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (smb Samba) Ls(path string) ([]os.FileInfo, error) {
|
|
path, err := toSambaPath(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dir, err := smb.share.Open(path)
|
|
if err != nil {
|
|
return nil, fromSambaErr(err)
|
|
}
|
|
defer dir.Close()
|
|
|
|
fs, err := dir.Readdir(-1) // lists all files
|
|
return fs, fromSambaErr(err)
|
|
}
|
|
|
|
func (smb Samba) Cat(path string) (io.ReadCloser, error) {
|
|
path, err := toSambaPath(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
f, err := smb.share.Open(path)
|
|
return f, fromSambaErr(err)
|
|
}
|
|
|
|
func (smb Samba) Mkdir(path string) error {
|
|
path, err := toSambaPath(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return fromSambaErr(smb.share.Mkdir(path, os.ModeDir))
|
|
}
|
|
|
|
func (smb Samba) Rm(path string) error {
|
|
path, err := toSambaPath(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return fromSambaErr(smb.share.RemoveAll(path))
|
|
}
|
|
|
|
func (smb Samba) Mv(from, to string) error {
|
|
from, err := toSambaPath(from)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
to, err = toSambaPath(to)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return fromSambaErr(smb.share.Rename(from, to))
|
|
}
|
|
|
|
func (smb Samba) Save(path string, content io.Reader) error {
|
|
path, err := toSambaPath(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
f, err := smb.share.Create(path)
|
|
if err != nil {
|
|
return fromSambaErr(err)
|
|
}
|
|
|
|
_, err = io.Copy(f, content)
|
|
if err != nil {
|
|
f.Close()
|
|
return fromSambaErr(err)
|
|
}
|
|
|
|
return f.Close()
|
|
}
|
|
|
|
func (smb Samba) Touch(path string) error {
|
|
path, err := toSambaPath(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
f, err := smb.share.Create(path)
|
|
if err != nil {
|
|
return fromSambaErr(err)
|
|
}
|
|
return fromSambaErr(f.Close())
|
|
}
|
|
|
|
func toSambaPath(path string) (string, error) {
|
|
if strings.ContainsRune(path, '\\') {
|
|
// Backslashes aren't allowed on Windows, so we are conservative here
|
|
// since Samba volumes are often (not always) exposed from Windows
|
|
return "", ErrNotAllowed
|
|
}
|
|
|
|
path = strings.TrimLeft(path, `/`)
|
|
return strings.ReplaceAll(path, `/`, `\`), nil
|
|
}
|
|
|
|
func fromSambaErr(err error) error {
|
|
switch {
|
|
case os.IsPermission(err):
|
|
return ErrPermissionDenied
|
|
default:
|
|
return err
|
|
}
|
|
}
|