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>