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/include/utf_util_win.h" 22 #define GET_CURRENT_DIR _getcwd 23 #else 24 #include <unistd.h> 25 26 #include "webrtc/base/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 #if defined(WEBRTC_IOS) 45 // Defined in iosfileutils.mm. No header file to discourage use elsewhere. 46 std::string IOSResourcePath(std::string name, std::string extension); 47 #endif 48 49 namespace { 50 51 #ifdef WIN32 52 const char* kPathDelimiter = "\\"; 53 #else 54 const char* kPathDelimiter = "/"; 55 #endif 56 57 #ifdef WEBRTC_ANDROID 58 const char* kRootDirName = "/sdcard/"; 59 #else 60 // The file we're looking for to identify the project root dir. 61 const char* kProjectRootFileName = "DEPS"; 62 const char* kOutputDirName = "out"; 63 const char* kFallbackPath = "./"; 64 #endif 65 #if !defined(WEBRTC_IOS) 66 const char* kResourcesDirName = "resources"; 67 #endif 68 69 char relative_dir_path[FILENAME_MAX]; 70 bool relative_dir_path_set = false; 71 72 } // namespace 73 74 const char* kCannotFindProjectRootDir = "ERROR_CANNOT_FIND_PROJECT_ROOT_DIR"; 75 76 void SetExecutablePath(const std::string& path) { 77 std::string working_dir = WorkingDir(); 78 std::string temp_path = path; 79 80 // Handle absolute paths; convert them to relative paths to the working dir. 81 if (path.find(working_dir) != std::string::npos) { 82 temp_path = path.substr(working_dir.length() + 1); 83 } 84 // On Windows, when tests are run under memory tools like DrMemory and TSan, 85 // slashes occur in the path as directory separators. Make sure we replace 86 // such cases with backslashes in order for the paths to be correct. 87 #ifdef WIN32 88 std::replace(temp_path.begin(), temp_path.end(), '/', '\\'); 89 #endif 90 91 // Trim away the executable name; only store the relative dir path. 92 temp_path = temp_path.substr(0, temp_path.find_last_of(kPathDelimiter)); 93 strncpy(relative_dir_path, temp_path.c_str(), FILENAME_MAX); 94 relative_dir_path_set = true; 95 } 96 97 bool FileExists(std::string& file_name) { 98 struct stat file_info = {0}; 99 return stat(file_name.c_str(), &file_info) == 0; 100 } 101 102 #ifdef WEBRTC_ANDROID 103 104 std::string ProjectRootPath() { 105 return kRootDirName; 106 } 107 108 std::string OutputPath() { 109 return kRootDirName; 110 } 111 112 std::string WorkingDir() { 113 return kRootDirName; 114 } 115 116 #else // WEBRTC_ANDROID 117 118 std::string ProjectRootPath() { 119 std::string path = WorkingDir(); 120 if (path == kFallbackPath) { 121 return kCannotFindProjectRootDir; 122 } 123 if (relative_dir_path_set) { 124 path = path + kPathDelimiter + relative_dir_path; 125 } 126 // Check for our file that verifies the root dir. 127 size_t path_delimiter_index = path.find_last_of(kPathDelimiter); 128 while (path_delimiter_index != std::string::npos) { 129 std::string root_filename = path + kPathDelimiter + kProjectRootFileName; 130 if (FileExists(root_filename)) { 131 return path + kPathDelimiter; 132 } 133 // Move up one directory in the directory tree. 134 path = path.substr(0, path_delimiter_index); 135 path_delimiter_index = path.find_last_of(kPathDelimiter); 136 } 137 // Reached the root directory. 138 fprintf(stderr, "Cannot find project root directory!\n"); 139 return kCannotFindProjectRootDir; 140 } 141 142 std::string OutputPath() { 143 std::string path = ProjectRootPath(); 144 if (path == kCannotFindProjectRootDir) { 145 return kFallbackPath; 146 } 147 path += kOutputDirName; 148 if (!CreateDir(path)) { 149 return kFallbackPath; 150 } 151 return path + kPathDelimiter; 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 rtc::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 #if defined(WEBRTC_IOS) 216 return IOSResourcePath(name, extension); 217 #else 218 std::string platform = "win"; 219 #ifdef WEBRTC_LINUX 220 platform = "linux"; 221 #endif // WEBRTC_LINUX 222 #ifdef WEBRTC_MAC 223 platform = "mac"; 224 #endif // WEBRTC_MAC 225 226 #ifdef WEBRTC_ARCH_64_BITS 227 std::string architecture = "64"; 228 #else 229 std::string architecture = "32"; 230 #endif // WEBRTC_ARCH_64_BITS 231 232 std::string resources_path = ProjectRootPath() + kResourcesDirName + 233 kPathDelimiter; 234 std::string resource_file = resources_path + name + "_" + platform + "_" + 235 architecture + "." + extension; 236 if (FileExists(resource_file)) { 237 return resource_file; 238 } 239 // Try without architecture. 240 resource_file = resources_path + name + "_" + platform + "." + extension; 241 if (FileExists(resource_file)) { 242 return resource_file; 243 } 244 // Try without platform. 245 resource_file = resources_path + name + "_" + architecture + "." + extension; 246 if (FileExists(resource_file)) { 247 return resource_file; 248 } 249 250 // Fall back on name without architecture or platform. 251 return resources_path + name + "." + extension; 252 #endif // defined (WEBRTC_IOS) 253 } 254 255 size_t GetFileSize(std::string filename) { 256 FILE* f = fopen(filename.c_str(), "rb"); 257 size_t size = 0; 258 if (f != NULL) { 259 if (fseek(f, 0, SEEK_END) == 0) { 260 size = ftell(f); 261 } 262 fclose(f); 263 } 264 return size; 265 } 266 267 } // namespace test 268 } // namespace webrtc 269