File Offsets for SCP (patch)

rapier rapier at psc.edu
Sat Nov 20 07:27:34 EST 2010


I don't know if anyone would be interested in this but I'm including a 
patch to allow for offsets when transferring files with SCP.

It's pretty simple and assumes the user knows what they are doing (for 
example, if transferring with a wild card the offset would apply to all 
files). -A is the number of bytes offset from the beginning of the 
files. -Z is the number of bytes inset from the end of the file.

We may be using this when transferring very large files (100GB+) over 
multiple parallel TCP streams by instantiating multiple SSH connections 
by means of a management application.

Any comments, questions, or suggestions are welcome.


--- ../canonical-openssh5.6/scp.c	2010-07-01 23:37:33.000000000 -0400
+++ scp.c	2010-11-19 17:17:26.000000000 -0500
@@ -302,6 +302,7 @@ struct passwd *pwd;
  uid_t userid;
  int errs, remin, remout;
  int pflag, iamremote, iamrecursive, targetshouldbedirectory;
+double fd_offset, fd_inset;

  #define	CMDNEEDS	64
  char cmd[CMDNEEDS];		/* must hold "rcp -r -p -d\0" */
@@ -324,6 +325,9 @@ main(int argc, char **argv)
  	extern char *optarg;
  	extern int optind;

+	fd_inset = 0;
+	fd_offset = 0;
+
  	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
  	sanitise_stdfd();

@@ -344,7 +348,7 @@ main(int argc, char **argv)
  	addargs(&args, "-oClearAllForwardings yes");

  	fflag = tflag = 0;
-	while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1)
+	while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:A:Z:")) != -1)
  		switch (ch) {
  		/* User-visible flags. */
  		case '1':
@@ -407,6 +411,16 @@ main(int argc, char **argv)
  			setmode(0, O_BINARY);
  #endif
  			break;
+		case 'A':
+			fd_offset = strtod(optarg, &endp);
+			if (fd_offset < 0 || *endp != '\0')
+                                usage();
+			break;
+		case 'Z':
+			fd_inset = strtod(optarg, &endp);
+			if (fd_inset < 0 || *endp != '\0')
+                                usage();
+			break;
  		default:
  			usage();
  		}
@@ -680,6 +694,16 @@ syserr:			run_err("%s: %s", name, strerr
  			run_err("%s: %s", name, "Negative file size");
  			goto next;
  		}
+		if (fd_offset > stb.st_size) {
+			run_err("Offset greater than file size");
+			goto next;
+		}
+		if (fd_inset > stb.st_size) {
+			run_err("Inset greater than file size");
+			goto next;
+		}
+		lseek (fd, fd_offset, SEEK_SET);
+		stb.st_size -= (fd_offset + fd_inset);
  		unset_nonblock(fd);
  		switch (stb.st_mode & S_IFMT) {
  		case S_IFREG:


More information about the openssh-unix-dev mailing list