Support off64_t for Android build

Android NDK R8e does not provide ftruncate64, but bionic has the
assembler code to access kernel function. We borrowed those
ftruncate64.S files from android source code repository.  It turns out
that x86 asm.h in NDK R8e is also broken, so latest asm.h was also
borrowed.
pull/89/head
Tatsuhiro Tsujikawa 2013-05-06 18:56:32 +09:00
parent 3a4acead2d
commit 5bc5665c6a
14 changed files with 368 additions and 14 deletions

View File

@ -67,6 +67,7 @@ AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_MKDIR_P
AC_PROG_YACC
AM_PROG_AS
AC_CHECK_TOOL([AR], [ar], [:])
if test "x$AR" = "x:"; then
@ -123,7 +124,14 @@ if test "x$with_libz" = "xyes"; then
fi
if test "x$have_zlib" = "xyes"; then
AC_DEFINE([HAVE_ZLIB], [1], [Define to 1 if you have zlib.])
AC_CHECK_FUNCS([gzbuffer gzsetparams])
# Android NDK arch-mips contains gzbuffer symbol but it is missing
# in zlib.h
AC_CHECK_DECL([gzbuffer], [have_decl_gzbuffer=yes], [],
[[#include <zlib.h>]])
if test "x$have_decl_gzbuffer" = "xyes"; then
AC_CHECK_FUNC([gzbuffer])
fi
AC_CHECK_FUNCS([gzsetparams])
fi
fi
@ -815,11 +823,26 @@ AC_SUBST([bashcompletiondir])
case "$host" in
*android*)
LIBS="$LIBS -lstdc++ -lsupc++"
case "$host" in
arm-*)
android_arm=yes
;;
mipsel-*)
android_mips=yes
;;
i686-*)
android_x86=yes
;;
esac
;;
*)
;;
esac
AM_CONDITIONAL([ANDROID_ARM], [test "x$android_arm" = "xyes"])
AM_CONDITIONAL([ANDROID_MIPS], [test "x$android_mips" = "xyes"])
AM_CONDITIONAL([ANDROID_X86], [test "x$android_x86" = "xyes"])
if test "x$ARIA2_STATIC" = "xyes"; then
LDFLAGS="$LDFLAGS -all-static -static-libgcc -static-libstdc++"
dnl For non-MinGW build, we need additional libs for static build.

View File

