Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132993386
D2210.id24678.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D2210.id24678.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D2210: Linux getdents/getdents64 rewrite.
Attached
Detach File
Event Timeline
Log In to Comment