Implement _FILE_OFFSET_BITS (mostly).

I still don't think we can make stdio's fseeko and ftello work, but we can
have everything else, and very few programs use fseeko/ftello (and they can
just refrain from using _FILE_OFFSET_BITS and be no worse off than they are
today).

Bug: 11865851
Change-Id: Ic3cb409aae6713f4b345de954bcc4241fcd969ec
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 4c4cfbd..0f016d7 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -59,22 +59,29 @@
 
 extern int creat(const char*, mode_t);
 extern int creat64(const char*, mode_t);
-extern int fallocate64(int, int, off64_t, off64_t);
-extern int fallocate(int, int, off_t, off_t);
 extern int fcntl(int, int, ...);
 extern int openat(int, const char*, int, ...);
 extern int openat64(int, const char*, int, ...);
 extern int open(const char*, int, ...);
 extern int open64(const char*, int, ...);
-extern int posix_fadvise64(int, off64_t, off64_t, int);
-extern int posix_fadvise(int, off_t, off_t, int);
-extern int posix_fallocate64(int, off64_t, off64_t);
-extern int posix_fallocate(int, off_t, off_t);
 extern ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int);
 extern ssize_t tee(int, int, size_t, unsigned int);
 extern int unlinkat(int, const char*, int);
 extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int);
 
+#if defined(__USE_FILE_OFFSET64)
+extern int fallocate(int, int, off_t, off_t) __RENAME(fallocate64);
+extern int posix_fadvise(int, off_t, off_t, int) __RENAME(posix_fadvise64);
+extern int posix_fallocate(int, off_t, off_t) __RENAME(posix_fallocate);
+#else
+extern int fallocate(int, int, off_t, off_t);
+extern int posix_fadvise(int, off_t, off_t, int);
+extern int posix_fallocate(int, off_t, off_t);
+#endif
+extern int fallocate64(int, int, off64_t, off64_t);
+extern int posix_fadvise64(int, off64_t, off64_t, int);
+extern int posix_fallocate64(int, off64_t, off64_t);
+
 extern int __open_2(const char*, int);
 extern int __open_real(const char*, int, ...) __RENAME(open);
 extern int __openat_2(int, const char*, int);
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index b04aa24..ff454da 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -57,8 +57,6 @@
 
 __BEGIN_DECLS
 
-#define	_FSTDIO			/* Define for new stdio with functions. */
-
 typedef off_t fpos_t;		/* stdio file position type */
 
 /*
@@ -282,11 +280,22 @@
 extern int rename(const char*, const char*);
 extern int renameat(int, const char*, int, const char*);
 
+#if defined(__USE_FILE_OFFSET64)
+/* Not possible. */
+int	 fgetpos(FILE * __restrict, fpos_t * __restrict)
+	__attribute__((__error__("not available with _FILE_OFFSET_BITS=64")));
+int	 fsetpos(FILE *, const fpos_t *)
+	__attribute__((__error__("not available with _FILE_OFFSET_BITS=64")));
+int	 fseeko(FILE *, off_t, int)
+	__attribute__((__error__("not available with _FILE_OFFSET_BITS=64")));
+off_t	 ftello(FILE *)
+	__attribute__((__error__("not available with _FILE_OFFSET_BITS=64")));
+#else
 int	 fgetpos(FILE * __restrict, fpos_t * __restrict);
 int	 fsetpos(FILE *, const fpos_t *);
-
 int	 fseeko(FILE *, off_t, int);
 off_t	 ftello(FILE *);
+#endif
 
 #if __ISO_C_VISIBLE >= 1999 || __BSD_VISIBLE
 int	 snprintf(char * __restrict, size_t, const char * __restrict, ...)
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 48763d7..29665e5 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -378,6 +378,15 @@
 # define __USE_BSD 1
 #endif
 
