summaryrefslogtreecommitdiffstats
path: root/sys/compat
diff options
context:
space:
mode:
authorswallace <swallace@FreeBSD.org>1995-08-28 00:50:08 +0000
committerswallace <swallace@FreeBSD.org>1995-08-28 00:50:08 +0000
commit6f51a7615899188fd49e4446341be92684c778de (patch)
treea04bf3e208541111be16771f6bd69604346e274d /sys/compat
parent3de11c3b09cdec723b035bb30b7c9dd56e6a63fe (diff)
downloadFreeBSD-src-6f51a7615899188fd49e4446341be92684c778de.zip
FreeBSD-src-6f51a7615899188fd49e4446341be92684c778de.tar.gz
Modified linux_readdir() function to properly handle Linux readdir()
calls with a byte size of 1. This special case was not correctly emulated. Now programs such as a simple 'ls' to a commercial Macintosh emulator called 'executor' will work correctly.
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/linux/linux_file.c41
1 files changed, 27 insertions, 14 deletions
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index b846068..03f22a9 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: linux_file.c,v 1.2 1995/06/07 21:27:57 sos Exp $
+ * $Id: linux_file.c,v 1.1 1995/06/25 17:32:34 sos Exp $
*/
#include <i386/linux/linux.h>
@@ -339,14 +339,15 @@ linux_readdir(struct proc *p, struct linux_readdir_args *args, int *retval)
struct vattr va;
off_t off;
struct linux_dirent linux_dirent;
- int buflen, error, eofflag, nbytes, justone;
+ int buflen, error, eofflag, nbytes, justone, blockoff;
#ifdef DEBUG
printf("Linux-emul(%d): readdir(%d, *, %d)\n",
p->p_pid, args->fd, args->count);
#endif
- if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0)
+ if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
return (error);
+}
if ((fp->f_flag & FREAD) == 0)
return (EBADF);
@@ -356,8 +357,9 @@ linux_readdir(struct proc *p, struct linux_readdir_args *args, int *retval)
if (vp->v_type != VDIR)
return (EINVAL);
- if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
+ if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
return error;
+ }
nbytes = args->count;
if (nbytes == 1) {
@@ -367,10 +369,11 @@ linux_readdir(struct proc *p, struct linux_readdir_args *args, int *retval)
else
justone = 0;
- buflen = max(va.va_blocksize, nbytes);
+ off = fp->f_offset;
+ blockoff = off % va.va_blocksize;
+ buflen = max(va.va_blocksize, (nbytes + blockoff));
buf = malloc(buflen, M_TEMP, M_WAITOK);
VOP_LOCK(vp);
- off = fp->f_offset;
again:
aiov.iov_base = buf;
aiov.iov_len = buflen;
@@ -380,26 +383,34 @@ again:
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_procp = p;
auio.uio_resid = buflen;
- auio.uio_offset = off;
+ auio.uio_offset = off - (off_t)blockoff;
error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *) 0, 0);
- if (error)
+ if (error) {
goto out;
+}
inp = buf;
+ inp += blockoff;
outp = (caddr_t) args->dent;
resid = nbytes;
- if ((len = buflen - auio.uio_resid) == 0)
+ if ((len = buflen - auio.uio_resid - blockoff) == 0) {
goto eof;
+ }
while (len > 0) {
- reclen = ((struct dirent *) inp)->d_reclen;
- if (reclen & 3)
- panic("linux_readdir");
- off += reclen;
bdp = (struct dirent *) inp;
+ reclen = bdp->d_reclen;
+ if (reclen & 3) {
+ printf("linux_readdir: reclen=%d\n", reclen);
+ error = EFAULT;
+ goto out;
+ }
+
+ off += reclen;
if (bdp->d_fileno == 0) {
inp += reclen;
+ len -= reclen;
continue;
}
linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
@@ -411,8 +422,9 @@ again:
linux_dirent.doff = (linux_off_t) linuxreclen;
linux_dirent.dreclen = (u_short) bdp->d_namlen;
strcpy(linux_dirent.dname, bdp->d_name);
- if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen)))
+ if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
goto out;
+ }
inp += reclen;
outp += linuxreclen;
resid -= linuxreclen;
@@ -427,6 +439,7 @@ again:
if (justone)
nbytes = resid + linuxreclen;
+
eof:
*retval = nbytes - resid;
out:
OpenPOWER on IntegriCloud