| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/os_compat_android.h" |
| |
| #include <asm/unistd.h> |
| #include <errno.h> |
| #include <limits.h> |
| #include <math.h> |
| #include <sys/stat.h> |
| #include <sys/syscall.h> |
| #include <unistd.h> |
| #include "base/strings/string_util.h" |
| |
| #if !defined(__LP64__) |
| #include <time64.h> |
| #endif |
| |
| #include "base/files/file.h" |
| #include "base/rand_util.h" |
| #include "base/strings/string_piece.h" |
| |
| extern "C" { |
| // There is no futimes() avaiable in Bionic, so we provide our own |
| // implementation until it is there. |
| int futimes(int fd, const struct timeval tv[2]) { |
| if (tv == NULL) |
| return syscall(__NR_utimensat, fd, NULL, NULL, 0); |
| |
| if (tv[0].tv_usec < 0 || tv[0].tv_usec >= 1000000 || |
| tv[1].tv_usec < 0 || tv[1].tv_usec >= 1000000) { |
| errno = EINVAL; |
| return -1; |
| } |
| |
| // Convert timeval to timespec. |
| struct timespec ts[2]; |
| ts[0].tv_sec = tv[0].tv_sec; |
| ts[0].tv_nsec = tv[0].tv_usec * 1000; |
| ts[1].tv_sec = tv[1].tv_sec; |
| ts[1].tv_nsec = tv[1].tv_usec * 1000; |
| return syscall(__NR_utimensat, fd, NULL, ts, 0); |
| } |
| |
| #if !defined(__LP64__) |
| // 32-bit Android has only timegm64() and not timegm(). |
| // We replicate the behaviour of timegm() when the result overflows time_t. |
| time_t timegm(struct tm* const t) { |
| // time_t is signed on Android. |
| static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1)); |
| static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1)); |
| time64_t result = timegm64(t); |
| if (result < kTimeMin || result > kTimeMax) |
| return -1; |
| return result; |
| } |
| #endif |
| |
| // The following is only needed when building with GCC 4.6 or higher |
| // (i.e. not with Android GCC 4.4.3, nor with Clang). |
| // |
| // GCC is now capable of optimizing successive calls to sin() and cos() into |
| // a single call to sincos(). This means that source code that looks like: |
| // |
| // double c, s; |
| // c = cos(angle); |
| // s = sin(angle); |
| // |
| // Will generate machine code that looks like: |
| // |
| // double c, s; |
| // sincos(angle, &s, &c); |
| // |
| // Unfortunately, sincos() and friends are not part of the Android libm.so |
| // library provided by the NDK for API level 9. When the optimization kicks |
| // in, it makes the final build fail with a puzzling message (puzzling |
| // because 'sincos' doesn't appear anywhere in the sources!). |
| // |
| // To solve this, we provide our own implementation of the sincos() function |
| // and related friends. Note that we must also explicitely tell GCC to disable |
| // optimizations when generating these. Otherwise, the generated machine code |
| // for each function would simply end up calling itself, resulting in a |
| // runtime crash due to stack overflow. |
| // |
| #if defined(__GNUC__) && !defined(__clang__) && \ |
| !defined(ANDROID_SINCOS_PROVIDED) |
| |
| // For the record, Clang does not support the 'optimize' attribute. |
| // In the unlikely event that it begins performing this optimization too, |
| // we'll have to find a different way to achieve this. NOTE: Tested with O1 |
| // which still performs the optimization. |
| // |
| #define GCC_NO_OPTIMIZE __attribute__((optimize("O0"))) |
| |
| GCC_NO_OPTIMIZE |
| void sincos(double angle, double* s, double *c) { |
| *c = cos(angle); |
| *s = sin(angle); |
| } |
| |
| GCC_NO_OPTIMIZE |
| void sincosf(float angle, float* s, float* c) { |
| *c = cosf(angle); |
| *s = sinf(angle); |
| } |
| |
| #endif // __GNUC__ && !__clang__ |
| |
| // An implementation of mkdtemp, since it is not exposed by the NDK |
| // for native API level 9 that we target. |
| // |
| // For any changes in the mkdtemp function, you should manually run the unittest |
| // OsCompatAndroidTest.DISABLED_TestMkdTemp in your local machine to check if it |
| // passes. Please don't enable it, since it creates a directory and may be |
| // source of flakyness. |
| char* mkdtemp(char* path) { |
| if (!path) { |
| errno = EINVAL; |
| return nullptr; |
| } |
| |
| const int path_len = strlen(path); |
| |
| // The last six characters of 'path' must be XXXXXX. |
| const base::StringPiece kSuffix("XXXXXX"); |
| const int kSuffixLen = kSuffix.length(); |
| if (!base::EndsWith(base::StringPiece(path, path_len), kSuffix)) { |
| errno = EINVAL; |
| return nullptr; |
| } |
| |
| // If the path contains a directory, as in /tmp/foo/XXXXXXXX, make sure |
| // that /tmp/foo exists, otherwise we're going to loop a really long |
| // time for nothing below |
| char* dirsep = strrchr(path, '/'); |
| if (dirsep) { |
| *dirsep = '\0'; // Terminating directory path temporarily |
| |
| base::stat_wrapper_t st; |
| int ret = base::File::Stat(path, &st); |
| |
| *dirsep = '/'; // Restoring directory separator |
| if (ret < 0) // Directory probably does not exist |
| return nullptr; |
| if (!S_ISDIR(st.st_mode)) { // Not a directory |
| errno = ENOTDIR; |
| return nullptr; |
| } |
| } |
| |
| // Max number of tries using different random suffixes. |
| const int kMaxTries = 100; |
| |
| // Now loop until we CAN create a directory by that name or we reach the max |
| // number of tries. |
| for (int i = 0; i < kMaxTries; ++i) { |
| // Fill the suffix XXXXXX with a random string composed of a-z chars. |
| for (int pos = 0; pos < kSuffixLen; ++pos) { |
| char rand_char = static_cast<char>(base::RandInt('a', 'z')); |
| path[path_len - kSuffixLen + pos] = rand_char; |
| } |
| if (mkdir(path, 0700) == 0) { |
| // We just created the directory succesfully. |
| return path; |
| } |
| if (errno != EEXIST) { |
| // The directory doesn't exist, but an error occured |
| return nullptr; |
| } |
| } |
| |
| // We reached the max number of tries. |
| return nullptr; |
| } |
| |
| } // extern "C" |