mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-21 15:45:02 +00:00
Fix the getdirentries of ibcs2 to handle uneven DIRBLKSIZ offsets.
Same bug as was in linux. Also, fix problem where an entry would be skipped next call if not enough room in buffer current call.
This commit is contained in:
parent
1d5aafcd70
commit
4b0855b73b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=11417
@ -314,7 +314,7 @@ ibcs2_getdents(p, uap, retval)
|
|||||||
struct iovec aiov;
|
struct iovec aiov;
|
||||||
struct ibcs2_dirent idb;
|
struct ibcs2_dirent idb;
|
||||||
off_t off; /* true file offset */
|
off_t off; /* true file offset */
|
||||||
int buflen, error, eofflag;
|
int buflen, error, eofflag, blockoff;
|
||||||
#define BSD_DIRENT(cp) ((struct direct *)(cp))
|
#define BSD_DIRENT(cp) ((struct direct *)(cp))
|
||||||
#define IBCS2_RECLEN(reclen) (reclen + sizeof(u_short))
|
#define IBCS2_RECLEN(reclen) (reclen + sizeof(u_short))
|
||||||
|
|
||||||
@ -325,10 +325,13 @@ ibcs2_getdents(p, uap, retval)
|
|||||||
vp = (struct vnode *)fp->f_data;
|
vp = (struct vnode *)fp->f_data;
|
||||||
if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */
|
if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
buflen = min(MAXBSIZE, SCARG(uap, nbytes));
|
|
||||||
|
off = fp->f_offset;
|
||||||
|
blockoff = off % DIRBLKSIZ;
|
||||||
|
buflen = max(DIRBLKSIZ, SCARG(uap, nbytes) + blockoff);
|
||||||
|
buflen = min(buflen, MAXBSIZE);
|
||||||
buf = malloc(buflen, M_TEMP, M_WAITOK);
|
buf = malloc(buflen, M_TEMP, M_WAITOK);
|
||||||
VOP_LOCK(vp);
|
VOP_LOCK(vp);
|
||||||
off = fp->f_offset;
|
|
||||||
again:
|
again:
|
||||||
aiov.iov_base = buf;
|
aiov.iov_base = buf;
|
||||||
aiov.iov_len = buflen;
|
aiov.iov_len = buflen;
|
||||||
@ -338,7 +341,7 @@ ibcs2_getdents(p, uap, retval)
|
|||||||
auio.uio_segflg = UIO_SYSSPACE;
|
auio.uio_segflg = UIO_SYSSPACE;
|
||||||
auio.uio_procp = p;
|
auio.uio_procp = p;
|
||||||
auio.uio_resid = buflen;
|
auio.uio_resid = buflen;
|
||||||
auio.uio_offset = off;
|
auio.uio_offset = off - (off_t)blockoff;
|
||||||
/*
|
/*
|
||||||
* First we read into the malloc'ed buffer, then
|
* First we read into the malloc'ed buffer, then
|
||||||
* we massage it into user space, one record at a time.
|
* we massage it into user space, one record at a time.
|
||||||
@ -346,17 +349,21 @@ ibcs2_getdents(p, uap, retval)
|
|||||||
if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL))
|
if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL))
|
||||||
goto out;
|
goto out;
|
||||||
inp = buf;
|
inp = buf;
|
||||||
|
inp += blockoff;
|
||||||
outp = SCARG(uap, buf);
|
outp = SCARG(uap, buf);
|
||||||
resid = SCARG(uap, nbytes);
|
resid = SCARG(uap, nbytes);
|
||||||
if ((len = buflen - auio.uio_resid) == 0)
|
if ((len = buflen - auio.uio_resid - blockoff) == 0)
|
||||||
goto eof;
|
goto eof;
|
||||||
for (; len > 0; len -= reclen) {
|
for (; len > 0; len -= reclen) {
|
||||||
reclen = BSD_DIRENT(inp)->d_reclen;
|
reclen = BSD_DIRENT(inp)->d_reclen;
|
||||||
if (reclen & 3)
|
if (reclen & 3) {
|
||||||
panic("ibcs2_getdents");
|
printf("ibcs2_getdents: reclen=%d\n", reclen);
|
||||||
off += reclen; /* each entry points to next */
|
error = EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (BSD_DIRENT(inp)->d_ino == 0) {
|
if (BSD_DIRENT(inp)->d_ino == 0) {
|
||||||
inp += reclen; /* it is a hole; squish it out */
|
inp += reclen; /* it is a hole; squish it out */
|
||||||
|
off += reclen;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (reclen > len || resid < IBCS2_RECLEN(reclen)) {
|
if (reclen > len || resid < IBCS2_RECLEN(reclen)) {
|
||||||
@ -377,6 +384,7 @@ ibcs2_getdents(p, uap, retval)
|
|||||||
BSD_DIRENT(inp)->d_namlen + 1)) != 0)
|
BSD_DIRENT(inp)->d_namlen + 1)) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
/* advance past this real entry */
|
/* advance past this real entry */
|
||||||
|
off += reclen;
|
||||||
inp += reclen;
|
inp += reclen;
|
||||||
/* advance output past iBCS2-shaped entry */
|
/* advance output past iBCS2-shaped entry */
|
||||||
outp += IBCS2_RECLEN(reclen);
|
outp += IBCS2_RECLEN(reclen);
|
||||||
@ -413,7 +421,7 @@ ibcs2_read(p, uap, retval)
|
|||||||
char name[14];
|
char name[14];
|
||||||
} idb;
|
} idb;
|
||||||
off_t off; /* true file offset */
|
off_t off; /* true file offset */
|
||||||
int buflen, error, eofflag, size;
|
int buflen, error, eofflag, size, blockoff;
|
||||||
|
|
||||||
if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) {
|
if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) {
|
||||||
if (error == EINVAL)
|
if (error == EINVAL)
|
||||||
@ -426,11 +434,15 @@ ibcs2_read(p, uap, retval)
|
|||||||
vp = (struct vnode *)fp->f_data;
|
vp = (struct vnode *)fp->f_data;
|
||||||
if (vp->v_type != VDIR)
|
if (vp->v_type != VDIR)
|
||||||
return read(p, (struct read_args *)uap, retval);
|
return read(p, (struct read_args *)uap, retval);
|
||||||
|
|
||||||
DPRINTF(("ibcs2_read: read directory\n"));
|
DPRINTF(("ibcs2_read: read directory\n"));
|
||||||
buflen = max(MAXBSIZE, SCARG(uap, nbytes));
|
|
||||||
|
off = fp->f_offset;
|
||||||
|
blockoff = off % DIRBLKSIZ;
|
||||||
|
buflen = max(DIRBLKSIZ, SCARG(uap, nbytes) + blockoff);
|
||||||
|
buflen = min(buflen, MAXBSIZE);
|
||||||
buf = malloc(buflen, M_TEMP, M_WAITOK);
|
buf = malloc(buflen, M_TEMP, M_WAITOK);
|
||||||
VOP_LOCK(vp);
|
VOP_LOCK(vp);
|
||||||
off = fp->f_offset;
|
|
||||||
again:
|
again:
|
||||||
aiov.iov_base = buf;
|
aiov.iov_base = buf;
|
||||||
aiov.iov_len = buflen;
|
aiov.iov_len = buflen;
|
||||||
@ -440,7 +452,7 @@ ibcs2_read(p, uap, retval)
|
|||||||
auio.uio_segflg = UIO_SYSSPACE;
|
auio.uio_segflg = UIO_SYSSPACE;
|
||||||
auio.uio_procp = p;
|
auio.uio_procp = p;
|
||||||
auio.uio_resid = buflen;
|
auio.uio_resid = buflen;
|
||||||
auio.uio_offset = off & ~(DIRBLKSIZ - 1);
|
auio.uio_offset = off - (off_t)blockoff;
|
||||||
/*
|
/*
|
||||||
* First we read into the malloc'ed buffer, then
|
* First we read into the malloc'ed buffer, then
|
||||||
* we massage it into user space, one record at a time.
|
* we massage it into user space, one record at a time.
|
||||||
@ -449,16 +461,19 @@ ibcs2_read(p, uap, retval)
|
|||||||
DPRINTF(("VOP_READDIR failed: %d\n", error));
|
DPRINTF(("VOP_READDIR failed: %d\n", error));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
inp = buf + (off & (DIRBLKSIZ - 1));
|
inp = buf;
|
||||||
buflen -= off & (DIRBLKSIZ - 1);
|
inp += blockoff;
|
||||||
outp = SCARG(uap, buf);
|
outp = SCARG(uap, buf);
|
||||||
resid = SCARG(uap, nbytes);
|
resid = SCARG(uap, nbytes);
|
||||||
if ((len = buflen - auio.uio_resid) == 0)
|
if ((len = buflen - auio.uio_resid - blockoff) == 0)
|
||||||
goto eof;
|
goto eof;
|
||||||
for (; len > 0 && resid > 0; len -= reclen) {
|
for (; len > 0 && resid > 0; len -= reclen) {
|
||||||
reclen = BSD_DIRENT(inp)->d_reclen;
|
reclen = BSD_DIRENT(inp)->d_reclen;
|
||||||
if (reclen & 3)
|
if (reclen & 3) {
|
||||||
panic("ibcs2_read");
|
printf("ibcs2_read: reclen=%d\n", reclen);
|
||||||
|
error = EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (BSD_DIRENT(inp)->d_ino == 0) {
|
if (BSD_DIRENT(inp)->d_ino == 0) {
|
||||||
inp += reclen; /* it is a hole; squish it out */
|
inp += reclen; /* it is a hole; squish it out */
|
||||||
off += reclen;
|
off += reclen;
|
||||||
|
Loading…
Reference in New Issue
Block a user