diff --git a/libc/Android.mk b/libc/Android.mk index ea46bf995..7edadd7d2 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -232,6 +232,7 @@ libc_bionic_src_files := \ 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 09516480d..0555983a0 100644 --- a/libc/SYSCALLS.TXT +++ b/libc/SYSCALLS.TXT @@ -169,6 +169,9 @@ int truncate|truncate64(const char*, off_t) arm64,x86_64 # (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 83e6a970d..f039bcb93 100644 --- a/libc/arch-arm/syscalls.mk +++ b/libc/arch-arm/syscalls.mk @@ -56,6 +56,7 @@ syscall_src += arch-arm/syscalls/epoll_ctl.S 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 000000000..c6992b01a --- /dev/null +++ b/libc/arch-arm/syscalls/fallocate64.S @@ -0,0 +1,22 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +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 f1de5a545..07ad5d531 100644 --- a/libc/arch-arm64/syscalls.mk +++ b/libc/arch-arm64/syscalls.mk @@ -48,6 +48,7 @@ syscall_src += arch-arm64/syscalls/epoll_ctl.S 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 000000000..e79b96a69 --- /dev/null +++ b/libc/arch-arm64/syscalls/fallocate.S @@ -0,0 +1,24 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +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 8d87b295f..a376c1286 100644 --- a/libc/arch-mips/syscalls.mk +++ b/libc/arch-mips/syscalls.mk @@ -56,6 +56,7 @@ syscall_src += arch-mips/syscalls/epoll_ctl.S 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 000000000..e844d1690 --- /dev/null +++ b/libc/arch-mips/syscalls/fallocate64.S @@ -0,0 +1,23 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + .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 b7d1e0834..6d368b32e 100644 --- a/libc/arch-x86/syscalls.mk +++ b/libc/arch-x86/syscalls.mk @@ -55,6 +55,7 @@ syscall_src += arch-x86/syscalls/epoll_ctl.S 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 000000000..7e03c548c --- /dev/null +++ b/libc/arch-x86/syscalls/fallocate64.S @@ -0,0 +1,42 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +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 ec09e7744..13d921a61 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/epoll_ctl.S 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 000000000..e6959ca65 --- /dev/null +++ b/libc/arch-x86_64/syscalls/fallocate.S @@ -0,0 +1,20 @@ +/* Generated by gensyscalls.py. Do not edit. */ + +#include + +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 d7ccdb95e..411daa005 100644 --- a/libc/bionic/legacy_32_bit_support.cpp +++ b/libc/bionic/legacy_32_bit_support.cpp @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -86,6 +87,11 @@ ssize_t pwrite(int fd, const void* buf, size_t byte_count, off_t offset) { return pwrite64(fd, buf, byte_count, static_cast(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(offset), static_cast(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 000000000..bdc1636b9 --- /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 + +#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 f6a89efdc..b7b91f233 100644 --- a/libc/include/fcntl.h +++ b/libc/include/fcntl.h @@ -41,11 +41,15 @@ __BEGIN_DECLS #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 a094fac3a..d14243e72 100644 --- a/tests/fcntl_test.cpp +++ b/tests/fcntl_test.cpp @@ -19,6 +19,8 @@ #include #include +#include "TemporaryFile.h" + TEST(fcntl, fcntl_smoke) { int fd = open("/proc/version", O_RDONLY); ASSERT_TRUE(fd != -1); @@ -34,3 +36,50 @@ TEST(fcntl, fcntl_smoke) { 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); +}