blob: f6327c41f3d256354a36ec681bc3b0c0ae5505be [file] [log] [blame]
// Copyright 2016 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/utils/file_io.h"
#include "android/base/system/Win32UnicodeString.h"
#include "android/base/memory/ScopedPtr.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef _WIN32
#include <direct.h>
#include <windows.h>
using android::base::Win32UnicodeString;
using android::base::ScopedCPtr;
#endif
// Provide different macros for different number of string arguments where each
// string argument requires conversion
#ifdef _WIN32
#define WIDEN_CALL_1(func, str1, ...) \
_w ## func(Win32UnicodeString(str1).c_str() , ##__VA_ARGS__)
#define WIDEN_CALL_2(func, str1, str2, ...) \
_w ## func(Win32UnicodeString(str1).c_str(), \
Win32UnicodeString(str2).c_str() , ##__VA_ARGS__)
#else
#define WIDEN_CALL_1(func, str1, ...) func(str1 , ##__VA_ARGS__)
#define WIDEN_CALL_2(func, str1, str2, ...) func(str1, str2 , ##__VA_ARGS__)
#endif
extern "C" {
FILE* android_fopen(const char* path, const char* mode) {
return WIDEN_CALL_2(fopen, path, mode);
}
FILE* android_popen(const char* path, const char* mode) {
return WIDEN_CALL_2(popen, path, mode);
}
int android_open_without_mode(const char* path, int flags) {
return WIDEN_CALL_1(open, path, flags);
}
int android_open_with_mode(const char* path, int flags, mode_t mode) {
return WIDEN_CALL_1(open, path, flags, mode);
}
int android_stat(const char* path, struct stat* buf) {
#ifdef _WIN32
// Make sure we use the stat call that matches the type of stat struct we
// are getting. The incoming struct is a "struct _stati64" and this is the
// matching call for that struct. Unfortunately the macro doesn't take care
// of that.
return _wstati64(Win32UnicodeString(path).c_str(), buf);
#else
return stat(path, buf);
#endif
}
int android_lstat(const char* path, struct stat* buf) {
#ifdef _WIN32
// Windows doesn't seem to have an lstat function so just use regular stat
return android_stat(path, buf);
#else
return lstat(path, buf);
#endif
}
int android_access(const char* path, int mode) {
return WIDEN_CALL_1(access, path, mode);
}
#ifdef _WIN32
// The Windows version does not have a mode parameter so just drop that name to
// avoid compiler warnings about unused parameters
int android_mkdir(const char* path, mode_t) {
return _wmkdir(Win32UnicodeString(path).c_str());
}
#else
int android_mkdir(const char* path, mode_t mode) {
return mkdir(path, mode);
}
#endif
int android_creat(const char* path, mode_t mode) {
return WIDEN_CALL_1(creat, path, mode);
}
int android_unlink(const char* path) {
return WIDEN_CALL_1(unlink, path);
}
int android_chmod(const char* path, mode_t mode) {
return WIDEN_CALL_1(chmod, path, mode);
}
// The code below uses the fact that GCC supports something called weak linking.
// Several functions in glibc are weakly linked which means that if the same
// function name is found in the application binary that function will be used
// instead. On Windows we use this to change these calls to call the wchar_t
// equivalent function with the parameter converted from UTF-8 to UTF-16.
//
// Unfortunately stat is not weakly linked which is why it is not listed here
// and any code that calls stat should use android_stat instead.
#ifdef _WIN32
// getcwd cannot use the same macro as the other calls because it places data
// in one of its parameters and it returns a char pointer, not a result code
char* __cdecl getcwd(char* buffer, int maxlen) {
ScopedCPtr<wchar_t> wideCwd(_wgetcwd(nullptr, 0));
if (wideCwd.get() == nullptr) {
return nullptr;
}
if (buffer == nullptr) {
// This is a valid use case and we need to allocate memory and return it
auto narrowCwd = Win32UnicodeString::convertToUtf8(wideCwd.get());
return strdup(narrowCwd.c_str());
}
int written = Win32UnicodeString::convertToUtf8(buffer,
maxlen,
wideCwd.get());
if (written < 0 || written >= maxlen) {
return nullptr;
}
return buffer;
}
int __cdecl remove(const char* path) {
return WIDEN_CALL_1(remove, path);
}
int __cdecl rmdir(const char* dirname) {
return WIDEN_CALL_1(rmdir, dirname);
}
int __cdecl chmod(const char* filename, int pmode) {
return WIDEN_CALL_1(chmod, filename, pmode);
}
int __cdecl unlink(const char* filename) {
return WIDEN_CALL_1(unlink, filename);
}
int __cdecl mkdir(const char* dirname) {
return WIDEN_CALL_1(mkdir, dirname);
}
int __cdecl creat(const char* path, int mode) {
return WIDEN_CALL_1(creat, path, mode);
}
int __cdecl access(const char* path, int mode) {
return WIDEN_CALL_1(access, path, mode);
}
int __cdecl open(const char* pathname, int flags, ...) {
va_list ap;
// Since open comes in two versions and C does not support function
// overloading we use varargs for the mode parameters instead.
va_start(ap, flags);
int result = WIDEN_CALL_1(open, pathname, flags, va_arg(ap, int));
va_end(ap);
return result;
}
FILE* __cdecl fopen(const char* path, const char* mode) {
return WIDEN_CALL_2(fopen, path, mode);
}
#endif // _WIN32
} // extern "C"