+void show_flist_stats(void)
+{
+ /* Nothing yet */
+}
+
+static void list_file_entry(struct file_struct *f)
+{
+ char permbuf[PERMSTRING_SIZE];
+
+ if (!f->basename) {
+ /* this can happen if duplicate names were removed */
+ return;
+ }
+
+ permstring(permbuf, f->mode);
+
+#ifdef SUPPORT_LINKS
+ if (preserve_links && S_ISLNK(f->mode)) {
+ rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
+ permbuf,
+ (double)f->length, timestring(f->modtime),
+ f_name(f, NULL), f->u.link);
+ } else
+#endif
+ {
+ rprintf(FINFO, "%s %11.0f %s %s\n",
+ permbuf,
+ (double)f->length, timestring(f->modtime),
+ f_name(f, NULL));
+ }
+}
+
+/* Stat either a symlink or its referent, depending on the settings of
+ * copy_links, copy_unsafe_links, etc. Returns -1 on error, 0 on success.
+ *
+ * If path is the name of a symlink, then the linkbuf buffer (which must hold
+ * MAXPATHLEN chars) will be set to the symlink's target string.
+ *
+ * The stat structure pointed to by stp will contain information about the
+ * link or the referent as appropriate, if they exist. */
+static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf)
+{
+#ifdef SUPPORT_LINKS
+ if (copy_links)
+ return do_stat(path, stp);
+ if (link_stat(path, stp, copy_dirlinks) < 0)
+ return -1;
+ if (S_ISLNK(stp->st_mode)) {
+ int llen = readlink(path, linkbuf, MAXPATHLEN - 1);
+ if (llen < 0)
+ return -1;
+ linkbuf[llen] = '\0';
+ if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) {
+ if (verbose > 1) {
+ rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n",
+ path, linkbuf);
+ }
+ return do_stat(path, stp);
+ }
+ }
+ return 0;
+#else
+ return do_stat(path, stp);
+#endif
+}
+
+int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks)
+{
+#ifdef SUPPORT_LINKS
+ if (copy_links)
+ return do_stat(path, stp);
+ if (do_lstat(path, stp) < 0)
+ return -1;
+ if (follow_dirlinks && S_ISLNK(stp->st_mode)) {
+ STRUCT_STAT st;
+ if (do_stat(path, &st) == 0 && S_ISDIR(st.st_mode))
+ *stp = st;
+ }
+ return 0;
+#else
+ return do_stat(path, stp);
+#endif
+}
+
+/* This function is used to check if a file should be included/excluded
+ * from the list of files based on its name and type etc. The value of
+ * filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */
+static int is_excluded(char *fname, int is_dir, int filter_level)
+{
+#if 0 /* This currently never happens, so avoid a useless compare. */
+ if (filter_level == NO_FILTERS)
+ return 0;
+#endif
+ if (fname) {
+ /* never exclude '.', even if somebody does --exclude '*' */
+ if (fname[0] == '.' && !fname[1])
+ return 0;
+ /* Handle the -R version of the '.' dir. */
+ if (fname[0] == '/') {
+ int len = strlen(fname);
+ if (fname[len-1] == '.' && fname[len-2] == '/')
+ return 0;
+ }
+ }
+ if (server_filter_list.head
+ && check_filter(&server_filter_list, fname, is_dir) < 0)
+ return 1;
+ if (filter_level != ALL_FILTERS)
+ return 0;
+ if (filter_list.head
+ && check_filter(&filter_list, fname, is_dir) < 0)
+ return 1;
+ return 0;
+}