[PATCH] Support symlinks in scp of openssh 2
Chip Salzenberg
chip at valinux.com
Fri Aug 18 21:37:06 EST 2000
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
More information about the openssh-unix-dev
mailing list