From 6e310d38fcdeacb8055bb7e83d4e64c37fd54a38 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 2 Sep 2009 09:06:29 -0700 Subject: [PATCH] Have --fake-super turn a symlink into a file when NO_SYMLINK_XATTRS is defined. --- flist.c | 2 +- generator.c | 4 ++-- rsync.h | 3 +++ syscall.c | 41 +++++++++++++++++++++++++++++++++++++++++ t_unsafe.c | 1 + tls.c | 5 +++-- trimslash.c | 1 + 7 files changed, 52 insertions(+), 5 deletions(-) diff --git a/flist.c b/flist.c index 6eb02c7b..8b08ff6f 100644 --- a/flist.c +++ b/flist.c @@ -196,7 +196,7 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) if (link_stat(path, stp, copy_dirlinks) < 0) return -1; if (S_ISLNK(stp->st_mode)) { - int llen = readlink(path, linkbuf, MAXPATHLEN - 1); + int llen = do_readlink(path, linkbuf, MAXPATHLEN - 1); if (llen < 0) return -1; linkbuf[llen] = '\0'; diff --git a/generator.c b/generator.c index 2aa07cd0..5f6afd6f 100644 --- a/generator.c +++ b/generator.c @@ -946,7 +946,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx, break; case TYPE_SYMLINK: #ifdef SUPPORT_LINKS - if ((len = readlink(cmpbuf, lnk, MAXPATHLEN-1)) <= 0) + if ((len = do_readlink(cmpbuf, lnk, MAXPATHLEN-1)) <= 0) continue; lnk[len] = '\0'; if (strcmp(lnk, F_SYMLINK(file)) != 0) @@ -1369,7 +1369,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, int len; if (S_ISLNK(sx.st.st_mode) - && (len = readlink(fname, lnk, MAXPATHLEN-1)) > 0 + && (len = do_readlink(fname, lnk, MAXPATHLEN-1)) > 0 && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') { /* The link is pointing to the right place. */ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); diff --git a/rsync.h b/rsync.h index c8115fce..4d4a7642 100644 --- a/rsync.h +++ b/rsync.h @@ -981,6 +981,9 @@ extern int errno; #ifdef HAVE_READLINK #define SUPPORT_LINKS 1 +#ifndef NO_SYMLINK_XATTRS +#define do_readlink(path, buf, bufsiz) readlink(path, buf, bufsiz) +#endif #endif #ifdef HAVE_LINK #define SUPPORT_HARD_LINKS 1 diff --git a/syscall.c b/syscall.c index 2d704a89..945a11d4 100644 --- a/syscall.c +++ b/syscall.c @@ -31,6 +31,7 @@ extern int dry_run; extern int am_root; +extern int am_sender; extern int read_only; extern int list_only; extern int preserve_perms; @@ -58,8 +59,48 @@ int do_symlink(const char *lnk, const char *fname) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; + +#ifdef NO_SYMLINK_XATTRS + /* For --fake-super, we create a normal file with mode 0600 + * and write the lnk into it. */ + if (am_root < 0) { + int ok, len = strlen(lnk); + int fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR); + if (fd < 0) + return -1; + ok = write(fd, lnk, len) == len; + if (close(fd) < 0) + ok = 0; + return ok ? 0 : -1; + } +#endif + return symlink(lnk, fname); } + +#ifdef NO_SYMLINK_XATTRS +ssize_t do_readlink(const char *path, char *buf, size_t bufsiz) +{ + /* For --fake-super, we read the link from the file. */ + if (am_root < 0) { + int fd = open(path, O_RDONLY|O_NOFOLLOW); + if (fd >= 0) { + int len = read(fd, buf, bufsiz); + close(fd); + return len; + } + if (errno != ELOOP) + return -1; + /* A real symlink needs to be turned into a fake one on the receiving + * side, so tell the generator that the link has no length. */ + if (!am_sender) + return 0; + /* Otherwise fall through and let the sender report the real length. */ + } + + return readlink(path, buf, bufsiz); +} +#endif #endif #ifdef HAVE_LINK diff --git a/t_unsafe.c b/t_unsafe.c index 9ba0aaa5..550bc4b3 100644 --- a/t_unsafe.c +++ b/t_unsafe.c @@ -25,6 +25,7 @@ int dry_run = 0; int am_root = 0; +int am_sender = 1; int read_only = 0; int list_only = 0; int human_readable = 0; diff --git a/tls.c b/tls.c index 8cc57482..1c5953d7 100644 --- a/tls.c +++ b/tls.c @@ -43,6 +43,7 @@ /* These are to make syscall.o shut up. */ int dry_run = 0; int am_root = 0; +int am_sender = 1; int read_only = 1; int list_only = 0; int link_times = 0; @@ -147,9 +148,9 @@ static void list_file(const char *fname) buf.st_uid = buf.st_gid = 0; strlcpy(linkbuf, " -> ", sizeof linkbuf); /* const-cast required for silly UNICOS headers */ - len = readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4); + len = do_readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4); if (len == -1) - failed("readlink", fname); + failed("do_readlink", fname); else /* it's not nul-terminated */ linkbuf[4+len] = 0; diff --git a/trimslash.c b/trimslash.c index 40f2eb9b..448064ab 100644 --- a/trimslash.c +++ b/trimslash.c @@ -23,6 +23,7 @@ /* These are to make syscall.o shut up. */ int dry_run = 0; int am_root = 0; +int am_sender = 1; int read_only = 1; int list_only = 0; int preserve_perms = 0; -- 2.34.1