diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2014-10-27 14:29:05 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2014-10-27 14:29:05 +0000 |
commit | 8013ac6c7f6f5b009ecb43ee9f2f4a5994261a39 (patch) | |
tree | 56c90e3d2ab324dd71cca1bf4d959bb2ce22e94c | |
parent | 1500d877408a2c88f70ef9f99eac98f2cb83b499 (diff) | |
download | illumos-joyent-8013ac6c7f6f5b009ecb43ee9f2f4a5994261a39.tar.gz |
OS-3451 lxbrand 64bit pread64/pwrite64 args incorrect
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/iovec.c | 56 | ||||
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/lx_brand.c | 4 | ||||
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h | 2 |
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, |