1 /* Path manipulation routines for GDB and gdbserver. 2 3 Copyright (C) 1986-2024 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "pathstuff.h" 21 #include "host-defs.h" 22 #include "filenames.h" 23 #include "gdb_tilde_expand.h" 24 25 #ifdef USE_WIN32API 26 #include <windows.h> 27 #endif 28 29 /* See gdbsupport/pathstuff.h. */ 30 31 char *current_directory; 32 33 /* See gdbsupport/pathstuff.h. */ 34 35 gdb::unique_xmalloc_ptr<char> 36 gdb_realpath (const char *filename) 37 { 38 /* On most hosts, we rely on canonicalize_file_name to compute 39 the FILENAME's realpath. 40 41 But the situation is slightly more complex on Windows, due to some 42 versions of GCC which were reported to generate paths where 43 backslashes (the directory separator) were doubled. For instance: 44 c:\\some\\double\\slashes\\dir 45 ... instead of ... 46 c:\some\double\slashes\dir 47 Those double-slashes were getting in the way when comparing paths, 48 for instance when trying to insert a breakpoint as follow: 49 (gdb) b c:/some/double/slashes/dir/foo.c:4 50 No source file named c:/some/double/slashes/dir/foo.c:4. 51 (gdb) b c:\some\double\slashes\dir\foo.c:4 52 No source file named c:\some\double\slashes\dir\foo.c:4. 53 To prevent this from happening, we need this function to always 54 strip those extra backslashes. While canonicalize_file_name does 55 perform this simplification, it only works when the path is valid. 56 Since the simplification would be useful even if the path is not 57 valid (one can always set a breakpoint on a file, even if the file 58 does not exist locally), we rely instead on GetFullPathName to 59 perform the canonicalization. */ 60 61 #if defined (_WIN32) 62 { 63 char buf[MAX_PATH]; 64 DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL); 65 66 /* The file system is case-insensitive but case-preserving. 67 So it is important we do not lowercase the path. Otherwise, 68 we might not be able to display the original casing in a given 69 path. */ 70 if (len > 0 && len < MAX_PATH) 71 return make_unique_xstrdup (buf); 72 } 73 #else 74 { 75 char *rp = canonicalize_file_name (filename); 76 77 if (rp != NULL) 78 return gdb::unique_xmalloc_ptr<char> (rp); 79 } 80 #endif 81 82 /* This system is a lost cause, just dup the buffer. */ 83 return make_unique_xstrdup (filename); 84 } 85 86 /* See gdbsupport/pathstuff.h. */ 87 88 std::string 89 gdb_realpath_keepfile (const char *filename) 90 { 91 const char *base_name = lbasename (filename); 92 char *dir_name; 93 94 /* Extract the basename of filename, and return immediately 95 a copy of filename if it does not contain any directory prefix. */ 96 if (base_name == filename) 97 return filename; 98 99 dir_name = (char *) alloca ((size_t) (base_name - filename + 2)); 100 /* Allocate enough space to store the dir_name + plus one extra 101 character sometimes needed under Windows (see below), and 102 then the closing \000 character. */ 103 strncpy (dir_name, filename, base_name - filename); 104 dir_name[base_name - filename] = '\000'; 105 106 #ifdef HAVE_DOS_BASED_FILE_SYSTEM 107 /* We need to be careful when filename is of the form 'd:foo', which 108 is equivalent of d:./foo, which is totally different from d:/foo. */ 109 if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':') 110 { 111 dir_name[2] = '.'; 112 dir_name[3] = '\000'; 113 } 114 #endif 115 116 /* Canonicalize the directory prefix, and build the resulting 117 filename. If the dirname realpath already contains an ending 118 directory separator, avoid doubling it. */ 119 gdb::unique_xmalloc_ptr<char> path_storage = gdb_realpath (dir_name); 120 const char *real_path = path_storage.get (); 121 return path_join (real_path, base_name); 122 } 123 124 /* See gdbsupport/pathstuff.h. */ 125 126 std::string 127 gdb_abspath (const char *path) 128 { 129 gdb_assert (path != NULL && path[0] != '\0'); 130 131 if (path[0] == '~') 132 return gdb_tilde_expand (path); 133 134 if (IS_ABSOLUTE_PATH (path) || current_directory == NULL) 135 return path; 136 137 return path_join (current_directory, path); 138 } 139 140 /* See gdbsupport/pathstuff.h. */ 141 142 const char * 143 child_path (const char *parent, const char *child) 144 { 145 /* The child path must start with the parent path. */ 146 size_t parent_len = strlen (parent); 147 if (filename_ncmp (parent, child, parent_len) != 0) 148 return NULL; 149 150 /* The parent path must be a directory and the child must contain at 151 least one component underneath the parent. */ 152 const char *child_component; 153 if (parent_len > 0 && IS_DIR_SEPARATOR (parent[parent_len - 1])) 154 { 155 /* The parent path ends in a directory separator, so it is a 156 directory. The first child component starts after the common 157 prefix. */ 158 child_component = child + parent_len; 159 } 160 else 161 { 162 /* The parent path does not end in a directory separator. The 163 first character in the child after the common prefix must be 164 a directory separator. 165 166 Note that CHILD must hold at least parent_len characters for 167 filename_ncmp to return zero. If the character at parent_len 168 is nul due to CHILD containing the same path as PARENT, the 169 IS_DIR_SEPARATOR check will fail here. */ 170 if (!IS_DIR_SEPARATOR (child[parent_len])) 171 return NULL; 172 173 /* The first child component starts after the separator after the 174 common prefix. */ 175 child_component = child + parent_len + 1; 176 } 177 178 /* The child must contain at least one non-separator character after 179 the parent. */ 180 while (*child_component != '\0') 181 { 182 if (!IS_DIR_SEPARATOR (*child_component)) 183 return child_component; 184 185 child_component++; 186 } 187 return NULL; 188 } 189 190 /* See gdbsupport/pathstuff.h. */ 191 192 std::string 193 path_join (gdb::array_view<const char *> paths) 194 { 195 std::string ret; 196 197 for (int i = 0; i < paths.size (); ++i) 198 { 199 const char *path = paths[i]; 200 201 if (i > 0) 202 gdb_assert (strlen (path) == 0 || !IS_ABSOLUTE_PATH (path)); 203 204 if (!ret.empty () && !IS_DIR_SEPARATOR (ret.back ())) 205 ret += '/'; 206 207 ret.append (path); 208 } 209 210 return ret; 211 } 212 213 /* See gdbsupport/pathstuff.h. */ 214 215 bool 216 contains_dir_separator (const char *path) 217 { 218 for (; *path != '\0'; path++) 219 { 220 if (IS_DIR_SEPARATOR (*path)) 221 return true; 222 } 223 224 return false; 225 } 226 227 /* See gdbsupport/pathstuff.h. */ 228 229 std::string 230 get_standard_cache_dir () 231 { 232 #ifdef __APPLE__ 233 #define HOME_CACHE_DIR "Library/Caches" 234 #else 235 #define HOME_CACHE_DIR ".cache" 236 #endif 237 238 #ifndef __APPLE__ 239 const char *xdg_cache_home = getenv ("XDG_CACHE_HOME"); 240 if (xdg_cache_home != NULL && xdg_cache_home[0] != '\0') 241 { 242 /* Make sure the path is absolute and tilde-expanded. */ 243 std::string abs = gdb_abspath (xdg_cache_home); 244 return path_join (abs.c_str (), "gdb"); 245 } 246 #endif 247 248 const char *home = getenv ("HOME"); 249 if (home != NULL && home[0] != '\0') 250 { 251 /* Make sure the path is absolute and tilde-expanded. */ 252 std::string abs = gdb_abspath (home); 253 return path_join (abs.c_str (), HOME_CACHE_DIR, "gdb"); 254 } 255 256 #ifdef WIN32 257 const char *win_home = getenv ("LOCALAPPDATA"); 258 if (win_home != NULL && win_home[0] != '\0') 259 { 260 /* Make sure the path is absolute and tilde-expanded. */ 261 std::string abs = gdb_abspath (win_home); 262 return path_join (abs.c_str (), "gdb"); 263 } 264 #endif 265 266 return {}; 267 } 268 269 /* See gdbsupport/pathstuff.h. */ 270 271 std::string 272 get_standard_temp_dir () 273 { 274 #ifdef WIN32 275 const char *tmp = getenv ("TMP"); 276 if (tmp != nullptr) 277 return tmp; 278 279 tmp = getenv ("TEMP"); 280 if (tmp != nullptr) 281 return tmp; 282 283 error (_("Couldn't find temp dir path, both TMP and TEMP are unset.")); 284 285 #else 286 const char *tmp = getenv ("TMPDIR"); 287 if (tmp != nullptr) 288 return tmp; 289 290 return "/tmp"; 291 #endif 292 } 293 294 /* See pathstuff.h. */ 295 296 std::string 297 get_standard_config_dir () 298 { 299 #ifdef __APPLE__ 300 #define HOME_CONFIG_DIR "Library/Preferences" 301 #else 302 #define HOME_CONFIG_DIR ".config" 303 #endif 304 305 #ifndef __APPLE__ 306 const char *xdg_config_home = getenv ("XDG_CONFIG_HOME"); 307 if (xdg_config_home != NULL && xdg_config_home[0] != '\0') 308 { 309 /* Make sure the path is absolute and tilde-expanded. */ 310 std::string abs = gdb_abspath (xdg_config_home); 311 return path_join (abs.c_str (), "gdb"); 312 } 313 #endif 314 315 const char *home = getenv ("HOME"); 316 if (home != NULL && home[0] != '\0') 317 { 318 /* Make sure the path is absolute and tilde-expanded. */ 319 std::string abs = gdb_abspath (home); 320 return path_join (abs.c_str (), HOME_CONFIG_DIR, "gdb"); 321 } 322 323 return {}; 324 } 325 326 /* See pathstuff.h. */ 327 328 std::string 329 get_standard_config_filename (const char *filename) 330 { 331 std::string config_dir = get_standard_config_dir (); 332 if (config_dir != "") 333 { 334 const char *tmp = (*filename == '.') ? (filename + 1) : filename; 335 std::string path = config_dir + SLASH_STRING + std::string (tmp); 336 return path; 337 } 338 339 return {}; 340 } 341 342 /* See pathstuff.h. */ 343 344 std::string 345 find_gdb_home_config_file (const char *name, struct stat *buf) 346 { 347 gdb_assert (name != nullptr); 348 gdb_assert (*name != '\0'); 349 350 std::string config_dir_file = get_standard_config_filename (name); 351 if (!config_dir_file.empty ()) 352 { 353 if (stat (config_dir_file.c_str (), buf) == 0) 354 return config_dir_file; 355 } 356 357 const char *homedir = getenv ("HOME"); 358 if (homedir != nullptr && homedir[0] != '\0') 359 { 360 /* Make sure the path is absolute and tilde-expanded. */ 361 std::string abs = gdb_abspath (homedir); 362 std::string path = string_printf ("%s/%s", abs.c_str (), name); 363 if (stat (path.c_str (), buf) == 0) 364 return path; 365 } 366 367 return {}; 368 } 369 370 /* See gdbsupport/pathstuff.h. */ 371 372 const char * 373 get_shell () 374 { 375 const char *ret = getenv ("SHELL"); 376 if (ret == NULL) 377 ret = "/bin/sh"; 378 379 return ret; 380 } 381 382 /* See gdbsupport/pathstuff.h. */ 383 384 gdb::char_vector 385 make_temp_filename (const std::string &f) 386 { 387 gdb::char_vector filename_temp (f.length () + 8); 388 strcpy (filename_temp.data (), f.c_str ()); 389 strcat (filename_temp.data () + f.size (), "-XXXXXX"); 390 return filename_temp; 391 } 392