+/*
+ * _FILE_OFFSET_BITS 64 support.
+ */
+#if !defined(__LP64__) && defined(_FILE_OFFSET_BITS)
+#if _FILE_OFFSET_BITS == 64
+#define __USE_FILE_OFFSET64 1
+#endif
+#endif
+
 /*-
  * POSIX.1 requires that the macros we test be defined before any standard
  * header file is included.
diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h
index 1663222..6857f60 100644
--- a/libc/include/sys/mman.h
+++ b/libc/include/sys/mman.h
@@ -49,8 +49,13 @@
 #define POSIX_MADV_WILLNEED   MADV_WILLNEED
 #define POSIX_MADV_DONTNEED   MADV_DONTNEED
 
+#if defined(__USE_FILE_OFFSET64)
+extern void* mmap(void*, size_t, int, int, int, off_t) __RENAME(mmap64);
+#else
 extern void* mmap(void*, size_t, int, int, int, off_t);
+#endif
 extern void* mmap64(void*, size_t, int, int, int, off64_t);
+
 extern int munmap(void*, size_t);
 extern int msync(const void*, size_t, int);
 extern int mprotect(const void*, size_t, int);
diff --git a/libc/include/sys/sendfile.h b/libc/include/sys/sendfile.h
index 81a3c44..c588e68 100644
--- a/libc/include/sys/sendfile.h
+++ b/libc/include/sys/sendfile.h
@@ -34,7 +34,11 @@
 
 __BEGIN_DECLS
 
+#if defined(__USE_FILE_OFFSET64)
+extern ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) __RENAME(sendfile64);
+#else
 extern ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);
+#endif
 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 a5fa692..a6b0fd8 100644
--- a/libc/include/sys/types.h
+++ b/libc/include/sys/types.h
@@ -90,16 +90,14 @@
 typedef __kernel_time_t __time_t;
 typedef __time_t time_t;
 
-/* This historical accident means that we had a 32-bit off_t on 32-bit architectures. */
-#if !defined(__LP64__)
-typedef __kernel_off_t off_t;
-typedef __kernel_loff_t loff_t;
+#if defined(__USE_FILE_OFFSET64) || defined(__LP64__)
+typedef int64_t off_t;
+typedef off_t loff_t;
 typedef loff_t off64_t;
 #else
-/* We could re-use the LP32 definitions, but that would mean that although off_t and loff_t/off64_t
- * would be the same size, they wouldn't actually be the same type, which can lead to warnings. */
+/* This historical accident means that we had a 32-bit off_t on 32-bit architectures. */
 typedef __kernel_off_t off_t;
-typedef off_t loff_t;
+typedef __kernel_loff_t loff_t;
 typedef loff_t off64_t;
 #endif
 
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 6403d4a..25d48b6 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -146,22 +146,14 @@
 extern int fchown(int, uid_t, gid_t);
 extern int fchownat(int, const char*, uid_t, gid_t, int);
 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);
 
 extern int close(int);
-extern off_t lseek(int, off_t, int);
-extern off64_t lseek64(int, off64_t, int);
 
 extern ssize_t read(int, void *, size_t);
 extern ssize_t write(int, const void *, size_t);
-extern ssize_t pread(int, void *, size_t, off_t);
-extern ssize_t pread64(int, void *, size_t, off64_t);
-extern ssize_t pwrite(int, const void *, size_t, off_t);
-extern ssize_t pwrite64(int, const void *, size_t, off64_t);
 
 extern int dup(int);
 extern int dup2(int, int);
@@ -171,7 +163,24 @@
 extern int flock(int, int);
 extern int fsync(int);
 extern int fdatasync(int);
+
+#if defined(__USE_FILE_OFFSET64)
+extern int truncate(const char *, off_t) __RENAME(truncate64);
+extern off_t lseek(int, off_t, int) __RENAME(lseek64);
+extern ssize_t pread(int, void *, size_t, off_t) __RENAME(pread64);
+extern ssize_t pwrite(int, const void *, size_t, off_t) __RENAME(pwrite64);
+extern int ftruncate(int, off_t) __RENAME(ftruncate64);
+#else
+extern int truncate(const char *, off_t);
+extern off_t lseek(int, off_t, int);
+extern ssize_t pread(int, void *, size_t, off_t);
+extern ssize_t pwrite(int, const void *, size_t, off_t);
 extern int ftruncate(int, off_t);
+#endif
+extern int truncate64(const char *, off64_t);
+extern off64_t lseek64(int, off64_t, int);
+extern ssize_t pread64(int, void *, size_t, off64_t);
+extern ssize_t pwrite64(int, const void *, size_t, off64_t);
 extern int ftruncate64(int, off64_t);
 
 extern int pause(void);