Hello,
about a year ago I ran into situation where there's a
"metadirectory"
containing directories and symlinks to files. There was a need to mirror
the contents of files and directories gathered via symlinks to this
metadirectory, regular mirroring of the tree wouldn't do any good.
The attached patch gives the user ability to define how many symbolic
links rsync should follow before actually adding it to the file list.
Any code behaviour without the new parameter is unchanged, I've used the
previous versions of the patch with rsync 2.5.x for the last year and
might just as well share the patch. Consider merging the patch for the
next release, please reply to me directly for additional feedback or
issues.
Cheers,
-Antti
-------------- next part --------------
Index: flist.c
==================================================================RCS file:
/cvsroot/rsync/flist.c,v
retrieving revision 1.169
diff -u -r1.169 flist.c
--- flist.c 22 Jan 2004 18:39:32 -0000 1.169
+++ flist.c 24 Jan 2004 20:30:08 -0000
@@ -50,6 +50,7 @@
extern int one_file_system;
extern int make_backups;
extern int preserve_links;
+extern int follow_links_depth;
extern int preserve_hard_links;
extern int preserve_perms;
extern int preserve_devices;
@@ -725,6 +726,65 @@
/* IRIX cc cares that the operands to the ternary have the same type. */
#define MALLOC(ap, i) (ap ? (void*) string_area_malloc(ap, i) : malloc(i))
+void make_file_stat(struct file_struct * file, STRUCT_STAT *st)
+{
+ file->modtime = st->st_mtime;
+ file->length = st->st_size;
+ file->mode = st->st_mode;
+ file->uid = st->st_uid;
+ file->gid = st->st_gid;
+ if (preserve_hard_links) {
+ if (protocol_version < 28 ? S_ISREG(st->st_mode)
+ : !S_ISDIR(st->st_mode) && st->st_nlink > 1) {
+ if (!file->link_u.idev) {
+ if (!(file->link_u.idev = new(struct idev)))
+ out_of_memory("file inode data");
+ }
+ file->F_DEV = st->st_dev;
+ file->F_INODE = st->st_ino;
+ }
+ }
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+ if (IS_DEVICE(st->st_mode))
+ file->u.rdev = st->st_rdev;
+#endif
+}
+
+#if SUPPORT_LINKS
+void links_depth(struct string_area **ap, struct file_struct * file)
+{
+ char currbuf[MAXPATHLEN], linkbuf[MAXPATHLEN];
+ STRUCT_STAT st;
+ int i;
+
+ memset(currbuf, 0, MAXPATHLEN);
+ memset(linkbuf, 0, MAXPATHLEN);
+ strncpy(currbuf, file->u.link, MAXPATHLEN);
+ for (i = 0; i < follow_links_depth; i++) {
+ if (link_stat(currbuf, &st) != 0) {
+ break;
+ }
+ if (S_ISLNK(st.st_mode)) {
+ int buflen = readlink(currbuf, linkbuf, MAXPATHLEN - 1);
+ if (buflen > 0) {
+ linkbuf[buflen] = '\0';
+ strncpy(currbuf, linkbuf, MAXPATHLEN);
+ }
+ } else {
+ /* Not a symlink, quit */
+ break;
+ }
+#if 0
+ fprintf(stderr, "\n%s:%i [#%i] %s -> %s\n", __FILE__, __LINE__,
i, file->u.link, currbuf);
+#endif
+ }
+ make_file_stat(file, &st);
+ if (file->u.link && S_ISLNK(st.st_mode)) {
+ file->u.link = STRDUP(ap, currbuf);
+ }
+}
+#endif
+
/**
* Create a file_struct for a named file by reading its stat()
* information and performing extensive checks against global
@@ -825,28 +885,15 @@
file->basename = STRDUP(ap, fname);
}
- file->modtime = st.st_mtime;
- file->length = st.st_size;
- file->mode = st.st_mode;
- file->uid = st.st_uid;
- file->gid = st.st_gid;
- if (preserve_hard_links) {
- if (protocol_version < 28 ? S_ISREG(st.st_mode)
- : !S_ISDIR(st.st_mode) && st.st_nlink > 1) {
- if (!(file->link_u.idev = new(struct idev)))
- out_of_memory("file inode data");
- file->F_DEV = st.st_dev;
- file->F_INODE = st.st_ino;
- }
- }
-#ifdef HAVE_STRUCT_STAT_ST_RDEV
- if (IS_DEVICE(st.st_mode))
- file->u.rdev = st.st_rdev;
-#endif
+ make_file_stat(file, &st);
#if SUPPORT_LINKS
- if (S_ISLNK(st.st_mode))
+ if (S_ISLNK(st.st_mode)) {
file->u.link = STRDUP(ap, linkbuf);
+ if ((follow_links_depth >= 1) && preserve_links) {
+ links_depth(ap, file);
+ }
+ }
#endif
if (always_checksum && S_ISREG(st.st_mode)) {
Index: options.c
==================================================================RCS file:
/cvsroot/rsync/options.c,v
retrieving revision 1.127
diff -u -r1.127 options.c
--- options.c 23 Jan 2004 09:32:50 -0000 1.127
+++ options.c 24 Jan 2004 20:30:08 -0000
@@ -38,6 +38,7 @@
int archive_mode = 0;
int copy_links = 0;
int preserve_links = 0;
+int follow_links_depth = 0;
int preserve_hard_links = 0;
int preserve_perms = 0;
int preserve_devices = 0;
@@ -224,6 +225,7 @@
rprintf(F," --suffix=SUFFIX backup suffix (default %s w/o
--backup-dir)\n",BACKUP_SUFFIX);
rprintf(F," -u, --update update only (don't overwrite
newer files)\n");
rprintf(F," -l, --links copy symlinks as
symlinks\n");
+ rprintf(F," --links-depth=NUM follow symlinks up to NUM
depth\n");
rprintf(F," -L, --copy-links copy the referent of
symlinks\n");
rprintf(F," --copy-unsafe-links copy links outside the source
tree\n");
rprintf(F," --safe-links ignore links outside the
destination tree\n");
@@ -328,6 +330,7 @@
{"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude,
0, 0, 0 },
{"update", 'u', POPT_ARG_NONE, &update_only,
0, 0, 0 },
{"links", 'l', POPT_ARG_NONE,
&preserve_links, 0, 0, 0 },
+ {"links-depth", 0, POPT_ARG_INT, &follow_links_depth ,
0, 0, 0 },
{"copy-links", 'L', POPT_ARG_NONE, ©_links,
0, 0, 0 },
{"whole-file", 'W', POPT_ARG_VAL, &whole_file,
1, 0, 0 },
{"no-whole-file", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0
},