1/* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/test/testsupport/fileutils.h" 12 13#include <assert.h> 14 15#ifdef WIN32 16#include <direct.h> 17#include <tchar.h> 18#include <windows.h> 19#include <algorithm> 20 21#include "webrtc/system_wrappers/interface/utf_util_win.h" 22#define GET_CURRENT_DIR _getcwd 23#else 24#include <unistd.h> 25 26#include "webrtc/system_wrappers/interface/scoped_ptr.h" 27#define GET_CURRENT_DIR getcwd 28#endif 29 30#include <sys/stat.h> // To check for directory existence. 31#ifndef S_ISDIR // Not defined in stat.h on Windows. 32#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 33#endif 34 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38 39#include "webrtc/typedefs.h" // For architecture defines 40 41namespace webrtc { 42namespace test { 43 44namespace { 45 46#ifdef WIN32 47const char* kPathDelimiter = "\\"; 48#else 49const char* kPathDelimiter = "/"; 50#endif 51 52#ifdef WEBRTC_ANDROID 53const char* kResourcesDirName = "resources"; 54#else 55// The file we're looking for to identify the project root dir. 56const char* kProjectRootFileName = "DEPS"; 57const char* kResourcesDirName = "resources"; 58#endif 59 60const char* kFallbackPath = "./"; 61const char* kOutputDirName = "out"; 62char relative_dir_path[FILENAME_MAX]; 63bool relative_dir_path_set = false; 64 65} // namespace 66 67const char* kCannotFindProjectRootDir = "ERROR_CANNOT_FIND_PROJECT_ROOT_DIR"; 68 69std::string OutputPathAndroid(); 70std::string ProjectRootPathAndroid(); 71 72void SetExecutablePath(const std::string& path) { 73 std::string working_dir = WorkingDir(); 74 std::string temp_path = path; 75 76 // Handle absolute paths; convert them to relative paths to the working dir. 77 if (path.find(working_dir) != std::string::npos) { 78 temp_path = path.substr(working_dir.length() + 1); 79 } 80 // On Windows, when tests are run under memory tools like DrMemory and TSan, 81 // slashes occur in the path as directory separators. Make sure we replace 82 // such cases with backslashes in order for the paths to be correct. 83#ifdef WIN32 84 std::replace(temp_path.begin(), temp_path.end(), '/', '\\'); 85#endif 86 87 // Trim away the executable name; only store the relative dir path. 88 temp_path = temp_path.substr(0, temp_path.find_last_of(kPathDelimiter)); 89 strncpy(relative_dir_path, temp_path.c_str(), FILENAME_MAX); 90 relative_dir_path_set = true; 91} 92 93bool FileExists(std::string& file_name) { 94 struct stat file_info = {0}; 95 return stat(file_name.c_str(), &file_info) == 0; 96} 97 98std::string OutputPathImpl() { 99 std::string path = ProjectRootPath(); 100 if (path == kCannotFindProjectRootDir) { 101 return kFallbackPath; 102 } 103 path += kOutputDirName; 104 if (!CreateDir(path)) { 105 return kFallbackPath; 106 } 107 return path + kPathDelimiter; 108} 109 110#ifdef WEBRTC_ANDROID 111 112std::string ProjectRootPath() { 113 return ProjectRootPathAndroid(); 114} 115 116std::string OutputPath() { 117 return OutputPathAndroid(); 118} 119 120std::string WorkingDir() { 121 return ProjectRootPath(); 122} 123 124#else // WEBRTC_ANDROID 125 126std::string ProjectRootPath() { 127 std::string path = WorkingDir(); 128 if (path == kFallbackPath) { 129 return kCannotFindProjectRootDir; 130 } 131 if (relative_dir_path_set) { 132 path = path + kPathDelimiter + relative_dir_path; 133 } 134 // Check for our file that verifies the root dir. 135 size_t path_delimiter_index = path.find_last_of(kPathDelimiter); 136 while (path_delimiter_index != std::string::npos) { 137 std::string root_filename = path + kPathDelimiter + kProjectRootFileName; 138 if (FileExists(root_filename)) { 139 return path + kPathDelimiter; 140 } 141 // Move up one directory in the directory tree. 142 path = path.substr(0, path_delimiter_index); 143 path_delimiter_index = path.find_last_of(kPathDelimiter); 144 } 145 // Reached the root directory. 146 fprintf(stderr, "Cannot find project root directory!\n"); 147 return kCannotFindProjectRootDir; 148} 149 150std::string OutputPath() { 151 return OutputPathImpl(); 152} 153 154std::string WorkingDir() { 155 char path_buffer[FILENAME_MAX]; 156 if (!GET_CURRENT_DIR(path_buffer, sizeof(path_buffer))) { 157 fprintf(stderr, "Cannot get current directory!\n"); 158 return kFallbackPath; 159 } else { 160 return std::string(path_buffer); 161 } 162} 163 164#endif // !WEBRTC_ANDROID 165 166// Generate a temporary filename in a safe way. 167// Largely copied from talk/base/{unixfilesystem,win32filesystem}.cc. 168std::string TempFilename(const std::string &dir, const std::string &prefix) { 169#ifdef WIN32 170 wchar_t filename[MAX_PATH]; 171 if (::GetTempFileName(ToUtf16(dir).c_str(), 172 ToUtf16(prefix).c_str(), 0, filename) != 0) 173 return ToUtf8(filename); 174 assert(false); 175 return ""; 176#else 177 int len = dir.size() + prefix.size() + 2 + 6; 178 scoped_ptr<char[]> tempname(new char[len]); 179 180 snprintf(tempname.get(), len, "%s/%sXXXXXX", dir.c_str(), 181 prefix.c_str()); 182 int fd = ::mkstemp(tempname.get()); 183 if (fd == -1) { 184 assert(false); 185 return ""; 186 } else { 187 ::close(fd); 188 } 189 std::string ret(tempname.get()); 190 return ret; 191#endif 192} 193 194bool CreateDir(std::string directory_name) { 195 struct stat path_info = {0}; 196 // Check if the path exists already: 197 if (stat(directory_name.c_str(), &path_info) == 0) { 198 if (!S_ISDIR(path_info.st_mode)) { 199 fprintf(stderr, "Path %s exists but is not a directory! Remove this " 200 "file and re-run to create the directory.\n", 201 directory_name.c_str()); 202 return false; 203 } 204 } else { 205#ifdef WIN32 206 return _mkdir(directory_name.c_str()) == 0; 207#else 208 return mkdir(directory_name.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0; 209#endif 210 } 211 return true; 212} 213 214std::string ResourcePath(std::string name, std::string extension) { 215 std::string platform = "win"; 216#ifdef WEBRTC_LINUX 217 platform = "linux"; 218#endif // WEBRTC_LINUX 219#ifdef WEBRTC_MAC 220 platform = "mac"; 221#endif // WEBRTC_MAC 222 223#ifdef WEBRTC_ARCH_64_BITS 224 std::string architecture = "64"; 225#else 226 std::string architecture = "32"; 227#endif // WEBRTC_ARCH_64_BITS 228 229 std::string resources_path = ProjectRootPath() + kResourcesDirName + 230 kPathDelimiter; 231 std::string resource_file = resources_path + name + "_" + platform + "_" + 232 architecture + "." + extension; 233 if (FileExists(resource_file)) { 234 return resource_file; 235 } 236 // Try without architecture. 237 resource_file = resources_path + name + "_" + platform + "." + extension; 238 if (FileExists(resource_file)) { 239 return resource_file; 240 } 241 // Try without platform. 242 resource_file = resources_path + name + "_" + architecture + "." + extension; 243 if (FileExists(resource_file)) { 244 return resource_file; 245 } 246 247 // Fall back on name without architecture or platform. 248 return resources_path + name + "." + extension; 249} 250 251size_t GetFileSize(std::string filename) { 252 FILE* f = fopen(filename.c_str(), "rb"); 253 size_t size = 0; 254 if (f != NULL) { 255 if (fseek(f, 0, SEEK_END) == 0) { 256 size = ftell(f); 257 } 258 fclose(f); 259 } 260 return size; 261} 262 263} // namespace test 264} // namespace webrtc 265