Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 8 Oct 2005 22:42:26 GMT
From:      soc-chenk <soc-chenk@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 85017 for review
Message-ID:  <200510082242.j98MgQYk011198@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=85017

Change 85017 by soc-chenk@soc-chenk_leavemealone on 2005/10/08 22:41:37

	conceptionally bad code eliminated from readdir handler
	Submitted by:	soc-chenk

Affected files ...

.. //depot/projects/soc2005/fuse4bsd2/fuse_module/fuse.c#12 edit
.. //depot/projects/soc2005/fuse4bsd2/fuselib/fuselib-2.4.0.diff#3 edit

Differences ...

==== //depot/projects/soc2005/fuse4bsd2/fuse_module/fuse.c#12 (text+ko) ====

@@ -3569,7 +3569,6 @@
 }
 
 #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
-#define DIRENTSIZE(n) (sizeof(struct dirent) - MAXNAMLEN + (n))
 
 static int
 fuse_readdir(struct vop_readdir_args *ap)
@@ -3646,13 +3645,25 @@
 	err = fuse_read_directbackend(vp, fufh, uio, cred, td, FUSE_READDIR,
 	                              fuse_dir_buffeater, &cookediov);
 #else
-	err = fuse_read_biobackend(vp, NULL, uio, cred, td, FUSE_READDIR,
-	                           fuse_dir_buffeater, &cookediov);
+	/*
+	 * We tried hard to use bio, but offsety readdir can't be handled
+	 * properly that way -- the offset field of fuse_dirents can't be
+	 * mapped to an offset of a bio buffer
+	 */
+	err = fuse_read_directbackend(vp, get_filehandle(vp, td, cred, FREAD),
+	                              uio, cred, td, FUSE_READDIR,
+	                              fuse_dir_buffeater, &cookediov);
 #endif
 	fuse_iov_teardown(&cookediov);
 	return (err);
 }
 
+/* A hack for being able to please the GENERIC_DIRSIZ macro */
+
+struct pseudo_dirent {
+	uint32_t d_namlen;
+};
+
 static int
 fuse_dir_buffeater(struct uio *uio, size_t reqsize, void *buf, size_t bufsize, void *param)
 {
@@ -3700,7 +3711,7 @@
 
 	cookediov = param;
 
-	DEBUG2G("entering loop\n");
+	DEBUG2G("entering loop with bufsize %d\n", bufsize);
 
 	/*
 	 * Can we avoid infite loops? An infinite loop could occur only if we
@@ -3714,15 +3725,23 @@
 	 *      was completed, otherwise we hed exited above with -1.
 	 */  
 
-	while (bufsize >= FUSE_NAME_OFFSET) {
+	for (;;) {
 #if ZERO_PAD_INCOMPLETE_BUFS
 		int i;
 		char *c;
 #endif
+
+		if (bufsize < FUSE_NAME_OFFSET) {
+			err = -1;
+			break;
+		}
+
 		cou++;
 		fudge = (struct fuse_dirent *)buf;
 		freclen = FUSE_DIRENT_SIZE(fudge);
 
+		DEBUG("bufsize %d, freclen %d\n", bufsize, freclen);
+
 		/*
 		 * Here is an exit condition: we terminate the whole reading
 		 * process if a fresh chunk of buffer is already too short to
@@ -3747,42 +3766,17 @@
 			break;
 		}
 #endif
-			
+
 		/* Sanity checks */
-		if (fudge->off < uio->uio_offset) {
-			DEBUG2G("offsets out of sync at %d: fudge->off %d, uio->uio_offset %d\n",
-			        cou, (int)fudge->off, (int)uio->uio_offset);
-			err = EIO;
-			break;
-		}
 
-		/*
-		 * The "imaginary" amount of incoming data, 
-		 * we fake towards userspace that we got this much,
-		 * to maintain offset consistency.
-		 * (The whole story starts with the "off" field of
-		 * fuse_dirent being imaginary -- it need not to be
-		 * the same as the amount of data got from the daemon.
-		 * It should be at least as much as the incoming data though,
-		 * hence the above sanity check.)
-		 */  
-		bytesavail = fudge->off - uio->uio_offset;
-		if (!fudge->namelen || fudge->namelen >  MAXNAMLEN) {
-			DEBUG2G("bogus namelen at %d\n", cou);
-			err = EIO;
-			break;
-		}
-		if (freclen > bytesavail) {
-			DEBUG2G("inconsistent fuse dirent at %d\n", cou);
-			err = EIO;
-			break;
-		}
-		if (DIRENTSIZE(fudge->namelen) > bytesavail) {
-			DEBUG2G("fuse dirent is mystically too tight for our purposes at %d\n", cou);
+		if (!fudge->namelen || fudge->namelen > MAXNAMLEN) {
+			DEBUG2G("bogus namelen %d at turn %d\n",
+			        fudge->namelen, cou);
 			err = EIO;
 			break;
 		}
 
+		bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)&fudge->namelen); 
 
 		/*
 		 * Exit condition 2: if the pretended amount of input is more
@@ -3796,9 +3790,6 @@
 			break;
 		}
 
-		DEBUG("bytesavail %d, fudge->off %llu, fudge->namelen %d, uio->uio_offset %d\n",
-		      bytesavail, fudge->off, fudge->namelen, (int)uio->uio_offset);
-
 		fuse_iov_audit(cookediov);
 		fuse_iov_adjust(cookediov, bytesavail);
 		de = (struct dirent *) cookediov->base;
@@ -3806,17 +3797,22 @@
 		de->d_reclen = bytesavail;
 		de->d_type = fudge->type; 
 		de->d_namlen = fudge->namelen;
-		memcpy((char *)cookediov->base + DIRENTSIZE(-1),
+		memcpy((char *)cookediov->base + sizeof(struct dirent) - MAXNAMLEN - 1,
 		       (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
+		((char *)cookediov->base)[bytesavail] = '\0';
 
+		DEBUG("bytesavail %d, fudge->off %llu, fudge->namelen %d, uio->uio_offset %d, name %s\n",
+		      bytesavail, fudge->off, fudge->namelen, (int)uio->uio_offset,
+		      (char *)cookediov->base + sizeof(struct dirent) - MAXNAMLEN - 1);
+
 		err = uiomove(cookediov->base, cookediov->len, uio);
 
 		if (err)
 			break;
 
-		buf = (char*)buf + bytesavail;
-		reqsize -= bytesavail;
-		bufsize -= bytesavail;
+		buf = (char*)buf + freclen;
+		bufsize -= freclen;
+		uio->uio_offset = fudge->off;
 	}
 
 	return (err);

==== //depot/projects/soc2005/fuse4bsd2/fuselib/fuselib-2.4.0.diff#3 (text+ko) ====

@@ -56,7 +56,7 @@
          st.st_ino = de->d_ino;
          st.st_mode = de->d_type << 12;
 +#ifdef __FreeBSD__
-+        if (filler(buf, de->d_name, &st, 0))
++        if (filler(buf, de->d_name, &st, telldir(dp)))
 +#else
          if (filler(buf, de->d_name, &st, de->d_off))
 +#endif



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200510082242.j98MgQYk011198>