I'm fond of the "-a" (archive) option of cp, and I'm a heavy user of scp, so I guess it's inevitable that I would eventually add support for "-a" to scp. :-) Actually, it's a "-L" flag for preserving symlinks, and a "-a" flag that is shorthand for "-Lpr". Please let me know if I'm not doing this right.... I made a great effort to limit the number of code lines changed, so as to minimize the difficulty of understanding and accepting this patch. Index: scp.1 --- scp.1.prev +++ scp.1 Fri Aug 18 04:24:46 2000 @@ -20,5 +20,5 @@ .Sh SYNOPSIS .Nm scp -.Op Fl pqrvC46 +.Op Fl aLpqrvC46 .Op Fl P Ar port .Op Fl c Ar cipher @@ -69,4 +69,9 @@ .It Fl o Ar ssh_options specify options to be passed to ssh. For example: "-o UsePriviledgePort=no" +.It Fl a +Archival copy. Shorthand for "-Lpr". +.It Fl L +Preserves symbolic links as such, instead of following them and +copying their targets. .It Fl p Preserves modification times, access times, and modes from the Index: scp.c --- scp.c.prev +++ scp.c Fri Aug 18 04:14:40 2000 @@ -253,5 +253,5 @@ struct passwd *pwd; uid_t userid; int errs, remin, remout; -int pflag, iamremote, iamrecursive, targetshouldbedirectory; +int linkflag, pflag, iamremote, iamrecursive, targetshouldbedirectory; #define CMDNEEDS 64 @@ -280,5 +280,5 @@ main(argc, argv) memset(sshoptions,0,sizeof(sshoptions)); sshoptionsend = sshoptions; - while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:o:S:q46")) != EOF) + while ((ch = getopt(argc, argv, "adfLprtvBCc:i:P:o:S:q46")) != EOF) switch (ch) { /* User-visible flags. */ @@ -289,4 +289,12 @@ main(argc, argv) IPv6 = 1; break; + case 'a': + linkflag = 1; + pflag = 1; + iamrecursive = 1; + break; + case 'L': + linkflag = 1; + break; case 'p': pflag = 1; @@ -549,12 +557,24 @@ source(argc, argv) name = argv[indx]; statbytes = 0; - if ((fd = open(name, O_RDONLY, 0)) < 0) - goto syserr; - if (fstat(fd, &stb) < 0) { + if (linkflag) { + fd = -1; + result = lstat(name, &stb); + } + else { + if ((fd = open(name, O_RDONLY, 0)) < 0) + goto syserr; + result = fstat(fd, &stb); + } + if (result < 0) { syserr: run_err("%s: %s", name, strerror(errno)); goto next; } switch (stb.st_mode & S_IFMT) { + case S_IFLNK: + /* readlink later */ + break; case S_IFREG: + if (fd < 0 && (fd = open(name, O_RDONLY, 0)) < 0) + goto syserr; break; case S_IFDIR: @@ -586,6 +606,7 @@ syserr: run_err("%s: %s", name, strerr } #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) - (void) sprintf(buf, "C%04o %lu %s\n", - (unsigned int) (stb.st_mode & FILEMODEMASK), + (void) sprintf(buf, "%c%04o %lu %s\n", + ((stb.st_mode & S_IFMT) == S_IFLNK) ? 'L' : 'C', + (unsigned int) (stb.st_mode & FILEMODEMASK), (unsigned long) stb.st_size, last); @@ -609,5 +630,8 @@ next: (void) close(fd); amt = stb.st_size - i; if (!haderr) { - result = atomicio(read, fd, bp, amt); + if ((stb.st_mode & S_IFMT) == S_IFLNK) + result = readlink(name, bp, amt); + else + result = atomicio(read, fd, bp, amt); if (result != amt) haderr = result >= 0 ? EIO : errno; @@ -625,5 +649,5 @@ next: (void) close(fd); progressmeter(1); - if (close(fd) < 0 && !haderr) + if (fd >= 0 && close(fd) < 0 && !haderr) haderr = errno; if (!haderr) @@ -775,5 +799,5 @@ sink(argc, argv) continue; } - if (*cp != 'C' && *cp != 'D') { + if (*cp != 'C' && *cp != 'D' && *cp != 'L') { /* * Check for the case "rcp remote:foo\* local:bar". @@ -816,5 +840,5 @@ sink(argc, argv) np = targ; curfile = cp; - exists = stat(np, &stb) == 0; + exists = (buf[0] == 'L' ? lstat : stat)(np, &stb) == 0; if (buf[0] == 'D') { int mod_flag = pflag; @@ -845,9 +869,14 @@ sink(argc, argv) continue; } - omode = mode; - mode |= S_IWRITE; - if ((ofd = open(np, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0) { -bad: run_err("%s: %s", np, strerror(errno)); - continue; + if (buf[0] == 'L') + ofd = omode = -1; + else { + omode = mode; + mode |= S_IWRITE; + if ((ofd = open(np, O_WRONLY | O_CREAT | O_TRUNC, + mode)) < 0) { +bad: run_err("%s: %s", np, strerror(errno)); + continue; + } } (void) atomicio(write, remout, "", 1); @@ -891,4 +920,12 @@ bad: run_err("%s: %s", np, strerror(er if (showprogress) progressmeter(1); + if (buf[0] == 'L') { + if (size >= PIPE_BUF) + SCREWUP("symlink bigger than PIPE_BUF"); + bp[size] = '\0'; + wrerr = (symlink(bp, np) < 0) ? YES : NO; + wrerrno = errno; + goto done; + } if (count != 0 && wrerr == NO && (j = atomicio(write, ofd, bp, count)) != count) { @@ -917,5 +954,4 @@ bad: run_err("%s: %s", np, strerror(er wrerrno = errno; } - (void) response(); if (setimes && wrerr == NO) { setimes = 0; @@ -926,4 +962,5 @@ bad: run_err("%s: %s", np, strerror(er } } +done: (void) response(); switch (wrerr) { case YES: -- Chip Salzenberg - a.k.a. - <chip at valinux.com> "I wanted to play hopscotch with the impenetrable mystery of existence, but he stepped in a wormhole and had to go in early." // MST3K