summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWayne Davison <wayned@samba.org>2014-06-13 15:58:26 -0700
committerWayne Davison <wayned@samba.org>2014-06-13 16:05:08 -0700
commitba43e88527980718f99b680c3a3e3e2a3a97b6f3 (patch)
treebe31f6fbf70b92a8f41e4cbc7d93349e20fed85f
parentff08acd4f24e74019dd75420fd8373fad563c1af (diff)
downloadrsync-ba43e88527980718f99b680c3a3e3e2a3a97b6f3.tar.gz
rsync-ba43e88527980718f99b680c3a3e3e2a3a97b6f3.tar.bz2
rsync-ba43e88527980718f99b680c3a3e3e2a3a97b6f3.zip
Fix hard-link bugs when receiver isn't capable.
If the receiving side cannot hard-link symlinks and/or special files (including devices) then we now properly handle incoming hard-linked items (creating separate identical items).
-rw-r--r--NEWS4
-rw-r--r--flist.c9
-rw-r--r--generator.c41
-rw-r--r--hlink.c2
4 files changed, 33 insertions, 23 deletions
diff --git a/NEWS b/NEWS
index 22766ce6..5f2e7387 100644
--- a/NEWS
+++ b/NEWS
@@ -59,6 +59,10 @@ Changes since 3.1.0:
transfer failure. This removal is flagged in the compatibility code, so
if a better fix can be discovered, we have a way to flip it on again.
+ - Fixed a bug when the receiver is not configured to be able to hard link
+ symlimks/devices/special-file items but the sender sent some of these
+ items flagged as hard-linked.
+
- We now generate a better error if the buffer overflows in do_mknod().
- Fixed a problem reading more than 16 ACLs on some OSes.
diff --git a/flist.c b/flist.c
index fed0391f..c24672e8 100644
--- a/flist.c
+++ b/flist.c
@@ -948,7 +948,14 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
memcpy(bp, basename, basename_len);
#ifdef SUPPORT_HARD_LINKS
- if (xflags & XMIT_HLINKED)
+ if (xflags & XMIT_HLINKED
+#ifndef CAN_HARDLINK_SYMLINK
+ && !S_ISLNK(mode)
+#endif
+#ifndef CAN_HARDLINK_SPECIAL
+ && !IS_SPECIAL(mode) && !IS_DEVICE(mode)
+#endif
+ )
file->flags |= FLAG_HLINKED;
#endif
file->modtime = (time_t)modtime;
diff --git a/generator.c b/generator.c
index 63399d3d..91009a53 100644
--- a/generator.c
+++ b/generator.c
@@ -1511,7 +1511,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
if (itemizing)
itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
-#if defined SUPPORT_HARD_LINKS && defined CAN_HARDLINK_SYMLINK
+#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
#endif
@@ -1537,7 +1537,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fnamecmp = fnamecmpbuf;
}
}
- if (atomic_create(file, fname, sl, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) {
+ if (atomic_create(file, fname, sl, NULL, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) {
set_file_attrs(fname, file, NULL, NULL, 0);
if (itemizing) {
if (statret == 0 && !S_ISLNK(sx.st.st_mode))
@@ -1618,7 +1618,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fname, (int)file->mode,
(long)major(rdev), (long)minor(rdev));
}
- if (atomic_create(file, fname, NULL, rdev, &sx, del_for_flag)) {
+ if (atomic_create(file, fname, NULL, NULL, rdev, &sx, del_for_flag)) {
set_file_attrs(fname, file, NULL, NULL, 0);
if (itemizing) {
itemize(fnamecmp, file, ndx, statret, &sx,
@@ -1923,11 +1923,11 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
/* If we are replacing an existing hard link, symlink, device, or special file,
- * create a temp-name item and rename it into place. Only a symlink or hard
- * link puts a non-NULL value into the lnk arg. Only a device puts a non-0
- * value into the rdev arg. Specify 0 for the del_for_flag if there is not a
- * file to replace. This returns 1 on success and 0 on failure. */
-int atomic_create(struct file_struct *file, char *fname, const char *lnk,
+ * create a temp-name item and rename it into place. A symlimk specifies slnk,
+ * a hard link specifies hlnk, otherwise we create a device based on rdev.
+ * Specify 0 for the del_for_flag if there is not a file to replace. This
+ * returns 1 on success and 0 on failure. */
+int atomic_create(struct file_struct *file, char *fname, const char *slnk, const char *hlnk,
dev_t rdev, stat_x *sxp, int del_for_flag)
{
char tmpname[MAXPATHLEN];
@@ -1952,23 +1952,22 @@ int atomic_create(struct file_struct *file, char *fname, const char *lnk,
create_name = skip_atomic ? fname : tmpname;
- if (lnk) {
+ if (slnk) {
#ifdef SUPPORT_LINKS
- if (S_ISLNK(file->mode)
-#ifdef SUPPORT_HARD_LINKS /* The first symlink in a hard-linked cluster is always created. */
- && (!F_IS_HLINKED(file) || file->flags & FLAG_HLINK_FIRST)
-#endif
- ) {
- if (do_symlink(lnk, create_name) < 0) {
- rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
- full_fname(create_name), lnk);
- return 0;
- }
- } else
+ if (do_symlink(slnk, create_name) < 0) {
+ rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
+ full_fname(create_name), slnk);
+ return 0;
+ }
+#else
+ return 0;
#endif
+ } else if (hlnk) {
#ifdef SUPPORT_HARD_LINKS
- if (!hard_link_one(file, create_name, lnk, 0))
+ if (!hard_link_one(file, create_name, hlnk, 0))
return 0;
+#else
+ return 0;
#endif
} else {
if (do_mknod(create_name, file->mode, rdev) < 0) {
diff --git a/hlink.c b/hlink.c
index df8e9182..3b578985 100644
--- a/hlink.c
+++ b/hlink.c
@@ -231,7 +231,7 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
}
}
- if (atomic_create(file, fname, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) {
+ if (atomic_create(file, fname, NULL, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) {
if (itemizing) {
itemize(fname, file, ndx, statret, sxp,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,