2015-03-28 11:50:23 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								package  sftp  
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:53:18 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"bufio" 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-03 17:39:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"context" 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 22:28:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"crypto/rand" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"encoding/hex" 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
									
										
										
										
											2020-12-19 12:39:48 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"hash" 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"io" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"os" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"os/exec" 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-11 19:10:51 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"path" 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-07-23 14:21:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/restic/restic/internal/backend" 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-15 16:23:39 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/restic/restic/internal/backend/layout" 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-08 13:04:34 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/restic/restic/internal/backend/limiter" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/restic/restic/internal/backend/location" 
							 
						 
					
						
							
								
									
										
										
										
											2017-07-23 14:21:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/restic/restic/internal/debug" 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-12 17:45:34 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/restic/restic/internal/errors" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/restic/restic/internal/restic" 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-11 19:10:51 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-16 16:00:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/cenkalti/backoff/v4" 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-11 19:10:51 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/pkg/sftp" 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-30 12:24:04 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"golang.org/x/sync/errgroup" 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-01-24 20:23:50 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// SFTP is a backend in a directory accessed via SFTP.  
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								type  SFTP  struct  {  
						 
					
						
							
								
									
										
										
										
											2015-05-03 16:43:27 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									c  * sftp . Client 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									p  string 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									cmd     * exec . Cmd 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result  <- chan  error 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-06-06 13:17:07 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									posixRename  bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-15 16:23:39 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									layout . Layout 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:06 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									Config 
							 
						 
					
						
							
								
									
										
										
										
											2022-04-26 19:15:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									backend . Modes 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-31 22:51:35 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								var  _  restic . Backend  =  & SFTP { }  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-06-08 13:04:34 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  NewFactory ( )  location . Factory  {  
						 
					
						
							
								
									
										
										
										
											2023-06-08 17:32:43 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  location . NewLimitedBackendFactory ( "sftp" ,  ParseConfig ,  location . NoPassword ,  limiter . WrapBackendConstructor ( Create ) ,  limiter . WrapBackendConstructor ( Open ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-08 13:04:34 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								const  defaultLayout  =  "default"  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-20 19:49:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  startClient ( cfg  Config )  ( * SFTP ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									program ,  args ,  err  :=  buildSSHCommand ( cfg ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-03 21:05:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									debug . Log ( "start client %v %v" ,  program ,  args ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Connect to a remote host and request the sftp subsystem via the 'ssh' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// command.  This assumes that passwordless login is correctly configured. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									cmd  :=  exec . Command ( program ,  args ... ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:53:18 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// prefix the errors with the program name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									stderr ,  err  :=  cmd . StderrPipe ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-29 21:54:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  errors . Wrap ( err ,  "cmd.StderrPipe" ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:53:18 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									go  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										sc  :=  bufio . NewScanner ( stderr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  sc . Scan ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fmt . Fprintf ( os . Stderr ,  "subprocess %v: %v\n" ,  program ,  sc . Text ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// get stdin and stdout 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									wr ,  err  :=  cmd . StdinPipe ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-29 21:54:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  errors . Wrap ( err ,  "cmd.StdinPipe" ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									rd ,  err  :=  cmd . StdoutPipe ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-29 21:54:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  errors . Wrap ( err ,  "cmd.StdoutPipe" ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-03-13 21:09:16 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									bg ,  err  :=  backend . StartForeground ( cmd ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-17 23:02:47 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-20 21:26:01 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  backend . IsErrDot ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  errors . Errorf ( "cannot implicitly run relative executable %v found in current directory, use -o sftp.command=./<command> to override" ,  cmd . Path ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// wait in a different goroutine 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ch  :=  make ( chan  error ,  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									go  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										err  :=  cmd . Wait ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-09-27 22:35:08 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										debug . Log ( "ssh command exited, err %v" ,  err ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												sftp: persist "ssh command exited" error
If our ssh process has died, not only the next, but all subsequent
calls to clientError() should indicate the error.
restic output when the ssh process is killed with "kill -9":
  Save(<data/afb68adbf9>) returned error, retrying after 253.661803ms: Write: failed to send packet header: write |1: file already closed
  Save(<data/afb68adbf9>) returned error, retrying after 580.752212ms: ssh command exited: signal: killed
  Save(<data/afb68adbf9>) returned error, retrying after 790.150468ms: ssh command exited: signal: killed
  Save(<data/afb68adbf9>) returned error, retrying after 1.769595051s: ssh command exited: signal: killed
  [...]
  error in cleanup handler: ssh command exited: signal: killed
Before this patch:
  Save(<data/de698d934f>) returned error, retrying after 252.84163ms: Write: failed to send packet header: write |1: file already closed
  Save(<data/de698d934f>) returned error, retrying after 660.236963ms: OpenFile: failed to send packet header: write |1: file already closed
  Save(<data/de698d934f>) returned error, retrying after 568.049909ms: OpenFile: failed to send packet header: write |1: file already closed
  Save(<data/de698d934f>) returned error, retrying after 2.428813824s: OpenFile: failed to send packet header: write |1: file already closed
  [...]
  error in cleanup handler: failed to send packet header: write |1: file already closed
											 
										 
										
											2018-05-30 19:28:14 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										for  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ch  <-  errors . Wrap ( err ,  "ssh command exited" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// open the SFTP session 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									client ,  err  :=  sftp . NewClientPipe ( rd ,  wr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-21 17:48:36 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  errors . Errorf ( "unable to start the sftp session, error: %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-17 23:02:47 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  =  bg ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errors . Wrap ( err ,  "bg" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-06-06 13:17:07 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									_ ,  posixRename  :=  client . HasExtension ( "posix-rename@openssh.com" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & SFTP { c :  client ,  cmd :  cmd ,  result :  ch ,  posixRename :  posixRename } ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// clientError returns an error if the client has exited. Otherwise, nil is  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// returned immediately.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  clientError ( )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  err  :=  <- r . result : 
							 
						 
					
						
							
								
									
										
										
										
											2016-09-27 22:35:08 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										debug . Log ( "client has exited with err %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-12-16 16:00:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  backoff . Permanent ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Open opens an sftp backend as described by the config by running  
						 
					
						
							
								
									
										
										
										
											2022-07-30 12:57:18 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// "ssh" with the appropriate arguments (or cfg.Command, if set).  
						 
					
						
							
								
									
										
										
										
											2020-09-19 22:01:32 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  Open ( ctx  context . Context ,  cfg  Config )  ( * SFTP ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									debug . Log ( "open backend with config %#v" ,  cfg ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-20 19:49:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sftp ,  err  :=  startClient ( cfg ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-07 19:56:59 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-20 19:49:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										debug . Log ( "unable to start program: %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-07 19:56:59 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-20 19:49:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  open ( ctx ,  sftp ,  cfg ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-20 19:49:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  open ( ctx  context . Context ,  sftp  * SFTP ,  cfg  Config )  ( * SFTP ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2023-04-07 23:02:35 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  err  error 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-15 16:23:39 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sftp . Layout ,  err  =  layout . ParseLayout ( ctx ,  sftp ,  cfg . Layout ,  defaultLayout ,  cfg . Path ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:17:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									debug . Log ( "layout: %v\n" ,  sftp . Layout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-15 16:27:04 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi ,  err  :=  sftp . c . Stat ( sftp . Layout . Filename ( restic . Handle { Type :  restic . ConfigFile } ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-04-26 19:15:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									m  :=  backend . DeriveModesFromFileInfo ( fi ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									debug . Log ( "using (%03O file, %03O dir) permissions" ,  m . File ,  m . Dir ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sftp . Config  =  cfg 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sftp . p  =  cfg . Path 
							 
						 
					
						
							
								
									
										
										
										
											2022-04-26 19:15:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sftp . Modes  =  m 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  sftp ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-30 12:24:04 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  mkdirAllDataSubdirs ( ctx  context . Context ,  nconn  uint )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Run multiple MkdirAll calls concurrently. These involve multiple 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// round-trips and we do a lot of them, so this whole operation can be slow 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// on high-latency links. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									g ,  _  :=  errgroup . WithContext ( ctx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Use errgroup's built-in semaphore, because r.sem is not initialized yet. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									g . SetLimit ( int ( nconn ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-07-16 15:10:06 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  _ ,  d  :=  range  r . Paths ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-30 12:24:04 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										d  :=  d 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										g . Go ( func ( )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// First try Mkdir. For most directories in Paths, this takes one 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// round trip, not counting duplicate parent creations causes by 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// concurrency. MkdirAll first does Stat, then recursive MkdirAll 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// on the parent, so calls typically take three round trips. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  :=  r . c . Mkdir ( d ) ;  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  r . c . MkdirAll ( d ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-07-16 15:10:06 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-30 12:24:04 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  g . Wait ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-07-16 15:10:06 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Join combines path components with slashes (according to the sftp spec).  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Join ( p  ... string )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  path . Join ( p ... ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ReadDir returns the entries for a directory.  
						 
					
						
							
								
									
										
										
										
											2023-05-18 19:18:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  ReadDir ( _  context . Context ,  dir  string )  ( [ ] os . FileInfo ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2017-10-28 14:16:27 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi ,  err  :=  r . c . ReadDir ( dir ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// sftp client does not specify dir name on error, so add it here 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									err  =  errors . Wrapf ( err ,  "(%v)" ,  dir ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  fi ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:17:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// IsNotExist returns true if the error is caused by a not existing file.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  IsNotExist ( err  error )  bool  {  
						 
					
						
							
								
									
										
										
										
											2021-03-10 20:38:22 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  errors . Is ( err ,  os . ErrNotExist ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:17:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  buildSSHCommand ( cfg  Config )  ( cmd  string ,  args  [ ] string ,  err  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  cfg . Command  !=  ""  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-13 20:50:37 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										args ,  err  :=  backend . SplitShellStrings ( cfg . Command ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  "" ,  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  args [ 0 ] ,  args [ 1 : ] ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									cmd  =  "ssh" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-03-08 16:45:33 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									host ,  port  :=  cfg . Host ,  cfg . Port 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									args  =  [ ] string { host } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  port  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										args  =  append ( args ,  "-p" ,  port ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-02-15 19:17:41 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-28 18:22:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  cfg . User  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										args  =  append ( args ,  "-l" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										args  =  append ( args ,  cfg . User ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									args  =  append ( args ,  "-s" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									args  =  append ( args ,  "sftp" ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  cmd ,  args ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-28 18:22:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-09-23 11:21:27 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Create creates an sftp backend as described by the config by running "ssh"  
						 
					
						
							
								
									
										
										
										
											2022-07-30 12:57:18 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// with the appropriate arguments (or cfg.Command, if set).  
						 
					
						
							
								
									
										
										
										
											2020-09-19 22:01:32 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  Create ( ctx  context . Context ,  cfg  Config )  ( * SFTP ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2022-08-20 19:49:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sftp ,  err  :=  startClient ( cfg ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-03 21:05:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:41:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										debug . Log ( "unable to start program: %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-03 21:05:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-15 16:23:39 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sftp . Layout ,  err  =  layout . ParseLayout ( ctx ,  sftp ,  cfg . Layout ,  defaultLayout ,  cfg . Path ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-04-26 19:15:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sftp . Modes  =  backend . DefaultModes 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-04 20:39:45 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// test if config file already exists 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-15 16:27:04 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									_ ,  err  =  sftp . c . Lstat ( sftp . Layout . Filename ( restic . Handle { Type :  restic . ConfigFile } ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  ==  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-05-03 16:43:27 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  errors . New ( "config file already exists" ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-14 11:56:45 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-19 18:56:01 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// create paths for data and refs 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-30 12:24:04 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  =  sftp . mkdirAllDataSubdirs ( ctx ,  cfg . Connections ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-07-16 15:10:06 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-20 19:49:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// repurpose existing connection 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  open ( ctx ,  sftp ,  cfg ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-28 18:22:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-07 19:56:59 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Connections ( )  uint  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  r . Config . Connections 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// Location returns this backend's location (the directory name).  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Location ( )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  r . p 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-19 12:39:48 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Hasher may return a hash function for calculating a content hash for the backend  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Hasher ( )  hash . Hash  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-05-01 20:07:29 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// HasAtomicReplace returns whether Save() can atomically replace files  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  HasAtomicReplace ( )  bool  {  
						 
					
						
							
								
									
										
										
										
											2022-06-06 13:17:07 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  r . posixRename 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-01 20:07:29 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-11 19:10:51 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Join joins the given paths and cleans them afterwards. This always uses  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// forward slashes, which is required by sftp.  
						 
					
						
							
								
									
										
										
										
											2015-11-02 14:53:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  Join ( parts  ... string )  string  {  
						 
					
						
							
								
									
										
										
										
											2016-08-11 19:10:51 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  path . Clean ( path . Join ( parts ... ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-11-02 14:53:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 22:28:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// tempSuffix generates a random string suffix that should be sufficiently long  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// to avoid accidential conflicts  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  tempSuffix ( )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  nonce  [ 16 ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									_ ,  err  :=  rand . Read ( nonce [ : ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										panic ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  hex . EncodeToString ( nonce [ : ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-01-24 01:15:35 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Save stores data in the backend at the handle.  
						 
					
						
							
								
									
										
										
										
											2023-05-18 19:18:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Save ( _  context . Context ,  h  restic . Handle ,  rd  restic . RewindReader )  error  {  
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  r . clientError ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									filename  :=  r . Filename ( h ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 22:28:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									tmpFilename  :=  filename  +  "-restic-temp-"  +  tempSuffix ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 21:35:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									dirname  :=  r . Dirname ( h ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-05-03 21:18:49 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// create new file 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 22:28:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									f ,  err  :=  r . c . OpenFile ( tmpFilename ,  os . O_CREATE | os . O_EXCL | os . O_WRONLY ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-05-03 21:18:49 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-05 17:51:09 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  r . IsNotExist ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// error is caused by a missing directory, try to create it 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-01 17:26:38 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										mkdirErr  :=  r . c . MkdirAll ( r . Dirname ( h ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-05 17:51:09 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  mkdirErr  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											debug . Log ( "error creating dir %v: %v" ,  r . Dirname ( h ) ,  mkdirErr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// try again 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 22:28:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											f ,  err  =  r . c . OpenFile ( tmpFilename ,  os . O_CREATE | os . O_EXCL | os . O_WRONLY ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-05 17:51:09 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 21:35:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// pkg/sftp doesn't allow creating with a mode. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Chmod while the file is still empty. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  ==  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-04-26 19:15:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										err  =  f . Chmod ( r . Modes . File ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 21:35:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:17:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errors . Wrap ( err ,  "OpenFile" ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 21:35:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Try not to leave a partial file behind. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										rmErr  :=  r . c . Remove ( f . Name ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  rmErr  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											debug . Log ( "sftp: failed to remove broken file %v: %v" , 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 22:28:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												f . Name ( ) ,  rmErr ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 21:35:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-01 12:19:48 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// save data, make sure to use the optimized sftp upload method 
							 
						 
					
						
							
								
									
										
										
										
											2020-12-18 23:41:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									wbytes ,  err  :=  f . ReadFrom ( rd ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-05-11 21:53:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										_  =  f . Close ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-07 09:13:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										err  =  r . checkNoSpace ( dirname ,  rd . Length ( ) ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:17:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  errors . Wrap ( err ,  "Write" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-18 23:41:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// sanity check 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  wbytes  !=  rd . Length ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										_  =  f . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errors . Errorf ( "wrote %d bytes instead of the expected %d bytes" ,  wbytes ,  rd . Length ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:17:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  =  f . Close ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 22:28:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errors . Wrap ( err ,  "Close" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-06-06 13:17:07 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Prefer POSIX atomic rename if available. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  r . posixRename  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										err  =  r . c . PosixRename ( tmpFilename ,  filename ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										err  =  r . c . Rename ( tmpFilename ,  filename ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 22:28:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  errors . Wrap ( err ,  "Rename" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 21:35:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// checkNoSpace checks if err was likely caused by lack of available space  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// on the remote, and if so, makes it permanent.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  checkNoSpace ( dir  string ,  size  int64 ,  origErr  error )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// The SFTP protocol has a message for ENOSPC, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// but pkg/sftp doesn't export it and OpenSSH's sftp-server 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// sends FX_FAILURE instead. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									e ,  ok  :=  origErr . ( * sftp . StatusError ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									_ ,  hasExt  :=  r . c . HasExtension ( "statvfs@openssh.com" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! ok  ||  e . FxCode ( )  !=  sftp . ErrSSHFxFailure  ||  ! hasExt  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  origErr 
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:40:24 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 21:35:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fsinfo ,  err  :=  r . c . StatVFS ( dir ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										debug . Log ( "sftp: StatVFS returned %v" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  origErr 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-07 09:13:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  fsinfo . Favail  ==  0  ||  fsinfo . Frsize * fsinfo . Bavail  <  uint64 ( size )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 21:35:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										err  :=  errors . New ( "sftp: no space left on device" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  backoff . Permanent ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  origErr 
							 
						 
					
						
							
								
									
										
										
										
											2016-01-24 01:15:35 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-16 23:59:16 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Load runs fn with a reader that yields the contents of the file at h at the  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// given offset.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Load ( ctx  context . Context ,  h  restic . Handle ,  length  int ,  offset  int64 ,  fn  func ( rd  io . Reader )  error )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  backend . DefaultLoad ( ctx ,  h ,  length ,  offset ,  r . openReader ,  fn ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-18 19:18:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  openReader ( _  context . Context ,  h  restic . Handle ,  length  int ,  offset  int64 )  ( io . ReadCloser ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:26:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									f ,  err  :=  r . c . Open ( r . Filename ( h ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-22 22:01:12 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  offset  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										_ ,  err  =  f . Seek ( offset ,  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-23 16:20:07 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											_  =  f . Close ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-22 22:01:12 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  length  >  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-01 12:19:48 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// unlimited reads usually use io.Copy which needs WriteTo support at the underlying reader 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// limited reads are usually combined with io.ReadFull which reads all required bytes into a buffer in one go 
							 
						 
					
						
							
								
									
										
										
										
											2023-04-07 23:02:35 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  backend . LimitReadCloser ( f ,  int64 ( length ) ) ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-22 22:01:12 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-07 23:02:35 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  f ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-22 22:01:12 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-01-23 23:27:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Stat returns information about a blob.  
						 
					
						
							
								
									
										
										
										
											2023-05-18 19:18:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Stat ( _  context . Context ,  h  restic . Handle )  ( restic . FileInfo ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  r . clientError ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-31 22:51:35 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  restic . FileInfo { } ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:26:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi ,  err  :=  r . c . Lstat ( r . Filename ( h ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-01-23 23:27:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-31 22:51:35 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  restic . FileInfo { } ,  errors . Wrap ( err ,  "Lstat" ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-01-23 23:27:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-20 19:34:38 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  restic . FileInfo { Size :  fi . Size ( ) ,  Name :  h . Name } ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2016-01-23 23:27:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-28 11:50:23 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Remove removes the content stored at name.  
						 
					
						
							
								
									
										
										
										
											2023-05-18 19:18:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Remove ( _  context . Context ,  h  restic . Handle )  error  {  
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  r . clientError ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-04-10 22:26:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  r . c . Remove ( r . Filename ( h ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-20 19:34:38 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// List runs fn for each file in the backend which has the type t. When an  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// error occurs (or fn returns an error), List stops and returns it.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( r  * SFTP )  List ( ctx  context . Context ,  t  restic . FileType ,  fn  func ( restic . FileInfo )  error )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									basedir ,  subdirs  :=  r . Basedir ( t ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									walker  :=  r . c . Walk ( basedir ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-07 19:56:59 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ok  :=  walker . Step ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-20 19:34:38 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  walker . Err ( )  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-10 21:35:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  r . IsNotExist ( walker . Err ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												debug . Log ( "ignoring non-existing directory" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2018-01-20 19:34:38 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  walker . Err ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-30 15:50:30 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-20 19:34:38 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  walker . Path ( )  ==  basedir  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  walker . Stat ( ) . IsDir ( )  &&  ! subdirs  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											walker . SkipDir ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi  :=  walker . Stat ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! fi . Mode ( ) . IsRegular ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										debug . Log ( "send %v\n" ,  path . Base ( walker . Path ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										rfi  :=  restic . FileInfo { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Name :  path . Base ( walker . Path ( ) ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Size :  fi . Size ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ctx . Err ( )  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  ctx . Err ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-28 11:50:23 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-20 19:34:38 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										err  :=  fn ( rfi ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ctx . Err ( )  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  ctx . Err ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-20 19:34:38 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  ctx . Err ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								var  closeTimeout  =  2  *  time . Second  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// Close closes the sftp connection and terminates the underlying command.  
						 
					
						
							
								
									
										
										
										
											2016-01-24 20:23:50 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Close ( )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  r  ==  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-05-01 17:13:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-01-26 22:16:17 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  :=  r . c . Close ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-09-27 22:35:08 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									debug . Log ( "Close returned error %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-07-05 11:06:28 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// wait for closeTimeout before killing the process 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  err  :=  <- r . result : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  <- time . After ( closeTimeout ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-01-24 20:23:50 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  r . cmd . Process . Kill ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-07-05 11:06:28 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-28 19:17:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// get the error, but ignore it 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									<- r . result 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-04 19:20:15 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2017-10-14 13:38:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-09-19 22:01:32 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  deleteRecursive ( ctx  context . Context ,  name  string )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									entries ,  err  :=  r . ReadDir ( ctx ,  name ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-14 16:08:15 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errors . Wrap ( err ,  "ReadDir" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  fi  :=  range  entries  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										itemName  :=  r . Join ( name ,  fi . Name ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  fi . IsDir ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-19 22:01:32 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											err  :=  r . deleteRecursive ( ctx ,  itemName ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-14 16:08:15 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  errors . Wrap ( err ,  "ReadDir" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											err  =  r . c . RemoveDirectory ( itemName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  errors . Wrap ( err ,  "RemoveDirectory" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										err  :=  r . c . Remove ( itemName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  errors . Wrap ( err ,  "ReadDir" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-14 13:38:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Delete removes all data in the backend.  
						 
					
						
							
								
									
										
										
										
											2020-09-19 22:01:32 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( r  * SFTP )  Delete ( ctx  context . Context )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  r . deleteRecursive ( ctx ,  r . p ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-14 13:38:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}