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