summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2014-10-27 14:29:05 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2014-10-27 14:29:05 +0000
commit8013ac6c7f6f5b009ecb43ee9f2f4a5994261a39 (patch)
tree56c90e3d2ab324dd71cca1bf4d959bb2ce22e94c
parent1500d877408a2c88f70ef9f99eac98f2cb83b499 (diff)
downloadillumos-joyent-8013ac6c7f6f5b009ecb43ee9f2f4a5994261a39.tar.gz
OS-3451 lxbrand 64bit pread64/pwrite64 args incorrect
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/iovec.c56
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_brand.c4
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h2
3 files changed, 60 insertions, 2 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/iovec.c b/usr/src/lib/brand/lx/lx_brand/common/iovec.c
index f7b8bab756..03dec0051a 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/iovec.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/iovec.c
@@ -65,6 +65,61 @@ lx_read(uintptr_t p1, uintptr_t p2, uintptr_t p3)
return (ret);
}
+#if defined(_LP64)
+long
+lx_pread(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
+{
+ int fd = (int)p1;
+ void *buf = (void *)p2;
+ size_t nbyte = (size_t)p3;
+ off64_t off = (off64_t)p4;
+ ssize_t ret;
+
+ if (lx_is_directory(fd))
+ return (-EISDIR);
+
+ ret = pread64(fd, buf, nbyte, off);
+
+ if (ret < 0)
+ return (-errno);
+
+ return (ret);
+}
+
+/*
+ * On Linux, the pwrite(2) system call behaves identically to Solaris except
+ * in the case of the file being opened with O_APPEND. In that case Linux's
+ * pwrite(2) ignores the offset parameter and instead appends the data to the
+ * file without modifying the current seek pointer.
+ */
+long
+lx_pwrite(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
+{
+ int fd = (int)p1;
+ void *buf = (void *)p2;
+ size_t nbyte = (size_t)p3;
+ off64_t off = (off64_t)p4;
+ ssize_t ret;
+ int rval;
+ struct stat64 statbuf;
+
+ if ((rval = fcntl(fd, F_GETFL, 0)) < 0)
+ return (-errno);
+
+ if (!(rval & O_APPEND)) {
+ ret = pwrite64(fd, buf, nbyte, off);
+ } else if ((ret = fstat64(fd, &statbuf)) == 0) {
+ ret = pwrite64(fd, buf, nbyte, statbuf.st_size);
+ }
+
+ if (ret < 0)
+ return (-errno);
+
+ return (ret);
+}
+
+#else /* 32 bit */
+
long
lx_pread64(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5)
{
@@ -120,6 +175,7 @@ lx_pwrite64(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
return (ret);
}
+#endif
/*
* Implementation of Linux readv() and writev() system calls.
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 03c9a13c20..f136c587fa 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
@@ -1133,8 +1133,8 @@ static struct lx_sysent sysents[] = {
{"rt_sigprocmask", lx_rt_sigprocmask, 0, 4}, /* 14 */
{"rt_sigreturn", lx_rt_sigreturn, 0, 0}, /* 15 */
{"ioctl", lx_ioctl, 0, 3}, /* 16 */
- {"pread64", lx_pread64, 0, 5}, /* 17 */
- {"pwrite64", lx_pwrite64, 0, 5}, /* 18 */
+ {"pread64", lx_pread, 0, 4}, /* 17 */
+ {"pwrite64", lx_pwrite, 0, 4}, /* 18 */
{"readv", lx_readv, 0, 3}, /* 19 */
{"writev", lx_writev, 0, 3}, /* 20 */
{"access", lx_access, 0, 2}, /* 21 */
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 cad87ce872..06bbd95d29 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
@@ -86,6 +86,8 @@ extern long lx_fadvise64_64(uintptr_t, off64_t, off64_t, uintptr_t);
extern long lx_read(uintptr_t, uintptr_t, uintptr_t);
extern long lx_readv(uintptr_t, uintptr_t, uintptr_t);
extern long lx_writev(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_pread(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_pwrite(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern long lx_pread64(uintptr_t, uintptr_t, uintptr_t, uintptr_t,
uintptr_t);
extern long lx_pwrite64(uintptr_t, uintptr_t, uintptr_t, uintptr_t,