Detect and report when open or opendir succeed but read and
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index f6ae224..8bc3ab3 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -57,7 +57,7 @@ extern int relative_paths;
 extern int implied_dirs;
 extern int copy_links;
 extern int copy_unsafe_links;
-extern int remote_version;
+extern int protocol_version;
 extern int io_error;
 extern int sanitize_paths;
 
@@ -262,19 +262,26 @@ static int check_exclude_file(char *fname, int is_dir, int exclude_level)
        if (exclude_level == NO_EXCLUDES)
                return 0;
 #endif
-       if (fname && fname[0] == '.' && !fname[1]) {
+       if (fname) {
                /* never exclude '.', even if somebody does --exclude '*' */
-               return 0;
+               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_exclude_list &&
-           check_exclude(server_exclude_list, fname, is_dir))
+       if (server_exclude_list
+        && check_exclude(server_exclude_list, fname, is_dir))
                return 1;
        if (exclude_level != ALL_EXCLUDES)
                return 0;
        if (exclude_list && check_exclude(exclude_list, fname, is_dir))
                return 1;
-       if (local_exclude_list &&
-           check_exclude(local_exclude_list, fname, is_dir))
+       if (local_exclude_list
+        && check_exclude(local_exclude_list, fname, is_dir))
                return 1;
        return 0;
 }
