Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/scp.1 b/scp.1
- index 5471ea31..48644e0e 100644
- --- a/scp.1
- +++ b/scp.1
- @@ -8,9 +8,9 @@
- .\"
- .\" Created: Sun May 7 00:14:37 1995 ylo
- .\"
- -.\" $OpenBSD: scp.1,v 1.95 2021/01/26 15:40:17 naddy Exp $
- +.\" $OpenBSD: scp.1,v 1.95 2021/03/31 15:40:17 rapier Exp $
- .\"
- -.Dd $Mdocdate: January 26 2021 $
- +.Dd $Mdocdate: March 31 2021 $
- .Dt SCP 1
- .Os
- .Sh NAME
- @@ -228,6 +228,8 @@ Recursively copy entire directories.
- Note that
- .Nm
- follows symbolic links encountered in the tree traversal.
- +.It Fl R
- +Resume failed or interrupted transfer. Identical files will be skipped. Remote must have resume option.
- .It Fl S Ar program
- Name of
- .Ar program
- @@ -235,6 +237,10 @@ to use for the encrypted connection.
- The program must understand
- .Xr ssh 1
- options.
- +.It Fl s Ar program
- +Path to scp on remote system. Useful if remote has multiple scp installs.
- +For example, using the resume option but the default remote scp does not have the resume option.
- +Use -s to point the version that does - e.g. -s /opt/hpnssh/bin/scp
- .It Fl T
- Disable strict filename checking.
- By default when copying files from a remote host to a local directory
- @@ -273,3 +279,4 @@ source code from the Regents of the University of California.
- .Sh AUTHORS
- .An Timo Rinne Aq Mt [email protected]
- .An Tatu Ylonen Aq Mt [email protected]
- +.An Chris Rapier Aq Mt [email protected]
- diff --git a/scp.c b/scp.c
- index 165962d2..f5bee05e 100644
- --- a/scp.c
- +++ b/scp.c
- @@ -17,6 +17,7 @@
- /*
- * Copyright (c) 1999 Theo de Raadt. All rights reserved.
- * Copyright (c) 1999 Aaron Campbell. All rights reserved.
- + * Copyright (c) 2021 Chris Rapier. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- @@ -122,6 +123,7 @@
- #include "misc.h"
- #include "progressmeter.h"
- #include "utf8.h"
- +#include <openssl/evp.h>
- extern char *__progname;
- @@ -159,9 +161,20 @@ int sshport = -1;
- /* This is the program to execute for the secured connection. ("ssh" or -S) */
- char *ssh_program = _PATH_SSH_PROGRAM;
- +/* this is path to the remote scp program allowing the user to specify
- + * a non-default scp */
- +char *remote_path;
- +
- /* This is used to store the pid of ssh_program */
- pid_t do_cmd_pid = -1;
- +/* Flag to indicate that this is a file resume */
- +int resume_flag = 0; /* 0 is off, 1 is on */
- +
- +//int fcount = 0; /*tmp track number of files xferred */
- +
- +char hostname[HOST_NAME_MAX + 1];
- +
- static void
- killchild(int signo)
- {
- @@ -196,6 +209,9 @@ do_local_cmd(arglist *a)
- int status;
- pid_t pid;
- + //if (verbose_mode)
- + // fprintf(stderr, "In do_local_cmd\n");
- +
- if (a->num == 0)
- fatal("do_local_cmd: no arguments");
- @@ -295,7 +311,6 @@ do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
- addargs(&args, "--");
- addargs(&args, "%s", host);
- addargs(&args, "%s", cmd);
- -
- execvp(ssh_program, args.list);
- perror(ssh_program);
- exit(1);
- @@ -388,13 +403,17 @@ int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
- #define CMDNEEDS 64
- char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
- +/* forward declarations */
- int response(void);
- +int debug_response(char *); /* debugging responses -cjr. rm for prod*/
- void rsource(char *, struct stat *);
- void sink(int, char *[], const char *);
- void source(int, char *[]);
- void tolocal(int, char *[]);
- void toremote(int, char *[]);
- void usage(void);
- +void calculate_hash(char *, char *, off_t); /*get the hash of file to length*/
- +void rand_str(char *, size_t); /*gen randome char string */
- int
- main(int argc, char **argv)
- @@ -405,6 +424,10 @@ main(int argc, char **argv)
- extern char *optarg;
- extern int optind;
- + /* we use this to prepend the debugging statements
- + * so we know which side is saying what */
- + gethostname(hostname, HOST_NAME_MAX + 1);
- +
- /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
- sanitise_stdfd();
- @@ -412,6 +435,9 @@ main(int argc, char **argv)
- msetlocale();
- + /* for use with rand function when resume option is used*/
- + srand(time(NULL));
- +
- /* Copy argv, because we modify it */
- newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));
- for (n = 0; n < argc; n++)
- @@ -432,7 +458,7 @@ main(int argc, char **argv)
- fflag = Tflag = tflag = 0;
- while ((ch = getopt(argc, argv,
- - "12346ABCTdfpqrtvF:J:P:S:c:i:l:o:")) != -1) {
- + "12346ABCTdfpqrtvRF:J:P:S:c:i:l:o:s:")) != -1) {
- switch (ch) {
- /* User-visible flags. */
- case '1':
- @@ -487,6 +513,9 @@ main(int argc, char **argv)
- case 'S':
- ssh_program = xstrdup(optarg);
- break;
- + case 's':
- + remote_path = xstrdup(optarg);
- + break;
- case 'v':
- addargs(&args, "-v");
- addargs(&remote_remote_args, "-v");
- @@ -497,6 +526,9 @@ main(int argc, char **argv)
- addargs(&remote_remote_args, "-q");
- showprogress = 0;
- break;
- + case 'R':
- + resume_flag = 1;
- + break;
- /* Server options. */
- case 'd':
- @@ -564,10 +596,20 @@ main(int argc, char **argv)
- remin = remout = -1;
- do_cmd_pid = -1;
- /* Command to be executed on remote system using "ssh". */
- - (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
- - verbose_mode ? " -v" : "",
- - iamrecursive ? " -r" : "", pflag ? " -p" : "",
- - targetshouldbedirectory ? " -d" : "");
- + /* the command uses the first scp in the users
- + * path. This isn't necessarily going to be the 'right' scp to use.
- + * So the current solution is to give the user the option of
- + * entering the path to correct scp. If they don't then it defaults
- + * to whatever scp is first in their path -cjr */
- + (void) snprintf(cmd, sizeof cmd, "%s%s%s%s%s%s",
- + remote_path ? remote_path : "scp",
- + verbose_mode ? " -v" : "",
- + iamrecursive ? " -r" : "", pflag ? " -p" : "",
- + targetshouldbedirectory ? " -d" : "",
- + resume_flag ? " -R" : "");
- +
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Sending cmd %s\n", hostname, cmd);
- (void) ssh_signal(SIGPIPE, lostconn);
- @@ -578,6 +620,7 @@ main(int argc, char **argv)
- verifydir(argv[argc - 1]);
- tolocal(argc, argv); /* Dest is local host. */
- }
- +
- /*
- * Finally check the exit status of the ssh process, if one was forked
- * and no error has occurred yet
- @@ -616,6 +659,9 @@ do_times(int fd, int verb, const struct stat *sb)
- /* strlen(2^64) == 20; strlen(10^6) == 7 */
- char buf[(20 + 7 + 2) * 2 + 2];
- + //if (verbose_mode)
- + // fprintf(stderr, "In do_times\n");
- +
- (void)snprintf(buf, sizeof(buf), "T%llu 0 %llu 0\n",
- (unsigned long long) (sb->st_mtime < 0 ? 0 : sb->st_mtime),
- (unsigned long long) (sb->st_atime < 0 ? 0 : sb->st_atime));
- @@ -634,6 +680,9 @@ parse_scp_uri(const char *uri, char **userp, char **hostp, int *portp,
- {
- int r;
- + //if (verbose_mode)
- + // fprintf (stderr, "In parse_scp_uri\n");
- +
- r = parse_uri("scp", uri, userp, hostp, portp, pathp);
- if (r == 0 && *pathp == NULL)
- *pathp = xstrdup(".");
- @@ -897,6 +946,9 @@ toremote(int argc, char **argv)
- int i, r;
- u_int j;
- + //if (verbose_mode)
- + // fprintf (stderr, "In toremote\n");
- +
- memset(&alist, '\0', sizeof(alist));
- alist.list = NULL;
- @@ -987,6 +1039,7 @@ toremote(int argc, char **argv)
- if (do_local_cmd(&alist) != 0)
- errs = 1;
- } else { /* local to remote */
- + fprintf (stderr,"Local to remote (toremote)\n");
- if (remin == -1) {
- xasprintf(&bp, "%s -t %s%s", cmd,
- *targ == '-' ? "-- " : "", targ);
- @@ -1016,6 +1069,9 @@ tolocal(int argc, char **argv)
- arglist alist;
- int i, r, sport = -1;
- + //if (verbose_mode)
- + // fprintf (stderr,"In tolocal\n");
- +
- memset(&alist, '\0', sizeof(alist));
- alist.list = NULL;
- @@ -1067,20 +1123,89 @@ tolocal(int argc, char **argv)
- free(src);
- }
- +/* calculate the hash of a file up to length bytes
- + * this is used to determine if remote and local file
- + * fragments match. There may be a more efficient process for the hashing */
- +void calculate_hash(char *filename, char *output, off_t length)
- +{
- +#define HASH_LEN 40 /*40 sha1, 64 blake2s256*/
- +#define hash_buflen 1024 /* 1024 is an arbitrary size */
- + int n, md_len;
- + EVP_MD_CTX *c;
- + const EVP_MD *md;
- + char buf[hash_buflen];
- + ssize_t bytes;
- + unsigned char out[EVP_MAX_MD_SIZE];
- + char tmp[3];
- + FILE *file_ptr;
- + *output = '\0';
- +
- + //open file for calculating hash
- + file_ptr = fopen(filename, "r");
- + if (file_ptr==NULL)
- + {
- + if (verbose_mode) {
- + fprintf(stderr, "%s: error opening file %s\n", hostname, filename);
- + /* file the expected output with spaces */
- + snprintf(output, HASH_LEN, "%s", " ");
- + }
- + return;
- + }
- +
- + md = EVP_get_digestbyname("sha1");
- + c = EVP_MD_CTX_new();
- + EVP_DigestInit_ex(c, md, NULL);
- +
- + while (length > 0) {
- + if (length > hash_buflen)
- + bytes=fread(buf, 1, hash_buflen, file_ptr);
- + else
- + bytes=fread(buf, 1, length, file_ptr);
- + EVP_DigestUpdate(c, buf, bytes);
- + length -= hash_buflen;
- + }
- + EVP_DigestFinal_ex(c, out, &md_len);
- +
- + /* convert the hash into a string */
- + for(n=0; n < md_len; n++) {
- + snprintf(tmp, 3, "%02x", out[n]);
- + strcat(output, tmp);
- + }
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: HASH IS '%s' of length %ld\n", hostname, output, strlen(output));
- + fclose(file_ptr);
- +}
- +
- +#define TYPE_OVERFLOW(type, val) \
- + ((sizeof(type) == 4 && (val) > INT32_MAX) || \
- + (sizeof(type) == 8 && (val) > INT64_MAX) || \
- + (sizeof(type) != 4 && sizeof(type) != 8))
- +
- void
- source(int argc, char **argv)
- {
- struct stat stb;
- static BUF buffer;
- BUF *bp;
- - off_t i, statbytes;
- + off_t i, statbytes, xfer_size;
- size_t amt, nr;
- int fd = -1, haderr, indx;
- - char *last, *name, buf[PATH_MAX + 128], encname[PATH_MAX];
- + char *cp, *last, *name, buf[PATH_MAX + 128], encname[PATH_MAX];
- int len;
- + char hashsum[HASH_LEN], test_hashsum[HASH_LEN];
- + char inbuf[PATH_MAX + 128];
- + size_t insize;
- + unsigned long long ull;
- + char *match; /* used to communicate fragment match */
- + match = "\0"; /*default is to fail the match. NULL and F both indicate fail*/
- +
- + //if (verbose_mode)
- + // fprintf (stderr, "%s In source\n", hostname);
- for (indx = 0; indx < argc; ++indx) {
- name = argv[indx];
- + //if (verbose_mode)
- + // fprintf(stderr, "%s index is %d, name is %s\n", hostname, indx, name);
- statbytes = 0;
- len = strlen(name);
- while (len > 1 && name[len-1] == '/')
- @@ -1102,6 +1227,16 @@ syserr: run_err("%s: %s", name, strerror(errno));
- unset_nonblock(fd);
- switch (stb.st_mode & S_IFMT) {
- case S_IFREG:
- + // only calculate hash if we are in resume mode and a file
- + if (resume_flag) {
- + calculate_hash(name, hashsum, stb.st_size);
- + // debug -cjr
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Name is '%s' and hash '%s'\n", hostname, name, hashsum);
- + // debug -cjr
- + //if (verbose_mode)
- + // fprintf (stderr,"%s: size of %s is %ld\n", hostname, name, stb.st_size);
- + }
- break;
- case S_IFDIR:
- if (iamrecursive) {
- @@ -1123,14 +1258,119 @@ syserr: run_err("%s: %s", name, strerror(errno));
- goto next;
- }
- #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
- - snprintf(buf, sizeof buf, "C%04o %lld %s\n",
- - (u_int) (stb.st_mode & FILEMODEMASK),
- - (long long)stb.st_size, last);
- - if (verbose_mode)
- - fmprintf(stderr, "Sending file modes: %s", buf);
- + /* Add a hash of the file along with the filemode if in resume */
- + if (resume_flag)
- + snprintf(buf, sizeof buf, "C%04o %lld %s %s\n",
- + (u_int) (stb.st_mode & FILEMODEMASK),
- + (long long)stb.st_size, hashsum, last);
- + else
- + snprintf(buf, sizeof buf, "C%04o %lld %s\n",
- + (u_int) (stb.st_mode & FILEMODEMASK),
- + (long long)stb.st_size, last);
- +
- + //if (verbose_mode)
- + // fmprintf(stderr, "%s: Sending file modes: %s", hostname, buf);
- +
- (void) atomicio(vwrite, remout, buf, strlen(buf));
- - if (response() < 0)
- +
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: inbuf length %ld buf length %ld\n", hostname, strlen(inbuf), strlen(buf));
- +
- + if (resume_flag) { /* get the hash response from the remote */
- + (void) atomicio(read, remin, inbuf, 127);
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: we got '%s' in inbuf length %ld buf was %ld\n", hostname, inbuf, strlen(inbuf), strlen(buf));
- + }
- + /*if (debug_response("position 1") < 0) {*/
- + if (response() < 0) {
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: response is less than 0\n", hostname);
- goto next;
- + }
- + xfer_size = stb.st_size;
- +
- + /* we only do the following in resume mode because we have a
- + * new buf from the remote to parse */
- + if (resume_flag) {
- + cp = inbuf;
- + if (*cp == 'R') { // resume file transfer
- + char *in_hashsum; /* where to hold the incoming hash */
- + in_hashsum = calloc(HASH_LEN+1, sizeof(char));
- + for (++cp; cp < inbuf + 5; cp++) {
- + /* skip over the mode */
- + }
- + if (*cp++ != ' ') {
- + fprintf(stderr, "%s: mode not delineated!\n", hostname);
- + }
- +
- + if (!isdigit((unsigned char)*cp))
- + fprintf(stderr, "%s: size not present\n", hostname);
- + ull = strtoull(cp, &cp, 10);
- + if (!cp || *cp++ != ' ')
- + fprintf(stderr, "%s: size not delimited\n", hostname);
- + if (TYPE_OVERFLOW(off_t, ull))
- + fprintf(stderr, "%s: size out of range\n", hostname);
- + insize = (off_t)ull;
- +
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: received size of %ld\n", hostname, insize);
- +
- + /* copy the cp pointer byte by byte */
- + for (int i = 0; i < HASH_LEN; i++) {
- + strncat(in_hashsum, cp++, 1);
- + }
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: in_hashsum '%s'\n", hostname, in_hashsum);
- +
- + /*get the hash of the source file to the byte length we just got*/
- + calculate_hash(name, test_hashsum, insize);
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: calculated hashsum of local %s to %ld is %s\n", hostname, last, insize, test_hashsum);
- + /* compare the incoming hash to the hash of the local file*/
- + if (strcmp(in_hashsum, test_hashsum) == 0) {
- + /* the fragments match so we should seek to the appropriate place in the
- + * local file and set the remote file to append */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: File fragments match\n", hostname);
- + //fprintf(stderr, "%s: seeking to %ld\n", hostname, insize);
- + xfer_size = stb.st_size - insize;
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: xfer_size: %ld, stb.st_size: %ld insize: %ld\n",
- + // hostname, xfer_size, stb.st_size, insize);
- + if (lseek(fd, insize, SEEK_CUR) != (off_t)insize) {
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: lseek did not return %ld\n", hostname, insize) ;
- + goto next;
- + }
- + match = "M";
- + } else {
- + /* the fragments don't match so we should start over from the begining */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: File fragments do not match '%s'(in) '%s'(local)\n",
- + // hostname, in_hashsum, test_hashsum);
- + match = "F";
- + xfer_size = stb.st_size;
- + }
- + free(in_hashsum);
- + }
- + if (*cp == 'S') { /* skip file */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Should be skipping this file\n", hostname);
- + goto next;
- + }
- + if (*cp == 'C') { /*transfer entire file*/
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Resending entire file\n", hostname);
- + xfer_size = stb.st_size;
- + }
- + /* need to send the match status
- + * We always send the match status or we get out of sync
- + */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: sending match %s\n", hostname, match);
- + (void) atomicio(vwrite, remout, match, 1);
- + }
- +
- if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
- next: if (fd != -1) {
- (void) close(fd);
- @@ -1138,22 +1378,27 @@ next: if (fd != -1) {
- }
- continue;
- }
- - if (showprogress)
- - start_progress_meter(curfile, stb.st_size, &statbytes);
- +
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: going to xfer %ld\n", hostname, xfer_size);
- + if (showprogress) {
- + start_progress_meter(curfile, xfer_size, &statbytes);
- + }
- set_nonblock(remout);
- - for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
- + for (haderr = i = 0; i < xfer_size; i += bp->cnt) {
- amt = bp->cnt;
- - if (i + (off_t)amt > stb.st_size)
- - amt = stb.st_size - i;
- + if (i + (off_t)amt > xfer_size)
- + amt = xfer_size - i;
- if (!haderr) {
- - if ((nr = atomicio(read, fd,
- - bp->buf, amt)) != amt) {
- + if ((nr = atomicio(read, fd, bp->buf, amt)) != amt) {
- haderr = errno;
- memset(bp->buf + nr, 0, amt - nr);
- }
- }
- /* Keep writing after error to retain sync */
- if (haderr) {
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: had error %d\n", hostname, haderr);
- (void)atomicio(vwrite, remout, bp->buf, amt);
- memset(bp->buf, 0, amt);
- continue;
- @@ -1173,6 +1418,7 @@ next: if (fd != -1) {
- (void) atomicio(vwrite, remout, "", 1);
- else
- run_err("%s: %s", name, strerror(haderr));
- + /*(void) debug_response("position 2");*/
- (void) response();
- if (showprogress)
- stop_progress_meter();
- @@ -1186,6 +1432,9 @@ rsource(char *name, struct stat *statp)
- struct dirent *dp;
- char *last, *vect[1], path[PATH_MAX];
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: In rsource\n", hostname);
- +
- if (!(dirp = opendir(name))) {
- run_err("%s: %s", name, strerror(errno));
- return;
- @@ -1228,33 +1477,39 @@ rsource(char *name, struct stat *statp)
- (void) response();
- }
- -#define TYPE_OVERFLOW(type, val) \
- - ((sizeof(type) == 4 && (val) > INT32_MAX) || \
- - (sizeof(type) == 8 && (val) > INT64_MAX) || \
- - (sizeof(type) != 4 && sizeof(type) != 8))
- -
- void
- sink(int argc, char **argv, const char *src)
- {
- static BUF buffer;
- - struct stat stb;
- + struct stat stb, cpstat, npstat;
- BUF *bp;
- off_t i;
- size_t j, count;
- int amt, exists, first, ofd;
- mode_t mode, omode, mask;
- - off_t size, statbytes;
- + off_t size, statbytes, xfer_size;
- unsigned long long ull;
- int setimes, targisdir, wrerr;
- - char ch, *cp, *np, *targ, *why, *vect[1], buf[16384], visbuf[16384];
- + char ch, *cp, *np, *np_tmp, *targ, *why, *vect[1], buf[16384], visbuf[16384];
- char **patterns = NULL;
- size_t n, npatterns = 0;
- struct timeval tv[2];
- + char remote_hashsum[HASH_LEN+1];
- + char local_hashsum[HASH_LEN+1];
- + char tmpbuf[128];
- + char outbuf[128];
- + char match;
- + int bad_match_flag = 0;
- + np = '\0';
- + np_tmp = '\0';
- #define atime tv[0]
- #define mtime tv[1]
- #define SCREWUP(str) { why = str; goto screwup; }
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: LOCAL In sink with %s\n", hostname, src);
- +
- if (TYPE_OVERFLOW(time_t, 0) || TYPE_OVERFLOW(off_t, 0))
- SCREWUP("Unexpected off_t/time_t size");
- @@ -1270,9 +1525,16 @@ sink(int argc, char **argv, const char *src)
- if (targetshouldbedirectory)
- verifydir(targ);
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: Sending null to remout.\n",hostname);
- +
- (void) atomicio(vwrite, remout, "", 1);
- if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
- targisdir = 1;
- +
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Target is %s with a size of %ld\n", hostname, targ, stb.st_size);
- +
- if (src != NULL && !iamrecursive && !Tflag) {
- /*
- * Prepare to try to restrict incoming filenames to match
- @@ -1281,7 +1543,11 @@ sink(int argc, char **argv, const char *src)
- if (brace_expand(src, &patterns, &npatterns) != 0)
- fatal_f("could not expand pattern");
- }
- +
- for (first = 1;; first = 0) {
- + bad_match_flag = 0; /* used in resume mode. */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: position 1 buf is %s\n", hostname, buf);
- cp = buf;
- if (atomicio(read, remin, cp, 1) != 1)
- goto done;
- @@ -1309,6 +1575,8 @@ sink(int argc, char **argv, const char *src)
- continue;
- }
- if (buf[0] == 'E') {
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: Sending null to remout.\n", hostname);
- (void) atomicio(vwrite, remout, "", 1);
- goto done;
- }
- @@ -1316,6 +1584,9 @@ sink(int argc, char **argv, const char *src)
- *--cp = 0;
- cp = buf;
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: buf is %s\n", hostname, buf);
- +
- if (*cp == 'T') {
- setimes++;
- cp++;
- @@ -1343,9 +1614,17 @@ sink(int argc, char **argv, const char *src)
- if (!cp || *cp++ != '\0' || atime.tv_usec < 0 ||
- atime.tv_usec > 999999)
- SCREWUP("atime.usec not delimited");
- +
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: Sending null to remout.\n", hostname);
- (void) atomicio(vwrite, remout, "", 1);
- continue;
- }
- + if (*cp == 'R') { /*resume file transfer (dont' think I need this here)*/
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Received a RESUME request with %s\n", hostname, cp);
- + resume_flag = 1;
- + }
- if (*cp != 'C' && *cp != 'D') {
- /*
- * Check for the case "rcp remote:foo\* local:bar".
- @@ -1361,6 +1640,18 @@ sink(int argc, char **argv, const char *src)
- SCREWUP("expected control record");
- }
- mode = 0;
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: buf is %s\n", hostname, buf);
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: cp is %s\n", hostname, cp);
- + /* we need to track if this object is a directory
- + * before we move the pointer. If we are in resume mode
- + * we might endup trying to get an mdsum on a directory
- + * and that doesn't work */
- + int dir_flag = 0;
- + if (*cp == 'D')
- + dir_flag = 1;
- +
- for (++cp; cp < buf + 5; cp++) {
- if (*cp < '0' || *cp > '7')
- SCREWUP("bad mode");
- @@ -1371,6 +1662,10 @@ sink(int argc, char **argv, const char *src)
- if (*cp++ != ' ')
- SCREWUP("mode not delimited");
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: cp is %s\n", hostname, cp);
- +
- +
- if (!isdigit((unsigned char)*cp))
- SCREWUP("size not present");
- ull = strtoull(cp, &cp, 10);
- @@ -1380,11 +1675,29 @@ sink(int argc, char **argv, const char *src)
- SCREWUP("size out of range");
- size = (off_t)ull;
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: cp is %s\n", hostname, cp);
- +
- + if (resume_flag && !dir_flag) {
- + *remote_hashsum = '\0';
- + for (int i = 0; i < HASH_LEN; i++) {
- + strncat (remote_hashsum, cp++, 1);
- + }
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: %s\n", hostname, remote_hashsum);
- + if (!cp || *cp++ != ' ')
- + SCREWUP("hash not delimited");
- + }
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: cp is %s\n", hostname, cp);
- +
- if (*cp == '\0' || strchr(cp, '/') != NULL ||
- strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) {
- run_err("error: unexpected filename: %s", cp);
- exit(1);
- }
- + //if (verbose_mode)
- + // fprintf(stderr, "%s cp is %s\n", hostname, cp);
- if (npatterns > 0) {
- for (n = 0; n < npatterns; n++) {
- if (fnmatch(patterns[n], cp, 0) == 0)
- @@ -1442,11 +1755,173 @@ sink(int argc, char **argv, const char *src)
- }
- omode = mode;
- mode |= S_IWUSR;
- + stat(cp, &cpstat);
- + xfer_size = size;
- + if (resume_flag) {
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: np is %s\n", hostname, np);
- + /* does the file exist and if it does it writable? */
- + if (stat(np, &npstat) == -1) {
- + //if (verbose_mode)
- + // fprintf(stderr, "%s Local file does not exist size is %ld!\n",
- + // hostname, npstat.st_size);
- + npstat.st_size = 0;
- + } else {
- + /* check to see if the file is writeable
- + * if it isn't then we need to skip it but
- + * before we skip it we need to send the remote
- + * what they are expecting so 128 bytes and then
- + * a null */
- + if (access (np, W_OK) != 0) {
- + fprintf(stderr, "scp: %s: Permission denied on %s\n", np, hostname);
- + snprintf(outbuf, 128, "S%-126s", " ");
- + (void)atomicio(vwrite, remout, outbuf, strlen(outbuf));
- + (void)atomicio(vwrite, remout, "", 1);
- + continue;
- + }
- + }
- + /* this file is already here do we need to move it?
- + * Check to make sure npstat.st_size > 0. If it is 0 then we
- + * may trying to be moving a zero byte file in which case this
- + * following block fails. See on 0 byte files the hashes will
- + * always match and the file won't be created even though it should
- + */
- + if (xfer_size == npstat.st_size && (npstat.st_size > 0)) {
- + calculate_hash(np, local_hashsum, npstat.st_size);
- + if (strcmp(local_hashsum,remote_hashsum) == 0) {
- + /* we can skip this file if we want to. */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Files are the same\n", hostname);
- + /* the remote is expecting something so we need to send them something*/
- + snprintf(outbuf, 128, "S%-126s", " ");
- + (void)atomicio(vwrite, remout, outbuf, strlen(outbuf));
- + //if (verbose_mode)
- + // fprintf(stderr,"%s: sent '%s' to remote\n", hostname, outbuf);
- + /* the remote is waiting on an ack so send a null */
- + (void)atomicio(vwrite, remout, "", 1);
- + fprintf (stderr, "Skipping identical file: %s\n", np);
- + continue;
- + } else {
- + /* file sizes are the same but they don't match */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: target(%ld) is different than source(%ld)!\n",
- + // hostname, npstat.st_size, size);
- + snprintf(tmpbuf, sizeof outbuf, "C%04o %lld %s",
- + (u_int) (npstat.st_mode & FILEMODEMASK),
- + (long long)npstat.st_size, local_hashsum);
- + snprintf(outbuf, 128, "%-127s", tmpbuf);
- + (void) atomicio(vwrite, remout, outbuf, strlen(outbuf));
- + bad_match_flag = 1;
- + }
- + }
- + /* if npstat.st_size is 0 then the local file doesn't exist and
- + * we have to move it. Since we are in resume mode treat it as a resume */
- + if (npstat.st_size < xfer_size || (npstat.st_size == 0)) {
- + char rand_string[9];
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: %s is smaller than %s\n", hostname, np, cp);
- + calculate_hash(np, local_hashsum, npstat.st_size);
- +#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
- + snprintf(tmpbuf, sizeof outbuf, "R%04o %lld %s",
- + (u_int) (npstat.st_mode & FILEMODEMASK),
- + (long long)npstat.st_size, local_hashsum);
- + snprintf(outbuf, 128, "%-127s", tmpbuf);
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: new buf is %s of length %ld\n",
- + // hostname, outbuf, strlen(outbuf));
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Sending new file (%s) modes: %s\n",
- + // hostname, np, outbuf);
- + /*now we have to send np's length and hash to the other end
- + * if the computed hashes match then we seek to np's length in
- + * file and append to np starting from there */
- + (void) atomicio(vwrite, remout, outbuf, strlen(outbuf));
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: New size: %ld, size: %ld, st_size: %ld\n",
- + // hostname, size - npstat.st_size, size, npstat.st_size);
- + xfer_size = size - npstat.st_size;
- + resume_flag = 1;
- + np_tmp = strndup(np, strlen(np));
- + /* We should have a random component to avoid clobbering a
- + * local file */
- + rand_str(rand_string, 8);
- + strcat(np, rand_string);
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Will concat %s to %s after xfer\n",
- + // hostname, np, np_tmp);
- + } else if (npstat.st_size > size) {
- + /* the target file is larger than the source.
- + * so we need to overwrite it */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: target(%ld) is larger than source(%ld)!\n",
- + // hostname, npstat.st_size, size);
- + snprintf(tmpbuf, sizeof outbuf, "C%04o %lld %s",
- + (u_int) (npstat.st_mode & FILEMODEMASK),
- + (long long)npstat.st_size, local_hashsum);
- + snprintf(outbuf, 128, "%-127s", tmpbuf);
- + (void) atomicio(vwrite, remout, outbuf, strlen(outbuf));
- + bad_match_flag = 1;
- + }
- +
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: CP is %s(%ld) NP is %s(%ld)\n",
- + // hostname, cp, size, np, npstat.st_size);
- + /* we are in resume mode so we need this *here* and not later
- + * because we need to get the file match information from the remote
- + * outside of resume mode we don't get that so we get out of sync
- + * so we have a test for the resume_flag after this block */
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: Sending null to remout.\n", hostname);
- + (void) atomicio(vwrite, remout, "", 1);
- +
- + /* the remote is always going to send a match status
- + * so we need to read it so we don't get out of sync */
- + (void) atomicio(read, remin, &match, 1);
- + if (match != 'M') {/*fragments do not match*/
- + /* expected response of F, M and NULL *but*
- + * anything other than M is a failure */
- + xfer_size = size;
- + bad_match_flag = 1;
- + if (match == 'F') {
- + /* got an F for failure and not NULL
- + * so we want to swap over the filename from
- + * the temp back to the original */
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: match status is F\n", hostname);
- + if (np_tmp != NULL)
- + np = strndup(np_tmp, strlen(np_tmp));
- + else {
- + //run_err("%s: np_tmp is NULL", hostname);
- + continue;
- + }
- +
- + }
- + } else {
- + //if (verbose_mode)
- + // fprintf(stderr, "%s match status is M\n", hostname);
- + bad_match_flag = 0; /* while this is set at the beginning of the
- + * loop I'm setting it here explicitly as well */
- + }
- + }
- +
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Creating file. mode is %d for %s\n",
- + // hostname, mode, np);
- if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) == -1) {
- bad: run_err("%s: %s", np, strerror(errno));
- continue;
- }
- - (void) atomicio(vwrite, remout, "", 1);
- +
- + /* in the case of not using the resume function we need this vwrite here
- + * in the case of using the resume flag it comes in the above if (resume_flag) block
- + * why? because scp is weird and depends on an intricate and silly dance of
- + * call and response at just the right time. That's why */
- + if (!resume_flag) {
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: Sending null to remout.\n", hostname);
- + (void) atomicio(vwrite, remout, "", 1);
- + }
- +
- if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
- (void) close(ofd);
- continue;
- @@ -1461,14 +1936,19 @@ bad: run_err("%s: %s", np, strerror(errno));
- */
- statbytes = 0;
- if (showprogress)
- - start_progress_meter(curfile, size, &statbytes);
- + start_progress_meter(curfile, xfer_size, &statbytes);
- set_nonblock(remin);
- - for (count = i = 0; i < size; i += bp->cnt) {
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: xfer_size is %ld\n", hostname, xfer_size);
- + //int total_bytes = 0;
- + for (count = i = 0; i < xfer_size; i += bp->cnt) {
- amt = bp->cnt;
- - if (i + amt > size)
- - amt = size - i;
- + if (i + amt > xfer_size)
- + amt = xfer_size - i;
- count += amt;
- + /* read the data from the socket*/
- do {
- +
- j = atomicio6(read, remin, cp, amt,
- scpio, &statbytes);
- if (j == 0) {
- @@ -1477,10 +1957,10 @@ bad: run_err("%s: %s", np, strerror(errno));
- "dropped connection");
- exit(1);
- }
- + //total_bytes += amt;
- amt -= j;
- cp += j;
- } while (amt > 0);
- -
- if (count == bp->cnt) {
- /* Keep reading so we stay sync'd up. */
- if (!wrerr) {
- @@ -1495,6 +1975,8 @@ bad: run_err("%s: %s", np, strerror(errno));
- cp = bp->buf;
- }
- }
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: total received bytes is %d\n", hostname, total_bytes);
- unset_nonblock(remin);
- if (count != 0 && !wrerr &&
- atomicio(vwrite, ofd, bp->buf, count) != count) {
- @@ -1502,8 +1984,80 @@ bad: run_err("%s: %s", np, strerror(errno));
- wrerr = 1;
- }
- if (!wrerr && (!exists || S_ISREG(stb.st_mode)) &&
- - ftruncate(ofd, size) != 0)
- + ftruncate(ofd, xfer_size) != 0)
- note_err("%s: truncate: %s", np, strerror(errno));
- +
- + /* if np_tmp isn't set then we don't have a resume file to cat */
- + /* likewise, bad match flag means no resume flag */
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: resume_flag: %d, np_tmp: %s, bad_match_flag: %d\n",
- + // hostname, resume_flag, np_tmp, bad_match_flag);
- + if (resume_flag && np_tmp && !bad_match_flag) {
- + FILE *orig, *resume;
- + char res_buf[512]; /* set at 512 just because, might want to increase*/
- + ssize_t res_bytes = 0;
- + off_t sum = 0;
- + struct stat res_stat;
- + *res_buf = '\0';
- + orig = NULL; /*supress warnings*/
- + resume = NULL; /*supress warnings*/
- +
- + //if (verbose_mode)
- + // fprintf(stderr, "%s: Resume flag is set. Going to concat %s to %s now\n",
- + // hostname, np, np_tmp);
- + /* np/ofd is the resume file so open np_tmp for appending
- + * close ofd because we are going to be shifting it
- + * and I don't wnat the same file open in multiple descriptors */
- + if (close(ofd) == -1)
- + note_err("%s: close: %s", np, strerror(errno));
- + /* orig is the target file, resume is the temp file */
- + orig = fopen(np_tmp, "a"); /*open for appending*/
- + if (orig == NULL) {
- + fprintf(stderr, "%s: Could not open %s for appending.", hostname, np_tmp);
- + goto stopcat;
- + }
- + resume = fopen(np, "r"); /*open for reading only*/
- + if (resume == NULL) {
- + fprintf(stderr, "%s: Could not open %s for reading.", hostname, np);
- + goto stopcat;
- + }
- + /* get the number of bytes in the temp file*/
- + if (fstat(fileno(resume), &res_stat) == -1) {
- + fprintf(stderr, "%s: Could not stat %s", hostname, np);
- + goto stopcat;
- + }
- + /* while the number of bytes read from the temp file
- + * is less than the size of the file read in a chunk and
- + * write it to the target file */
- + do {
- + res_bytes = fread(res_buf, 1, 512, resume);
- + fwrite(res_buf, 1, res_bytes, orig);
- + sum += res_bytes;
- + } while (sum < res_stat.st_size);
- +
- +stopcat: if (orig)
- + fclose(orig);
- + if (resume)
- + fclose(resume);
- + /* delete the resume file */
- + remove(np);
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: np(%s) and np_tmp(%s)\n", hostname, np, np_tmp);
- + np = np_tmp;
- + //if (verbose_mode)
- + // fprintf (stderr, "%s np(%s) and np_tmp(%s)\n", hostname, np, np_tmp);
- + /* reset ofd to the original np */
- + if ((ofd = open(np_tmp, O_WRONLY)) == -1) {
- + free(np_tmp);
- + fprintf(stderr, "%s: couldn't open %s in append function\n", hostname, np_tmp);
- + atomicio(vwrite, remout, "", 1);
- + goto bad;
- + }
- + free(np_tmp);
- + //fcount++;
- + }
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: Current file count is %d\n", hostname, fcount);
- if (pflag) {
- if (exists || omode != mode)
- #ifdef HAVE_FCHMOD
- @@ -1538,8 +2092,10 @@ bad: run_err("%s: %s", np, strerror(errno));
- }
- }
- /* If no error was noted then signal success for this file */
- - if (note_err(NULL) == 0)
- - (void) atomicio(vwrite, remout, "", 1);
- + if (note_err(NULL) == 0) {
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: Sending null to remout.\n", hostname);
- + (void) atomicio(vwrite, remout, "", 1); }
- }
- done:
- for (n = 0; n < npatterns; n++)
- @@ -1563,6 +2119,9 @@ response(void)
- lostconn(0);
- cp = rbuf;
- + //if (verbose_mode)
- + // fprintf (stderr, "%s: In response is %d and cp is '%s'\n", hostname, resp, cp);
- +
- switch (resp) {
- case 0: /* ok */
- return (0);
- @@ -1592,13 +2151,64 @@ response(void)
- /* NOTREACHED */
- }
- +/* remove for production */
- +int
- +debug_response(char *message)
- +{
- + char ch, *cp, resp, rbuf[2048], visbuf[2048];
- +
- + fprintf(stderr, "LOCAL in reponse at %s\n", message);
- + if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
- + lostconn(0);
- +
- + cp = rbuf;
- + fprintf (stderr, "LOCAL In response is %d and cp is '%s'\n", resp, cp);
- + fprintf (stderr, "LOCAL In response and printed cp sizeof resp is %ld\n", sizeof(resp));
- +
- + switch (resp) {
- + case 0: /* ok */
- + fprintf(stderr, "LOCAL returning 0\n");
- + return (0);
- + default:
- + *cp++ = resp;
- + /* FALLTHROUGH */
- + case 1: /* error, followed by error msg */
- + case 2: /* fatal error, "" */
- + fprintf(stderr, "LOCAL in response case 2\n");
- + do {
- + if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
- + lostconn(0);
- + *cp++ = ch;
- + } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
- + fprintf(stderr, "LOCAL in response case 2 after do loop\n");
- +
- + if (!iamremote) {
- + cp[-1] = '\0';
- + (void) snmprintf(visbuf, sizeof(visbuf),
- + NULL, "%s\n", rbuf);
- + (void) atomicio(vwrite, STDERR_FILENO,
- + visbuf, strlen(visbuf));
- + fprintf(stderr, "LOCAL in response case after atomicio (sent '%s')\n", visbuf);
- + }
- + ++errs;
- + fprintf(stderr, "LOCAL in response case resp is %d\n", resp);
- + if (resp == 1) {
- + fprintf(stderr, "LOCAL in response case returning -1\n");
- + return (-1);
- + }
- + fprintf(stderr, "LOCAL in response case about to exit\n");
- + exit(1);
- + }
- + /* NOTREACHED */
- +}
- +
- void
- usage(void)
- {
- (void) fprintf(stderr,
- - "usage: scp [-346ABCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
- + "usage: scp [-346ABCpqrTvR] [-c cipher] [-F ssh_config] [-i identity_file]\n"
- " [-J destination] [-l limit] [-o ssh_option] [-P port]\n"
- - " [-S program] source ... target\n");
- + " [-S program] [-s filepath of remote scp] source ... target\n");
- exit(1);
- }
- @@ -1737,3 +2347,15 @@ lostconn(int signo)
- else
- exit(1);
- }
- +
- +void rand_str(char *dest, size_t length) {
- + char charset[] = "0123456789"
- + "abcdefghijklmnopqrstuvwxyz"
- + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- +
- + while (length-- > 0) {
- + size_t index = (double) rand() / RAND_MAX * (sizeof charset - 1);
- + *dest++ = charset[index];
- + }
- + *dest = '\0';
- +}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement