Ensure we have the off64_t variant of every function that takes an off_t.

Change-Id: Ib2eee0cf13162be3b62559b84e90c6dcf5aab1c3
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 88c980f..132e383 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -118,7 +118,7 @@
 int         close (int)                      1
 int         creat(const char*, mode_t)       stub
 off_t       lseek(int, off_t, int)           1
-int         __llseek:_llseek (int, unsigned long, unsigned long, loff_t*, int)  1
+int         __llseek:_llseek (int, unsigned long, unsigned long, off64_t*, int)  1
 pid_t       getpid ()    1
 void *      mmap(void *, size_t, int, int, int, long)  stub
 void *      __mmap2:mmap2(void*, size_t, int, int, int, long)   1
@@ -153,7 +153,8 @@
 void        sync(void)  1
 int         __fcntl64:fcntl64(int, int, void *)  1
 int         __fstatfs64:fstatfs64(int, size_t, struct statfs *)  1
-ssize_t     sendfile(int out_fd, int in_fd, off_t *offset, size_t count)  1
+ssize_t     sendfile(int out_fd, int in_fd, off_t* offset, size_t count)  1
+ssize_t     sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count)  1
 int         fstatat:fstatat64(int dirfd, const char *path, struct stat *buf, int flags)   1
 int         mkdirat(int dirfd, const char *pathname, mode_t mode)  1
 int         fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags)  1
@@ -191,6 +192,7 @@
 int     symlink(const char *, const char *)  1
 int     fchdir(int)    1
 int     truncate(const char*, off_t)    1
+int     truncate64(const char*, off64_t)    1
 int     setxattr(const char *, const char *, const void *, size_t, int) 1
 int     lsetxattr(const char *, const char *, const void *, size_t, int) 1
 ssize_t getxattr(const char *, const char *, void *, size_t) 1
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index 252a428..33e520f 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -84,6 +84,7 @@
 syscall_src += arch-arm/syscalls/__fcntl64.S
 syscall_src += arch-arm/syscalls/__fstatfs64.S
 syscall_src += arch-arm/syscalls/sendfile.S
+syscall_src += arch-arm/syscalls/sendfile64.S
 syscall_src += arch-arm/syscalls/fstatat.S
 syscall_src += arch-arm/syscalls/mkdirat.S
 syscall_src += arch-arm/syscalls/fchownat.S
@@ -116,6 +117,7 @@
 syscall_src += arch-arm/syscalls/symlink.S
 syscall_src += arch-arm/syscalls/fchdir.S
 syscall_src += arch-arm/syscalls/truncate.S
+syscall_src += arch-arm/syscalls/truncate64.S
 syscall_src += arch-arm/syscalls/setxattr.S
 syscall_src += arch-arm/syscalls/lsetxattr.S
 syscall_src += arch-arm/syscalls/getxattr.S
diff --git a/libc/arch-arm/syscalls/sendfile64.S b/libc/arch-arm/syscalls/sendfile64.S
new file mode 100644
index 0000000..87de344
--- /dev/null
+++ b/libc/arch-arm/syscalls/sendfile64.S
@@ -0,0 +1,15 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+#include <linux/err.h>
+#include <machine/asm.h>
+
+ENTRY(sendfile64)
+    mov     ip, r7
+    ldr     r7, =__NR_sendfile64
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(sendfile64)
diff --git a/libc/arch-arm/syscalls/truncate64.S b/libc/arch-arm/syscalls/truncate64.S
new file mode 100644
index 0000000..059bd97
--- /dev/null
+++ b/libc/arch-arm/syscalls/truncate64.S
@@ -0,0 +1,15 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+#include <linux/err.h>
+#include <machine/asm.h>
+
+ENTRY(truncate64)
+    mov     ip, r7
+    ldr     r7, =__NR_truncate64
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(truncate64)
diff --git a/libc/arch-mips/syscalls.mk b/libc/arch-mips/syscalls.mk
index 23393a2..b34b0a9 100644
--- a/libc/arch-mips/syscalls.mk
+++ b/libc/arch-mips/syscalls.mk
@@ -87,6 +87,7 @@
 syscall_src += arch-mips/syscalls/__fcntl64.S
 syscall_src += arch-mips/syscalls/__fstatfs64.S
 syscall_src += arch-mips/syscalls/sendfile.S
+syscall_src += arch-mips/syscalls/sendfile64.S
 syscall_src += arch-mips/syscalls/fstatat.S
 syscall_src += arch-mips/syscalls/mkdirat.S
 syscall_src += arch-mips/syscalls/fchownat.S
@@ -119,6 +120,7 @@
 syscall_src += arch-mips/syscalls/symlink.S
 syscall_src += arch-mips/syscalls/fchdir.S
 syscall_src += arch-mips/syscalls/truncate.S
+syscall_src += arch-mips/syscalls/truncate64.S
 syscall_src += arch-mips/syscalls/setxattr.S
 syscall_src += arch-mips/syscalls/lsetxattr.S
 syscall_src += arch-mips/syscalls/getxattr.S
diff --git a/libc/arch-mips/syscalls/sendfile64.S b/libc/arch-mips/syscalls/sendfile64.S
new file mode 100644
index 0000000..5b74709
--- /dev/null
+++ b/libc/arch-mips/syscalls/sendfile64.S
@@ -0,0 +1,22 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+    .text
+    .globl sendfile64
+    .align 4
+    .ent sendfile64
+
+sendfile64:
+    .set noreorder
+    .cpload $t9
+    li $v0, __NR_sendfile64
+    syscall
+    bnez $a3, 1f
+    move $a0, $v0
+    j $ra
+    nop
+1:
+    la $t9,__set_errno
+    j $t9
+    nop
+    .set reorder
+    .end sendfile64
diff --git a/libc/arch-mips/syscalls/truncate64.S b/libc/arch-mips/syscalls/truncate64.S
new file mode 100644
index 0000000..57f0b5f
--- /dev/null
+++ b/libc/arch-mips/syscalls/truncate64.S
@@ -0,0 +1,22 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+    .text
+    .globl truncate64
+    .align 4
+    .ent truncate64
+
+truncate64:
+    .set noreorder
+    .cpload $t9
+    li $v0, __NR_truncate64
+    syscall
+    bnez $a3, 1f
+    move $a0, $v0
+    j $ra
+    nop
+1:
+    la $t9,__set_errno
+    j $t9
+    nop
+    .set reorder
+    .end truncate64
diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk
index 11573de..7180cf2 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -88,6 +88,7 @@
 syscall_src += arch-x86/syscalls/__fcntl64.S
 syscall_src += arch-x86/syscalls/__fstatfs64.S
 syscall_src += arch-x86/syscalls/sendfile.S
+syscall_src += arch-x86/syscalls/sendfile64.S
 syscall_src += arch-x86/syscalls/fstatat.S
 syscall_src += arch-x86/syscalls/mkdirat.S
 syscall_src += arch-x86/syscalls/fchownat.S
@@ -120,6 +121,7 @@
 syscall_src += arch-x86/syscalls/symlink.S
 syscall_src += arch-x86/syscalls/fchdir.S
 syscall_src += arch-x86/syscalls/truncate.S
+syscall_src += arch-x86/syscalls/truncate64.S
 syscall_src += arch-x86/syscalls/setxattr.S
 syscall_src += arch-x86/syscalls/lsetxattr.S
 syscall_src += arch-x86/syscalls/getxattr.S
diff --git a/libc/arch-x86/syscalls/sendfile64.S b/libc/arch-x86/syscalls/sendfile64.S
new file mode 100644
index 0000000..9731806
--- /dev/null
+++ b/libc/arch-x86/syscalls/sendfile64.S
@@ -0,0 +1,30 @@
+/* autogenerated by gensyscalls.py */
+#include <linux/err.h>
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ENTRY(sendfile64)
+    pushl   %ebx
+    pushl   %ecx
+    pushl   %edx
+    pushl   %esi
+    mov     20(%esp), %ebx
+    mov     24(%esp), %ecx
+    mov     28(%esp), %edx
+    mov     32(%esp), %esi
+    movl    $__NR_sendfile64, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+    orl     $-1, %eax
+1:
+    popl    %esi
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(sendfile64)
diff --git a/libc/arch-x86/syscalls/truncate64.S b/libc/arch-x86/syscalls/truncate64.S
new file mode 100644
index 0000000..f9118bb
--- /dev/null
+++ b/libc/arch-x86/syscalls/truncate64.S
@@ -0,0 +1,27 @@
+/* autogenerated by gensyscalls.py */
+#include <linux/err.h>
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ENTRY(truncate64)
+    pushl   %ebx
+    pushl   %ecx
+    pushl   %edx
+    mov     16(%esp), %ebx
+    mov     20(%esp), %ecx
+    mov     24(%esp), %edx
+    movl    $__NR_truncate64, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+    orl     $-1, %eax
+1:
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(truncate64)
diff --git a/libc/bionic/lseek64.c b/libc/bionic/lseek64.c
index db0c413..c24ae64 100644
--- a/libc/bionic/lseek64.c
+++ b/libc/bionic/lseek64.c
@@ -25,16 +25,16 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #include <unistd.h>
 
-extern int __llseek(int fd, unsigned long  offset_hi, unsigned long  offset_lo, loff_t*  result, int  whence);
+extern int __llseek(int fd, unsigned long offset_hi, unsigned long offset_lo, off64_t* result, int whence);
 
-off64_t lseek64(int fd, off64_t off, int whence)
-{
-    loff_t  result;
+off64_t lseek64(int fd, off64_t off, int whence) {
+  off64_t result;
+  if (__llseek(fd, (unsigned long)(off >> 32),(unsigned long)(off), &result, whence) < 0) {
+    return -1;
+  }
 
-    if ( __llseek(fd, (unsigned long)(off >> 32),(unsigned long)(off), &result, whence ) < 0 )
-        return -1;
-
-    return result;
+  return result;
 }
diff --git a/libc/include/sys/sendfile.h b/libc/include/sys/sendfile.h
index d5aba26..81a3c44 100644
--- a/libc/include/sys/sendfile.h
+++ b/libc/include/sys/sendfile.h
@@ -25,6 +25,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _SYS_SENDFILE_H_
 #define _SYS_SENDFILE_H_
 
@@ -33,7 +34,8 @@
 
 __BEGIN_DECLS
 
-extern ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
+extern ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);
+extern ssize_t sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count);
 
 __END_DECLS
 
diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h
index a0ce405..8b7fea8 100644
--- a/libc/include/sys/types.h
+++ b/libc/include/sys/types.h
@@ -65,7 +65,7 @@
 typedef __kernel_off_t       off_t;
 #endif
 typedef __kernel_loff_t      loff_t;
-typedef loff_t               off64_t;  /* GLibc-specific */
+typedef loff_t               off64_t;
 
 typedef __kernel_pid_t		 pid_t;
 
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 61d3d6e..60964f0 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -122,6 +122,7 @@
 extern int fchown(int, uid_t, gid_t);
 extern int lchown(const char *, uid_t, gid_t);
 extern int truncate(const char *, off_t);
+extern int truncate64(const char *, off64_t);
 extern char *getcwd(char *, size_t);
 
 extern int sync(void);
diff --git a/tests/Android.mk b/tests/Android.mk
index 39e9409..e60b908 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -80,6 +80,7 @@
     string_test.cpp \
     strings_test.cpp \
     stubs_test.cpp \
+    sys_sendfile_test.cpp \
     sys_stat_test.cpp \
     system_properties_test.cpp \
     time_test.cpp \
diff --git a/tests/TemporaryFile.h b/tests/TemporaryFile.h
new file mode 100644
index 0000000..878fb13
--- /dev/null
+++ b/tests/TemporaryFile.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+class TemporaryFile {
+ public:
+  TemporaryFile() {
+#if __BIONIC__
+    const char* tmp_dir = "/data/local/tmp";
+#else
+    const char* tmp_dir = "/tmp";
+#endif
+    snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
+    fd = mkstemp(filename);
+  }
+
+  ~TemporaryFile() {
+    close(fd);
+    unlink(filename);
+  }
+
+  int fd;
+  char filename[1024];
+};
diff --git a/tests/sys_sendfile_test.cpp b/tests/sys_sendfile_test.cpp
new file mode 100644
index 0000000..bf23d3d
--- /dev/null
+++ b/tests/sys_sendfile_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include "TemporaryFile.h"
+
+#include <sys/sendfile.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+TEST(sys_sendfile, sendfile) {
+  TemporaryFile src_file;
+  ASSERT_EQ(5, TEMP_FAILURE_RETRY(write(src_file.fd, "hello", 5)));
+
+  TemporaryFile dst_file;
+
+  off_t offset = 2;
+  size_t count = 2;
+  ssize_t rc = sendfile(dst_file.fd, src_file.fd, &offset, count);
+  ASSERT_EQ(2, rc);
+  ASSERT_EQ(4, offset);
+
+  ASSERT_EQ(0, lseek(dst_file.fd, 0, SEEK_SET));
+  char buf[3];
+  buf[2] = '\0';
+  ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(dst_file.fd, &buf, 2)));
+  ASSERT_STREQ("ll", buf);
+}
+
+#if __BIONIC__
+TEST(sys_sendfile, sendfile64) {
+  TemporaryFile src_file;
+  ASSERT_EQ(5, TEMP_FAILURE_RETRY(write(src_file.fd, "hello", 5)));
+
+  TemporaryFile dst_file;
+
+  off64_t offset = 2;
+  size_t count = 2;
+  ssize_t rc = sendfile64(dst_file.fd, src_file.fd, &offset, count);
+  ASSERT_EQ(2, rc);
+  ASSERT_EQ(4, offset);
+
+  ASSERT_EQ(0, lseek(dst_file.fd, 0, SEEK_SET));
+  char buf[3];
+  buf[2] = '\0';
+  ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(dst_file.fd, &buf, 2)));
+  ASSERT_STREQ("ll", buf);
+}
+#endif
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 3ccaf3b..3193083 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <gtest/gtest.h>
+#include "TemporaryFile.h"
 
 #include <stdint.h>
 #include <unistd.h>
@@ -32,3 +33,43 @@
   void* final_break = sbrk(0);
   ASSERT_EQ(final_break, new_break);
 }
+
+TEST(unistd, truncate) {
+  TemporaryFile tf;
+  ASSERT_EQ(0, close(tf.fd));
+  ASSERT_EQ(0, truncate(tf.filename, 123));
+
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(123, sb.st_size);
+}
+
+TEST(unistd, truncate64) {
+  TemporaryFile tf;
+  ASSERT_EQ(0, close(tf.fd));
+  ASSERT_EQ(0, truncate64(tf.filename, 123));
+
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(123, sb.st_size);
+}
+
+TEST(unistd, ftruncate) {
+  TemporaryFile tf;
+  ASSERT_EQ(0, ftruncate(tf.fd, 123));
+  ASSERT_EQ(0, close(tf.fd));
+
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(123, sb.st_size);
+}
+
+TEST(unistd, ftruncate64) {
+  TemporaryFile tf;
+  ASSERT_EQ(0, ftruncate64(tf.fd, 123));
+  ASSERT_EQ(0, close(tf.fd));
+
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(123, sb.st_size);
+}