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 41 namespace webrtc { 42 namespace test { 43 44 namespace { 45 46 #ifdef WIN32 47 const char* kPathDelimiter = "\\"; 48 #else 49 const char* kPathDelimiter = "/"; 50 #endif 51 52 #ifdef WEBRTC_ANDROID 53 const char* kResourcesDirName = "resources"; 54 #else 55 // The file we're looking for to identify the project root dir. 56 const char* kProjectRootFileName = "DEPS"; 57 const char* kResourcesDirName = "resources"; 58 #endif 59 60 const char* kFallbackPath = "./"; 61 const char* kOutputDirName = "out"; 62 char relative_dir_path[FILENAME_MAX]; 63 bool relative_dir_path_set = false; 64 65 } // namespace 66 67 const char* kCannotFindProjectRootDir = "ERROR_CANNOT_FIND_PROJECT_ROOT_DIR"; 68 69 std::string OutputPathAndroid(); 70 std::string ProjectRootPathAndroid(); 71 72 void 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 93 bool FileExists(std::string& file_name) { 94 struct stat file_info = {0}; 95 return stat(file_name.c_str(), &file_info) == 0; 96 } 97 98 std::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 112 std::string ProjectRootPath() { 113 return ProjectRootPathAndroid(); 114 } 115 116 std::string OutputPath() { 117 return OutputPathAndroid(); 118 } 119 120 std::string WorkingDir() { 121 return ProjectRootPath(); 122 } 123 124 #else // WEBRTC_ANDROID 125 126 std::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 150 std::string OutputPath() { 151 return OutputPathImpl(); 152 } 153 154 std::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. 168 std::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 194 bool 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 214 std::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 251 size_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