diff --git a/client_test.go b/client_test.go index 0409da0..8297e49 100644 --- a/client_test.go +++ b/client_test.go @@ -81,6 +81,7 @@ func testConn(t *testing.T, disableEPSV bool) { t.Errorf("'%s'", buf) } r.Close() + r.Close() // test we can close two times } // Read with deadline diff --git a/ftp.go b/ftp.go index 567e2fd..c29cb38 100644 --- a/ftp.go +++ b/ftp.go @@ -47,8 +47,9 @@ type Entry struct { // Response represents a data-connection type Response struct { - conn net.Conn - c *ServerConn + conn net.Conn + c *ServerConn + closed bool } // Connect is an alias to Dial, for backward compatibility @@ -337,7 +338,7 @@ func (c *ServerConn) NameList(path string) (entries []string, err error) { return } - r := &Response{conn, c} + r := &Response{conn: conn, c: c} defer r.Close() scanner := bufio.NewScanner(r) @@ -368,7 +369,7 @@ func (c *ServerConn) List(path string) (entries []*Entry, err error) { return } - r := &Response{conn, c} + r := &Response{conn: conn, c: c} defer r.Close() scanner := bufio.NewScanner(r) @@ -445,7 +446,7 @@ func (c *ServerConn) RetrFrom(path string, offset uint64) (*Response, error) { return nil, err } - return &Response{conn, c}, nil + return &Response{conn: conn, c: c}, nil } // Stor issues a STOR FTP command to store a file to the remote FTP server. @@ -536,12 +537,17 @@ func (r *Response) Read(buf []byte) (int, error) { } // Close implements the io.Closer interface on a FTP data connection. +// After the first call, Close will do nothing and return nil. func (r *Response) Close() error { + if r.closed { + return nil + } err := r.conn.Close() _, _, err2 := r.c.conn.ReadResponse(StatusClosingDataConnection) if err2 != nil { err = err2 } + r.closed = true return err }