Using --keep-dirlinks : recursive symlinks problem

Wayne Davison wayned at samba.org
Wed Aug 25 07:32:06 GMT 2004


On Fri, Aug 20, 2004 at 04:50:45PM +0400, Ivan S. Manida wrote:
> Or please kick me in the right direction for a workaround which would 
> make --keep-dirlinks consider sane symlinks only.

Seems like the only good solution for this is to keep track of the
device and inode of all the dirs we visit so that we can eliminate all
duplicate directories.  Attached is a patch that does this using a
simple binary insertion sort.  Very minimally tested.  Thoughts?
Optimizations?

..wayne..
-------------- next part --------------
--- flist.c	12 Aug 2004 18:20:07 -0000	1.236
+++ flist.c	25 Aug 2004 07:27:12 -0000
@@ -724,6 +724,43 @@ void receive_file_entry(struct file_stru
 }
 
 
+static BOOL saw_dir(dev_t dev, ino_t ino)
+{
+	static struct dirinfo { dev_t dev; ino_t ino; } *dirarray;
+	static int dirarray_cnt, dirarray_size;
+	int low, high;
+
+	if (dirarray_cnt == dirarray_size) {
+		dirarray = realloc_array(dirarray, struct dirinfo,
+					 dirarray_size += 4096);
+	}
+
+	for (low = 0, high = dirarray_cnt - 1; low <= high; ) {
+		int j = (low + high) / 2;
+		if (ino == dirarray[j].ino) {
+			if (dev == dirarray[j].dev)
+				return True;
+			if (dev > dirarray[j].dev)
+				low = j + 1;
+			else
+				high = j - 1;
+		} else if (ino > dirarray[j].ino)
+			low = j + 1;
+		else
+			high = j - 1;
+	}
+
+	if (low < dirarray_cnt) {
+		memmove(dirarray + low + 1, dirarray + low,
+			(dirarray_cnt - low) * sizeof dirarray[0]);
+	}
+	dirarray[low].dev = dev;
+	dirarray[low].ino = ino;
+	dirarray_cnt++;
+
+	return False;
+}
+
 /**
  * Create a file_struct for a named file by reading its stat()
  * information and performing extensive checks against global
@@ -802,9 +839,14 @@ struct file_struct *make_file(char *fnam
 	if (exclude_level == NO_EXCLUDES)
 		goto skip_excludes;
 
-	if (S_ISDIR(st.st_mode) && !recurse && !files_from) {
-		rprintf(FINFO, "skipping directory %s\n", thisname);
-		return NULL;
+	if (S_ISDIR(st.st_mode)) {
+		if (!recurse && !files_from) {
+			rprintf(FINFO, "skipping directory %s\n", thisname);
+			return NULL;
+		}
+		if ((keep_dirlinks || copy_links)
+		    && saw_dir(st.st_dev, st.st_ino))
+			return NULL;
 	}
 
 	/* We only care about directories because we need to avoid recursing


More information about the rsync mailing list