Browse Source

Added notes on how to avoid/detect client->server copy issues (cf. issue #31)

Signed-off-by: Russ Magee <rmagee@gmail.com>
Russ Magee 7 months ago
parent
commit
b016e3cd77
2 changed files with 16 additions and 6 deletions
  1. 10 0
      README.md
  2. 6 6
      xsd/xsd.go

+ 10 - 0
README.md

@@ -200,6 +200,16 @@ NOTE: Renaming while copying (eg., 'cp /foo/bar/fileA ./fileB') is NOT supported
 
 If the 'pv' pipeview utility is available (http://www.ivarch.com/programs/pv.shtml) file transfer progress and bandwidth control will be available (suppress the former with the -q option, set the latter with -L &lt;bytes_per_second&gt;).
 
+Special care should be taken when doing client->server copies: since the tarpipe (should) always succeed at least sending data to the remote side, a destination with no write permission will not return a nonzero status and the client closes its end after sending all data, giving the server no opportunity to send an error code to the client.
+It is recommended to test beforehand if the server-side destination is writable (and optionally if the destination already exists, if one does not want to clobber an existing path) by:
+
+```
+$ xs -x "test -w /dest/path" me@myserver  ## If clobbering /dest/path is OK, or
+$ xs -x "test -w /dest/path -o ! -e /dest/path" me@myserver  ## To prevent clobbering
+```
+
+Perhaps in future a more complex handshake will be devised to allow the client to half-close the tarpipe, allowing the server to complete its side of the operation and send back its success or failure code, but the current connection protocol does not allow this. If this is a deal-breaking feature, please contact the maintainer.
+
 ### Tunnels
 
 Simple tunnels (client -> server, no reverse tunnels for now) are supported.

+ 6 - 6
xsd/xsd.go

@@ -800,15 +800,15 @@ func main() {
 					log.Printf("[Client->Server copy]\n")
 					addr := hc.RemoteAddr()
 					hname := goutmp.GetHost(addr.String())
-					logger.LogNotice(fmt.Sprintf("[Running copy for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
+					logger.LogNotice(fmt.Sprintf("[c->s copy for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
 					cmdStatus, runErr := runClientToServerCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
 					// Returned hopefully via an EOF or exit/logout;
 					// Clear current op so user can enter next, or EOF
 					rec.SetOp([]byte{0})
 					if runErr != nil {
-						logger.LogErr(fmt.Sprintf("[Error running cp for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
+						logger.LogErr(fmt.Sprintf("[c->s copy error for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
 					} else {
-						logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
+						logger.LogNotice(fmt.Sprintf("[c->s copy completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
 					}
 					// TODO: Test this with huge files.. see Bug #22 - do we need to
 					//   sync w/sender (client) that we've gotten all data?
@@ -824,13 +824,13 @@ func main() {
 					log.Printf("[Server->Client copy]\n")
 					addr := hc.RemoteAddr()
 					hname := goutmp.GetHost(addr.String())
-					logger.LogNotice(fmt.Sprintf("[Running copy for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
+					logger.LogNotice(fmt.Sprintf("[s->c copy for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
 					cmdStatus, runErr := runServerToClientCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
 					if runErr != nil {
-						logger.LogErr(fmt.Sprintf("[Error spawning cp for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
+						logger.LogErr(fmt.Sprintf("[s->c copy error for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
 					} else {
 						// Returned hopefully via an EOF or exit/logout;
-						logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
+						logger.LogNotice(fmt.Sprintf("[s->c copy completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
 					}
 					// HACK: Bug #22: (xc) Need to wait for rcvr to get final data
 					// TODO: Await specific msg from client to inform they have gotten all data from the tarpipe