2017-05-11 14:39:54 +00:00
|
|
|
package sftp_test
|
|
|
|
|
|
|
|
import (
|
2018-01-16 13:20:59 +00:00
|
|
|
"bufio"
|
2017-05-11 14:39:54 +00:00
|
|
|
"fmt"
|
2018-01-16 13:20:59 +00:00
|
|
|
"io"
|
2017-05-11 14:39:54 +00:00
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2017-07-23 07:51:42 +00:00
|
|
|
"path"
|
|
|
|
"strings"
|
2017-05-11 14:39:54 +00:00
|
|
|
|
|
|
|
"github.com/pkg/sftp"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
|
)
|
|
|
|
|
|
|
|
func Example() {
|
|
|
|
var conn *ssh.Client
|
|
|
|
|
|
|
|
// open an SFTP session over an existing ssh connection.
|
|
|
|
sftp, err := sftp.NewClient(conn)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer sftp.Close()
|
|
|
|
|
|
|
|
// walk a directory
|
|
|
|
w := sftp.Walk("/home/user")
|
|
|
|
for w.Step() {
|
|
|
|
if w.Err() != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
log.Println(w.Path())
|
|
|
|
}
|
|
|
|
|
|
|
|
// leave your mark
|
|
|
|
f, err := sftp.Create("hello.txt")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
if _, err := f.Write([]byte("Hello world!")); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// check it's there
|
|
|
|
fi, err := sftp.Lstat("hello.txt")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
log.Println(fi)
|
|
|
|
}
|
|
|
|
|
|
|
|
func ExampleNewClientPipe() {
|
|
|
|
// Connect to a remote host and request the sftp subsystem via the 'ssh'
|
|
|
|
// command. This assumes that passwordless login is correctly configured.
|
|
|
|
cmd := exec.Command("ssh", "example.com", "-s", "sftp")
|
|
|
|
|
|
|
|
// send errors from ssh to stderr
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
|
|
|
|
// get stdin and stdout
|
|
|
|
wr, err := cmd.StdinPipe()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
rd, err := cmd.StdoutPipe()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// start the process
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer cmd.Wait()
|
|
|
|
|
|
|
|
// open the SFTP session
|
|
|
|
client, err := sftp.NewClientPipe(rd, wr)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// read a directory
|
|
|
|
list, err := client.ReadDir("/")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// print contents
|
|
|
|
for _, item := range list {
|
|
|
|
fmt.Println(item.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
// close the connection
|
|
|
|
client.Close()
|
|
|
|
}
|
2017-07-23 07:51:42 +00:00
|
|
|
|
|
|
|
func ExampleClient_Mkdir_parents() {
|
|
|
|
// Example of mimicing 'mkdir --parents'; I.E. recursively create
|
|
|
|
// directoryies and don't error if any directories already exists.
|
|
|
|
var conn *ssh.Client
|
|
|
|
|
|
|
|
client, err := sftp.NewClient(conn)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer client.Close()
|
|
|
|
|
2017-09-30 14:27:27 +00:00
|
|
|
sshFxFailure := uint32(4)
|
2017-07-23 07:51:42 +00:00
|
|
|
mkdirParents := func(client *sftp.Client, dir string) (err error) {
|
|
|
|
var parents string
|
2018-01-16 13:20:59 +00:00
|
|
|
|
2017-09-30 14:27:27 +00:00
|
|
|
if path.IsAbs(dir) {
|
|
|
|
// Otherwise, an absolute path given below would be turned in to a relative one
|
|
|
|
// by splitting on "/"
|
|
|
|
parents = "/"
|
|
|
|
}
|
2018-01-16 13:20:59 +00:00
|
|
|
|
2017-07-23 07:51:42 +00:00
|
|
|
for _, name := range strings.Split(dir, "/") {
|
2017-09-30 14:27:27 +00:00
|
|
|
if name == "" {
|
|
|
|
// Paths with double-/ in them should just move along
|
|
|
|
// this will also catch the case of the first character being a "/", i.e. an absolute path
|
|
|
|
continue
|
|
|
|
}
|
2017-07-23 07:51:42 +00:00
|
|
|
parents = path.Join(parents, name)
|
|
|
|
err = client.Mkdir(parents)
|
|
|
|
if status, ok := err.(*sftp.StatusError); ok {
|
2017-09-30 14:27:27 +00:00
|
|
|
if status.Code == sshFxFailure {
|
2017-07-23 07:51:42 +00:00
|
|
|
var fi os.FileInfo
|
|
|
|
fi, err = client.Stat(parents)
|
|
|
|
if err == nil {
|
|
|
|
if !fi.IsDir() {
|
|
|
|
return fmt.Errorf("File exists: %s", parents)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = mkdirParents(client, "/tmp/foo/bar")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2018-01-16 13:20:59 +00:00
|
|
|
|
|
|
|
func ExampleFile_ReadFrom_bufio() {
|
|
|
|
// Using Bufio to buffer writes going to an sftp.File won't buffer as it
|
|
|
|
// skips buffering if the underlying writer support ReadFrom. The
|
|
|
|
// workaround is to wrap your writer in a struct that only implements
|
|
|
|
// io.Writer.
|
|
|
|
//
|
|
|
|
// For background see github.com/pkg/sftp/issues/125
|
|
|
|
|
|
|
|
var data_source io.Reader
|
|
|
|
var f *sftp.File
|
|
|
|
type writerOnly struct{ io.Writer }
|
|
|
|
bw := bufio.NewWriter(writerOnly{f}) // no ReadFrom()
|
|
|
|
bw.ReadFrom(data_source)
|
|
|
|
}
|