Have --fake-super turn a symlink into a file when
authorWayne Davison <wayned@samba.org>
Wed, 2 Sep 2009 16:06:29 +0000 (09:06 -0700)
committerWayne Davison <wayned@samba.org>
Wed, 2 Sep 2009 16:06:29 +0000 (09:06 -0700)
NO_SYMLINK_XATTRS is defined.

flist.c
generator.c
rsync.h
syscall.c
t_unsafe.c
tls.c
trimslash.c

diff --git a/flist.c b/flist.c
index 6eb02c7..8b08ff6 100644 (file)
--- 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';
index 2aa07cd..5f6afd6 100644 (file)
@@ -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 c8115fc..4d4a764 100644 (file)
--- 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
index 2d704a8..945a11d 100644 (file)
--- 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
index 9ba0aaa..550bc4b 100644 (file)
@@ -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 8cc5748..1c5953d 100644 (file)
--- 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;
index 40f2eb9..448064a 100644 (file)
@@ -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;