1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define TRACE_TAG ADB 18 19 #include "adb_utils.h" 20 21 #include <libgen.h> 22 #include <stdlib.h> 23 #include <sys/stat.h> 24 #include <sys/types.h> 25 #include <unistd.h> 26 27 #include <algorithm> 28 29 #include <android-base/logging.h> 30 #include <android-base/stringprintf.h> 31 #include <android-base/strings.h> 32 33 #include "adb.h" 34 #include "adb_trace.h" 35 #include "sysdeps.h" 36 37 #ifdef _WIN32 38 # ifndef WIN32_LEAN_AND_MEAN 39 # define WIN32_LEAN_AND_MEAN 40 # endif 41 # include "windows.h" 42 # include "shlobj.h" 43 #endif 44 45 ADB_MUTEX_DEFINE(basename_lock); 46 ADB_MUTEX_DEFINE(dirname_lock); 47 48 #if defined(_WIN32) 49 constexpr char kNullFileName[] = "NUL"; 50 #else 51 constexpr char kNullFileName[] = "/dev/null"; 52 #endif 53 54 void close_stdin() { 55 int fd = unix_open(kNullFileName, O_RDONLY); 56 if (fd == -1) { 57 fatal_errno("failed to open %s", kNullFileName); 58 } 59 60 if (TEMP_FAILURE_RETRY(dup2(fd, STDIN_FILENO)) == -1) { 61 fatal_errno("failed to redirect stdin to %s", kNullFileName); 62 } 63 unix_close(fd); 64 } 65 66 bool getcwd(std::string* s) { 67 char* cwd = getcwd(nullptr, 0); 68 if (cwd != nullptr) *s = cwd; 69 free(cwd); 70 return (cwd != nullptr); 71 } 72 73 bool directory_exists(const std::string& path) { 74 struct stat sb; 75 return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode); 76 } 77 78 std::string escape_arg(const std::string& s) { 79 std::string result = s; 80 81 // Escape any ' in the string (before we single-quote the whole thing). 82 // The correct way to do this for the shell is to replace ' with '\'' --- that is, 83 // close the existing single-quoted string, escape a single single-quote, and start 84 // a new single-quoted string. Like the C preprocessor, the shell will concatenate 85 // these pieces into one string. 86 for (size_t i = 0; i < s.size(); ++i) { 87 if (s[i] == '\'') { 88 result.insert(i, "'\\'"); 89 i += 2; 90 } 91 } 92 93 // Prefix and suffix the whole string with '. 94 result.insert(result.begin(), '\''); 95 result.push_back('\''); 96 return result; 97 } 98 99 std::string adb_basename(const std::string& path) { 100 // Copy path because basename may modify the string passed in. 101 std::string result(path); 102 103 // Use lock because basename() may write to a process global and return a 104 // pointer to that. Note that this locking strategy only works if all other 105 // callers to dirname in the process also grab this same lock. 106 adb_mutex_lock(&basename_lock); 107 108 // Note that if std::string uses copy-on-write strings, &str[0] will cause 109 // the copy to be made, so there is no chance of us accidentally writing to 110 // the storage for 'path'. 111 char* name = basename(&result[0]); 112 113 // In case dirname returned a pointer to a process global, copy that string 114 // before leaving the lock. 115 result.assign(name); 116 117 adb_mutex_unlock(&basename_lock); 118 119 return result; 120 } 121 122 std::string adb_dirname(const std::string& path) { 123 // Copy path because dirname may modify the string passed in. 124 std::string result(path); 125 126 // Use lock because dirname() may write to a process global and return a 127 // pointer to that. Note that this locking strategy only works if all other 128 // callers to dirname in the process also grab this same lock. 129 adb_mutex_lock(&dirname_lock); 130 131 // Note that if std::string uses copy-on-write strings, &str[0] will cause 132 // the copy to be made, so there is no chance of us accidentally writing to 133 // the storage for 'path'. 134 char* parent = dirname(&result[0]); 135 136 // In case dirname returned a pointer to a process global, copy that string 137 // before leaving the lock. 138 result.assign(parent); 139 140 adb_mutex_unlock(&dirname_lock); 141 142 return result; 143 } 144 145 // Given a relative or absolute filepath, create the directory hierarchy 146 // as needed. Returns true if the hierarchy is/was setup. 147 bool mkdirs(const std::string& path) { 148 // TODO: all the callers do unlink && mkdirs && adb_creat --- 149 // that's probably the operation we should expose. 150 151 // Implementation Notes: 152 // 153 // Pros: 154 // - Uses dirname, so does not need to deal with OS_PATH_SEPARATOR. 155 // - On Windows, uses mingw dirname which accepts '/' and '\\', drive letters 156 // (C:\foo), UNC paths (\\server\share\dir\dir\file), and Unicode (when 157 // combined with our adb_mkdir() which takes UTF-8). 158 // - Is optimistic wrt thinking that a deep directory hierarchy will exist. 159 // So it does as few stat()s as possible before doing mkdir()s. 160 // Cons: 161 // - Recursive, so it uses stack space relative to number of directory 162 // components. 163 164 // If path points to a symlink to a directory, that's fine. 165 struct stat sb; 166 if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) { 167 return true; 168 } 169 170 const std::string parent(adb_dirname(path)); 171 172 // If dirname returned the same path as what we passed in, don't go recursive. 173 // This can happen on Windows when walking up the directory hierarchy and not 174 // finding anything that already exists (unlike POSIX that will eventually 175 // find . or /). 176 if (parent == path) { 177 errno = ENOENT; 178 return false; 179 } 180 181 // Recursively make parent directories of 'path'. 182 if (!mkdirs(parent)) { 183 return false; 184 } 185 186 // Now that the parent directory hierarchy of 'path' has been ensured, 187 // create path itself. 188 if (adb_mkdir(path, 0775) == -1) { 189 const int saved_errno = errno; 190 // If someone else created the directory, that is ok. 191 if (directory_exists(path)) { 192 return true; 193 } 194 // There might be a pre-existing file at 'path', or there might have been some other error. 195 errno = saved_errno; 196 return false; 197 } 198 199 return true; 200 } 201 202 std::string dump_hex(const void* data, size_t byte_count) { 203 byte_count = std::min(byte_count, size_t(16)); 204 205 const uint8_t* p = reinterpret_cast<const uint8_t*>(data); 206 207 std::string line; 208 for (size_t i = 0; i < byte_count; ++i) { 209 android::base::StringAppendF(&line, "%02x", p[i]); 210 } 211 line.push_back(' '); 212 213 for (size_t i = 0; i < byte_count; ++i) { 214 int ch = p[i]; 215 line.push_back(isprint(ch) ? ch : '.'); 216 } 217 218 return line; 219 } 220 221 std::string perror_str(const char* msg) { 222 return android::base::StringPrintf("%s: %s", msg, strerror(errno)); 223 } 224 225 #if !defined(_WIN32) 226 // Windows version provided in sysdeps_win32.cpp 227 bool set_file_block_mode(int fd, bool block) { 228 int flags = fcntl(fd, F_GETFL, 0); 229 if (flags == -1) { 230 PLOG(ERROR) << "failed to fcntl(F_GETFL) for fd " << fd; 231 return false; 232 } 233 flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); 234 if (fcntl(fd, F_SETFL, flags) != 0) { 235 PLOG(ERROR) << "failed to fcntl(F_SETFL) for fd " << fd << ", flags " << flags; 236 return false; 237 } 238 return true; 239 } 240 #endif 241 242 std::string adb_get_homedir_path(bool check_env_first) { 243 #ifdef _WIN32 244 if (check_env_first) { 245 if (const char* const home = getenv("ANDROID_SDK_HOME")) { 246 return home; 247 } 248 } 249 250 WCHAR path[MAX_PATH]; 251 const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path); 252 if (FAILED(hr)) { 253 D("SHGetFolderPathW failed: %s", android::base::SystemErrorCodeToString(hr).c_str()); 254 return {}; 255 } 256 std::string home_str; 257 if (!android::base::WideToUTF8(path, &home_str)) { 258 return {}; 259 } 260 return home_str; 261 #else 262 if (const char* const home = getenv("HOME")) { 263 return home; 264 } 265 return {}; 266 #endif 267 } 268 269