From c16ccba01d00b42ad025b2262695f8ff53a11dd7 Mon Sep 17 00:00:00 2001 From: Arnaud Ysmal Date: Wed, 4 Dec 2013 23:30:50 +0100 Subject: [PATCH] The REST command must precede RETR/STOR --- ftp.go | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/ftp.go b/ftp.go index 94df1f2..4f7148b 100644 --- a/ftp.go +++ b/ftp.go @@ -236,13 +236,21 @@ func (c *ServerConn) cmd(expected int, format string, args ...interface{}) (int, return code, line, err } -// cmdDataConn executes a command which require a FTP data connection. -func (c *ServerConn) cmdDataConn(format string, args ...interface{}) (net.Conn, error) { +// cmdDataConnFrom executes a command which require a FTP data connection. +// Issues a REST FTP command to specify the number of bytes to skip for the transfer. +func (c *ServerConn) cmdDataConnFrom(offset uint64, format string, args ...interface{}) (net.Conn, error) { conn, err := c.openDataConn() if err != nil { return nil, err } + if offset != 0 { + _, _, err := c.cmd(StatusRequestFilePending, "REST %d", offset) + if err != nil { + return nil, err + } + } + _, err = c.conn.Cmd(format, args...) if err != nil { conn.Close() @@ -308,7 +316,7 @@ func parseListLine(line string) (*Entry, error) { // NameList issues an NLST FTP command. func (c *ServerConn) NameList(path string) (entries []string, err error) { - conn, err := c.cmdDataConn("NLST %s", path) + conn, err := c.cmdDataConnFrom(0, "NLST %s", path) if err != nil { return } @@ -328,7 +336,7 @@ func (c *ServerConn) NameList(path string) (entries []string, err error) { // List issues a LIST FTP command. func (c *ServerConn) List(path string) (entries []*Entry, err error) { - conn, err := c.cmdDataConn("LIST %s", path) + conn, err := c.cmdDataConnFrom(0, "LIST %s", path) if err != nil { return } @@ -385,19 +393,20 @@ func (c *ServerConn) CurrentDir() (string, error) { return msg[start+1 : end], nil } -// Rest issues a REST FTP command to specify the number of bytes to skip for -// the next transfer. -func (c *ServerConn) Rest(offset uint64) error { - _, _, err := c.cmd(StatusRequestFilePending, "REST %d", offset) - return err -} - // Retr issues a RETR FTP command to fetch the specified file from the remote // FTP server. // // The returned ReadCloser must be closed to cleanup the FTP data connection. func (c *ServerConn) Retr(path string) (io.ReadCloser, error) { - conn, err := c.cmdDataConn("RETR %s", path) + return c.RetrFrom(path, 0) +} + +// Retr issues a RETR FTP command to fetch the specified file from the remote +// FTP server, the server will not send the offset first bytes of the file. +// +// The returned ReadCloser must be closed to cleanup the FTP data connection. +func (c *ServerConn) RetrFrom(path string, offset uint64) (io.ReadCloser, error) { + conn, err := c.cmdDataConnFrom(offset, "RETR %s", path) if err != nil { return nil, err } @@ -411,7 +420,16 @@ func (c *ServerConn) Retr(path string) (io.ReadCloser, error) { // // Hint: io.Pipe() can be used if an io.Writer is required. func (c *ServerConn) Stor(path string, r io.Reader) error { - conn, err := c.cmdDataConn("STOR %s", path) + return c.StorFrom(path, r, 0) +} + +// Stor issues a STOR FTP command to store a file to the remote FTP server. +// Stor creates the specified file with the content of the io.Reader, writing +// on the server will start at the given file offset. +// +// Hint: io.Pipe() can be used if an io.Writer is required. +func (c *ServerConn) StorFrom(path string, r io.Reader, offset uint64) error { + conn, err := c.cmdDataConnFrom(offset, "STOR %s", path) if err != nil { return err }