github.com/mckael/restic@v0.8.3/internal/backend/sftp/config.go (about) 1 package sftp 2 3 import ( 4 "net/url" 5 "path" 6 "strings" 7 8 "github.com/restic/restic/internal/errors" 9 "github.com/restic/restic/internal/options" 10 ) 11 12 // Config collects all information required to connect to an sftp server. 13 type Config struct { 14 User, Host, Path string 15 Layout string `option:"layout" help:"use this backend directory layout (default: auto-detect)"` 16 Command string `option:"command" help:"specify command to create sftp connection"` 17 } 18 19 func init() { 20 options.Register("sftp", Config{}) 21 } 22 23 // ParseConfig parses the string s and extracts the sftp config. The 24 // supported configuration formats are sftp://user@host/directory 25 // and sftp:user@host:directory. The directory will be path Cleaned and can 26 // be an absolute path if it starts with a '/' (e.g. 27 // sftp://user@host//absolute and sftp:user@host:/absolute). 28 func ParseConfig(s string) (interface{}, error) { 29 var user, host, dir string 30 switch { 31 case strings.HasPrefix(s, "sftp://"): 32 // parse the "sftp://user@host/path" url format 33 url, err := url.Parse(s) 34 if err != nil { 35 return nil, errors.Wrap(err, "url.Parse") 36 } 37 if url.User != nil { 38 user = url.User.Username() 39 } 40 host = url.Host 41 dir = url.Path 42 if dir == "" { 43 return nil, errors.Errorf("invalid backend %q, no directory specified", s) 44 } 45 46 dir = dir[1:] 47 case strings.HasPrefix(s, "sftp:"): 48 // parse the sftp:user@host:path format, which means we'll get 49 // "user@host:path" in s 50 s = s[5:] 51 // split user@host and path at the colon 52 data := strings.SplitN(s, ":", 2) 53 if len(data) < 2 { 54 return nil, errors.New("sftp: invalid format, hostname or path not found") 55 } 56 host = data[0] 57 dir = data[1] 58 // split user and host at the "@" 59 data = strings.SplitN(host, "@", 2) 60 if len(data) == 2 { 61 user = data[0] 62 host = data[1] 63 } 64 default: 65 return nil, errors.New(`invalid format, does not start with "sftp:"`) 66 } 67 68 p := path.Clean(dir) 69 if strings.HasPrefix(p, "~") { 70 return nil, errors.Fatal("sftp path starts with the tilde (~) character, that fails for most sftp servers.\nUse a relative directory, most servers interpret this as relative to the user's home directory.") 71 } 72 73 return Config{ 74 User: user, 75 Host: host, 76 Path: p, 77 }, nil 78 }