Page MenuHomeFreeBSD

D2210.id24678.diff
No OneTemporary

D2210.id24678.diff

Index: sys/compat/linux/linux_file.c
===================================================================
--- sys/compat/linux/linux_file.c
+++ sys/compat/linux/linux_file.c
@@ -53,8 +53,6 @@
#include <sys/unistd.h>
#include <sys/vnode.h>
-#include <security/mac/mac_framework.h>
-
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
#include <machine/../linux32/linux32_proto.h>
@@ -296,237 +294,197 @@
LINUX_RECLEN64(LINUX_NAME_MAX))
#define LINUX_DIRBLKSIZ 512
-static int
-getdents_common(struct thread *td, struct linux_getdents64_args *args,
- int is64bit)
+/*
+ * Linux l_dirent is bigger than FreeBSD dirent, thus the buffer size
+ * passed to kern_getdirentries() must be smaller than the one passed
+ * to linux_getdents() by certain factor.
+ */
+#define LINUX_RECLEN_RATIO(X) X * offsetof(struct dirent, d_name) / \
+ offsetof(struct l_dirent, d_name);
+#define LINUX_RECLEN64_RATIO(X) X * offsetof(struct dirent, d_name) / \
+ offsetof(struct l_dirent64, d_name);
+
+int
+linux_getdents(struct thread *td, struct linux_getdents_args *args)
{
struct dirent *bdp;
- struct vnode *vp;
caddr_t inp, buf; /* BSD-format */
int len, reclen; /* BSD-format */
caddr_t outp; /* Linux-format */
- int resid, linuxreclen=0; /* Linux-format */
+ int resid, linuxreclen; /* Linux-format */
caddr_t lbuf; /* Linux-format */
- cap_rights_t rights;
- struct file *fp;
- struct uio auio;
- struct iovec aiov;
- off_t off;
+ long base;
struct l_dirent *linux_dirent;
- struct l_dirent64 *linux_dirent64;
- int buflen, error, eofflag, nbytes, justone;
- u_long *cookies = NULL, *cookiep;
- int ncookies;
+ int buflen, error, nbytes, justone;
+ size_t retval;
+
+#ifdef DEBUG
+ if (ldebug(getdents))
+ printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
+#endif
nbytes = args->count;
if (nbytes == 1) {
/* readdir(2) case. Always struct dirent. */
- if (is64bit)
- return (EINVAL);
nbytes = sizeof(*linux_dirent);
justone = 1;
} else
justone = 0;
- error = getvnode(td, args->fd, cap_rights_init(&rights, CAP_READ), &fp);
- if (error != 0)
- return (error);
-
- if ((fp->f_flag & FREAD) == 0) {
- fdrop(fp, td);
- return (EBADF);
- }
-
- off = foffset_lock(fp, 0);
- vp = fp->f_vnode;
- if (vp->v_type != VDIR) {
- foffset_unlock(fp, off, 0);
- fdrop(fp, td);
- return (EINVAL);
- }
-
-
buflen = max(LINUX_DIRBLKSIZ, nbytes);
+ buflen = LINUX_RECLEN_RATIO(buflen);
buflen = min(buflen, MAXBSIZE);
- buf = malloc(buflen, M_LINUX, M_WAITOK);
- lbuf = malloc(LINUX_MAXRECLEN, M_LINUX, M_WAITOK | M_ZERO);
- vn_lock(vp, LK_SHARED | LK_RETRY);
-
- aiov.iov_base = buf;
- aiov.iov_len = buflen;
- auio.uio_iov = &aiov;
- auio.uio_iovcnt = 1;
- auio.uio_rw = UIO_READ;
- auio.uio_segflg = UIO_SYSSPACE;
- auio.uio_td = td;
- auio.uio_resid = buflen;
- auio.uio_offset = off;
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
-#ifdef MAC
- /*
- * Do directory search MAC check using non-cached credentials.
- */
- if ((error = mac_vnode_check_readdir(td->td_ucred, vp)))
- goto out;
-#endif /* MAC */
- if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
- &cookies)))
- goto out;
+ error = kern_getdirentries(td, args->fd, buf, buflen,
+ &base, NULL, UIO_SYSSPACE);
+ if (error != 0) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+ lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
+
+ len = td->td_retval[0];
inp = buf;
- outp = (caddr_t)args->dirent;
+ outp = (caddr_t)args->dent;
resid = nbytes;
- if ((len = buflen - auio.uio_resid) <= 0)
- goto eof;
-
- cookiep = cookies;
-
- if (cookies) {
- /*
- * When using cookies, the vfs has the option of reading from
- * a different offset than that supplied (UFS truncates the
- * offset to a block boundary to make sure that it never reads
- * partway through a directory entry, even if the directory
- * has been compacted).
- */
- while (len > 0 && ncookies > 0 && *cookiep <= off) {
- bdp = (struct dirent *) inp;
- len -= bdp->d_reclen;
- inp += bdp->d_reclen;
- cookiep++;
- ncookies--;
- }
- }
+ retval = 0;
while (len > 0) {
- if (cookiep && ncookies == 0)
- break;
bdp = (struct dirent *) inp;
reclen = bdp->d_reclen;
- if (reclen & 3) {
- error = EFAULT;
- goto out;
- }
-
- if (bdp->d_fileno == 0) {
- inp += reclen;
- if (cookiep) {
- off = *cookiep++;
- ncookies--;
- } else
- off += reclen;
-
- len -= reclen;
- continue;
- }
- linuxreclen = (is64bit)
- ? LINUX_RECLEN64(bdp->d_namlen)
- : LINUX_RECLEN(bdp->d_namlen);
+ linuxreclen = LINUX_RECLEN(bdp->d_namlen);
- if (reclen > len || resid < linuxreclen) {
- outp++;
+ if (reclen > len)
break;
- }
+ if (resid < linuxreclen)
+ break;
+
+ linux_dirent = (struct l_dirent*)lbuf;
+ linux_dirent->d_ino = bdp->d_fileno;
if (justone) {
/* readdir(2) case. */
- linux_dirent = (struct l_dirent*)lbuf;
- linux_dirent->d_ino = bdp->d_fileno;
- linux_dirent->d_off = (l_off_t)linuxreclen;
- linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
+ linux_dirent->d_off = linuxreclen;
+ linux_dirent->d_reclen = bdp->d_namlen;
+
strlcpy(linux_dirent->d_name, bdp->d_name,
linuxreclen - offsetof(struct l_dirent, d_name));
- error = copyout(linux_dirent, outp, linuxreclen);
- }
- if (is64bit) {
- linux_dirent64 = (struct l_dirent64*)lbuf;
- linux_dirent64->d_ino = bdp->d_fileno;
- linux_dirent64->d_off = (cookiep)
- ? (l_off_t)*cookiep
- : (l_off_t)(off + reclen);
- linux_dirent64->d_reclen = (l_ushort)linuxreclen;
- linux_dirent64->d_type = bdp->d_type;
- strlcpy(linux_dirent64->d_name, bdp->d_name,
- linuxreclen - offsetof(struct l_dirent64, d_name));
- error = copyout(linux_dirent64, outp, linuxreclen);
- } else if (!justone) {
- linux_dirent = (struct l_dirent*)lbuf;
- linux_dirent->d_ino = bdp->d_fileno;
- linux_dirent->d_off = (cookiep)
- ? (l_off_t)*cookiep
- : (l_off_t)(off + reclen);
- linux_dirent->d_reclen = (l_ushort)linuxreclen;
+ } else {
+ linux_dirent->d_off = base + reclen;
+ linux_dirent->d_reclen = linuxreclen;
/*
* Copy d_type to last byte of l_dirent buffer
*/
- lbuf[linuxreclen-1] = bdp->d_type;
+ lbuf[linuxreclen - 1] = bdp->d_type;
strlcpy(linux_dirent->d_name, bdp->d_name,
linuxreclen - offsetof(struct l_dirent, d_name)-1);
- error = copyout(linux_dirent, outp, linuxreclen);
}
- if (error)
+ error = copyout(linux_dirent, outp, linuxreclen);
+ if (error != 0)
goto out;
inp += reclen;
- if (cookiep) {
- off = *cookiep++;
- ncookies--;
- } else
- off += reclen;
+ base += reclen;
+ len -= reclen;
+ retval += linuxreclen;
outp += linuxreclen;
resid -= linuxreclen;
- len -= reclen;
+
if (justone)
break;
}
- if (outp == (caddr_t)args->dirent) {
- nbytes = resid;
- goto eof;
- }
-
- if (justone)
- nbytes = resid + linuxreclen;
-
-eof:
- td->td_retval[0] = nbytes - resid;
+ td->td_retval[0] = retval;
out:
- free(cookies, M_TEMP);
-
- VOP_UNLOCK(vp, 0);
- foffset_unlock(fp, off, 0);
- fdrop(fp, td);
free(buf, M_LINUX);
free(lbuf, M_LINUX);
return (error);
}
int
-linux_getdents(struct thread *td, struct linux_getdents_args *args)
-{
-
-#ifdef DEBUG
- if (ldebug(getdents))
- printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
-#endif
-
- return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
-}
-
-int
linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
{
+ struct dirent *bdp;
+ caddr_t inp, buf; /* BSD-format */
+ int len, reclen; /* BSD-format */
+ caddr_t outp; /* Linux-format */
+ int resid, linuxreclen; /* Linux-format */
+ caddr_t lbuf; /* Linux-format */
+ long base;
+ struct l_dirent64 *linux_dirent64;
+ int buflen, error, nbytes;
+ size_t retval;
#ifdef DEBUG
if (ldebug(getdents64))
printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
#endif
- return (getdents_common(td, args, 1));
+ nbytes = args->count;
+
+ buflen = max(LINUX_DIRBLKSIZ, nbytes);
+ buflen = LINUX_RECLEN64_RATIO(buflen);
+ buflen = min(buflen, MAXBSIZE);
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+
+ error = kern_getdirentries(td, args->fd, buf, buflen,
+ &base, NULL, UIO_SYSSPACE);
+ if (error != 0) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+
+ lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
+
+ len = td->td_retval[0];
+ inp = buf;
+ outp = (caddr_t)args->dirent;
+ resid = nbytes;
+ retval = 0;
+
+ while (len > 0) {
+ bdp = (struct dirent *) inp;
+ reclen = bdp->d_reclen;
+
+ linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
+
+ if (reclen > len)
+ break;
+ if (resid < linuxreclen)
+ break;
+
+ linux_dirent64 = (struct l_dirent64*)lbuf;
+ linux_dirent64->d_ino = bdp->d_fileno;
+ linux_dirent64->d_off = base + reclen;
+ linux_dirent64->d_reclen = linuxreclen;
+ linux_dirent64->d_type = bdp->d_type;
+ strlcpy(linux_dirent64->d_name, bdp->d_name,
+ linuxreclen - offsetof(struct l_dirent64, d_name));
+ error = copyout(linux_dirent64, outp, linuxreclen);
+ if (error)
+ goto out;
+
+ inp += reclen;
+ base += reclen;
+ len -= reclen;
+
+ retval += linuxreclen;
+ outp += linuxreclen;
+ resid -= linuxreclen;
+ }
+
+ td->td_retval[0] = retval;
+
+out:
+ free(buf, M_TEMP);
+ free(lbuf, M_TEMP);
+ return (error);
}
/*

File Metadata

Mime Type
text/plain
Expires
Wed, Oct 22, 9:47 PM (4 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24069209
Default Alt Text
D2210.id24678.diff (9 KB)

Event Timeline