@ -324,7 +324,7 @@ void AbstractDiskWriter::seek(int64_t offset)
fileLength.QuadPart = offset;
if(SetFilePointerEx(fd_, fileLength, 0, FILE_BEGIN) == 0)
#else // !__MINGW32__
if(a2lseek(fd_, offset, SEEK_SET) == (off_t)-1)
if(a2lseek(fd_, offset, SEEK_SET) == (a2_off_t)-1)
#endif // !__MINGW32__
{
int errNum = fileError();
@ -453,7 +453,7 @@ void AbstractDiskWriter::truncate(int64_t length)
seek(length);
if(SetEndOfFile(fd_) == 0)
#else // !__MINGW32__
if(ftruncate(fd_, length) == -1)
if(a2ftruncate(fd_, length) == -1)
#endif // !__MINGW32__
{
int errNum = fileError();

View File

@ -493,7 +493,7 @@ bool FtpNegotiationCommand::recvSize() {
return false;
}
if(status == 213) {
if(size > std::numeric_limits<off_t>::max()) {
if(size > std::numeric_limits<a2_off_t>::max()) {
throw DL_ABORT_EX2(fmt(EX_TOO_LARGE_FILE, size),
error_code::FTP_PROTOCOL_ERROR);
}

View File

@ -100,7 +100,7 @@ Range HttpHeader::getRange() const
if(!util::parseLLIntNoThrow(contentLength, clenStr) ||
contentLength < 0) {
throw DL_ABORT_EX("Content-Length must be positive integer");
} else if(contentLength > std::numeric_limits<off_t>::max()) {
} else if(contentLength > std::numeric_limits<a2_off_t>::max()) {
throw DOWNLOAD_FAILURE_EXCEPTION
(fmt(EX_TOO_LARGE_FILE, contentLength));
} else if(contentLength == 0) {
@ -146,13 +146,13 @@ Range HttpHeader::getRange() const
startByte < 0 || endByte < 0 || entityLength < 0) {
throw DL_ABORT_EX("byte-range-spec must be positive");
}
if(startByte > std::numeric_limits<off_t>::max()) {
if(startByte > std::numeric_limits<a2_off_t>::max()) {
throw DOWNLOAD_FAILURE_EXCEPTION(fmt(EX_TOO_LARGE_FILE, startByte));
}
if(endByte > std::numeric_limits<off_t>::max()) {
if(endByte > std::numeric_limits<a2_off_t>::max()) {
throw DOWNLOAD_FAILURE_EXCEPTION(fmt(EX_TOO_LARGE_FILE, endByte));
}
if(entityLength > std::numeric_limits<off_t>::max()) {
if(entityLength > std::numeric_limits<a2_off_t>::max()) {
throw DOWNLOAD_FAILURE_EXCEPTION(fmt(EX_TOO_LARGE_FILE, entityLength));
}
return Range(startByte, endByte, entityLength);

View File

@ -256,6 +256,20 @@ SRCS = option_processing.cc\
FtpNegotiationConnectChain.h\
FtpTunnelRequestConnectChain.h
# Android NDK R8e does not provide ftruncate64. Use assembly code from
# android source code and link it.
if ANDROID_ARM
SRCS += android/arm-ftruncate64.S
endif # ANDROID_ARM
if ANDROID_MIPS
SRCS += android/mips-ftruncate64.S
endif # ANDROID_MIPS
if ANDROID_X86
SRCS += android/x86-ftruncate64.S android/x86-asm.h
endif # ANDROID_X86
if MINGW_BUILD
SRCS += WinConsoleFile.cc WinConsoleFile.h
endif # MINGW_BUILD

View File

@ -150,7 +150,7 @@ void SizeMetalinkParserState::endElement
// current metalink specification doesn't require size element.
int64_t size;
if(util::parseLLIntNoThrow(size, characters) && size >= 0 &&
size <= std::numeric_limits<off_t>::max()) {
size <= std::numeric_limits<a2_off_t>::max()) {
psm->setFileLengthOfEntry(size);
}
}

View File

@ -255,7 +255,7 @@ void SizeMetalinkParserStateV4::endElement
{
int64_t size;
if(util::parseLLIntNoThrow(size, characters) && size >= 0 &&
size <= std::numeric_limits<off_t>::max()) {
size <= std::numeric_limits<a2_off_t>::max()) {
psm->setFileLengthOfEntry(size);
} else {
psm->cancelEntryTransaction();

View File

@ -141,7 +141,37 @@
// For Windows, we share files for reading and writing.
# define a2open(path, flags, mode) _wsopen(path, flags, _SH_DENYNO, mode)
# define a2fopen(path, mode) _wfsopen(path, mode, _SH_DENYNO)
#else // !__MINGW32__
// # define a2ftruncate(fd, length): We don't use ftruncate in Mingw build
# define a2_off_t off_t
#elif defined(__ANDROID__) || defined(ANDROID)
# define a2lseek(fd, offset, origin) lseek64(fd, offset, origin)
// # define a2fseek(fp, offset, origin): No fseek64 and not used in aria2
# define a2fstat(fd, buf) fstat64(fd, buf)
// # define a2ftell(fd): No ftell64 and not used in aria2
# define a2_struct_stat struct stat
# define a2stat(path, buf) stat64(path, buf)
# define a2mkdir(path, openMode) mkdir(path, openMode)
# define a2utimbuf utimbuf
# define a2utime(path, times) ::utime(path, times)
# define a2unlink(path) unlink(path)
# define a2rmdir(path) rmdir(path)
# define a2rename(src, dest) rename(src, dest)
# define a2open(path, flags, mode) open(path, flags, mode)
# define a2fopen(path, mode) fopen(path, mode)
// Android NDK R8e does not provide ftruncate64 prototype, so let's
// define it here.
#ifdef __cplusplus
extern "C" {
#endif
extern int ftruncate64(int fd, off64_t length);
#ifdef __cplusplus
}
#endif
# define a2ftruncate(fd, length) ftruncate64(fd, length)
// Use off64_t directly since android does not offer transparent
// switching between off_t and off64_t.
# define a2_off_t off64_t
#else // !__MINGW32__ && !(defined(__ANDROID__) || defined(ANDROID))
# define a2lseek(fd, offset, origin) lseek(fd, offset, origin)
# define a2fseek(fp, offset, origin) fseek(fp, offset, origin)
# define a2fstat(fp, buf) fstat(fp, buf)
@ -156,7 +186,9 @@
# define a2rename(src, dest) rename(src, dest)
# define a2open(path, flags, mode) open(path, flags, mode)
# define a2fopen(path, mode) fopen(path, mode)
#endif // !__MINGW32__
# define a2ftruncate(fd, length) ftruncate(fd, length)
# define a2_off_t off_t
#endif
#define OPEN_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define DIR_OPEN_MODE S_IRWXU|S_IRWXG|S_IRWXO

2
src/android/README.rst Normal file
View File

@ -0,0 +1,2 @@
The files under this directory tree were copied from android source
code repository.

View File

@ -0,0 +1,15 @@
/* autogenerated by gensyscalls.py */
#include <asm/unistd.h>
#include <linux/err.h>
#include <machine/asm.h>
ENTRY(ftruncate64)
mov ip, r7
ldr r7, =__NR_ftruncate64
swi #0
mov r7, ip
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno
END(ftruncate64)

View File

@ -0,0 +1,22 @@
/* autogenerated by gensyscalls.py */
#include <asm/unistd.h>
.text
.globl ftruncate64
.align 4
.ent ftruncate64
ftruncate64:
.set noreorder
.cpload $t9
li $v0, __NR_ftruncate64
syscall
bnez $a3, 1f
move $a0, $v0
j $ra
nop
1:
la $t9,__set_errno
j $t9
nop
.set reorder
.end ftruncate64

218
src/android/x86-asm.h Normal file
View File

@ -0,0 +1,218 @@
/* $NetBSD: asm.h,v 1.40 2011/06/16 13:16:20 joerg Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)asm.h 5.5 (Berkeley) 5/7/91
*/
#ifndef _I386_ASM_H_
#define _I386_ASM_H_
#ifdef _KERNEL_OPT
#include "opt_multiprocessor.h"
#endif
#ifdef PIC
#define PIC_PROLOGUE \
pushl %ebx; \
call 1f; \
1: \
popl %ebx; \
addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
#define PIC_EPILOGUE \
popl %ebx
#define PIC_PLT(x) x@PLT
#define PIC_GOT(x) x@GOT(%ebx)
#define PIC_GOTOFF(x) x@GOTOFF(%ebx)
#else
#define PIC_PROLOGUE
#define PIC_EPILOGUE
#define PIC_PLT(x) x
#define PIC_GOT(x) x
#define PIC_GOTOFF(x) x
#endif
#ifdef __ELF__
# define _C_LABEL(x) x
#else
# ifdef __STDC__
# define _C_LABEL(x) _ ## x
# else
# define _C_LABEL(x) _/**/x
# endif
#endif
#define _ASM_LABEL(x) x
#define CVAROFF(x, y) _C_LABEL(x) + y
#ifdef __STDC__
# define __CONCAT(x,y) x ## y
# define __STRING(x) #x
#else
# define __CONCAT(x,y) x/**/y
# define __STRING(x) "x"
#endif
/* let kernels and others override entrypoint alignment */
#if !defined(_ALIGN_TEXT) && !defined(_KERNEL)
# ifdef _STANDALONE
# define _ALIGN_TEXT .align 1
# elif defined __ELF__
# define _ALIGN_TEXT .align 16
# else
# define _ALIGN_TEXT .align 4
# endif
#endif
#define _ENTRY(x) \
.text; _ALIGN_TEXT; .globl x; .type x,@function; x:
#define _LABEL(x) \
.globl x; x:
#ifdef _KERNEL
#define CPUVAR(off) %fs:__CONCAT(CPU_INFO_,off)
/* XXX Can't use __CONCAT() here, as it would be evaluated incorrectly. */
#ifdef __ELF__
#ifdef __STDC__
#define IDTVEC(name) \
ALIGN_TEXT; .globl X ## name; .type X ## name,@function; X ## name:
#define IDTVEC_END(name) \
.size X ## name, . - X ## name
#else
#define IDTVEC(name) \
ALIGN_TEXT; .globl X/**/name; .type X/**/name,@function; X/**/name:
#define IDTVEC_END(name) \
.size X/**/name, . - X/**/name
#endif /* __STDC__ */
#else
#ifdef __STDC__
#define IDTVEC(name) \
ALIGN_TEXT; .globl _X ## name; .type _X ## name,@function; _X ## name:
#define IDTVEC_END(name) \
.size _X ## name, . - _X ## name
#else
#define IDTVEC(name) \
ALIGN_TEXT; .globl _X/**/name; .type _X/**/name,@function; _X/**/name:
#define IDTVEC_END(name) \
.size _X/**/name, . - _X/**/name
#endif /* __STDC__ */
#endif /* __ELF__ */
#ifdef _STANDALONE
#define ALIGN_DATA .align 4
#define ALIGN_TEXT .align 4 /* 4-byte boundaries */
#define SUPERALIGN_TEXT .align 16 /* 15-byte boundaries */
#elif defined __ELF__
#define ALIGN_DATA .align 4
#define ALIGN_TEXT .align 16 /* 16-byte boundaries */
#define SUPERALIGN_TEXT .align 16 /* 16-byte boundaries */
#else
#define ALIGN_DATA .align 2
#define ALIGN_TEXT .align 4 /* 16-byte boundaries */
#define SUPERALIGN_TEXT .align 4 /* 16-byte boundaries */
#endif /* __ELF__ */
#define _ALIGN_TEXT ALIGN_TEXT
#ifdef GPROF
#ifdef __ELF__
#define MCOUNT_ASM call _C_LABEL(__mcount)
#else /* __ELF__ */
#define MCOUNT_ASM call _C_LABEL(mcount)
#endif /* __ELF__ */
#else /* GPROF */
#define MCOUNT_ASM /* nothing */
#endif /* GPROF */
#endif /* _KERNEL */
#ifdef GPROF
# ifdef __ELF__
# define _PROF_PROLOGUE \
pushl %ebp; movl %esp,%ebp; call PIC_PLT(__mcount); popl %ebp
# else
# define _PROF_PROLOGUE \
pushl %ebp; movl %esp,%ebp; call PIC_PLT(mcount); popl %ebp
# endif
#else
# define _PROF_PROLOGUE
#endif
#define ENTRY(y) _ENTRY(_C_LABEL(y)); _PROF_PROLOGUE
#define NENTRY(y) _ENTRY(_C_LABEL(y))
#define ASENTRY(y) _ENTRY(_ASM_LABEL(y)); _PROF_PROLOGUE
#define LABEL(y) _LABEL(_C_LABEL(y))
#define END(y) .size y, . - y
#define ASMSTR .asciz
#ifdef __ELF__
#define RCSID(x) .pushsection ".ident"; .asciz x; .popsection
#else
#define RCSID(x) .text; .asciz x
#endif
#ifdef NO_KERNEL_RCSIDS
#define __KERNEL_RCSID(_n, _s) /* nothing */
#else
#define __KERNEL_RCSID(_n, _s) RCSID(_s)
#endif
#ifdef __ELF__
#define WEAK_ALIAS(alias,sym) \
.weak alias; \
alias = sym
#endif
/*
* STRONG_ALIAS: create a strong alias.
*/
#define STRONG_ALIAS(alias,sym) \
.globl alias; \
alias = sym
#ifdef __STDC__
#define WARN_REFERENCES(sym,msg) \
.pushsection .gnu.warning. ## sym; \
.ascii msg; \
.popsection
#else
#define WARN_REFERENCES(sym,msg) \
.pushsection .gnu.warning./**/sym; \
.ascii msg; \
.popsection
#endif /* __STDC__ */
#endif /* !_I386_ASM_H_ */

View File

@ -0,0 +1,28 @@
/* autogenerated by gensyscalls.py */
#include <linux/err.h>
/* Android NDK R8e asm.h for x86 is broken. Use latest one from the repo */
#include "android/x86-asm.h"
#include <asm/unistd.h>
ENTRY(ftruncate64)
pushl %ebx
pushl %ecx
pushl %edx
mov 16(%esp), %ebx
mov 20(%esp), %ecx
mov 24(%esp), %edx
movl $__NR_ftruncate64, %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(ftruncate64)

View File

@ -251,7 +251,7 @@ void extractFileEntries
throw DOWNLOAD_FAILURE_EXCEPTION(fmt(EX_TOO_LARGE_FILE, length));
}
length += fileLengthData->i();
if(fileLengthData->i() > std::numeric_limits<off_t>::max()) {
if(fileLengthData->i() > std::numeric_limits<a2_off_t>::max()) {
throw DOWNLOAD_FAILURE_EXCEPTION(fmt(EX_TOO_LARGE_FILE, length));
}
std::string pathKey;
@ -310,7 +310,7 @@ void extractFileEntries
error_code::BITTORRENT_PARSE_ERROR);
}
int64_t totalLength = lengthData->i();
if(totalLength > std::numeric_limits<off_t>::max()) {
if(totalLength > std::numeric_limits<a2_off_t>::max()) {
throw DOWNLOAD_FAILURE_EXCEPTION(fmt(EX_TOO_LARGE_FILE, totalLength));
}
// For each uri in urlList, if it ends with '/', then