123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- package sftpfs
- import (
- "errors"
- "fmt"
- "io"
- "io/fs"
- "io/ioutil"
- "net/url"
- "os"
- "path/filepath"
- "strings"
- "time"
- "github.com/pkg/sftp"
- "golang.org/x/crypto/ssh"
- "imuslab.com/arozos/mod/filesystem/arozfs"
- )
- /*
- SFTP-FS.go
- SSH File Transfer Protocol as File System Abstraction
- */
- type SFTPFileSystemAbstraction struct {
- uuid string
- hierarchy string
- url string
- port int
- username string
- password string
- mountFolder string
- client *sftp.Client
- conn *ssh.Client
- }
- func NewSFTPFileSystemAbstraction(uuid string, hierarchy string, serverUrl string, port int, mountFolder string, username string, password string) (SFTPFileSystemAbstraction, error) {
- parsedUrl, err := url.Parse(serverUrl)
- if err != nil {
- return SFTPFileSystemAbstraction{}, errors.New("[SFTP] to parse url: " + err.Error())
- }
- // Get user name and pass
- //user := parsedUrl.User.Username()
- //, _ := parsedUrl.User.Password()
- // Parse Host and Port
- host := parsedUrl.Host
- fmt.Fprintf(os.Stdout, "Connecting to %s ...\n", host)
- var auths []ssh.AuthMethod
- // Use password authentication if provided
- if password != "" {
- auths = append(auths, ssh.Password(password))
- }
- // Initialize client configuration
- config := ssh.ClientConfig{
- User: username,
- Auth: auths,
- // Uncomment to ignore host key check
- HostKeyCallback: ssh.InsecureIgnoreHostKey(),
- //HostKeyCallback: ssh.FixedHostKey(hostKey),
- }
- addr := fmt.Sprintf("%s:%d", serverUrl, port)
- fmt.Println(addr, username, password)
- // Connect to server
- conn, err := ssh.Dial("tcp", addr, &config)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to connect to [%s] %v\n", addr, err)
- os.Exit(1)
- }
- // Create new SFTP client
- sc, err := sftp.NewClient(conn)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Unable to start SFTP subsystem: %v\n", err)
- os.Exit(1)
- }
- fmt.Println("Connection Succeed")
- return SFTPFileSystemAbstraction{
- uuid: uuid,
- hierarchy: hierarchy,
- url: serverUrl,
- port: port,
- username: username,
- password: password,
- mountFolder: mountFolder,
- client: sc,
- conn: conn,
- }, nil
- }
- func (s SFTPFileSystemAbstraction) Chmod(filename string, mode os.FileMode) error {
- filename = arozfs.GenericPathFilter(filename)
- return s.client.Chmod(filename, mode)
- }
- func (s SFTPFileSystemAbstraction) Chown(filename string, uid int, gid int) error {
- filename = arozfs.GenericPathFilter(filename)
- return s.client.Chown(filename, uid, gid)
- }
- func (s SFTPFileSystemAbstraction) Chtimes(filename string, atime time.Time, mtime time.Time) error {
- filename = arozfs.GenericPathFilter(filename)
- return s.client.Chtimes(filename, atime, mtime)
- }
- func (s SFTPFileSystemAbstraction) Create(filename string) (arozfs.File, error) {
- filename = arozfs.GenericPathFilter(filename)
- //TODO: ADD FILE TYPE CONVERSION
- return nil, arozfs.ErrNullOperation
- }
- func (s SFTPFileSystemAbstraction) Mkdir(filename string, mode os.FileMode) error {
- filename = arozfs.GenericPathFilter(filename)
- return s.client.Mkdir(filename)
- }
- func (s SFTPFileSystemAbstraction) MkdirAll(filename string, mode os.FileMode) error {
- filename = arozfs.GenericPathFilter(filename)
- return s.client.MkdirAll(filename)
- }
- func (s SFTPFileSystemAbstraction) Name() string {
- return ""
- }
- func (s SFTPFileSystemAbstraction) Open(filename string) (arozfs.File, error) {
- return nil, arozfs.ErrNullOperation
- }
- func (s SFTPFileSystemAbstraction) OpenFile(filename string, flag int, perm os.FileMode) (arozfs.File, error) {
- return nil, arozfs.ErrNullOperation
- }
- func (s SFTPFileSystemAbstraction) Remove(filename string) error {
- filename = arozfs.GenericPathFilter(filename)
- return s.client.Remove(filename)
- }
- func (s SFTPFileSystemAbstraction) RemoveAll(filename string) error {
- filename = arozfs.GenericPathFilter(filename)
- if s.IsDir(filename) {
- return s.client.RemoveDirectory(filename)
- }
- return s.Remove(filename)
- }
- func (s SFTPFileSystemAbstraction) Rename(oldname, newname string) error {
- oldname = arozfs.GenericPathFilter(oldname)
- newname = arozfs.GenericPathFilter(newname)
- return s.client.Rename(oldname, newname)
- }
- func (s SFTPFileSystemAbstraction) Stat(filename string) (os.FileInfo, error) {
- filename = arozfs.GenericPathFilter(filename)
- return s.client.Stat(filename)
- }
- func (s SFTPFileSystemAbstraction) Close() error {
- err := s.client.Close()
- if err != nil {
- return err
- }
- err = s.conn.Close()
- if err != nil {
- return err
- }
- return nil
- }
- /*
- Abstraction Utilities
- */
- func (s SFTPFileSystemAbstraction) VirtualPathToRealPath(subpath string, username string) (string, error) {
- return arozfs.GenericVirtualPathToRealPathTranslator(s.uuid, s.hierarchy, subpath, username)
- }
- func (s SFTPFileSystemAbstraction) RealPathToVirtualPath(fullpath string, username string) (string, error) {
- return arozfs.GenericRealPathToVirtualPathTranslator(s.uuid, s.hierarchy, fullpath, username)
- }
- func (s SFTPFileSystemAbstraction) FileExists(realpath string) bool {
- _, err := s.Stat(realpath)
- if err != nil {
- return false
- }
- return true
- }
- func (s SFTPFileSystemAbstraction) IsDir(realpath string) bool {
- info, err := s.Stat(realpath)
- if err != nil {
- return false
- }
- return info.IsDir()
- }
- func (s SFTPFileSystemAbstraction) Glob(realpathWildcard string) ([]string, error) {
- realpathWildcard = arozfs.GenericPathFilter(realpathWildcard)
- return s.client.Glob(realpathWildcard)
- }
- func (s SFTPFileSystemAbstraction) GetFileSize(realpath string) int64 {
- info, err := s.Stat(realpath)
- if err != nil {
- return 0
- }
- return info.Size()
- }
- func (s SFTPFileSystemAbstraction) GetModTime(realpath string) (int64, error) {
- info, err := s.Stat(realpath)
- if err != nil {
- return 0, err
- }
- return info.ModTime().Unix(), nil
- }
- func (s SFTPFileSystemAbstraction) WriteFile(filename string, content []byte, mode os.FileMode) error {
- filename = arozfs.GenericPathFilter(filename)
- f, err := s.client.OpenFile(filename, os.O_CREATE|os.O_WRONLY)
- if err != nil {
- return err
- }
- _, err = f.Write(content)
- return err
- }
- func (s SFTPFileSystemAbstraction) ReadFile(filename string) ([]byte, error) {
- filename = arozfs.GenericPathFilter(filename)
- f, err := s.client.OpenFile(filename, os.O_RDONLY)
- if err != nil {
- return []byte(""), err
- }
- return ioutil.ReadAll(f)
- }
- func (s SFTPFileSystemAbstraction) ReadDir(filename string) ([]fs.DirEntry, error) {
- result := []fs.DirEntry{}
- infos, err := s.client.ReadDir(filename)
- if err != nil {
- return result, err
- }
- for _, finfo := range infos {
- de := newDirEntryFromFileInfo(finfo)
- result = append(result, de)
- }
- return result, nil
- }
- func (s SFTPFileSystemAbstraction) WriteStream(filename string, stream io.Reader, mode os.FileMode) error {
- filename = arozfs.GenericPathFilter(filename)
- f, err := s.client.OpenFile(filename, os.O_CREATE|os.O_WRONLY)
- if err != nil {
- return err
- }
- _, err = io.Copy(f, stream)
- return err
- }
- func (s SFTPFileSystemAbstraction) ReadStream(filename string) (io.ReadCloser, error) {
- filename = arozfs.GenericPathFilter(filename)
- f, err := s.client.OpenFile(filename, os.O_RDONLY)
- if err != nil {
- return nil, err
- }
- return f, nil
- }
- func (s SFTPFileSystemAbstraction) Walk(root string, walkFn filepath.WalkFunc) error {
- walker := s.client.Walk(root)
- for walker.Step() {
- walkFn(walker.Path(), walker.Stat(), walker.Err())
- }
- return nil
- }
- func (s SFTPFileSystemAbstraction) Heartbeat() error {
- return nil
- }
- //Utilities
- func filterFilepath(rawpath string) string {
- rawpath = arozfs.ToSlash(filepath.Clean(strings.TrimSpace(rawpath)))
- if strings.HasPrefix(rawpath, "./") {
- return rawpath[1:]
- } else if rawpath == "." || rawpath == "" {
- return "/"
- }
- return rawpath
- }
|