From 101a3ff39c858b80f8cb1e98533332a03b17e626 Mon Sep 17 00:00:00 2001 From: Tony Blyler Date: Sat, 14 May 2016 11:24:44 -0400 Subject: [PATCH] Add resume support to downloads --- easysftp.go | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/easysftp.go b/easysftp.go index 19f7045..2488069 100644 --- a/easysftp.go +++ b/easysftp.go @@ -99,8 +99,8 @@ func (c *Client) Lstat(path string) (os.FileInfo, error) { return sftpClient.Lstat(path) } -// Download a file from the given path to the output writer -func (c *Client) Download(path string, output io.Writer) error { +// Download a file from the given path to the output writer with the given offset of the remote file +func (c *Client) Download(path string, output io.Writer, offset int64) error { sftpClient, err := c.newSftpClient() if err != nil { return err @@ -124,12 +124,18 @@ func (c *Client) Download(path string, output io.Writer) error { defer remote.Close() + _, err = remote.Seek(offset, 0) + if err != nil { + return err + } + _, err = io.Copy(output, remote) return err } // Mirror downloads an entire folder (recursively) or file underneath the given localParentPath -func (c *Client) Mirror(path string, localParentPath string) error { +// resume will continue downloading interrupted files +func (c *Client) Mirror(path string, localParentPath string, resume bool) error { sftpClient, err := c.newSftpClient() if err != nil { return err @@ -154,9 +160,19 @@ func (c *Client) Mirror(path string, localParentPath string) error { } } + flags := os.O_RDWR | os.O_CREATE + + if resume { + // append to the end of the file + flags |= os.O_APPEND + } else { + // truncate the file + flags |= os.O_TRUNC + } + file, err := os.OpenFile( localPath, - os.O_RDWR|os.O_CREATE|os.O_TRUNC, + flags, c.config.FileMode, ) if err != nil { @@ -165,7 +181,18 @@ func (c *Client) Mirror(path string, localParentPath string) error { defer file.Close() - return c.Download(path, file) + var offset int64 + if resume { + info, err := file.Stat() + if err != nil { + return err + } + + // we assume that the size of the file is the resume point + offset = info.Size() + } + + return c.Download(path, file, offset) } // download the whole directory recursively