| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | package sftp | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // sftp integration tests
 | 
					
						
							|  |  |  |  | // enable with -integration
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-02-13 11:37:13 +08:00
										 |  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2013-11-15 18:47:28 +08:00
										 |  |  |  | 	"crypto/sha1" | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | 	"encoding" | 
					
						
							|  |  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2013-11-08 19:11:02 +08:00
										 |  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	"os" | 
					
						
							|  |  |  |  | 	"os/exec" | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	"os/user" | 
					
						
							| 
									
										
										
										
											2013-11-08 18:00:26 +08:00
										 |  |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	"testing/quick" | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-15 03:27:51 +08:00
										 |  |  |  | 	"github.com/kr/fs" | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 	READONLY                = true | 
					
						
							|  |  |  |  | 	READWRITE               = false | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	NODELAY   time.Duration = 0 | 
					
						
							| 
									
										
										
										
											2013-11-08 18:00:26 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 	debuglevel = "ERROR" // set to "DEBUG" for debugging
 | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | type delayedWrite struct { | 
					
						
							|  |  |  |  | 	t time.Time | 
					
						
							|  |  |  |  | 	b []byte | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // delayedWriter wraps a writer and artificially delays the write. This is
 | 
					
						
							|  |  |  |  | // meant to mimic connections with various latencies. Error's returned from the
 | 
					
						
							|  |  |  |  | // underlying writer will panic so this should only be used over reliable
 | 
					
						
							|  |  |  |  | // connections.
 | 
					
						
							|  |  |  |  | type delayedWriter struct { | 
					
						
							|  |  |  |  | 	w      io.WriteCloser | 
					
						
							|  |  |  |  | 	ch     chan delayedWrite | 
					
						
							|  |  |  |  | 	closed chan struct{} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func newDelayedWriter(w io.WriteCloser, delay time.Duration) io.WriteCloser { | 
					
						
							|  |  |  |  | 	ch := make(chan delayedWrite, 128) | 
					
						
							|  |  |  |  | 	closed := make(chan struct{}) | 
					
						
							|  |  |  |  | 	go func() { | 
					
						
							|  |  |  |  | 		for writeMsg := range ch { | 
					
						
							| 
									
										
										
										
											2018-02-16 03:17:19 +08:00
										 |  |  |  | 			time.Sleep(time.Until(writeMsg.t.Add(delay))) | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 			n, err := w.Write(writeMsg.b) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				panic("write error") | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if n < len(writeMsg.b) { | 
					
						
							|  |  |  |  | 				panic("showrt write") | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		w.Close() | 
					
						
							|  |  |  |  | 		close(closed) | 
					
						
							|  |  |  |  | 	}() | 
					
						
							|  |  |  |  | 	return delayedWriter{w: w, ch: ch, closed: closed} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func (w delayedWriter) Write(b []byte) (int, error) { | 
					
						
							|  |  |  |  | 	bcopy := make([]byte, len(b)) | 
					
						
							|  |  |  |  | 	copy(bcopy, b) | 
					
						
							|  |  |  |  | 	w.ch <- delayedWrite{t: time.Now(), b: bcopy} | 
					
						
							|  |  |  |  | 	return len(b), nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func (w delayedWriter) Close() error { | 
					
						
							|  |  |  |  | 	close(w.ch) | 
					
						
							|  |  |  |  | 	<-w.closed | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | // netPipe provides a pair of io.ReadWriteClosers connected to each other.
 | 
					
						
							|  |  |  |  | // The functions is identical to os.Pipe with the exception that netPipe
 | 
					
						
							| 
									
										
										
										
											2017-07-04 04:14:51 +08:00
										 |  |  |  | // provides the Read/Close guarantees that os.File derrived pipes do not.
 | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | func netPipe(t testing.TB) (io.ReadWriteCloser, io.ReadWriteCloser) { | 
					
						
							|  |  |  |  | 	type result struct { | 
					
						
							|  |  |  |  | 		net.Conn | 
					
						
							|  |  |  |  | 		error | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	l, err := net.Listen("tcp", "127.0.0.1:0") | 
					
						
							| 
									
										
										
										
											2016-01-01 22:31:52 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	ch := make(chan result, 1) | 
					
						
							|  |  |  |  | 	go func() { | 
					
						
							|  |  |  |  | 		conn, err := l.Accept() | 
					
						
							|  |  |  |  | 		ch <- result{conn, err} | 
					
						
							|  |  |  |  | 		err = l.Close() | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Error(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	}() | 
					
						
							|  |  |  |  | 	c1, err := net.Dial("tcp", l.Addr().String()) | 
					
						
							| 
									
										
										
										
											2016-01-01 22:31:52 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | 		l.Close() // might cause another in the listening goroutine, but too bad
 | 
					
						
							| 
									
										
										
										
											2016-01-01 22:31:52 +08:00
										 |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | 	r := <-ch | 
					
						
							|  |  |  |  | 	if r.error != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return c1, r.Conn | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func testClientGoSvr(t testing.TB, readonly bool, delay time.Duration) (*Client, *exec.Cmd) { | 
					
						
							|  |  |  |  | 	c1, c2 := netPipe(t) | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-11 04:10:18 +08:00
										 |  |  |  | 	options := []ServerOption{WithDebug(os.Stderr)} | 
					
						
							|  |  |  |  | 	if readonly { | 
					
						
							|  |  |  |  | 		options = append(options, ReadOnly()) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | 	server, err := NewServer(c1, options...) | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-07 14:55:15 +08:00
										 |  |  |  | 	go server.Serve() | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | 	var ctx io.WriteCloser = c2 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	if delay > NODELAY { | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | 		ctx = newDelayedWriter(ctx, delay) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 15:22:48 +08:00
										 |  |  |  | 	client, err := NewClientPipe(c2, ctx) | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// dummy command...
 | 
					
						
							|  |  |  |  | 	return client, exec.Command("true") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | // testClient returns a *Client connected to a localy running sftp-server
 | 
					
						
							|  |  |  |  | // the *exec.Cmd returned must be defer Wait'd.
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | func testClient(t testing.TB, readonly bool, delay time.Duration) (*Client, *exec.Cmd) { | 
					
						
							| 
									
										
										
										
											2013-11-08 18:00:26 +08:00
										 |  |  |  | 	if !*testIntegration { | 
					
						
							|  |  |  |  | 		t.Skip("skipping intergration test") | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-01 14:09:51 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if *testServerImpl { | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | 		return testClientGoSvr(t, readonly, delay) | 
					
						
							| 
									
										
										
										
											2015-08-01 14:09:51 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-05 05:50:15 +08:00
										 |  |  |  | 	cmd := exec.Command(*testSftp, "-e", "-R", "-l", debuglevel) // log to stderr, read only
 | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | 	if !readonly { | 
					
						
							| 
									
										
										
										
											2014-01-05 05:50:15 +08:00
										 |  |  |  | 		cmd = exec.Command(*testSftp, "-e", "-l", debuglevel) // log to stderr
 | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	cmd.Stderr = os.Stdout | 
					
						
							|  |  |  |  | 	pw, err := cmd.StdinPipe() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	if delay > NODELAY { | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 		pw = newDelayedWriter(pw, delay) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	pr, err := cmd.StdoutPipe() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if err := cmd.Start(); err != nil { | 
					
						
							|  |  |  |  | 		t.Skipf("could not start sftp-server process: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-09-30 06:43:45 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	sftp, err := NewClientPipe(pr, pw) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-09-30 06:43:45 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	return sftp, cmd | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestNewClient(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err := sftp.Close(); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientLstat(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	f.Close() | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 	defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	want, err := os.Lstat(f.Name()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	got, err := sftp.Lstat(f.Name()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if !sameFile(want, got) { | 
					
						
							|  |  |  |  | 		t.Fatalf("Lstat(%q): want %#v, got %#v", f.Name(), want, got) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-04 03:54:19 +08:00
										 |  |  |  | func TestClientLstatIsNotExist(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	f.Close() | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | 	os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-04 03:54:19 +08:00
										 |  |  |  | 	if _, err := sftp.Lstat(f.Name()); !os.IsNotExist(err) { | 
					
						
							|  |  |  |  | 		t.Errorf("os.IsNotExist(%v) = false, want true", err) | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-28 10:52:54 +08:00
										 |  |  |  | func TestClientMkdir(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-09-30 05:32:16 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	dir, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-09-28 10:52:54 +08:00
										 |  |  |  | 	sub := path.Join(dir, "mkdir1") | 
					
						
							| 
									
										
										
										
											2014-09-30 05:32:16 +08:00
										 |  |  |  | 	if err := sftp.Mkdir(sub); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := os.Lstat(sub); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-09-28 10:52:54 +08:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-25 14:58:10 +08:00
										 |  |  |  | func TestClientMkdirAll(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2018-04-25 14:58:10 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	dir, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	sub := path.Join(dir, "mkdir1", "mkdir2", "mkdir3") | 
					
						
							|  |  |  |  | 	if err := sftp.MkdirAll(sub); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-25 23:11:13 +08:00
										 |  |  |  | 	info, err := os.Lstat(sub) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-04-25 14:58:10 +08:00
										 |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-25 23:11:13 +08:00
										 |  |  |  | 	if !info.IsDir() { | 
					
						
							|  |  |  |  | 		t.Fatalf("Expected mkdirall to create dir at: %s", sub) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-25 14:58:10 +08:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-09-28 10:52:54 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 12:53:14 +08:00
										 |  |  |  | func TestClientOpen(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-06 12:53:14 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	f.Close() | 
					
						
							| 
									
										
										
										
											2013-11-06 12:53:14 +08:00
										 |  |  |  | 	defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	got, err := sftp.Open(f.Name()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if err := got.Close(); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-04 03:54:19 +08:00
										 |  |  |  | func TestClientOpenIsNotExist(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2016-01-04 03:54:19 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if _, err := sftp.Open("/doesnt/exist/"); !os.IsNotExist(err) { | 
					
						
							|  |  |  |  | 		t.Errorf("os.IsNotExist(%v) = false, want true", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientStatIsNotExist(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2016-01-04 03:54:19 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if _, err := sftp.Stat("/doesnt/exist/"); !os.IsNotExist(err) { | 
					
						
							|  |  |  |  | 		t.Errorf("os.IsNotExist(%v) = false, want true", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | const seekBytes = 128 * 1024 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type seek struct { | 
					
						
							|  |  |  |  | 	offset int64 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func (s seek) Generate(r *rand.Rand, _ int) reflect.Value { | 
					
						
							|  |  |  |  | 	s.offset = int64(r.Int31n(seekBytes)) | 
					
						
							|  |  |  |  | 	return reflect.ValueOf(s) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-13 16:22:04 +08:00
										 |  |  |  | func (s seek) set(t *testing.T, r io.ReadSeeker) { | 
					
						
							| 
									
										
										
										
											2018-02-16 02:27:33 +08:00
										 |  |  |  | 	if _, err := r.Seek(s.offset, io.SeekStart); err != nil { | 
					
						
							| 
									
										
										
										
											2014-06-13 16:22:04 +08:00
										 |  |  |  | 		t.Fatalf("error while seeking with %+v: %v", s, err) | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-13 16:22:04 +08:00
										 |  |  |  | func (s seek) current(t *testing.T, r io.ReadSeeker) { | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	const mid = seekBytes / 2 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-13 16:22:04 +08:00
										 |  |  |  | 	skip := s.offset / 2 | 
					
						
							|  |  |  |  | 	if s.offset > mid { | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 		skip = -skip | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 02:27:33 +08:00
										 |  |  |  | 	if _, err := r.Seek(mid, io.SeekStart); err != nil { | 
					
						
							| 
									
										
										
										
											2014-06-13 16:22:04 +08:00
										 |  |  |  | 		t.Fatalf("error seeking to midpoint with %+v: %v", s, err) | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-16 02:27:33 +08:00
										 |  |  |  | 	if _, err := r.Seek(skip, io.SeekCurrent); err != nil { | 
					
						
							| 
									
										
										
										
											2014-06-13 16:22:04 +08:00
										 |  |  |  | 		t.Fatalf("error seeking from %d with %+v: %v", mid, s, err) | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-13 16:22:04 +08:00
										 |  |  |  | func (s seek) end(t *testing.T, r io.ReadSeeker) { | 
					
						
							| 
									
										
										
										
											2018-02-16 02:27:33 +08:00
										 |  |  |  | 	if _, err := r.Seek(-s.offset, io.SeekEnd); err != nil { | 
					
						
							| 
									
										
										
										
											2014-06-13 16:22:04 +08:00
										 |  |  |  | 		t.Fatalf("error seeking from end with %+v: %v", s, err) | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientSeek(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-06-12 03:17:53 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	fOS, err := ioutil.TempFile("", "seek-test") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer fOS.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	fSFTP, err := sftp.Open(fOS.Name()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer fSFTP.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	writeN(t, fOS, seekBytes) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err := quick.CheckEqual( | 
					
						
							|  |  |  |  | 		func(s seek) (string, int64) { s.set(t, fOS); return readHash(t, fOS) }, | 
					
						
							|  |  |  |  | 		func(s seek) (string, int64) { s.set(t, fSFTP); return readHash(t, fSFTP) }, | 
					
						
							|  |  |  |  | 		nil, | 
					
						
							|  |  |  |  | 	); err != nil { | 
					
						
							|  |  |  |  | 		t.Errorf("Seek: expected equal absolute seeks: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err := quick.CheckEqual( | 
					
						
							|  |  |  |  | 		func(s seek) (string, int64) { s.current(t, fOS); return readHash(t, fOS) }, | 
					
						
							|  |  |  |  | 		func(s seek) (string, int64) { s.current(t, fSFTP); return readHash(t, fSFTP) }, | 
					
						
							|  |  |  |  | 		nil, | 
					
						
							|  |  |  |  | 	); err != nil { | 
					
						
							|  |  |  |  | 		t.Errorf("Seek: expected equal seeks from middle: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err := quick.CheckEqual( | 
					
						
							|  |  |  |  | 		func(s seek) (string, int64) { s.end(t, fOS); return readHash(t, fOS) }, | 
					
						
							|  |  |  |  | 		func(s seek) (string, int64) { s.end(t, fSFTP); return readHash(t, fSFTP) }, | 
					
						
							|  |  |  |  | 		nil, | 
					
						
							|  |  |  |  | 	); err != nil { | 
					
						
							|  |  |  |  | 		t.Errorf("Seek: expected equal seeks from end: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-11-08 19:11:02 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | func TestClientCreate(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f.Close() | 
					
						
							|  |  |  |  | 	defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f2, err := sftp.Create(f.Name()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f2.Close() | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 12:32:21 +08:00
										 |  |  |  | func TestClientAppend(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-14 12:32:21 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f.Close() | 
					
						
							|  |  |  |  | 	defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f2, err := sftp.OpenFile(f.Name(), os.O_RDWR|os.O_APPEND) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f2.Close() | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | func TestClientCreateFailed(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f.Close() | 
					
						
							|  |  |  |  | 	defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f2, err := sftp.Create(f.Name()) | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	if err1, ok := err.(*StatusError); !ok || err1.Code != sshFxPermissionDenied { | 
					
						
							|  |  |  |  | 		t.Fatalf("Create: want: %v, got %#v", sshFxPermissionDenied, err) | 
					
						
							| 
									
										
										
										
											2013-11-06 16:29:59 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if err == nil { | 
					
						
							|  |  |  |  | 		f2.Close() | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-25 16:05:59 +08:00
										 |  |  |  | func TestClientFileName(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-09-25 16:05:59 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f2, err := sftp.Open(f.Name()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if got, want := f2.Name(), f.Name(); got != want { | 
					
						
							| 
									
										
										
										
											2015-09-25 16:17:46 +08:00
										 |  |  |  | 		t.Fatalf("Name: got %q want %q", want, got) | 
					
						
							| 
									
										
										
										
											2015-09-25 16:05:59 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 13:03:08 +08:00
										 |  |  |  | func TestClientFileStat(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-06 13:03:08 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	want, err := os.Lstat(f.Name()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f2, err := sftp.Open(f.Name()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	got, err := f2.Stat() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if !sameFile(want, got) { | 
					
						
							|  |  |  |  | 		t.Fatalf("Lstat(%q): want %#v, got %#v", f.Name(), want, got) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 03:07:21 +08:00
										 |  |  |  | func TestClientStatLink(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) // Windows does not support links.
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2016-04-27 03:07:21 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	realName := f.Name() | 
					
						
							|  |  |  |  | 	linkName := f.Name() + ".softlink" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// create a symlink that points at sftptest
 | 
					
						
							|  |  |  |  | 	if err := os.Symlink(realName, linkName); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.Remove(linkName) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// compare Lstat of links
 | 
					
						
							|  |  |  |  | 	wantLstat, err := os.Lstat(linkName) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	wantStat, err := os.Stat(linkName) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	gotLstat, err := sftp.Lstat(linkName) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	gotStat, err := sftp.Stat(linkName) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// check that stat is not lstat from os package
 | 
					
						
							|  |  |  |  | 	if sameFile(wantLstat, wantStat) { | 
					
						
							|  |  |  |  | 		t.Fatalf("Lstat / Stat(%q): both %#v %#v", f.Name(), wantLstat, wantStat) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// compare Lstat of links
 | 
					
						
							|  |  |  |  | 	if !sameFile(wantLstat, gotLstat) { | 
					
						
							|  |  |  |  | 		t.Fatalf("Lstat(%q): want %#v, got %#v", f.Name(), wantLstat, gotLstat) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// compare Stat of links
 | 
					
						
							|  |  |  |  | 	if !sameFile(wantStat, gotStat) { | 
					
						
							|  |  |  |  | 		t.Fatalf("Stat(%q): want %#v, got %#v", f.Name(), wantStat, gotStat) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// check that stat is not lstat
 | 
					
						
							|  |  |  |  | 	if sameFile(gotLstat, gotStat) { | 
					
						
							|  |  |  |  | 		t.Fatalf("Lstat / Stat(%q): both %#v %#v", f.Name(), gotLstat, gotStat) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 18:56:25 +08:00
										 |  |  |  | func TestClientRemove(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-08 18:56:25 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 18:56:25 +08:00
										 |  |  |  | 	if err := sftp.Remove(f.Name()); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := os.Lstat(f.Name()); !os.IsNotExist(err) { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-28 10:48:54 +08:00
										 |  |  |  | func TestClientRemoveDir(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-09-28 10:48:54 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	dir, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if err := sftp.Remove(dir); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := os.Lstat(dir); !os.IsNotExist(err) { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 18:56:25 +08:00
										 |  |  |  | func TestClientRemoveFailed(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-08 18:56:25 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if err := sftp.Remove(f.Name()); err == nil { | 
					
						
							|  |  |  |  | 		t.Fatalf("Remove(%v): want: permission denied, got %v", f.Name(), err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := os.Lstat(f.Name()); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 19:11:02 +08:00
										 |  |  |  | func TestClientRename(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-08 19:11:02 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 19:11:02 +08:00
										 |  |  |  | 	f2 := f.Name() + ".new" | 
					
						
							|  |  |  |  | 	if err := sftp.Rename(f.Name(), f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := os.Lstat(f.Name()); !os.IsNotExist(err) { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := os.Lstat(f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 19:46:03 +08:00
										 |  |  |  | func TestClientPosixRename(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-09-05 19:46:03 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 19:46:03 +08:00
										 |  |  |  | 	f2 := f.Name() + ".new" | 
					
						
							|  |  |  |  | 	if err := sftp.PosixRename(f.Name(), f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := os.Lstat(f.Name()); !os.IsNotExist(err) { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := os.Lstat(f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-22 05:45:40 +08:00
										 |  |  |  | func TestClientGetwd(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-12-22 05:45:40 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	lwd, err := os.Getwd() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	rwd, err := sftp.Getwd() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	if !filepath.IsAbs(rwd) { | 
					
						
							| 
									
										
										
										
											2015-12-22 05:45:40 +08:00
										 |  |  |  | 		t.Fatalf("Getwd: wanted absolute path, got %q", rwd) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	if filepath.ToSlash(lwd) != filepath.ToSlash(rwd) { | 
					
						
							| 
									
										
										
										
											2015-12-22 05:45:40 +08:00
										 |  |  |  | 		t.Fatalf("Getwd: want %q, got %q", lwd, rwd) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  |  | func TestClientReadLink(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-09-28 10:48:54 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	f2 := f.Name() + ".sym" | 
					
						
							|  |  |  |  | 	if err := os.Symlink(f.Name(), f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-07 16:05:16 +08:00
										 |  |  |  | 	if rl, err := sftp.ReadLink(f2); err != nil { | 
					
						
							| 
									
										
										
										
											2014-09-28 10:48:54 +08:00
										 |  |  |  | 		t.Fatal(err) | 
					
						
							| 
									
										
										
										
											2015-09-07 16:05:16 +08:00
										 |  |  |  | 	} else if rl != f.Name() { | 
					
						
							|  |  |  |  | 		t.Fatalf("unexpected link target: %v, not %v", rl, f.Name()) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-25 03:23:18 +08:00
										 |  |  |  | func TestClientLink(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2019-05-25 03:23:18 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	data := []byte("linktest") | 
					
						
							|  |  |  |  | 	_, err = f.Write(data) | 
					
						
							|  |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	f2 := f.Name() + ".link" | 
					
						
							|  |  |  |  | 	if err := sftp.Link(f.Name(), f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if st2, err := sftp.Stat(f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} else if int(st2.Size()) != len(data) { | 
					
						
							|  |  |  |  | 		t.Fatalf("unexpected link size: %v, not %v", st2.Size(), len(data)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 16:05:16 +08:00
										 |  |  |  | func TestClientSymlink(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-09-07 16:05:16 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	f2 := f.Name() + ".sym" | 
					
						
							|  |  |  |  | 	if err := sftp.Symlink(f.Name(), f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if rl, err := sftp.ReadLink(f2); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} else if rl != f.Name() { | 
					
						
							|  |  |  |  | 		t.Fatalf("unexpected link target: %v, not %v", rl, f.Name()) | 
					
						
							| 
									
										
										
										
											2014-09-28 10:48:54 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | func TestClientChmod(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) // No UNIX permissions.
 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	if err := sftp.Chmod(f.Name(), 0531); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if stat, err := os.Stat(f.Name()); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} else if stat.Mode()&os.ModePerm != 0531 { | 
					
						
							|  |  |  |  | 		t.Fatalf("invalid perm %o\n", stat.Mode()) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientChmodReadonly(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) // No UNIX permissions.
 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	if err := sftp.Chmod(f.Name(), 0531); err == nil { | 
					
						
							|  |  |  |  | 		t.Fatal("expected error") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientChown(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) // No UNIX permissions.
 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	usr, err := user.Current() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	chownto, err := user.Lookup("daemon") // seems common-ish...
 | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if usr.Uid != "0" { | 
					
						
							|  |  |  |  | 		t.Log("must be root to run chown tests") | 
					
						
							|  |  |  |  | 		t.Skip() | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  |  | 	toUID, err := strconv.Atoi(chownto.Uid) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  |  | 	toGID, err := strconv.Atoi(chownto.Gid) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	before, err := exec.Command("ls", "-nl", f.Name()).Output() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  |  | 	if err := sftp.Chown(f.Name(), toUID, toGID); err != nil { | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	after, err := exec.Command("ls", "-nl", f.Name()).Output() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 14:55:15 +08:00
										 |  |  |  | 	spaceRegex := regexp.MustCompile(`\s+`) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	beforeWords := spaceRegex.Split(string(before), -1) | 
					
						
							|  |  |  |  | 	if beforeWords[2] != "0" { | 
					
						
							|  |  |  |  | 		t.Fatalf("bad previous user? should be root") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	afterWords := spaceRegex.Split(string(after), -1) | 
					
						
							|  |  |  |  | 	if afterWords[2] != chownto.Uid || afterWords[3] != chownto.Gid { | 
					
						
							|  |  |  |  | 		t.Fatalf("bad chown: %#v", afterWords) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	t.Logf("before: %v", string(before)) | 
					
						
							|  |  |  |  | 	t.Logf(" after: %v", string(after)) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientChownReadonly(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) // No UNIX permissions.
 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	usr, err := user.Current() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	chownto, err := user.Lookup("daemon") // seems common-ish...
 | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if usr.Uid != "0" { | 
					
						
							|  |  |  |  | 		t.Log("must be root to run chown tests") | 
					
						
							|  |  |  |  | 		t.Skip() | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  |  | 	toUID, err := strconv.Atoi(chownto.Uid) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  |  | 	toGID, err := strconv.Atoi(chownto.Gid) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  |  | 	if err := sftp.Chown(f.Name(), toUID, toGID); err == nil { | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 		t.Fatal("expected error") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientChtimes(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	atime := time.Date(2013, 2, 23, 13, 24, 35, 0, time.UTC) | 
					
						
							|  |  |  |  | 	mtime := time.Date(1985, 6, 12, 6, 6, 6, 0, time.UTC) | 
					
						
							|  |  |  |  | 	if err := sftp.Chtimes(f.Name(), atime, mtime); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if stat, err := os.Stat(f.Name()); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} else if stat.ModTime().Sub(mtime) != 0 { | 
					
						
							|  |  |  |  | 		t.Fatalf("incorrect mtime: %v vs %v", stat.ModTime(), mtime) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientChtimesReadonly(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	atime := time.Date(2013, 2, 23, 13, 24, 35, 0, time.UTC) | 
					
						
							|  |  |  |  | 	mtime := time.Date(1985, 6, 12, 6, 6, 6, 0, time.UTC) | 
					
						
							|  |  |  |  | 	if err := sftp.Chtimes(f.Name(), atime, mtime); err == nil { | 
					
						
							|  |  |  |  | 		t.Fatal("expected error") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 13:21:35 +08:00
										 |  |  |  | func TestClientTruncate(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-05 13:21:35 +08:00
										 |  |  |  | 	fname := f.Name() | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 13:21:35 +08:00
										 |  |  |  | 	if n, err := f.Write([]byte("hello world")); n != 11 || err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err := sftp.Truncate(fname, 5); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if stat, err := os.Stat(fname); err != nil { | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 		t.Fatal(err) | 
					
						
							| 
									
										
										
										
											2015-08-05 13:21:35 +08:00
										 |  |  |  | 	} else if stat.Size() != 5 { | 
					
						
							|  |  |  |  | 		t.Fatalf("unexpected size: %d", stat.Size()) | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 13:21:35 +08:00
										 |  |  |  | func TestClientTruncateReadonly(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-08-05 13:21:35 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	fname := f.Name() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if n, err := f.Write([]byte("hello world")); n != 11 || err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err := sftp.Truncate(fname, 5); err == nil { | 
					
						
							|  |  |  |  | 		t.Fatal("expected error") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if stat, err := os.Stat(fname); err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} else if stat.Size() != 11 { | 
					
						
							|  |  |  |  | 		t.Fatalf("unexpected size: %d", stat.Size()) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-08-05 11:47:26 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | func sameFile(want, got os.FileInfo) bool { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	_, wantName := filepath.Split(want.Name()) | 
					
						
							|  |  |  |  | 	_, gotName := filepath.Split(got.Name()) | 
					
						
							|  |  |  |  | 	return wantName == gotName && | 
					
						
							| 
									
										
										
										
											2013-11-06 12:40:35 +08:00
										 |  |  |  | 		want.Size() == got.Size() | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-11-08 18:00:26 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-30 08:24:24 +08:00
										 |  |  |  | func TestClientReadSimple(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-07-30 08:24:24 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	d, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.RemoveAll(d) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := ioutil.TempFile(d, "read-test") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	fname := f.Name() | 
					
						
							|  |  |  |  | 	f.Write([]byte("hello")) | 
					
						
							|  |  |  |  | 	f.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f2, err := sftp.Open(fname) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f2.Close() | 
					
						
							|  |  |  |  | 	stuff := make([]byte, 32) | 
					
						
							|  |  |  |  | 	n, err := f2.Read(stuff) | 
					
						
							|  |  |  |  | 	if err != nil && err != io.EOF { | 
					
						
							|  |  |  |  | 		t.Fatalf("err: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if n != 5 { | 
					
						
							|  |  |  |  | 		t.Fatalf("n should be 5, is %v", n) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if string(stuff[0:5]) != "hello" { | 
					
						
							|  |  |  |  | 		t.Fatalf("invalid contents") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | func TestClientReadDir(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp1, cmd1 := testClient(t, READONLY, NODELAY) | 
					
						
							|  |  |  |  | 	sftp2, cmd2 := testClientGoSvr(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | 	defer cmd1.Wait() | 
					
						
							|  |  |  |  | 	defer cmd2.Wait() | 
					
						
							|  |  |  |  | 	defer sftp1.Close() | 
					
						
							|  |  |  |  | 	defer sftp2.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	dir := os.TempDir() | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	d, err := os.Open(dir) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer d.Close() | 
					
						
							|  |  |  |  | 	osfiles, err := d.Readdir(4096) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	sftp1Files, err := sftp1.ReadDir(dir) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	sftp2Files, err := sftp2.ReadDir(dir) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	osFilesByName := map[string]os.FileInfo{} | 
					
						
							|  |  |  |  | 	for _, f := range osfiles { | 
					
						
							|  |  |  |  | 		osFilesByName[f.Name()] = f | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	sftp1FilesByName := map[string]os.FileInfo{} | 
					
						
							|  |  |  |  | 	for _, f := range sftp1Files { | 
					
						
							|  |  |  |  | 		sftp1FilesByName[f.Name()] = f | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	sftp2FilesByName := map[string]os.FileInfo{} | 
					
						
							|  |  |  |  | 	for _, f := range sftp2Files { | 
					
						
							|  |  |  |  | 		sftp2FilesByName[f.Name()] = f | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if len(osFilesByName) != len(sftp1FilesByName) || len(sftp1FilesByName) != len(sftp2FilesByName) { | 
					
						
							|  |  |  |  | 		t.Fatalf("os gives %v, sftp1 gives %v, sftp2 gives %v", len(osFilesByName), len(sftp1FilesByName), len(sftp2FilesByName)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for name, osF := range osFilesByName { | 
					
						
							|  |  |  |  | 		sftp1F, ok := sftp1FilesByName[name] | 
					
						
							|  |  |  |  | 		if !ok { | 
					
						
							|  |  |  |  | 			t.Fatalf("%v present in os but not sftp1", name) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		sftp2F, ok := sftp2FilesByName[name] | 
					
						
							|  |  |  |  | 		if !ok { | 
					
						
							|  |  |  |  | 			t.Fatalf("%v present in os but not sftp2", name) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		//t.Logf("%v: %v %v %v", name, osF, sftp1F, sftp2F)
 | 
					
						
							|  |  |  |  | 		if osF.Size() != sftp1F.Size() || sftp1F.Size() != sftp2F.Size() { | 
					
						
							|  |  |  |  | 			t.Fatalf("size %v %v %v", osF.Size(), sftp1F.Size(), sftp2F.Size()) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if osF.IsDir() != sftp1F.IsDir() || sftp1F.IsDir() != sftp2F.IsDir() { | 
					
						
							|  |  |  |  | 			t.Fatalf("isdir %v %v %v", osF.IsDir(), sftp1F.IsDir(), sftp2F.IsDir()) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if osF.ModTime().Sub(sftp1F.ModTime()) > time.Second || sftp1F.ModTime() != sftp2F.ModTime() { | 
					
						
							|  |  |  |  | 			t.Fatalf("modtime %v %v %v", osF.ModTime(), sftp1F.ModTime(), sftp2F.ModTime()) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if osF.Mode() != sftp1F.Mode() || sftp1F.Mode() != sftp2F.Mode() { | 
					
						
							|  |  |  |  | 			t.Fatalf("mode %x %x %x", osF.Mode(), sftp1F.Mode(), sftp2F.Mode()) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-15 18:17:11 +08:00
										 |  |  |  | var clientReadTests = []struct { | 
					
						
							|  |  |  |  | 	n int64 | 
					
						
							|  |  |  |  | }{ | 
					
						
							|  |  |  |  | 	{0}, | 
					
						
							|  |  |  |  | 	{1}, | 
					
						
							|  |  |  |  | 	{1000}, | 
					
						
							|  |  |  |  | 	{1024}, | 
					
						
							|  |  |  |  | 	{1025}, | 
					
						
							|  |  |  |  | 	{2048}, | 
					
						
							|  |  |  |  | 	{4096}, | 
					
						
							|  |  |  |  | 	{1 << 12}, | 
					
						
							|  |  |  |  | 	{1 << 13}, | 
					
						
							|  |  |  |  | 	{1 << 14}, | 
					
						
							|  |  |  |  | 	{1 << 15}, | 
					
						
							|  |  |  |  | 	{1 << 16}, | 
					
						
							|  |  |  |  | 	{1 << 17}, | 
					
						
							|  |  |  |  | 	{1 << 18}, | 
					
						
							|  |  |  |  | 	{1 << 19}, | 
					
						
							|  |  |  |  | 	{1 << 20}, | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientRead(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-15 18:17:11 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	d, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.RemoveAll(d) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for _, tt := range clientReadTests { | 
					
						
							|  |  |  |  | 		f, err := ioutil.TempFile(d, "read-test") | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer f.Close() | 
					
						
							| 
									
										
										
										
											2013-11-15 18:47:28 +08:00
										 |  |  |  | 		hash := writeN(t, f, tt.n) | 
					
						
							| 
									
										
										
										
											2013-11-15 18:17:11 +08:00
										 |  |  |  | 		f2, err := sftp.Open(f.Name()) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer f2.Close() | 
					
						
							| 
									
										
										
										
											2013-11-15 18:47:28 +08:00
										 |  |  |  | 		hash2, n := readHash(t, f2) | 
					
						
							|  |  |  |  | 		if hash != hash2 || tt.n != n { | 
					
						
							|  |  |  |  | 			t.Errorf("Read: hash: want: %q, got %q, read: want: %v, got %v", hash, hash2, tt.n, n) | 
					
						
							| 
									
										
										
										
											2013-11-15 18:17:11 +08:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-15 18:47:28 +08:00
										 |  |  |  | // readHash reads r until EOF returning the number of bytes read
 | 
					
						
							|  |  |  |  | // and the hash of the contents.
 | 
					
						
							|  |  |  |  | func readHash(t *testing.T, r io.Reader) (string, int64) { | 
					
						
							|  |  |  |  | 	h := sha1.New() | 
					
						
							|  |  |  |  | 	tr := io.TeeReader(r, h) | 
					
						
							|  |  |  |  | 	read, err := io.Copy(ioutil.Discard, tr) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return string(h.Sum(nil)), read | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // writeN writes n bytes of random data to w and returns the
 | 
					
						
							|  |  |  |  | // hash of that data.
 | 
					
						
							|  |  |  |  | func writeN(t *testing.T, w io.Writer, n int64) string { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	r := rand.New(rand.NewSource(time.Now().UnixNano())) | 
					
						
							| 
									
										
										
										
											2013-11-15 18:47:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	h := sha1.New() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	mw := io.MultiWriter(w, h) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	written, err := io.CopyN(mw, r, n) | 
					
						
							| 
									
										
										
										
											2013-11-15 18:47:28 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if written != n { | 
					
						
							|  |  |  |  | 		t.Fatalf("CopyN(%v): wrote: %v", n, written) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return string(h.Sum(nil)) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 18:00:26 +08:00
										 |  |  |  | var clientWriteTests = []struct { | 
					
						
							|  |  |  |  | 	n     int | 
					
						
							|  |  |  |  | 	total int64 // cumulative file size
 | 
					
						
							|  |  |  |  | }{ | 
					
						
							|  |  |  |  | 	{0, 0}, | 
					
						
							|  |  |  |  | 	{1, 1}, | 
					
						
							|  |  |  |  | 	{0, 1}, | 
					
						
							|  |  |  |  | 	{999, 1000}, | 
					
						
							|  |  |  |  | 	{24, 1024}, | 
					
						
							|  |  |  |  | 	{1023, 2047}, | 
					
						
							|  |  |  |  | 	{2048, 4095}, | 
					
						
							|  |  |  |  | 	{1 << 12, 8191}, | 
					
						
							|  |  |  |  | 	{1 << 13, 16383}, | 
					
						
							|  |  |  |  | 	{1 << 14, 32767}, | 
					
						
							|  |  |  |  | 	{1 << 15, 65535}, | 
					
						
							|  |  |  |  | 	{1 << 16, 131071}, | 
					
						
							|  |  |  |  | 	{1 << 17, 262143}, | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 	{1 << 18, 524287}, | 
					
						
							|  |  |  |  | 	{1 << 19, 1048575}, | 
					
						
							|  |  |  |  | 	{1 << 20, 2097151}, | 
					
						
							|  |  |  |  | 	{1 << 21, 4194303}, | 
					
						
							| 
									
										
										
										
											2013-11-08 18:00:26 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientWrite(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-08 18:00:26 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	d, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.RemoveAll(d) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f := path.Join(d, "writeTest") | 
					
						
							|  |  |  |  | 	w, err := sftp.Create(f) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer w.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for _, tt := range clientWriteTests { | 
					
						
							|  |  |  |  | 		got, err := w.Write(make([]byte, tt.n)) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if got != tt.n { | 
					
						
							|  |  |  |  | 			t.Errorf("Write(%v): wrote: want: %v, got %v", tt.n, tt.n, got) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		fi, err := os.Stat(f) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if total := fi.Size(); total != tt.total { | 
					
						
							|  |  |  |  | 			t.Errorf("Write(%v): size: want: %v, got %v", tt.n, tt.total, total) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-13 11:37:13 +08:00
										 |  |  |  | // ReadFrom is basically Write with io.Reader as the arg
 | 
					
						
							|  |  |  |  | func TestClientReadFrom(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-02-13 11:37:13 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	d, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.RemoveAll(d) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f := path.Join(d, "writeTest") | 
					
						
							|  |  |  |  | 	w, err := sftp.Create(f) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer w.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for _, tt := range clientWriteTests { | 
					
						
							|  |  |  |  | 		got, err := w.ReadFrom(bytes.NewReader(make([]byte, tt.n))) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if got != int64(tt.n) { | 
					
						
							|  |  |  |  | 			t.Errorf("Write(%v): wrote: want: %v, got %v", tt.n, tt.n, got) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		fi, err := os.Stat(f) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if total := fi.Size(); total != tt.total { | 
					
						
							|  |  |  |  | 			t.Errorf("Write(%v): size: want: %v, got %v", tt.n, tt.total, total) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | // Issue #145 in github
 | 
					
						
							|  |  |  |  | // Deadlock in ReadFrom when network drops after 1 good packet.
 | 
					
						
							|  |  |  |  | // Deadlock would occur anytime desiredInFlight-inFlight==2 and 2 errors
 | 
					
						
							|  |  |  |  | // occured in a row. The channel to report the errors only had a buffer
 | 
					
						
							|  |  |  |  | // of 1 and 2 would be sent.
 | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | var errFakeNet = errors.New("Fake network issue") | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | func TestClientReadFromDeadlock(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 	clientWriteDeadlock(t, 1, func(f *File) { | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | 		b := make([]byte, 32768*4) | 
					
						
							|  |  |  |  | 		content := bytes.NewReader(b) | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 		n, err := f.ReadFrom(content) | 
					
						
							|  |  |  |  | 		if n != 0 { | 
					
						
							|  |  |  |  | 			t.Fatal("Write should return 0", n) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 		if err != errFakeNet { | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 			t.Fatal("Didn't recieve correct error", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | 	}) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Write has exact same problem
 | 
					
						
							|  |  |  |  | func TestClientWriteDeadlock(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 	clientWriteDeadlock(t, 1, func(f *File) { | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | 		b := make([]byte, 32768*4) | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 		n, err := f.Write(b) | 
					
						
							|  |  |  |  | 		if n != 0 { | 
					
						
							|  |  |  |  | 			t.Fatal("Write should return 0", n) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 		if err != errFakeNet { | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 			t.Fatal("Didn't recieve correct error", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | 	}) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // shared body for both previous tests
 | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | func clientWriteDeadlock(t *testing.T, N int, badfunc func(*File)) { | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | 	if !*testServerImpl { | 
					
						
							|  |  |  |  | 		t.Skipf("skipping without -testserver") | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	d, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.RemoveAll(d) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f := path.Join(d, "writeTest") | 
					
						
							|  |  |  |  | 	w, err := sftp.Create(f) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer w.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Override sendPacket with failing version
 | 
					
						
							|  |  |  |  | 	// Replicates network error/drop part way through (after 1 good packet)
 | 
					
						
							|  |  |  |  | 	count := 0 | 
					
						
							|  |  |  |  | 	sendPacketTest := func(w io.Writer, m encoding.BinaryMarshaler) error { | 
					
						
							|  |  |  |  | 		count++ | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 		if count > N { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 			return errFakeNet | 
					
						
							| 
									
										
										
										
											2017-02-13 15:18:54 +08:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return sendPacket(w, m) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	sftp.clientConn.conn.sendPacketTest = sendPacketTest | 
					
						
							|  |  |  |  | 	defer func() { | 
					
						
							|  |  |  |  | 		sftp.clientConn.conn.sendPacketTest = nil | 
					
						
							|  |  |  |  | 	}() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// this locked (before the fix)
 | 
					
						
							|  |  |  |  | 	badfunc(w) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | // Read/WriteTo has this issue as well
 | 
					
						
							|  |  |  |  | func TestClientReadDeadlock(t *testing.T) { | 
					
						
							|  |  |  |  | 	clientReadDeadlock(t, 1, func(f *File) { | 
					
						
							|  |  |  |  | 		b := make([]byte, 32768*4) | 
					
						
							|  |  |  |  | 		n, err := f.Read(b) | 
					
						
							|  |  |  |  | 		if n != 0 { | 
					
						
							|  |  |  |  | 			t.Fatal("Write should return 0", n) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 		if err != errFakeNet { | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 			t.Fatal("Didn't recieve correct error", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientWriteToDeadlock(t *testing.T) { | 
					
						
							|  |  |  |  | 	clientReadDeadlock(t, 2, func(f *File) { | 
					
						
							|  |  |  |  | 		b := make([]byte, 32768*4) | 
					
						
							|  |  |  |  | 		buf := bytes.NewBuffer(b) | 
					
						
							|  |  |  |  | 		n, err := f.WriteTo(buf) | 
					
						
							|  |  |  |  | 		if n != 32768 { | 
					
						
							|  |  |  |  | 			t.Fatal("Write should return 0", n) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 		if err != errFakeNet { | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 			t.Fatal("Didn't recieve correct error", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func clientReadDeadlock(t *testing.T, N int, badfunc func(*File)) { | 
					
						
							|  |  |  |  | 	if !*testServerImpl { | 
					
						
							|  |  |  |  | 		t.Skipf("skipping without -testserver") | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	d, err := ioutil.TempDir("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.RemoveAll(d) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f := path.Join(d, "writeTest") | 
					
						
							|  |  |  |  | 	w, err := sftp.Create(f) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	// write the data for the read tests
 | 
					
						
							|  |  |  |  | 	b := make([]byte, 32768*4) | 
					
						
							|  |  |  |  | 	w.Write(b) | 
					
						
							|  |  |  |  | 	defer w.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// open new copy of file for read tests
 | 
					
						
							|  |  |  |  | 	r, err := sftp.Open(f) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer r.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Override sendPacket with failing version
 | 
					
						
							|  |  |  |  | 	// Replicates network error/drop part way through (after 1 good packet)
 | 
					
						
							|  |  |  |  | 	count := 0 | 
					
						
							|  |  |  |  | 	sendPacketTest := func(w io.Writer, m encoding.BinaryMarshaler) error { | 
					
						
							|  |  |  |  | 		count++ | 
					
						
							|  |  |  |  | 		if count > N { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 			return errFakeNet | 
					
						
							| 
									
										
										
										
											2017-02-14 08:24:04 +08:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return sendPacket(w, m) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	sftp.clientConn.conn.sendPacketTest = sendPacketTest | 
					
						
							|  |  |  |  | 	defer func() { | 
					
						
							|  |  |  |  | 		sftp.clientConn.conn.sendPacketTest = nil | 
					
						
							|  |  |  |  | 	}() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// this locked (before the fix)
 | 
					
						
							|  |  |  |  | 	badfunc(r) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | // taken from github.com/kr/fs/walk_test.go
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type Node struct { | 
					
						
							|  |  |  |  | 	name    string | 
					
						
							|  |  |  |  | 	entries []*Node // nil if the entry is a file
 | 
					
						
							|  |  |  |  | 	mark    int | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | var tree = &Node{ | 
					
						
							|  |  |  |  | 	"testdata", | 
					
						
							|  |  |  |  | 	[]*Node{ | 
					
						
							|  |  |  |  | 		{"a", nil, 0}, | 
					
						
							|  |  |  |  | 		{"b", []*Node{}, 0}, | 
					
						
							|  |  |  |  | 		{"c", nil, 0}, | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			"d", | 
					
						
							|  |  |  |  | 			[]*Node{ | 
					
						
							|  |  |  |  | 				{"x", nil, 0}, | 
					
						
							|  |  |  |  | 				{"y", []*Node{}, 0}, | 
					
						
							|  |  |  |  | 				{ | 
					
						
							|  |  |  |  | 					"z", | 
					
						
							|  |  |  |  | 					[]*Node{ | 
					
						
							|  |  |  |  | 						{"u", nil, 0}, | 
					
						
							|  |  |  |  | 						{"v", nil, 0}, | 
					
						
							|  |  |  |  | 					}, | 
					
						
							|  |  |  |  | 					0, | 
					
						
							|  |  |  |  | 				}, | 
					
						
							|  |  |  |  | 			}, | 
					
						
							|  |  |  |  | 			0, | 
					
						
							|  |  |  |  | 		}, | 
					
						
							|  |  |  |  | 	}, | 
					
						
							|  |  |  |  | 	0, | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func walkTree(n *Node, path string, f func(path string, n *Node)) { | 
					
						
							|  |  |  |  | 	f(path, n) | 
					
						
							|  |  |  |  | 	for _, e := range n.entries { | 
					
						
							|  |  |  |  | 		walkTree(e, filepath.Join(path, e.name), f) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func makeTree(t *testing.T) { | 
					
						
							|  |  |  |  | 	walkTree(tree, tree.name, func(path string, n *Node) { | 
					
						
							|  |  |  |  | 		if n.entries == nil { | 
					
						
							|  |  |  |  | 			fd, err := os.Create(path) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				t.Errorf("makeTree: %v", err) | 
					
						
							|  |  |  |  | 				return | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			fd.Close() | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							|  |  |  |  | 			os.Mkdir(path, 0770) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func checkMarks(t *testing.T, report bool) { | 
					
						
							|  |  |  |  | 	walkTree(tree, tree.name, func(path string, n *Node) { | 
					
						
							|  |  |  |  | 		if n.mark != 1 && report { | 
					
						
							|  |  |  |  | 			t.Errorf("node %s mark = %d; expected 1", path, n.mark) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		n.mark = 0 | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Assumes that each node name is unique. Good enough for a test.
 | 
					
						
							|  |  |  |  | // If clear is true, any incoming error is cleared before return. The errors
 | 
					
						
							|  |  |  |  | // are always accumulated, though.
 | 
					
						
							|  |  |  |  | func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error { | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		*errors = append(*errors, err) | 
					
						
							|  |  |  |  | 		if clear { | 
					
						
							|  |  |  |  | 			return nil | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return err | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	name := info.Name() | 
					
						
							|  |  |  |  | 	walkTree(tree, tree.name, func(path string, n *Node) { | 
					
						
							|  |  |  |  | 		if n.name == name { | 
					
						
							|  |  |  |  | 			n.mark++ | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestClientWalk(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	makeTree(t) | 
					
						
							|  |  |  |  | 	errors := make([]error, 0, 10) | 
					
						
							|  |  |  |  | 	clear := true | 
					
						
							| 
									
										
										
										
											2016-01-08 04:56:04 +08:00
										 |  |  |  | 	markFn := func(walker *fs.Walker) error { | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 		for walker.Step() { | 
					
						
							| 
									
										
										
										
											2016-01-08 04:56:04 +08:00
										 |  |  |  | 			err := mark(walker.Path(), walker.Stat(), walker.Err(), &errors, clear) | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-08 04:56:04 +08:00
										 |  |  |  | 				return err | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-08 04:56:04 +08:00
										 |  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2013-11-08 18:24:50 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	// Expect no errors.
 | 
					
						
							|  |  |  |  | 	err := markFn(sftp.Walk(tree.name)) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatalf("no error expected, found: %s", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if len(errors) != 0 { | 
					
						
							|  |  |  |  | 		t.Fatalf("unexpected errors: %s", errors) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	checkMarks(t, true) | 
					
						
							|  |  |  |  | 	errors = errors[0:0] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Test permission errors.  Only possible if we're not root
 | 
					
						
							|  |  |  |  | 	// and only on some file systems (AFS, FAT).  To avoid errors during
 | 
					
						
							|  |  |  |  | 	// all.bash on those file systems, skip during go test -short.
 | 
					
						
							|  |  |  |  | 	if os.Getuid() > 0 && !testing.Short() { | 
					
						
							|  |  |  |  | 		// introduce 2 errors: chmod top-level directories to 0
 | 
					
						
							|  |  |  |  | 		os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0) | 
					
						
							|  |  |  |  | 		os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 3) capture errors, expect two.
 | 
					
						
							|  |  |  |  | 		// mark respective subtrees manually
 | 
					
						
							|  |  |  |  | 		markTree(tree.entries[1]) | 
					
						
							|  |  |  |  | 		markTree(tree.entries[3]) | 
					
						
							|  |  |  |  | 		// correct double-marking of directory itself
 | 
					
						
							|  |  |  |  | 		tree.entries[1].mark-- | 
					
						
							|  |  |  |  | 		tree.entries[3].mark-- | 
					
						
							|  |  |  |  | 		err := markFn(sftp.Walk(tree.name)) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Fatalf("expected no error return from Walk, got %s", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if len(errors) != 2 { | 
					
						
							|  |  |  |  | 			t.Errorf("expected 2 errors, got %d: %s", len(errors), errors) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		// the inaccessible subtrees were marked manually
 | 
					
						
							|  |  |  |  | 		checkMarks(t, true) | 
					
						
							|  |  |  |  | 		errors = errors[0:0] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 4) capture errors, stop after first error.
 | 
					
						
							|  |  |  |  | 		// mark respective subtrees manually
 | 
					
						
							|  |  |  |  | 		markTree(tree.entries[1]) | 
					
						
							|  |  |  |  | 		markTree(tree.entries[3]) | 
					
						
							|  |  |  |  | 		// correct double-marking of directory itself
 | 
					
						
							|  |  |  |  | 		tree.entries[1].mark-- | 
					
						
							|  |  |  |  | 		tree.entries[3].mark-- | 
					
						
							|  |  |  |  | 		clear = false // error will stop processing
 | 
					
						
							|  |  |  |  | 		err = markFn(sftp.Walk(tree.name)) | 
					
						
							|  |  |  |  | 		if err == nil { | 
					
						
							|  |  |  |  | 			t.Fatalf("expected error return from Walk") | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if len(errors) != 1 { | 
					
						
							|  |  |  |  | 			t.Errorf("expected 1 error, got %d: %s", len(errors), errors) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		// the inaccessible subtrees were marked manually
 | 
					
						
							|  |  |  |  | 		checkMarks(t, false) | 
					
						
							|  |  |  |  | 		errors = errors[0:0] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// restore permissions
 | 
					
						
							|  |  |  |  | 		os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770) | 
					
						
							|  |  |  |  | 		os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// cleanup
 | 
					
						
							|  |  |  |  | 	if err := os.RemoveAll(tree.name); err != nil { | 
					
						
							|  |  |  |  | 		t.Errorf("removeTree: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-18 21:20:24 +08:00
										 |  |  |  | type MatchTest struct { | 
					
						
							|  |  |  |  | 	pattern, s string | 
					
						
							|  |  |  |  | 	match      bool | 
					
						
							|  |  |  |  | 	err        error | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | var matchTests = []MatchTest{ | 
					
						
							|  |  |  |  | 	{"abc", "abc", true, nil}, | 
					
						
							|  |  |  |  | 	{"*", "abc", true, nil}, | 
					
						
							|  |  |  |  | 	{"*c", "abc", true, nil}, | 
					
						
							|  |  |  |  | 	{"a*", "a", true, nil}, | 
					
						
							|  |  |  |  | 	{"a*", "abc", true, nil}, | 
					
						
							|  |  |  |  | 	{"a*", "ab/c", false, nil}, | 
					
						
							|  |  |  |  | 	{"a*/b", "abc/b", true, nil}, | 
					
						
							|  |  |  |  | 	{"a*/b", "a/c/b", false, nil}, | 
					
						
							|  |  |  |  | 	{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil}, | 
					
						
							|  |  |  |  | 	{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil}, | 
					
						
							|  |  |  |  | 	{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil}, | 
					
						
							|  |  |  |  | 	{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil}, | 
					
						
							|  |  |  |  | 	{"a*b?c*x", "abxbbxdbxebxczzx", true, nil}, | 
					
						
							|  |  |  |  | 	{"a*b?c*x", "abxbbxdbxebxczzy", false, nil}, | 
					
						
							|  |  |  |  | 	{"ab[c]", "abc", true, nil}, | 
					
						
							|  |  |  |  | 	{"ab[b-d]", "abc", true, nil}, | 
					
						
							|  |  |  |  | 	{"ab[e-g]", "abc", false, nil}, | 
					
						
							|  |  |  |  | 	{"ab[^c]", "abc", false, nil}, | 
					
						
							|  |  |  |  | 	{"ab[^b-d]", "abc", false, nil}, | 
					
						
							|  |  |  |  | 	{"ab[^e-g]", "abc", true, nil}, | 
					
						
							|  |  |  |  | 	{"a\\*b", "a*b", true, nil}, | 
					
						
							|  |  |  |  | 	{"a\\*b", "ab", false, nil}, | 
					
						
							|  |  |  |  | 	{"a?b", "a☺b", true, nil}, | 
					
						
							|  |  |  |  | 	{"a[^a]b", "a☺b", true, nil}, | 
					
						
							|  |  |  |  | 	{"a???b", "a☺b", false, nil}, | 
					
						
							|  |  |  |  | 	{"a[^a][^a][^a]b", "a☺b", false, nil}, | 
					
						
							|  |  |  |  | 	{"[a-ζ]*", "α", true, nil}, | 
					
						
							|  |  |  |  | 	{"*[a-ζ]", "A", false, nil}, | 
					
						
							|  |  |  |  | 	{"a?b", "a/b", false, nil}, | 
					
						
							|  |  |  |  | 	{"a*b", "a/b", false, nil}, | 
					
						
							|  |  |  |  | 	{"[\\]a]", "]", true, nil}, | 
					
						
							|  |  |  |  | 	{"[\\-]", "-", true, nil}, | 
					
						
							|  |  |  |  | 	{"[x\\-]", "x", true, nil}, | 
					
						
							|  |  |  |  | 	{"[x\\-]", "-", true, nil}, | 
					
						
							|  |  |  |  | 	{"[x\\-]", "z", false, nil}, | 
					
						
							|  |  |  |  | 	{"[\\-x]", "x", true, nil}, | 
					
						
							|  |  |  |  | 	{"[\\-x]", "-", true, nil}, | 
					
						
							|  |  |  |  | 	{"[\\-x]", "a", false, nil}, | 
					
						
							|  |  |  |  | 	{"[]a]", "]", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[-]", "-", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[x-]", "x", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[x-]", "-", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[x-]", "z", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[-x]", "x", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[-x]", "-", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[-x]", "a", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"\\", "a", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[a-b-c]", "a", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[", "a", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[^", "a", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"[^bc", "a", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"a[", "a", false, nil}, | 
					
						
							|  |  |  |  | 	{"a[", "ab", false, ErrBadPattern}, | 
					
						
							|  |  |  |  | 	{"*x", "xxx", true, nil}, | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func errp(e error) string { | 
					
						
							|  |  |  |  | 	if e == nil { | 
					
						
							|  |  |  |  | 		return "<nil>" | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return e.Error() | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // contains returns true if vector contains the string s.
 | 
					
						
							|  |  |  |  | func contains(vector []string, s string) bool { | 
					
						
							|  |  |  |  | 	for _, elem := range vector { | 
					
						
							|  |  |  |  | 		if elem == s { | 
					
						
							|  |  |  |  | 			return true | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return false | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | var globTests = []struct { | 
					
						
							|  |  |  |  | 	pattern, result string | 
					
						
							|  |  |  |  | }{ | 
					
						
							| 
									
										
										
										
											2017-07-21 06:25:28 +08:00
										 |  |  |  | 	{"match.go", "match.go"}, | 
					
						
							|  |  |  |  | 	{"mat?h.go", "match.go"}, | 
					
						
							|  |  |  |  | 	{"ma*ch.go", "match.go"}, | 
					
						
							| 
									
										
										
										
											2016-11-18 21:20:24 +08:00
										 |  |  |  | 	{"../*/match.go", "../sftp/match.go"}, | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type globTest struct { | 
					
						
							|  |  |  |  | 	pattern string | 
					
						
							|  |  |  |  | 	matches []string | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func (test *globTest) buildWant(root string) []string { | 
					
						
							|  |  |  |  | 	var want []string | 
					
						
							|  |  |  |  | 	for _, m := range test.matches { | 
					
						
							|  |  |  |  | 		want = append(want, root+filepath.FromSlash(m)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	sort.Strings(want) | 
					
						
							|  |  |  |  | 	return want | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestMatch(t *testing.T) { | 
					
						
							|  |  |  |  | 	for _, tt := range matchTests { | 
					
						
							|  |  |  |  | 		pattern := tt.pattern | 
					
						
							|  |  |  |  | 		s := tt.s | 
					
						
							|  |  |  |  | 		ok, err := Match(pattern, s) | 
					
						
							|  |  |  |  | 		if ok != tt.match || err != tt.err { | 
					
						
							|  |  |  |  | 			t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestGlob(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2016-11-18 21:20:24 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for _, tt := range globTests { | 
					
						
							|  |  |  |  | 		pattern := tt.pattern | 
					
						
							|  |  |  |  | 		result := tt.result | 
					
						
							|  |  |  |  | 		matches, err := sftp.Glob(pattern) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Errorf("Glob error for %q: %s", pattern, err) | 
					
						
							|  |  |  |  | 			continue | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if !contains(matches, result) { | 
					
						
							|  |  |  |  | 			t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	for _, pattern := range []string{"no_match", "../*/no_match"} { | 
					
						
							|  |  |  |  | 		matches, err := sftp.Glob(pattern) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			t.Errorf("Glob error for %q: %s", pattern, err) | 
					
						
							|  |  |  |  | 			continue | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if len(matches) != 0 { | 
					
						
							|  |  |  |  | 			t.Errorf("Glob(%#q) = %#v want []", pattern, matches) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestGlobError(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2016-11-18 21:20:24 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	_, err := sftp.Glob("[7]") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Error("expected error for bad pattern; got none") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func TestGlobUNC(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2016-11-18 21:20:24 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 	// Just make sure this runs without crashing for now.
 | 
					
						
							|  |  |  |  | 	// See issue 15879.
 | 
					
						
							|  |  |  |  | 	sftp.Glob(`\\?\C:\*`) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:12:08 +08:00
										 |  |  |  | // sftp/issue/42, abrupt server hangup would result in client hangs.
 | 
					
						
							|  |  |  |  | func TestServerRoughDisconnect(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) | 
					
						
							| 
									
										
										
										
											2016-01-01 22:31:52 +08:00
										 |  |  |  | 	if *testServerImpl { | 
					
						
							|  |  |  |  | 		t.Skipf("skipping with -testserver") | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2016-01-01 22:31:52 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							| 
									
										
										
										
											2015-06-15 18:12:08 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := sftp.Open("/dev/zero") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f.Close() | 
					
						
							|  |  |  |  | 	go func() { | 
					
						
							|  |  |  |  | 		time.Sleep(100 * time.Millisecond) | 
					
						
							|  |  |  |  | 		cmd.Process.Kill() | 
					
						
							|  |  |  |  | 	}() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	io.Copy(ioutil.Discard, f) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-30 02:27:52 +08:00
										 |  |  |  | // sftp/issue/181, abrupt server hangup would result in client hangs.
 | 
					
						
							|  |  |  |  | // due to broadcastErr filling up the request channel
 | 
					
						
							|  |  |  |  | // this reproduces it about 50% of the time
 | 
					
						
							|  |  |  |  | func TestServerRoughDisconnect2(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) | 
					
						
							| 
									
										
										
										
											2017-06-30 02:27:52 +08:00
										 |  |  |  | 	if *testServerImpl { | 
					
						
							|  |  |  |  | 		t.Skipf("skipping with -testserver") | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READONLY, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-06-30 02:27:52 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := sftp.Open("/dev/zero") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f.Close() | 
					
						
							|  |  |  |  | 	b := make([]byte, 32768*100) | 
					
						
							|  |  |  |  | 	go func() { | 
					
						
							|  |  |  |  | 		time.Sleep(1 * time.Millisecond) | 
					
						
							|  |  |  |  | 		cmd.Process.Kill() | 
					
						
							|  |  |  |  | 	}() | 
					
						
							|  |  |  |  | 	for { | 
					
						
							|  |  |  |  | 		_, err = f.Read(b) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 04:46:20 +08:00
										 |  |  |  | // sftp/issue/234 - abrupt shutdown during ReadFrom hangs client
 | 
					
						
							|  |  |  |  | func TestServerRoughDisconnect3(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) | 
					
						
							| 
									
										
										
										
											2018-03-16 04:46:20 +08:00
										 |  |  |  | 	if *testServerImpl { | 
					
						
							|  |  |  |  | 		t.Skipf("skipping with -testserver") | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2018-03-16 04:46:20 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	rf, err := sftp.OpenFile("/dev/null", os.O_RDWR) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer rf.Close() | 
					
						
							|  |  |  |  | 	lf, err := os.Open("/dev/zero") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer lf.Close() | 
					
						
							|  |  |  |  | 	go func() { | 
					
						
							|  |  |  |  | 		time.Sleep(10 * time.Millisecond) | 
					
						
							|  |  |  |  | 		cmd.Process.Kill() | 
					
						
							|  |  |  |  | 	}() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	io.Copy(rf, lf) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // sftp/issue/234 - also affected Write
 | 
					
						
							|  |  |  |  | func TestServerRoughDisconnect4(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) | 
					
						
							| 
									
										
										
										
											2018-03-16 04:46:20 +08:00
										 |  |  |  | 	if *testServerImpl { | 
					
						
							|  |  |  |  | 		t.Skipf("skipping with -testserver") | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2018-03-16 04:46:20 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	rf, err := sftp.OpenFile("/dev/null", os.O_RDWR) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer rf.Close() | 
					
						
							|  |  |  |  | 	lf, err := os.Open("/dev/zero") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer lf.Close() | 
					
						
							|  |  |  |  | 	go func() { | 
					
						
							|  |  |  |  | 		time.Sleep(10 * time.Millisecond) | 
					
						
							|  |  |  |  | 		cmd.Process.Kill() | 
					
						
							|  |  |  |  | 	}() | 
					
						
							|  |  |  |  | 	b := make([]byte, 32768*200) | 
					
						
							|  |  |  |  | 	lf.Read(b) | 
					
						
							|  |  |  |  | 	for { | 
					
						
							|  |  |  |  | 		_, err = rf.Write(b) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	io.Copy(rf, lf) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-26 01:44:19 +08:00
										 |  |  |  | // sftp/issue/26 writing to a read only file caused client to loop.
 | 
					
						
							|  |  |  |  | func TestClientWriteToROFile(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(t) | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	sftp, cmd := testClient(t, READWRITE, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-12-26 01:44:19 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	defer sftp.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	f, err := sftp.Open("/dev/zero") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer f.Close() | 
					
						
							|  |  |  |  | 	_, err = f.Write([]byte("hello")) | 
					
						
							|  |  |  |  | 	if err == nil { | 
					
						
							|  |  |  |  | 		t.Fatal("expected error, got", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | func benchmarkRead(b *testing.B, bufsize int, delay time.Duration) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(b) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | 	size := 10*1024*1024 + 123 // ~10MiB
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// open sftp client
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 	sftp, cmd := testClient(b, READONLY, delay) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							| 
									
										
										
										
											2017-03-15 03:27:51 +08:00
										 |  |  |  | 	// defer sftp.Close()
 | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	buf := make([]byte, bufsize) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  |  | 	b.SetBytes(int64(size)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  |  | 		offset := 0 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f2, err := sftp.Open("/dev/zero") | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer f2.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		for offset < size { | 
					
						
							|  |  |  |  | 			n, err := io.ReadFull(f2, buf) | 
					
						
							|  |  |  |  | 			offset += n | 
					
						
							|  |  |  |  | 			if err == io.ErrUnexpectedEOF && offset != size { | 
					
						
							|  |  |  |  | 				b.Fatalf("read too few bytes! want: %d, got: %d", size, n) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				b.Fatal(err) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			offset += n | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkRead1k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkRead(b, 1*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkRead16k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkRead(b, 16*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkRead32k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkRead(b, 32*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkRead128k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkRead(b, 128*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkRead512k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkRead(b, 512*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkRead1MiB(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkRead(b, 1024*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkRead4MiB(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkRead(b, 4*1024*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | func BenchmarkRead4MiBDelay10Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkRead(b, 4*1024*1024, 10*time.Millisecond) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | func BenchmarkRead4MiBDelay50Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkRead(b, 4*1024*1024, 50*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkRead4MiBDelay150Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkRead(b, 4*1024*1024, 150*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func benchmarkWrite(b *testing.B, bufsize int, delay time.Duration) { | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | 	size := 10*1024*1024 + 123 // ~10MiB
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// open sftp client
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 	sftp, cmd := testClient(b, false, delay) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | 	defer cmd.Wait() | 
					
						
							| 
									
										
										
										
											2017-03-15 03:27:51 +08:00
										 |  |  |  | 	// defer sftp.Close()
 | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	data := make([]byte, size) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  |  | 	b.SetBytes(int64(size)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  |  | 		offset := 0 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f2, err := sftp.Create(f.Name()) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer f2.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		for offset < size { | 
					
						
							|  |  |  |  | 			n, err := f2.Write(data[offset:min(len(data), offset+bufsize)]) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				b.Fatal(err) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if offset+n < size && n != bufsize { | 
					
						
							|  |  |  |  | 				b.Fatalf("wrote too few bytes! want: %d, got: %d", size, n) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			offset += n | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f2.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		fi, err := os.Stat(f.Name()) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if fi.Size() != int64(size) { | 
					
						
							|  |  |  |  | 			b.Fatalf("wrong file size: want %d, got %d", size, fi.Size()) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite1k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkWrite(b, 1*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite16k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkWrite(b, 16*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite32k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkWrite(b, 32*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite128k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkWrite(b, 128*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite512k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkWrite(b, 512*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite1MiB(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkWrite(b, 1024*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite4MiB(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkWrite(b, 4*1024*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite4MiBDelay10Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkWrite(b, 4*1024*1024, 10*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite4MiBDelay50Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkWrite(b, 4*1024*1024, 50*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkWrite4MiBDelay150Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkWrite(b, 4*1024*1024, 150*time.Millisecond) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-16 06:54:02 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 10:21:59 +08:00
										 |  |  |  | func benchmarkReadFrom(b *testing.B, bufsize int, delay time.Duration) { | 
					
						
							|  |  |  |  | 	size := 10*1024*1024 + 123 // ~10MiB
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// open sftp client
 | 
					
						
							|  |  |  |  | 	sftp, cmd := testClient(b, false, delay) | 
					
						
							|  |  |  |  | 	defer cmd.Wait() | 
					
						
							|  |  |  |  | 	// defer sftp.Close()
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	data := make([]byte, size) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  |  | 	b.SetBytes(int64(size)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  |  | 		f, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f2, err := sftp.Create(f.Name()) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer f2.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f2.ReadFrom(bytes.NewReader(data)) | 
					
						
							|  |  |  |  | 		f2.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		fi, err := os.Stat(f.Name()) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if fi.Size() != int64(size) { | 
					
						
							|  |  |  |  | 			b.Fatalf("wrong file size: want %d, got %d", size, fi.Size()) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		os.Remove(f.Name()) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom1k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkReadFrom(b, 1*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-06-26 10:21:59 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom16k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkReadFrom(b, 16*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-06-26 10:21:59 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom32k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkReadFrom(b, 32*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-06-26 10:21:59 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom128k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkReadFrom(b, 128*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-06-26 10:21:59 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom512k(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkReadFrom(b, 512*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-06-26 10:21:59 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom1MiB(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkReadFrom(b, 1024*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-06-26 10:21:59 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom4MiB(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  |  | 	benchmarkReadFrom(b, 4*1024*1024, NODELAY) | 
					
						
							| 
									
										
										
										
											2017-06-26 10:21:59 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom4MiBDelay10Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkReadFrom(b, 4*1024*1024, 10*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom4MiBDelay50Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkReadFrom(b, 4*1024*1024, 50*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkReadFrom4MiBDelay150Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkReadFrom(b, 4*1024*1024, 150*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | func benchmarkCopyDown(b *testing.B, fileSize int64, delay time.Duration) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(b) | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 	// Create a temp file and fill it with zero's.
 | 
					
						
							|  |  |  |  | 	src, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer src.Close() | 
					
						
							|  |  |  |  | 	srcFilename := src.Name() | 
					
						
							|  |  |  |  | 	defer os.Remove(srcFilename) | 
					
						
							|  |  |  |  | 	zero, err := os.Open("/dev/zero") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	n, err := io.Copy(src, io.LimitReader(zero, fileSize)) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if n < fileSize { | 
					
						
							|  |  |  |  | 		b.Fatal("short copy") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	zero.Close() | 
					
						
							|  |  |  |  | 	src.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	sftp, cmd := testClient(b, READONLY, delay) | 
					
						
							|  |  |  |  | 	defer cmd.Wait() | 
					
						
							| 
									
										
										
										
											2017-03-15 03:27:51 +08:00
										 |  |  |  | 	// defer sftp.Close()
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  |  | 	b.SetBytes(fileSize) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  |  | 		dst, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer os.Remove(dst.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		src, err := sftp.Open(srcFilename) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer src.Close() | 
					
						
							|  |  |  |  | 		n, err := io.Copy(dst, src) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatalf("copy error: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if n < fileSize { | 
					
						
							|  |  |  |  | 			b.Fatal("unable to copy all bytes") | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		dst.Close() | 
					
						
							|  |  |  |  | 		fi, err := os.Stat(dst.Name()) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if fi.Size() != fileSize { | 
					
						
							|  |  |  |  | 			b.Fatalf("wrong file size: want %d, got %d", fileSize, fi.Size()) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		os.Remove(dst.Name()) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkCopyDown10MiBDelay10Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkCopyDown(b, 10*1024*1024, 10*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkCopyDown10MiBDelay50Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkCopyDown(b, 10*1024*1024, 50*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkCopyDown10MiBDelay150Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkCopyDown(b, 10*1024*1024, 150*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func benchmarkCopyUp(b *testing.B, fileSize int64, delay time.Duration) { | 
					
						
							| 
									
										
										
										
											2019-01-19 07:59:30 +08:00
										 |  |  |  | 	skipIfWindows(b) | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 	// Create a temp file and fill it with zero's.
 | 
					
						
							|  |  |  |  | 	src, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer src.Close() | 
					
						
							|  |  |  |  | 	srcFilename := src.Name() | 
					
						
							|  |  |  |  | 	defer os.Remove(srcFilename) | 
					
						
							|  |  |  |  | 	zero, err := os.Open("/dev/zero") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	n, err := io.Copy(src, io.LimitReader(zero, fileSize)) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if n < fileSize { | 
					
						
							|  |  |  |  | 		b.Fatal("short copy") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	zero.Close() | 
					
						
							|  |  |  |  | 	src.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	sftp, cmd := testClient(b, false, delay) | 
					
						
							|  |  |  |  | 	defer cmd.Wait() | 
					
						
							| 
									
										
										
										
											2017-03-15 03:27:51 +08:00
										 |  |  |  | 	// defer sftp.Close()
 | 
					
						
							| 
									
										
										
										
											2015-06-03 00:36:35 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  |  | 	b.SetBytes(fileSize) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  |  | 		tmp, err := ioutil.TempFile("", "sftptest") | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		tmp.Close() | 
					
						
							|  |  |  |  | 		defer os.Remove(tmp.Name()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		dst, err := sftp.Create(tmp.Name()) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer dst.Close() | 
					
						
							|  |  |  |  | 		src, err := os.Open(srcFilename) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		defer src.Close() | 
					
						
							|  |  |  |  | 		n, err := io.Copy(dst, src) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatalf("copy error: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if n < fileSize { | 
					
						
							|  |  |  |  | 			b.Fatal("unable to copy all bytes") | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		fi, err := os.Stat(tmp.Name()) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			b.Fatal(err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if fi.Size() != fileSize { | 
					
						
							|  |  |  |  | 			b.Fatalf("wrong file size: want %d, got %d", fileSize, fi.Size()) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		os.Remove(tmp.Name()) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkCopyUp10MiBDelay10Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkCopyUp(b, 10*1024*1024, 10*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkCopyUp10MiBDelay50Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkCopyUp(b, 10*1024*1024, 50*time.Millisecond) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func BenchmarkCopyUp10MiBDelay150Msec(b *testing.B) { | 
					
						
							|  |  |  |  | 	benchmarkCopyUp(b, 10*1024*1024, 150*time.Millisecond) | 
					
						
							| 
									
										
										
										
											2014-10-09 05:41:54 +08:00
										 |  |  |  | } |