summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorPatrick Mooney <patrick.f.mooney@gmail.com>2015-05-19 20:57:50 +0000
committerPatrick Mooney <patrick.f.mooney@gmail.com>2015-05-20 14:04:42 +0000
commiteb8244c4ef2358dc7ec61e6acb96f4a9c7d9fa4d (patch)
tree1019eebbc03637f80fc9761b9742214c874240f0 /usr/src
parented907ffaebd1dabd93b28c7a9ddfd607ef5290bc (diff)
downloadillumos-joyent-eb8244c4ef2358dc7ec61e6acb96f4a9c7d9fa4d.tar.gz
OS-4320 lxbrand convert getdents to IKE
OS-4282 lxbrand segfault in lx_getdents Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/dir.c195
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_brand.c8
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h2
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_syscall.c8
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_syscalls.h3
-rw-r--r--usr/src/uts/common/brand/lx/syscall/lx_getdents.c349
-rw-r--r--usr/src/uts/intel/Makefile.files1
7 files changed, 362 insertions, 204 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/dir.c b/usr/src/lib/brand/lx/lx_brand/common/dir.c
index 0fda763c19..ed10dfb822 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/dir.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/dir.c
@@ -21,7 +21,7 @@
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2014 Joyent, Inc. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
*/
#include <string.h>
@@ -46,54 +46,6 @@ struct lx_old_dirent {
};
/*
- * The positioning of d_type depends on d_reclen, since it follows
- * d_name which varies in size. Because d_type is not being emulated
- * beyond DT_UNKNOWN (0), this can be achieved by zero-filling the
- * structure to d_reclen bytes after the end of d_name.
- */
-struct lx_dirent {
- long d_ino;
- long d_off;
- ushort_t d_reclen;
- char d_name[LX_NAMEMAX];
- uchar_t d_type;
-};
-
-/* base definition of linux_dirent from readdir.c - sizeof is 12 */
-typedef struct {
- ulong_t d_ino;
- ulong_t d_off;
- ushort_t d_reclen;
- char d_name[1];
-} lx_linux_dirent_t;
-
-/*
- * Record must be long enough to house d_name string, null terminator and
- * d_type field. It's then padded to nearest 8-byte boundary
- */
-#define LX_RECLEN(namelen) \
- ((offsetof(struct lx_dirent, d_name) + 2 + (namelen) + 7) & ~7)
-
-/*
- * Bytes after d_name string until d_reclen should be zeroed.
- * Includes zero-terminating d_name
- */
-#define LX_ZEROLEN(namelen) \
- (LX_RECLEN(namelen) - \
- ((offsetof(struct lx_dirent, d_name) + (namelen))))
-
-struct lx_dirent64 {
- uint64_t d_ino;
- int64_t d_off;
- ushort_t d_reclen;
- uchar_t d_type;
- char d_name[LX_NAMEMAX];
-};
-
-#define LX_RECLEN64(namelen) \
- ((offsetof(struct lx_dirent64, d_name) + 1 + (namelen) + 7) & ~7)
-
-/*
* Read in one dirent structure from fd into dirp.
* p3 (count) is ignored.
*/
@@ -128,148 +80,3 @@ lx_readdir(uintptr_t p1, uintptr_t p2, uintptr_t p3)
return (rc);
}
-
-/*
- * Read in dirent structures from p1 (fd) into p2 (buffer).
- * p3 (count) is the size of the memory area.
- */
-long
-lx_getdents(uintptr_t p1, uintptr_t p2, uintptr_t p3)
-{
- int fd = (int)p1;
- void *buf = (void *)p2;
- void *sbuf, *lbuf;
- int lbufsz = (uint_t)p3;
- int sbufsz;
- int namelen;
- struct dirent *sd;
- struct lx_dirent *ld;
- int bytes, rc;
-
- /*
- * readdir will pass in the full size, but some test code calls getdents
- * directly and uses the bare struct. For these, just pretend we got
- * a single full-size entry so we can obtain the proper errno.
- */
- if (lbufsz == sizeof (lx_linux_dirent_t))
- lbufsz = sizeof (struct lx_dirent);
-
- if (lbufsz < sizeof (struct lx_dirent))
- return (-EINVAL);
-
- /*
- * The Linux dirent is bigger than the Solaris dirent. To
- * avoid inadvertently consuming more of the directory than we can
- * pass back to the Linux app, we hand the kernel a smaller buffer
- * than the app handed us.
- */
- sbufsz = (lbufsz / 32) * 24;
-
- sbuf = SAFE_ALLOCA(sbufsz);
- lbuf = SAFE_ALLOCA(lbufsz);
- if (sbuf == NULL || lbuf == NULL)
- return (-ENOMEM);
-
- if ((bytes = getdents(fd, sbuf, sbufsz)) < 0)
- return (-errno);
-
- /* munge the Solaris buffer to a linux buffer. */
- sd = (struct dirent *)sbuf;
- ld = (struct lx_dirent *)lbuf;
- rc = 0;
- while (bytes > 0) {
- namelen = strlen(sd->d_name);
- if (namelen >= LX_NAMEMAX)
- namelen = LX_NAMEMAX - 1;
- ld->d_ino = (uint64_t)sd->d_ino;
- ld->d_off = (int64_t)sd->d_off;
-
- (void) strncpy(ld->d_name, sd->d_name, namelen);
- /*
- * Zero out the rest of the record.
- * This effective sets ld->d_type = 0 and zero-terminates d_name
- */
- memset(ld->d_name + namelen, '\0', LX_ZEROLEN(namelen));
- ld->d_reclen = (ushort_t)LX_RECLEN(namelen);
-
- bytes -= (int)sd->d_reclen;
- rc += (int)ld->d_reclen;
-
- sd = (struct dirent *)(void *)((caddr_t)sd + sd->d_reclen);
- ld = (struct lx_dirent *)(void *)((caddr_t)ld + ld->d_reclen);
- }
-
- /* now copy the lbuf to the userland buffer */
- assert(rc <= lbufsz);
- if (uucopy(lbuf, buf, rc) != 0)
- return (-EFAULT);
-
- return (rc);
-}
-
-/*
- * Read in dirent64 structures from p1 (fd) into p2 (buffer).
- * p3 (count) is the size of the memory area.
- */
-long
-lx_getdents64(uintptr_t p1, uintptr_t p2, uintptr_t p3)
-{
- int fd = (uint_t)p1;
- void *buf = (void *)p2;
- void *sbuf, *lbuf;
- int lbufsz = (uint_t)p3;
- int sbufsz;
- int namelen;
- struct dirent *sd;
- struct lx_dirent64 *ld;
- int bytes, rc;
-
- if (lbufsz < sizeof (struct lx_dirent64))
- return (-EINVAL);
-
- /*
- * The Linux dirent64 is bigger than the Solaris dirent64. To
- * avoid inadvertently consuming more of the directory than we can
- * pass back to the Linux app, we hand the kernel a smaller buffer
- * than the app handed us.
- */
- sbufsz = (lbufsz / 32) * 24;
-
- sbuf = SAFE_ALLOCA(sbufsz);
- lbuf = SAFE_ALLOCA(lbufsz);
- if (sbuf == NULL || lbuf == NULL)
- return (-ENOMEM);
-
- if ((bytes = getdents(fd, sbuf, sbufsz)) < 0)
- return (-errno);
-
- /* munge the Solaris buffer to a linux buffer. */
- sd = (struct dirent *)sbuf;
- ld = (struct lx_dirent64 *)lbuf;
- rc = 0;
- while (bytes > 0) {
- namelen = strlen(sd->d_name);
- if (namelen >= LX_NAMEMAX)
- namelen = LX_NAMEMAX - 1;
- ld->d_ino = (uint64_t)sd->d_ino;
- ld->d_off = (int64_t)sd->d_off;
- ld->d_type = 0;
-
- (void) strncpy(ld->d_name, sd->d_name, namelen);
- ld->d_name[namelen] = 0;
- ld->d_reclen = (ushort_t)LX_RECLEN64(namelen);
-
- bytes -= (int)sd->d_reclen;
- rc += (int)ld->d_reclen;
-
- sd = (struct dirent *)(void *)((caddr_t)sd + sd->d_reclen);
- ld = (struct lx_dirent64 *)(void *)((caddr_t)ld + ld->d_reclen);
- }
-
- /* now copy the lbuf to the userland buffer */
- assert(rc <= lbufsz);
- if (uucopy(lbuf, buf, rc) != 0)
- return (-EFAULT);
-
- return (rc);
-}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
index e7083bec87..21da0771fc 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
@@ -992,7 +992,7 @@ static lx_syscall_handler_t lx_handlers[] = {
lx_fdatasync, /* 75: fdatasync */
lx_truncate, /* 76: truncate */
lx_ftruncate, /* 77: ftruncate */
- lx_getdents, /* 78: getdents */
+ NULL, /* 78: getdents */
lx_getcwd, /* 79: getcwd */
lx_chdir, /* 80: chdir */
lx_fchdir, /* 81: fchdir */
@@ -1131,7 +1131,7 @@ static lx_syscall_handler_t lx_handlers[] = {
NULL, /* 214: epoll_ctl_old */
NULL, /* 215: epoll_wait_old */
NULL, /* 216: remap_file_pages */
- lx_getdents64, /* 217: getdents64 */
+ NULL, /* 217: getdents64 */
NULL, /* 218: set_tid_address */
NULL, /* 219: restart_syscall */
lx_semtimedop, /* 220: semtimedop */
@@ -1386,7 +1386,7 @@ static lx_syscall_handler_t lx_handlers[] = {
lx_setfsuid16, /* 138: setfsuid16 */
lx_setfsgid16, /* 139: setfsgid16 */
lx_llseek, /* 140: llseek */
- lx_getdents, /* 141: getdents */
+ NULL, /* 141: getdents */
lx_select, /* 142: select */
lx_flock, /* 143: flock */
lx_msync, /* 144: msync */
@@ -1465,7 +1465,7 @@ static lx_syscall_handler_t lx_handlers[] = {
NULL, /* 217: pivot_root */
lx_mincore, /* 218: mincore */
lx_madvise, /* 219: madvise */
- lx_getdents64, /* 220: getdents64 */
+ NULL, /* 220: getdents64 */
NULL, /* 221: fcntl64 */
NULL, /* 222: tux */
NULL, /* 223: security */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
index 6eff748ff5..ed89a9083b 100644
--- a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
@@ -67,8 +67,6 @@ extern long lx_fcntl64(uintptr_t, uintptr_t, uintptr_t);
extern long lx_flock(uintptr_t, uintptr_t);
extern long lx_readlink(uintptr_t, uintptr_t, uintptr_t);
extern long lx_readdir(uintptr_t, uintptr_t, uintptr_t);
-extern long lx_getdents(uintptr_t, uintptr_t, uintptr_t);
-extern long lx_getdents64(uintptr_t, uintptr_t, uintptr_t);
extern long lx_execve(uintptr_t, uintptr_t, uintptr_t);
extern long lx_dup2(uintptr_t, uintptr_t);
extern long lx_dup3(uintptr_t, uintptr_t, uintptr_t);
diff --git a/usr/src/uts/common/brand/lx/os/lx_syscall.c b/usr/src/uts/common/brand/lx/os/lx_syscall.c
index 965aff2ca9..cce902a943 100644
--- a/usr/src/uts/common/brand/lx/os/lx_syscall.c
+++ b/usr/src/uts/common/brand/lx/os/lx_syscall.c
@@ -661,7 +661,7 @@ lx_sysent_t lx_sysent32[] = {
{"setfsuid16", NULL, 0, 1}, /* 138 */
{"setfsgid16", NULL, 0, 1}, /* 139 */
{"llseek", NULL, 0, 5}, /* 140 */
- {"getdents", NULL, 0, 3}, /* 141 */
+ {"getdents", lx_getdents_32, 0, 3}, /* 141 */
{"select", NULL, 0, 5}, /* 142 */
{"flock", NULL, 0, 2}, /* 143 */
{"msync", NULL, 0, 3}, /* 144 */
@@ -740,7 +740,7 @@ lx_sysent_t lx_sysent32[] = {
{"pivot_root", NULL, NOSYS_KERNEL, 0}, /* 217 */
{"mincore", NULL, 0, 3}, /* 218 */
{"madvise", NULL, 0, 3}, /* 219 */
- {"getdents64", NULL, 0, 3}, /* 220 */
+ {"getdents64", lx_getdents64, 0, 3}, /* 220 */
{"fcntl64", lx_fcntl64, 0, 3}, /* 221 */
{"tux", NULL, NOSYS_NO_EQUIV, 0}, /* 222 */
{"security", NULL, NOSYS_NO_EQUIV, 0}, /* 223 */
@@ -969,7 +969,7 @@ lx_sysent_t lx_sysent64[] = {
{"fdatasync", NULL, 0, 1}, /* 75 */
{"truncate", NULL, 0, 2}, /* 76 */
{"ftruncate", NULL, 0, 2}, /* 77 */
- {"getdents", NULL, 0, 3}, /* 78 */
+ {"getdents", lx_getdents_64, 0, 3}, /* 78 */
{"getcwd", NULL, 0, 2}, /* 79 */
{"chdir", NULL, 0, 1}, /* 80 */
{"fchdir", NULL, 0, 1}, /* 81 */
@@ -1108,7 +1108,7 @@ lx_sysent_t lx_sysent64[] = {
{"epoll_ctl_old", NULL, NOSYS_NULL, 0}, /* 214 */
{"epoll_wait_old", NULL, NOSYS_NULL, 0}, /* 215 */
{"remap_file_pages", NULL, NOSYS_NO_EQUIV, 0}, /* 216 */
- {"getdents64", NULL, 0, 3}, /* 217 */
+ {"getdents64", lx_getdents64, 0, 3}, /* 217 */
{"set_tid_address", lx_set_tid_address, 0, 1}, /* 218 */
{"restart_syscall", NULL, NOSYS_NULL, 0}, /* 219 */
{"semtimedop", NULL, 0, 4}, /* 220 */
diff --git a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h
index 8cbf9751a2..0f2977c47c 100644
--- a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h
+++ b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h
@@ -53,6 +53,9 @@ extern long lx_futex();
extern long lx_get_robust_list();
extern long lx_get_thread_area();
extern long lx_getcpu();
+extern long lx_getdents_32();
+extern long lx_getdents_64();
+extern long lx_getdents64();
extern long lx_getpid();
extern long lx_getppid();
extern long lx_getrandom();
diff --git a/usr/src/uts/common/brand/lx/syscall/lx_getdents.c b/usr/src/uts/common/brand/lx/syscall/lx_getdents.c
new file mode 100644
index 0000000000..a41ab19d65
--- /dev/null
+++ b/usr/src/uts/common/brand/lx/syscall/lx_getdents.c
@@ -0,0 +1,349 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <sys/systm.h>
+#include <sys/filio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/inttypes.h>
+#include <sys/vnode.h>
+#include <sys/dirent.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/sysmacros.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+
+#include <sys/lx_types.h>
+#include <sys/lx_misc.h>
+
+#define LX_NAMEMAX 256
+
+#define LX_GETDENTS_MAX_BUFSZ 65536
+
+/*
+ * Because the Linux dirent has an extra field (d_type), it's possible that
+ * each entry will be 8 bytes larger due to padding. To prevent overrun during
+ * translation, the illumos-native buffer is sized pessimistically.
+ */
+#define LTOS_GETDENTS_BUFSZ(bufsz, datasz) \
+ (((bufsz) / (datasz + 8)) * sizeof (struct dirent))
+
+/*
+ * Record must be long enough to house d_name string, null terminator and
+ * d_type field. It's then padded to nearest 8-byte boundary
+ */
+#define LX_RECLEN(l, t) \
+ ((offsetof(t, d_name) + 2 + (l) + 7) & ~7)
+
+/*
+ * Bytes after d_name string until d_reclen should be zeroed.
+ * Includes zero-terminating d_name
+ */
+#define LX_ZEROLEN(l, t) \
+ (LX_RECLEN(l, t) - \
+ ((offsetof(t, d_name) + (l))))
+
+/* The output format of getdents differs if the caller is 32 or 64 bit. */
+struct lx_dirent_32 {
+ uint32_t d_ino;
+ int32_t d_off;
+ ushort_t d_reclen;
+ char d_name[1];
+ uchar_t d_type;
+};
+
+struct lx_dirent_64 {
+ uint64_t d_ino;
+ int64_t d_off;
+ ushort_t d_reclen;
+ char d_name[1];
+ uchar_t d_type;
+};
+
+static long
+lx_getdents_common(int fd, caddr_t uptr, size_t count,
+ unsigned int lx_size, int (*outcb)(caddr_t, caddr_t, int))
+{
+ vnode_t *vp;
+ file_t *fp;
+ struct uio auio;
+ struct iovec aiov;
+ int error;
+ int sbufsz, lbufsz, bufsz;
+ void *lbuf, *sbuf;
+ size_t outb = 0;
+
+ if (count < lx_size) {
+ return (set_errno(EINVAL));
+ }
+ if ((fp = getf(fd)) == NULL) {
+ return (set_errno(EBADF));
+ }
+ vp = fp->f_vnode;
+ if (vp->v_type != VDIR) {
+ releasef(fd);
+ return (set_errno(ENOTDIR));
+ }
+ if (!(fp->f_flag & FREAD)) {
+ releasef(fd);
+ return (set_errno(EBADF));
+ }
+
+ if (count > LX_GETDENTS_MAX_BUFSZ) {
+ /*
+ * If the target buffer passed to us is huge, keep the
+ * translation buffers moderate in size. Iteration will be
+ * used to fill the request.
+ */
+ lbufsz = LX_GETDENTS_MAX_BUFSZ;
+ sbufsz = LTOS_GETDENTS_BUFSZ(LX_GETDENTS_MAX_BUFSZ, lx_size);
+ } else if (count < (lx_size + MAXPATHLEN)) {
+ /*
+ * If the target buffer is tiny, allocate a Linux-format buffer
+ * big enough to hold at least one max-length row while keeping
+ * the illumos-format buffer pesimistic in size.
+ *
+ * Assuming the buffer is truely tiny, it's likely that the
+ * result will not fit and an EINVAL will be tossed.
+ */
+ lbufsz = (lx_size + MAXPATHLEN);
+ sbufsz = MAX((LTOS_GETDENTS_BUFSZ(count, lx_size)),
+ sizeof (struct dirent));
+ } else {
+ lbufsz = count;
+ sbufsz = LTOS_GETDENTS_BUFSZ(count, lx_size);
+ }
+ bufsz = sbufsz;
+ lbuf = kmem_alloc(lbufsz, KM_SLEEP);
+ sbuf = kmem_alloc(sbufsz, KM_SLEEP);
+
+ aiov.iov_base = sbuf;
+ aiov.iov_len = sbufsz;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_loffset = fp->f_offset;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_resid = sbufsz;
+ auio.uio_fmode = 0;
+ auio.uio_extflg = UIO_COPY_CACHED;
+
+ /*
+ * Since we use a conservative buffer allocation for the differing
+ * struct sizing and Linux places fewer limits on getdents buffers in
+ * general, there's a chance we'll undershoot on the record count.
+ * When this happens, we can simply repeat the READDIR operation until
+ * the available records are exhausted or we've filled the user buffer.
+ */
+ while (1) {
+ int at_eof, res;
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READDIR(vp, &auio, fp->f_cred, &at_eof, NULL, 0);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ if (error != 0 || auio.uio_resid == sbufsz) {
+ break;
+ }
+ res = outcb(sbuf, lbuf, bufsz - auio.uio_resid);
+ VERIFY(res <= lbufsz);
+ if (res == 0) {
+ /* no records to copyout from this batch */
+ break;
+ } else if (res > count) {
+ /*
+ * For very small buffer sizes, it's possible that a
+ * single record is too large due to a long filename.
+ */
+ error = EINVAL;
+ break;
+ }
+
+ VERIFY(outb + res <= count);
+ if (copyout(lbuf, (void *)(uptr + outb), res) != 0) {
+ error = EFAULT;
+ break;
+ }
+ outb += res;
+
+ if (at_eof != 0 || (count - outb) < (lx_size + MAXPATHLEN)) {
+ /*
+ * If there are no records left or the remaining buffer
+ * space is not large enough to hold a max-length
+ * filename, do not continue iteration.
+ */
+ break;
+ }
+
+ /*
+ * We undershot the request buffer.
+ * Reset for another READDIR, taking care not to overshoot.
+ */
+ bufsz = MIN(sbufsz, LTOS_GETDENTS_BUFSZ(count - outb, lx_size));
+ auio.uio_resid = bufsz;
+ aiov.iov_len = bufsz;
+ aiov.iov_base = sbuf;
+ }
+
+ kmem_free(lbuf, lbufsz);
+ kmem_free(sbuf, sbufsz);
+
+ if (error) {
+ releasef(fd);
+ return (set_errno(error));
+ }
+
+ fp->f_offset = auio.uio_loffset;
+ releasef(fd);
+ return (outb);
+}
+
+
+static int
+lx_getdents_format32(caddr_t sbuf, caddr_t lbuf, int len)
+{
+ struct dirent *sd;
+ struct lx_dirent_32 *ld;
+ int namelen;
+ int size = 0;
+
+ while (len > 0) {
+ sd = (struct dirent *)sbuf;
+ ld = (struct lx_dirent_32 *)lbuf;
+ namelen = MIN(strlen(sd->d_name), LX_NAMEMAX - 1);
+
+ ld->d_ino = sd->d_ino;
+ ld->d_off = sd->d_off;
+ (void) strncpy(ld->d_name, sd->d_name, namelen);
+ ld->d_name[namelen] = 0;
+ ld->d_reclen = (ushort_t)LX_RECLEN(namelen,
+ struct lx_dirent_32);
+ /* Zero out any alignment padding and d_type */
+ bzero(ld->d_name + namelen,
+ LX_ZEROLEN(namelen, struct lx_dirent_32));
+
+ len -= sd->d_reclen;
+ size += ld->d_reclen;
+ sbuf += sd->d_reclen;
+ lbuf += ld->d_reclen;
+ }
+ return (size);
+}
+
+static int
+lx_getdents_format64(caddr_t sbuf, caddr_t lbuf, int len)
+{
+ struct dirent *sd;
+ struct lx_dirent_64 *ld;
+ int namelen;
+ int size = 0;
+
+ while (len > 0) {
+ sd = (struct dirent *)sbuf;
+ ld = (struct lx_dirent_64 *)lbuf;
+ namelen = MIN(strlen(sd->d_name), LX_NAMEMAX - 1);
+
+ ld->d_ino = sd->d_ino;
+ ld->d_off = sd->d_off;
+ (void) strncpy(ld->d_name, sd->d_name, namelen);
+ ld->d_name[namelen] = 0;
+ ld->d_reclen = (ushort_t)LX_RECLEN(namelen,
+ struct lx_dirent_64);
+ /* Zero out any alignment padding and d_type */
+ bzero(ld->d_name + namelen,
+ LX_ZEROLEN(namelen, struct lx_dirent_64));
+
+ len -= sd->d_reclen;
+ size += ld->d_reclen;
+ sbuf += sd->d_reclen;
+ lbuf += ld->d_reclen;
+ }
+ return (size);
+}
+
+long
+lx_getdents_32(int fd, caddr_t buf, size_t count)
+{
+ return (lx_getdents_common(fd, buf, count,
+ sizeof (struct lx_dirent_32), lx_getdents_format32));
+}
+
+long
+lx_getdents_64(int fd, caddr_t buf, size_t count)
+{
+ return (lx_getdents_common(fd, buf, count,
+ sizeof (struct lx_dirent_64), lx_getdents_format64));
+}
+
+struct lx_dirent64 {
+ uint64_t d_ino;
+ int64_t d_off;
+ ushort_t d_reclen;
+ uchar_t d_type;
+ char d_name[1];
+};
+
+#define LX_RECLEN64(namelen) \
+ ((offsetof(struct lx_dirent64, d_name) + 1 + (namelen) + 7) & ~7)
+
+#define LX_ZEROLEN64(namelen) \
+ (LX_RECLEN64(namelen) - \
+ ((offsetof(struct lx_dirent64, d_name) + (namelen))))
+
+static int
+lx_getdents64_format(caddr_t sbuf, caddr_t lbuf, int len)
+{
+ struct dirent *sd;
+ struct lx_dirent64 *ld;
+ int namelen;
+ int size = 0;
+
+ while (len > 0) {
+ sd = (struct dirent *)sbuf;
+ ld = (struct lx_dirent64 *)lbuf;
+ namelen = MIN(strlen(sd->d_name), LX_NAMEMAX - 1);
+
+ ld->d_ino = sd->d_ino;
+ ld->d_off = sd->d_off;
+ ld->d_type = 0;
+ (void) strncpy(ld->d_name, sd->d_name, namelen);
+ ld->d_name[namelen] = 0;
+ ld->d_reclen = (ushort_t)LX_RECLEN64(namelen);
+ /* Zero out any alignment padding */
+ bzero(ld->d_name + namelen, LX_ZEROLEN64(namelen));
+
+ len -= sd->d_reclen;
+ size += ld->d_reclen;
+ sbuf += sd->d_reclen;
+ lbuf += ld->d_reclen;
+ }
+ return (size);
+}
+
+
+long
+lx_getdents64(int fd, caddr_t buf, size_t count)
+{
+ return (lx_getdents_common(fd, buf, count,
+ sizeof (struct lx_dirent64), lx_getdents64_format));
+}
diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files
index add15d039a..5b6c75d630 100644
--- a/usr/src/uts/intel/Makefile.files
+++ b/usr/src/uts/intel/Makefile.files
@@ -291,6 +291,7 @@ LX_BRAND_OBJS = \
lx_errno.o \
lx_fcntl.o \
lx_futex.o \
+ lx_getdents.o \
lx_getpid.o \
lx_getrandom.o \
lx_id.o \