@@ -439,7 +446,7 @@ static void send_file_entry(struct file_struct *file, int f,
 
 #if SUPPORT_HARD_LINKS
        if (preserve_hard_links && S_ISREG(file->mode)) {
-               if (remote_version < 26) {
+               if (protocol_version < 26) {
                        /* 32-bit dev_t and ino_t */
                        write_int(f, (int) file->dev);
                        write_int(f, (int) file->inode);
@@ -452,7 +459,7 @@ static void send_file_entry(struct file_struct *file, int f,
 #endif
 
        if (always_checksum) {
-               if (remote_version < 21) {
+               if (protocol_version < 21) {
                        write_buf(f, file->sum, 2);
                } else {
                        write_buf(f, file->sum, MD4_SUM_LENGTH);
@@ -572,7 +579,7 @@ static void receive_file_entry(struct file_struct **fptr,
        }
 #if SUPPORT_HARD_LINKS
        if (preserve_hard_links && S_ISREG(file->mode)) {
-               if (remote_version < 26) {
+               if (protocol_version < 26) {
                        file->dev = read_int(f);
                        file->inode = read_int(f);
                } else {
@@ -586,7 +593,7 @@ static void receive_file_entry(struct file_struct **fptr,
                file->sum = (char *) malloc(MD4_SUM_LENGTH);
                if (!file->sum)
                        out_of_memory("md4 sum");
-               if (remote_version < 21) {
+               if (protocol_version < 21) {
                        read_buf(f, file->sum, 2);
                } else {
                        read_buf(f, file->sum, MD4_SUM_LENGTH);
@@ -686,8 +693,8 @@ struct file_struct *make_file(char *fname, struct string_area **ap,
                        }
                }
                io_error = 1;
-               rprintf(FERROR, "readlink %s: %s\n",
-                       fname, strerror(save_errno));
+               rprintf(FERROR, "readlink %s failed: %s\n",
+                       full_fname(fname), strerror(save_errno));
                return NULL;
        }
 
@@ -836,7 +843,8 @@ static void send_directory(int f, struct file_list *flist, char *dir)
        d = opendir(dir);
        if (!d) {
                io_error = 1;
-               rprintf(FERROR, "opendir(%s): %s\n", dir, strerror(errno));
+               rprintf(FERROR, "opendir %s failed: %s\n",
+                       full_fname(dir), strerror(errno));
                return;
        }
 
@@ -845,9 +853,8 @@ static void send_directory(int f, struct file_list *flist, char *dir)
        if (fname[l - 1] != '/') {
                if (l == MAXPATHLEN - 1) {
                        io_error = 1;
-                       rprintf(FERROR,
-                               "skipping long-named directory %s\n",
-                               fname);
+                       rprintf(FERROR, "skipping long-named directory: %s\n",
+                               full_fname(fname));
                        closedir(d);
                        return;
                }
@@ -866,18 +873,23 @@ static void send_directory(int f, struct file_list *flist, char *dir)
                        io_error = 1;
                        rprintf(FINFO,
                                "cannot cvs-exclude in long-named directory %s\n",
-                               fname);
+                               full_fname(fname));
                }
        }
 
-       for (di = readdir(d); di; di = readdir(d)) {
+       for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
                char *dname = d_name(di);
-               if (dname[0] == '.' && (dname[1] == '\0' ||
-                   (dname[1] == '.' && dname[2] == '\0')))
+               if (dname[0] == '.' && (dname[1] == '\0'
+                   || (dname[1] == '.' && dname[2] == '\0')))
                        continue;
                strlcpy(p, dname, MAXPATHLEN - l);
                send_file_name(f, flist, fname, recurse, 0);
        }
+       if (errno) {
+               io_error = 1;
+               rprintf(FERROR, "readdir(%s): (%d) %s\n",
+                   dir, errno, strerror(errno));
+       }
 
        if (local_exclude_list)
                free_exclude_list(&local_exclude_list); /* Zeros pointer too */
@@ -913,8 +925,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                io_start_buffering(f);
                if (filesfrom_fd >= 0) {
                        if (argv[0] && !push_dir(argv[0], 0)) {
-                               rprintf(FERROR, "push_dir %s : %s\n",
-                                       argv[0], strerror(errno));
+                               rprintf(FERROR, "push_dir %s failed: %s\n",
+                                       full_fname(argv[0]), strerror(errno));
                                exit_cleanup(RERR_FILESELECT);
                        }
                        use_ff_fd = 1;
@@ -938,14 +950,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                }
 
                l = strlen(fname);
-               if (l != 1 && fname[l - 1] == '/') {
-                       if ((l == 2) && (fname[0] == '.')) {
-                               /*  Turn ./ into just . rather than ./.
-                                  This was put in to avoid a problem with
-                                  rsync -aR --delete from ./
-                                  The send_file_name() below of ./ was
-                                  mysteriously preventing deletes */
-                               fname[1] = 0;
+               if (fname[l - 1] == '/') {
+                       if (l == 2 && fname[0] == '.') {
+                               /* Turn "./" into just "." rather than "./." */
+                               fname[1] = '\0';
                        } else {
                                strlcat(fname, ".", MAXPATHLEN);
                        }
@@ -954,8 +962,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                if (link_stat(fname, &st) != 0) {
                        if (f != -1) {
                                io_error = 1;
-                               rprintf(FERROR, "link_stat %s : %s\n",
-                                       fname, strerror(errno));
+                               rprintf(FERROR, "link_stat %s failed: %s\n",
+                                       full_fname(fname), strerror(errno));
                        }
                        continue;
                }
@@ -1021,8 +1029,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
 
                        if (!olddir) {
                                io_error = 1;
-                               rprintf(FERROR, "push_dir %s : %s\n",
-                                       dir, strerror(errno));
+                               rprintf(FERROR, "push_dir %s failed: %s\n",
+                                       full_fname(dir), strerror(errno));
                                continue;
                        }
 
@@ -1037,8 +1045,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                if (olddir != NULL) {
                        flist_dir = NULL;
                        if (pop_dir(olddir) != 0) {
-                               rprintf(FERROR, "pop_dir %s : %s\n",
-                                       dir, strerror(errno));
+                               rprintf(FERROR, "pop_dir %s failed: %s\n",
+                                       full_fname(dir), strerror(errno));
                                exit_cleanup(RERR_FILESELECT);
                        }
                }
@@ -1290,7 +1298,7 @@ void flist_free(struct file_list *flist)
  */
 static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
 {
-       int i;
+       int i, prev_i = 0;
        char *name, *prev_name = NULL;
 
        if (!flist || flist->count == 0)
@@ -1301,6 +1309,7 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
 
        for (i = no_dups? 0 : flist->count; i < flist->count; i++) {
                if (flist->files[i]->basename) {
+                       prev_i = i;
                        prev_name = f_name(flist->files[i]);
                        break;
                }
@@ -1315,6 +1324,11 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
                                        "removing duplicate name %s from file list %d\n",
                                        name, i);
                        }
+                       /* Make sure that if we unduplicate '.', that we don't
+                        * lose track of a user-specified starting point (or
+                        * else deletions will mysteriously fail with -R). */
+                       if (flist->files[i]->flags & FLAG_DELETE)
+                               flist->files[prev_i]->flags |= FLAG_DELETE;
                        /* it's not great that the flist knows the semantics of
                         * the file memory usage, but i'd rather not add a flag
                         * byte to that struct.
@@ -1324,6 +1338,10 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
                        else
                                free_file(flist->files[i]);
                }
+               else
+                       prev_i = i;
+               /* We set prev_name every iteration to avoid it becoming
+                * invalid when names[][] in f_name() wraps around. */
                prev_name = name;
        }