readdir() and read() errors ignored

Michael Brown mbrown at fensystems.co.uk
Sun Aug 24 19:51:20 EST 2003


> > A similar error can occur when open() succeeds but subsequent calls to 
> > read() fail: under these circumstances rsync will transfer zeroes instead 
> > of the actual file data and will again report no errors to the user.
> > The attached patch fixes both of these problems.
> There is a patch on-list for the read error.   Your fix is
> incorrect because it causes rsync to exit if a file is
> truncated during read.

I think it will only exit if an error occurs, not just if EOF is reached 
unexpectedly (it checks for read() returning <0, not !=expected), but no 
matter since there is already a patch.  Is your patch going to be 
integrated into HEAD CVS?

> I'll look closer at the readir error when i get a chance.

I've attached a new patch that only addresses the readdir() issue.  This 
patch has been tested and does solve the problem:

Before the patch:

[root at angel root]# ls /mnt/nfs/rsync-test/
ls: reading directory /mnt/nfs/rsync-test/: Permission denied
[root at angel root]# rsync -avP /mnt/nfs/rsync-test/ rsync-test/
building file list ...
1 file to consider
wrote 70 bytes  read 20 bytes  180.00 bytes/sec
total size is 0  speedup is 0.00
[root at angel root]# ls rsync-test/
[root at angel root]#

Here you can see rsync silently failing on an NFS-mounted directory for 
which opendir() succeeds but readdir() fails.

After the patch:

[root at angel root]# ls /mnt/nfs/rsync-test/
ls: reading directory /mnt/nfs/rsync-test/: Permission denied
[root at angel root]# ~/fixed-rsync -avP /mnt/nfs/rsync-test/ rsync-test/
building file list ...
readdir(.): Permission denied
1 file to consider

wrote 70 bytes  read 20 bytes  180.00 bytes/sec
total size is 0  speedup is 0.00
rsync error: some files could not be transferred (code 23) at main.c(628)
[root at angel root]#

Now rsync acts correctly and reports a partial transfer error to the user.


You can easily reproduce this situation: create an NFS export with the
default flag of "root_squash", create a directory on the NFS server with
permissions of e.g. 750 and try to rsync it as root.  opendir() succeeds
because Linux just looks at the directory permissions and doesn't bother
contacting the NFS server but readdir() fails because the NFS server maps 
requests from root to the anonymous user, who doesn't have access to the 
directory.

(Please Cc me on replies)

Michael
-------------- next part --------------
Index: flist.c
===================================================================
RCS file: /cvsroot/rsync/flist.c,v
retrieving revision 1.139
diff -u -r1.139 flist.c
--- flist.c	17 Aug 2003 21:29:11 -0000	1.139
+++ flist.c	23 Aug 2003 23:03:02 -0000
@@ -877,13 +877,18 @@
 		}
 	}
 
-	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')))
 			continue;
 		strlcpy(p, dname, MAXPATHLEN - l);
 		send_file_name(f, flist, fname, recurse, 0);
+	}
+	if ( errno ) {
+		io_error = 1;
+		rprintf(FERROR, "readdir(%s): %s\n", dir, strerror(errno));
+		/* Don't return yet; we want to clean up first */
 	}
 
 	if (local_exclude_list)
Index: rsync.c
===================================================================
RCS file: /cvsroot/rsync/rsync.c,v
retrieving revision 1.120
diff -u -r1.120 rsync.c
--- rsync.c	18 Feb 2003 18:07:36 -0000	1.120
+++ rsync.c	23 Aug 2003 23:03:02 -0000
@@ -86,7 +86,7 @@
 		return -1;
 	}
 
-	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 (strcmp(dname,".")==0 ||
 		    strcmp(dname,"..")==0)
@@ -99,6 +99,12 @@
 			return -1;
 		}
 	}	
+	if ( errno ) {
+		closedir(d);
+		rprintf(FERROR,"delete_file: readdir(%s): %s\n",
+			fname,strerror(errno));
+		return -1;
+	}
 
 	closedir(d);
 	


More information about the rsync mailing list