1 /* Path manipulation routines for GDB and gdbserver.
3 Copyright (C) 1986-2023 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 #include "common-defs.h"
21 #include "pathstuff.h"
22 #include "host-defs.h"
23 #include "filenames.h"
24 #include "gdb_tilde_expand.h"
30 /* See gdbsupport/pathstuff.h. */
32 char *current_directory
;
34 /* See gdbsupport/pathstuff.h. */
36 gdb::unique_xmalloc_ptr
<char>
37 gdb_realpath (const char *filename
)
39 /* On most hosts, we rely on canonicalize_file_name to compute
40 the FILENAME's realpath.
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 backslashes (the directory separator) were doubled. For instance:
45 c:\\some\\double\\slashes\\dir
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. */
65 DWORD len
= GetFullPathName (filename
, MAX_PATH
, buf
, NULL
);
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
71 if (len
> 0 && len
< MAX_PATH
)
72 return make_unique_xstrdup (buf
);
76 char *rp
= canonicalize_file_name (filename
);
79 return gdb::unique_xmalloc_ptr
<char> (rp
);
83 /* This system is a lost cause, just dup the buffer. */
84 return make_unique_xstrdup (filename
);
87 /* See gdbsupport/pathstuff.h. */
90 gdb_realpath_keepfile (const char *filename
)
92 const char *base_name
= lbasename (filename
);
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
)
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';
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] == ':')
113 dir_name
[3] = '\000';
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
);
125 /* See gdbsupport/pathstuff.h. */
128 gdb_abspath (const char *path
)
130 gdb_assert (path
!= NULL
&& path
[0] != '\0');
133 return gdb_tilde_expand (path
);
135 if (IS_ABSOLUTE_PATH (path
) || current_directory
== NULL
)
138 return path_join (current_directory
, path
);
141 /* See gdbsupport/pathstuff.h. */
144 child_path (const char *parent
, const char *child
)
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)
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]))
156 /* The parent path ends in a directory separator, so it is a
157 directory. The first child component starts after the common
159 child_component
= child
+ parent_len
;
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.
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
]))
174 /* The first child component starts after the separator after the
176 child_component
= child
+ parent_len
+ 1;
179 /* The child must contain at least one non-separator character after
181 while (*child_component
!= '\0')
183 if (!IS_DIR_SEPARATOR (*child_component
))
184 return child_component
;
191 /* See gdbsupport/pathstuff.h. */
194 path_join (gdb::array_view
<const char *> paths
)
198 for (int i
= 0; i
< paths
.size (); ++i
)
200 const char *path
= paths
[i
];
203 gdb_assert (strlen (path
) == 0 || !IS_ABSOLUTE_PATH (path
));
205 if (!ret
.empty () && !IS_DIR_SEPARATOR (ret
.back ()))
214 /* See gdbsupport/pathstuff.h. */
217 contains_dir_separator (const char *path
)
219 for (; *path
!= '\0'; path
++)
221 if (IS_DIR_SEPARATOR (*path
))
228 /* See gdbsupport/pathstuff.h. */
231 get_standard_cache_dir ()
234 #define HOME_CACHE_DIR "Library/Caches"
236 #define HOME_CACHE_DIR ".cache"
240 const char *xdg_cache_home
= getenv ("XDG_CACHE_HOME");
241 if (xdg_cache_home
!= NULL
&& xdg_cache_home
[0] != '\0')
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");
249 const char *home
= getenv ("HOME");
250 if (home
!= NULL
&& home
[0] != '\0')
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");
258 const char *win_home
= getenv ("LOCALAPPDATA");
259 if (win_home
!= NULL
&& win_home
[0] != '\0')
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");
270 /* See gdbsupport/pathstuff.h. */
273 get_standard_temp_dir ()
276 const char *tmp
= getenv ("TMP");
280 tmp
= getenv ("TEMP");
284 error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));
287 const char *tmp
= getenv ("TMPDIR");
295 /* See pathstuff.h. */
298 get_standard_config_dir ()
301 #define HOME_CONFIG_DIR "Library/Preferences"
303 #define HOME_CONFIG_DIR ".config"
307 const char *xdg_config_home
= getenv ("XDG_CONFIG_HOME");
308 if (xdg_config_home
!= NULL
&& xdg_config_home
[0] != '\0')
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");
316 const char *home
= getenv ("HOME");
317 if (home
!= NULL
&& home
[0] != '\0')
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");
327 /* See pathstuff.h. */
330 get_standard_config_filename (const char *filename
)
332 std::string config_dir
= get_standard_config_dir ();
333 if (config_dir
!= "")
335 const char *tmp
= (*filename
== '.') ? (filename
+ 1) : filename
;
336 std::string path
= config_dir
+ SLASH_STRING
+ std::string (tmp
);
343 /* See pathstuff.h. */
346 find_gdb_home_config_file (const char *name
, struct stat
*buf
)
348 gdb_assert (name
!= nullptr);
349 gdb_assert (*name
!= '\0');
351 std::string config_dir_file
= get_standard_config_filename (name
);
352 if (!config_dir_file
.empty ())
354 if (stat (config_dir_file
.c_str (), buf
) == 0)
355 return config_dir_file
;
358 const char *homedir
= getenv ("HOME");
359 if (homedir
!= nullptr && homedir
[0] != '\0')
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)
371 /* See gdbsupport/pathstuff.h. */
376 const char *ret
= getenv ("SHELL");
383 /* See gdbsupport/pathstuff.h. */
386 make_temp_filename (const std::string
&f
)
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
;