Add fallocate/fallocate64/posix_fallocate/posix_fallocate64.
Bug: 5287571
Bug: 12612860
Change-Id: I4501b9c6cdf9a830336ce0b3afc4ea716b6a0f6f
diff --git a/libc/Android.mk b/libc/Android.mk
index ea46bf9..7edadd7 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -232,6 +232,7 @@
bionic/pause.cpp \
bionic/pipe.cpp \
bionic/poll.cpp \
+ bionic/posix_fallocate.cpp \
bionic/pthread_atfork.cpp \
bionic/pthread_attr.cpp \
bionic/pthread_cond.cpp \
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 0951648..0555983 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -169,6 +169,9 @@
# (mmap only gets two lines because we only used the 64-bit variant on 32-bit systems.)
void* __mmap2:mmap2(void*, size_t, int, int, int, long) arm,mips,x86
void* mmap|mmap64(void*, size_t, int, int, int, off_t) arm64,x86_64
+# (fallocate only gets two lines because there is no 32-bit variant.)
+int fallocate64:fallocate(int, int, off64_t, off64_t) arm,mips,x86
+int fallocate|fallocate64(int, int, off_t, off_t) arm64,x86_64
# file system
int chdir(const char*) all
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index 83e6a97..f039bcb 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -56,6 +56,7 @@
syscall_src += arch-arm/syscalls/eventfd.S
syscall_src += arch-arm/syscalls/execve.S
syscall_src += arch-arm/syscalls/faccessat.S
+syscall_src += arch-arm/syscalls/fallocate64.S
syscall_src += arch-arm/syscalls/fchdir.S
syscall_src += arch-arm/syscalls/fchmod.S
syscall_src += arch-arm/syscalls/fchmodat.S
diff --git a/libc/arch-arm/syscalls/fallocate64.S b/libc/arch-arm/syscalls/fallocate64.S
new file mode 100644
index 0000000..c6992b0
--- /dev/null
+++ b/libc/arch-arm/syscalls/fallocate64.S
@@ -0,0 +1,22 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(fallocate64)
+ mov ip, sp
+ stmfd sp!, {r4, r5, r6, r7}
+ .cfi_def_cfa_offset 16
+ .cfi_rel_offset r4, 0
+ .cfi_rel_offset r5, 4
+ .cfi_rel_offset r6, 8
+ .cfi_rel_offset r7, 12
+ ldmfd ip, {r4, r5, r6}
+ ldr r7, =__NR_fallocate
+ swi #0
+ ldmfd sp!, {r4, r5, r6, r7}
+ .cfi_def_cfa_offset 0
+ cmn r0, #(MAX_ERRNO + 1)
+ bxls lr
+ neg r0, r0
+ b __set_errno
+END(fallocate64)
diff --git a/libc/arch-arm64/syscalls.mk b/libc/arch-arm64/syscalls.mk
index f1de5a5..07ad5d5 100644
--- a/libc/arch-arm64/syscalls.mk
+++ b/libc/arch-arm64/syscalls.mk
@@ -48,6 +48,7 @@
syscall_src += arch-arm64/syscalls/eventfd.S
syscall_src += arch-arm64/syscalls/execve.S
syscall_src += arch-arm64/syscalls/faccessat.S
+syscall_src += arch-arm64/syscalls/fallocate.S
syscall_src += arch-arm64/syscalls/fchdir.S
syscall_src += arch-arm64/syscalls/fchmod.S
syscall_src += arch-arm64/syscalls/fchmodat.S
diff --git a/libc/arch-arm64/syscalls/fallocate.S b/libc/arch-arm64/syscalls/fallocate.S
new file mode 100644
index 0000000..e79b96a
--- /dev/null
+++ b/libc/arch-arm64/syscalls/fallocate.S
@@ -0,0 +1,24 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(fallocate)
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+ str x8, [sp, #-16]!
+
+ mov x8, __NR_fallocate
+ svc #0
+
+ ldr x8, [sp], #16
+ ldp x29, x30, [sp], #16
+
+ cmn x0, #(MAX_ERRNO + 1)
+ cneg x0, x0, hi
+ b.hi __set_errno
+
+ ret
+END(fallocate)
+
+ .globl _C_LABEL(fallocate64)
+ .equ _C_LABEL(fallocate64), _C_LABEL(fallocate)
diff --git a/libc/arch-mips/syscalls.mk b/libc/arch-mips/syscalls.mk
index 8d87b29..a376c12 100644
--- a/libc/arch-mips/syscalls.mk
+++ b/libc/arch-mips/syscalls.mk
@@ -56,6 +56,7 @@
syscall_src += arch-mips/syscalls/eventfd.S
syscall_src += arch-mips/syscalls/execve.S
syscall_src += arch-mips/syscalls/faccessat.S
+syscall_src += arch-mips/syscalls/fallocate64.S
syscall_src += arch-mips/syscalls/fchdir.S
syscall_src += arch-mips/syscalls/fchmod.S
syscall_src += arch-mips/syscalls/fchmodat.S
diff --git a/libc/arch-mips/syscalls/fallocate64.S b/libc/arch-mips/syscalls/fallocate64.S
new file mode 100644
index 0000000..e844d16
--- /dev/null
+++ b/libc/arch-mips/syscalls/fallocate64.S
@@ -0,0 +1,23 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <asm/unistd.h>
+ .text
+ .globl fallocate64
+ .align 4
+ .ent fallocate64
+
+fallocate64:
+ .set noreorder
+ .cpload $t9
+ li $v0, __NR_fallocate
+ syscall
+ bnez $a3, 1f
+ move $a0, $v0
+ j $ra
+ nop
+1:
+ la $t9,__set_errno
+ j $t9
+ nop
+ .set reorder
+ .end fallocate64
diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk
index b7d1e08..6d368b3 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -55,6 +55,7 @@
syscall_src += arch-x86/syscalls/eventfd.S
syscall_src += arch-x86/syscalls/execve.S
syscall_src += arch-x86/syscalls/faccessat.S
+syscall_src += arch-x86/syscalls/fallocate64.S
syscall_src += arch-x86/syscalls/fchdir.S
syscall_src += arch-x86/syscalls/fchmod.S
syscall_src += arch-x86/syscalls/fchmodat.S
diff --git a/libc/arch-x86/syscalls/fallocate64.S b/libc/arch-x86/syscalls/fallocate64.S
new file mode 100644
index 0000000..7e03c54
--- /dev/null
+++ b/libc/arch-x86/syscalls/fallocate64.S
@@ -0,0 +1,42 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(fallocate64)
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+ .cfi_def_cfa_offset 24
+ .cfi_rel_offset ebx, 0
+ .cfi_rel_offset ecx, 4
+ .cfi_rel_offset edx, 8
+ .cfi_rel_offset esi, 12
+ .cfi_rel_offset edi, 16
+ .cfi_rel_offset ebp, 20
+ mov 28(%esp), %ebx
+ mov 32(%esp), %ecx
+ mov 36(%esp), %edx
+ mov 40(%esp), %esi
+ mov 44(%esp), %edi
+ mov 48(%esp), %ebp
+ movl $__NR_fallocate, %eax
+ int $0x80
+ cmpl $-MAX_ERRNO, %eax
+ jb 1f
+ negl %eax
+ pushl %eax
+ call __set_errno
+ addl $4, %esp
+ orl $-1, %eax
+1:
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %edx
+ popl %ecx
+ popl %ebx
+ ret
+END(fallocate64)
diff --git a/libc/arch-x86_64/syscalls.mk b/libc/arch-x86_64/syscalls.mk
index ec09e77..13d921a 100644
--- a/libc/arch-x86_64/syscalls.mk
+++ b/libc/arch-x86_64/syscalls.mk
@@ -49,6 +49,7 @@
syscall_src += arch-x86_64/syscalls/eventfd.S
syscall_src += arch-x86_64/syscalls/execve.S
syscall_src += arch-x86_64/syscalls/faccessat.S
+syscall_src += arch-x86_64/syscalls/fallocate.S
syscall_src += arch-x86_64/syscalls/fchdir.S
syscall_src += arch-x86_64/syscalls/fchmod.S
syscall_src += arch-x86_64/syscalls/fchmodat.S
diff --git a/libc/arch-x86_64/syscalls/fallocate.S b/libc/arch-x86_64/syscalls/fallocate.S
new file mode 100644
index 0000000..e6959ca
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/fallocate.S
@@ -0,0 +1,20 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(fallocate)
+ movq %rcx, %r10
+ movl $__NR_fallocate, %eax
+ syscall
+ cmpq $-MAX_ERRNO, %rax
+ jb 1f
+ negl %eax
+ movl %eax, %edi
+ call __set_errno
+ orq $-1, %rax
+1:
+ ret
+END(fallocate)
+
+ .globl _C_LABEL(fallocate64)
+ .equ _C_LABEL(fallocate64), _C_LABEL(fallocate)
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index d7ccdb9..411daa0 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -27,6 +27,7 @@
*/
#include <errno.h>
+#include <fcntl.h>
#include <stdarg.h>
#include <sys/resource.h>
#include <sys/types.h>
@@ -86,6 +87,11 @@
return pwrite64(fd, buf, byte_count, static_cast<off64_t>(offset));
}
+// There is no fallocate for 32-bit off_t, so we need to widen and call fallocate64.
+int fallocate(int fd, int mode, off_t offset, off_t length) {
+ return fallocate64(fd, mode, static_cast<off64_t>(offset), static_cast<off64_t>(length));
+}
+
// There is no getrlimit64 system call, so we need to use prlimit64.
int getrlimit64(int resource, rlimit64* limits64) {
return prlimit64(0, resource, NULL, limits64);
diff --git a/libc/bionic/posix_fallocate.cpp b/libc/bionic/posix_fallocate.cpp
new file mode 100644
index 0000000..bdc1636
--- /dev/null
+++ b/libc/bionic/posix_fallocate.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+
+#include "private/ErrnoRestorer.h"
+
+int posix_fallocate(int fd, off_t offset, off_t length) {
+ ErrnoRestorer errno_restorer;
+ return (fallocate(fd, 0, offset, length) == 0) ? 0 : errno;
+}
+
+int posix_fallocate64(int fd, off64_t offset, off64_t length) {
+ ErrnoRestorer errno_restorer;
+ return (fallocate64(fd, 0, offset, length) == 0) ? 0 : errno;
+}
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index f6a89ef..b7b91f2 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -41,11 +41,15 @@
#define O_ASYNC FASYNC
#endif
-extern int open(const char* path, int mode, ...);
-extern int openat(int fd, const char* path, int mode, ...);
-extern int unlinkat(int dirfd, const char *pathname, int flags);
-extern int fcntl(int fd, int command, ...);
-extern int creat(const char* path, mode_t mode);
+extern int creat(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 open(const char*, int, ...);
+extern int posix_fallocate64(int, off64_t, off64_t);
+extern int posix_fallocate(int, off_t, off_t);
+extern int unlinkat(int, const char*, int);
#if defined(__BIONIC_FORTIFY)
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index a094fac..d14243e 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -19,6 +19,8 @@
#include <errno.h>
#include <fcntl.h>
+#include "TemporaryFile.h"
+
TEST(fcntl, fcntl_smoke) {
int fd = open("/proc/version", O_RDONLY);
ASSERT_TRUE(fd != -1);
@@ -34,3 +36,50 @@
ASSERT_TRUE(flags != -1);
ASSERT_EQ(FD_CLOEXEC, flags & FD_CLOEXEC);
}
+
+TEST(fcntl, fallocate_EINVAL) {
+ TemporaryFile tf;
+
+#if !defined(__GLIBC__)
+ errno = 0;
+ ASSERT_EQ(-1, fallocate(tf.fd, 0, 0, -1));
+ ASSERT_EQ(EINVAL, errno);
+
+ errno = 0;
+ ASSERT_EQ(-1, fallocate64(tf.fd, 0, 0, -1));
+ ASSERT_EQ(EINVAL, errno);
+#endif
+
+ errno = 0;
+ ASSERT_EQ(EINVAL, posix_fallocate(tf.fd, 0, -1));
+ ASSERT_EQ(0, errno);
+
+ errno = 0;
+ ASSERT_EQ(EINVAL, posix_fallocate64(tf.fd, 0, -1));
+ ASSERT_EQ(0, errno);
+}
+
+TEST(fcntl, fallocate) {
+ TemporaryFile tf;
+ struct stat sb;
+ ASSERT_EQ(0, fstat(tf.fd, &sb));
+ ASSERT_EQ(0, sb.st_size);
+
+#if !defined(__GLIBC__)
+ ASSERT_EQ(0, fallocate(tf.fd, 0, 0, 1));
+ ASSERT_EQ(0, fstat(tf.fd, &sb));
+ ASSERT_EQ(1, sb.st_size);
+
+ ASSERT_EQ(0, fallocate64(tf.fd, 0, 0, 2));
+ ASSERT_EQ(0, fstat(tf.fd, &sb));
+ ASSERT_EQ(2, sb.st_size);
+#endif
+
+ ASSERT_EQ(0, posix_fallocate(tf.fd, 0, 3));
+ ASSERT_EQ(0, fstat(tf.fd, &sb));
+ ASSERT_EQ(3, sb.st_size);
+
+ ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, 4));
+ ASSERT_EQ(0, fstat(tf.fd, &sb));
+ ASSERT_EQ(4, sb.st_size);
+}