xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/pathstuff.cc (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
18dffb485Schristos /* Path manipulation routines for GDB and gdbserver.
28dffb485Schristos 
3*5ba1f45fSchristos    Copyright (C) 1986-2024 Free Software Foundation, Inc.
48dffb485Schristos 
58dffb485Schristos    This file is part of GDB.
68dffb485Schristos 
78dffb485Schristos    This program is free software; you can redistribute it and/or modify
88dffb485Schristos    it under the terms of the GNU General Public License as published by
98dffb485Schristos    the Free Software Foundation; either version 3 of the License, or
108dffb485Schristos    (at your option) any later version.
118dffb485Schristos 
128dffb485Schristos    This program is distributed in the hope that it will be useful,
138dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
148dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
158dffb485Schristos    GNU General Public License for more details.
168dffb485Schristos 
178dffb485Schristos    You should have received a copy of the GNU General Public License
188dffb485Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
198dffb485Schristos 
208dffb485Schristos #include "pathstuff.h"
218dffb485Schristos #include "host-defs.h"
228dffb485Schristos #include "filenames.h"
238dffb485Schristos #include "gdb_tilde_expand.h"
248dffb485Schristos 
258dffb485Schristos #ifdef USE_WIN32API
268dffb485Schristos #include <windows.h>
278dffb485Schristos #endif
288dffb485Schristos 
298dffb485Schristos /* See gdbsupport/pathstuff.h.  */
308dffb485Schristos 
314b169a6bSchristos char *current_directory;
324b169a6bSchristos 
334b169a6bSchristos /* See gdbsupport/pathstuff.h.  */
344b169a6bSchristos 
358dffb485Schristos gdb::unique_xmalloc_ptr<char>
368dffb485Schristos gdb_realpath (const char *filename)
378dffb485Schristos {
388dffb485Schristos /* On most hosts, we rely on canonicalize_file_name to compute
398dffb485Schristos    the FILENAME's realpath.
408dffb485Schristos 
418dffb485Schristos    But the situation is slightly more complex on Windows, due to some
428dffb485Schristos    versions of GCC which were reported to generate paths where
43*5ba1f45fSchristos    backslashes (the directory separator) were doubled.  For instance:
448dffb485Schristos       c:\\some\\double\\slashes\\dir
458dffb485Schristos    ... instead of ...
468dffb485Schristos       c:\some\double\slashes\dir
478dffb485Schristos    Those double-slashes were getting in the way when comparing paths,
488dffb485Schristos    for instance when trying to insert a breakpoint as follow:
498dffb485Schristos       (gdb) b c:/some/double/slashes/dir/foo.c:4
508dffb485Schristos       No source file named c:/some/double/slashes/dir/foo.c:4.
518dffb485Schristos       (gdb) b c:\some\double\slashes\dir\foo.c:4
528dffb485Schristos       No source file named c:\some\double\slashes\dir\foo.c:4.
538dffb485Schristos    To prevent this from happening, we need this function to always
548dffb485Schristos    strip those extra backslashes.  While canonicalize_file_name does
558dffb485Schristos    perform this simplification, it only works when the path is valid.
568dffb485Schristos    Since the simplification would be useful even if the path is not
578dffb485Schristos    valid (one can always set a breakpoint on a file, even if the file
588dffb485Schristos    does not exist locally), we rely instead on GetFullPathName to
598dffb485Schristos    perform the canonicalization.  */
608dffb485Schristos 
618dffb485Schristos #if defined (_WIN32)
628dffb485Schristos   {
638dffb485Schristos     char buf[MAX_PATH];
648dffb485Schristos     DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL);
658dffb485Schristos 
668dffb485Schristos     /* The file system is case-insensitive but case-preserving.
678dffb485Schristos        So it is important we do not lowercase the path.  Otherwise,
688dffb485Schristos        we might not be able to display the original casing in a given
698dffb485Schristos        path.  */
708dffb485Schristos     if (len > 0 && len < MAX_PATH)
718dffb485Schristos       return make_unique_xstrdup (buf);
728dffb485Schristos   }
738dffb485Schristos #else
748dffb485Schristos   {
758dffb485Schristos     char *rp = canonicalize_file_name (filename);
768dffb485Schristos 
778dffb485Schristos     if (rp != NULL)
788dffb485Schristos       return gdb::unique_xmalloc_ptr<char> (rp);
798dffb485Schristos   }
808dffb485Schristos #endif
818dffb485Schristos 
828dffb485Schristos   /* This system is a lost cause, just dup the buffer.  */
838dffb485Schristos   return make_unique_xstrdup (filename);
848dffb485Schristos }
858dffb485Schristos 
868dffb485Schristos /* See gdbsupport/pathstuff.h.  */
878dffb485Schristos 
884b169a6bSchristos std::string
898dffb485Schristos gdb_realpath_keepfile (const char *filename)
908dffb485Schristos {
918dffb485Schristos   const char *base_name = lbasename (filename);
928dffb485Schristos   char *dir_name;
938dffb485Schristos 
948dffb485Schristos   /* Extract the basename of filename, and return immediately
958dffb485Schristos      a copy of filename if it does not contain any directory prefix.  */
968dffb485Schristos   if (base_name == filename)
974b169a6bSchristos     return filename;
988dffb485Schristos 
998dffb485Schristos   dir_name = (char *) alloca ((size_t) (base_name - filename + 2));
1008dffb485Schristos   /* Allocate enough space to store the dir_name + plus one extra
1018dffb485Schristos      character sometimes needed under Windows (see below), and
1028dffb485Schristos      then the closing \000 character.  */
1038dffb485Schristos   strncpy (dir_name, filename, base_name - filename);
1048dffb485Schristos   dir_name[base_name - filename] = '\000';
1058dffb485Schristos 
1068dffb485Schristos #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1078dffb485Schristos   /* We need to be careful when filename is of the form 'd:foo', which
1088dffb485Schristos      is equivalent of d:./foo, which is totally different from d:/foo.  */
1098dffb485Schristos   if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':')
1108dffb485Schristos     {
1118dffb485Schristos       dir_name[2] = '.';
1128dffb485Schristos       dir_name[3] = '\000';
1138dffb485Schristos     }
1148dffb485Schristos #endif
1158dffb485Schristos 
1168dffb485Schristos   /* Canonicalize the directory prefix, and build the resulting
1178dffb485Schristos      filename.  If the dirname realpath already contains an ending
1188dffb485Schristos      directory separator, avoid doubling it.  */
1198dffb485Schristos   gdb::unique_xmalloc_ptr<char> path_storage = gdb_realpath (dir_name);
1208dffb485Schristos   const char *real_path = path_storage.get ();
1214b169a6bSchristos   return path_join (real_path, base_name);
1228dffb485Schristos }
1238dffb485Schristos 
1248dffb485Schristos /* See gdbsupport/pathstuff.h.  */
1258dffb485Schristos 
1264b169a6bSchristos std::string
1278dffb485Schristos gdb_abspath (const char *path)
1288dffb485Schristos {
1298dffb485Schristos   gdb_assert (path != NULL && path[0] != '\0');
1308dffb485Schristos 
1318dffb485Schristos   if (path[0] == '~')
1324b169a6bSchristos     return gdb_tilde_expand (path);
1338dffb485Schristos 
1348dffb485Schristos   if (IS_ABSOLUTE_PATH (path) || current_directory == NULL)
1354b169a6bSchristos     return path;
1368dffb485Schristos 
1374b169a6bSchristos   return path_join (current_directory, path);
1388dffb485Schristos }
1398dffb485Schristos 
1408dffb485Schristos /* See gdbsupport/pathstuff.h.  */
1418dffb485Schristos 
1428dffb485Schristos const char *
1438dffb485Schristos child_path (const char *parent, const char *child)
1448dffb485Schristos {
1458dffb485Schristos   /* The child path must start with the parent path.  */
1468dffb485Schristos   size_t parent_len = strlen (parent);
1478dffb485Schristos   if (filename_ncmp (parent, child, parent_len) != 0)
1488dffb485Schristos     return NULL;
1498dffb485Schristos 
1508dffb485Schristos   /* The parent path must be a directory and the child must contain at
1518dffb485Schristos      least one component underneath the parent.  */
1528dffb485Schristos   const char *child_component;
1538dffb485Schristos   if (parent_len > 0 && IS_DIR_SEPARATOR (parent[parent_len - 1]))
1548dffb485Schristos     {
1558dffb485Schristos       /* The parent path ends in a directory separator, so it is a
1568dffb485Schristos 	 directory.  The first child component starts after the common
1578dffb485Schristos 	 prefix.  */
1588dffb485Schristos       child_component = child + parent_len;
1598dffb485Schristos     }
1608dffb485Schristos   else
1618dffb485Schristos     {
1628dffb485Schristos       /* The parent path does not end in a directory separator.  The
1638dffb485Schristos 	 first character in the child after the common prefix must be
1648dffb485Schristos 	 a directory separator.
1658dffb485Schristos 
1668dffb485Schristos 	 Note that CHILD must hold at least parent_len characters for
1678dffb485Schristos 	 filename_ncmp to return zero.  If the character at parent_len
1688dffb485Schristos 	 is nul due to CHILD containing the same path as PARENT, the
1698dffb485Schristos 	 IS_DIR_SEPARATOR check will fail here.  */
1708dffb485Schristos       if (!IS_DIR_SEPARATOR (child[parent_len]))
1718dffb485Schristos 	return NULL;
1728dffb485Schristos 
1738dffb485Schristos       /* The first child component starts after the separator after the
1748dffb485Schristos 	 common prefix.  */
1758dffb485Schristos       child_component = child + parent_len + 1;
1768dffb485Schristos     }
1778dffb485Schristos 
1788dffb485Schristos   /* The child must contain at least one non-separator character after
1798dffb485Schristos      the parent.  */
1808dffb485Schristos   while (*child_component != '\0')
1818dffb485Schristos     {
1828dffb485Schristos       if (!IS_DIR_SEPARATOR (*child_component))
1838dffb485Schristos 	return child_component;
1848dffb485Schristos 
1858dffb485Schristos       child_component++;
1868dffb485Schristos     }
1878dffb485Schristos   return NULL;
1888dffb485Schristos }
1898dffb485Schristos 
1908dffb485Schristos /* See gdbsupport/pathstuff.h.  */
1918dffb485Schristos 
1924b169a6bSchristos std::string
1934b169a6bSchristos path_join (gdb::array_view<const char *> paths)
1944b169a6bSchristos {
1954b169a6bSchristos   std::string ret;
1964b169a6bSchristos 
1974b169a6bSchristos   for (int i = 0; i < paths.size (); ++i)
1984b169a6bSchristos     {
1994b169a6bSchristos       const char *path = paths[i];
2004b169a6bSchristos 
2014b169a6bSchristos       if (i > 0)
2024b169a6bSchristos 	gdb_assert (strlen (path) == 0 || !IS_ABSOLUTE_PATH (path));
2034b169a6bSchristos 
2044b169a6bSchristos       if (!ret.empty () && !IS_DIR_SEPARATOR (ret.back ()))
2054b169a6bSchristos 	  ret += '/';
2064b169a6bSchristos 
2074b169a6bSchristos       ret.append (path);
2084b169a6bSchristos     }
2094b169a6bSchristos 
2104b169a6bSchristos   return ret;
2114b169a6bSchristos }
2124b169a6bSchristos 
2134b169a6bSchristos /* See gdbsupport/pathstuff.h.  */
2144b169a6bSchristos 
2158dffb485Schristos bool
2168dffb485Schristos contains_dir_separator (const char *path)
2178dffb485Schristos {
2188dffb485Schristos   for (; *path != '\0'; path++)
2198dffb485Schristos     {
2208dffb485Schristos       if (IS_DIR_SEPARATOR (*path))
2218dffb485Schristos 	return true;
2228dffb485Schristos     }
2238dffb485Schristos 
2248dffb485Schristos   return false;
2258dffb485Schristos }
2268dffb485Schristos 
2278dffb485Schristos /* See gdbsupport/pathstuff.h.  */
2288dffb485Schristos 
2298dffb485Schristos std::string
2308dffb485Schristos get_standard_cache_dir ()
2318dffb485Schristos {
2328dffb485Schristos #ifdef __APPLE__
2338dffb485Schristos #define HOME_CACHE_DIR "Library/Caches"
2348dffb485Schristos #else
2358dffb485Schristos #define HOME_CACHE_DIR ".cache"
2368dffb485Schristos #endif
2378dffb485Schristos 
2388dffb485Schristos #ifndef __APPLE__
2398dffb485Schristos   const char *xdg_cache_home = getenv ("XDG_CACHE_HOME");
2404b169a6bSchristos   if (xdg_cache_home != NULL && xdg_cache_home[0] != '\0')
2418dffb485Schristos     {
2428dffb485Schristos       /* Make sure the path is absolute and tilde-expanded.  */
2434b169a6bSchristos       std::string abs = gdb_abspath (xdg_cache_home);
2444b169a6bSchristos       return path_join (abs.c_str (), "gdb");
2458dffb485Schristos     }
2468dffb485Schristos #endif
2478dffb485Schristos 
2488dffb485Schristos   const char *home = getenv ("HOME");
2494b169a6bSchristos   if (home != NULL && home[0] != '\0')
2508dffb485Schristos     {
2518dffb485Schristos       /* Make sure the path is absolute and tilde-expanded.  */
2524b169a6bSchristos       std::string abs = gdb_abspath (home);
2534b169a6bSchristos       return path_join (abs.c_str (), HOME_CACHE_DIR,  "gdb");
2548dffb485Schristos     }
2558dffb485Schristos 
2564b169a6bSchristos #ifdef WIN32
2574b169a6bSchristos   const char *win_home = getenv ("LOCALAPPDATA");
2584b169a6bSchristos   if (win_home != NULL && win_home[0] != '\0')
2594b169a6bSchristos     {
2604b169a6bSchristos       /* Make sure the path is absolute and tilde-expanded.  */
2614b169a6bSchristos       std::string abs = gdb_abspath (win_home);
2624b169a6bSchristos       return path_join (abs.c_str (), "gdb");
2634b169a6bSchristos     }
2644b169a6bSchristos #endif
2654b169a6bSchristos 
2668dffb485Schristos   return {};
2678dffb485Schristos }
2688dffb485Schristos 
2698dffb485Schristos /* See gdbsupport/pathstuff.h.  */
2708dffb485Schristos 
2718dffb485Schristos std::string
2728dffb485Schristos get_standard_temp_dir ()
2738dffb485Schristos {
2748dffb485Schristos #ifdef WIN32
2758dffb485Schristos   const char *tmp = getenv ("TMP");
2768dffb485Schristos   if (tmp != nullptr)
2778dffb485Schristos     return tmp;
2788dffb485Schristos 
2798dffb485Schristos   tmp = getenv ("TEMP");
2808dffb485Schristos   if (tmp != nullptr)
2818dffb485Schristos     return tmp;
2828dffb485Schristos 
2838dffb485Schristos   error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));
2848dffb485Schristos 
2858dffb485Schristos #else
2868dffb485Schristos   const char *tmp = getenv ("TMPDIR");
2878dffb485Schristos   if (tmp != nullptr)
2888dffb485Schristos     return tmp;
2898dffb485Schristos 
2908dffb485Schristos   return "/tmp";
2918dffb485Schristos #endif
2928dffb485Schristos }
2938dffb485Schristos 
2944b169a6bSchristos /* See pathstuff.h.  */
2954b169a6bSchristos 
2964b169a6bSchristos std::string
2974b169a6bSchristos get_standard_config_dir ()
2984b169a6bSchristos {
2994b169a6bSchristos #ifdef __APPLE__
3004b169a6bSchristos #define HOME_CONFIG_DIR "Library/Preferences"
3014b169a6bSchristos #else
3024b169a6bSchristos #define HOME_CONFIG_DIR ".config"
3034b169a6bSchristos #endif
3044b169a6bSchristos 
3054b169a6bSchristos #ifndef __APPLE__
3064b169a6bSchristos   const char *xdg_config_home = getenv ("XDG_CONFIG_HOME");
3074b169a6bSchristos   if (xdg_config_home != NULL && xdg_config_home[0] != '\0')
3084b169a6bSchristos     {
3094b169a6bSchristos       /* Make sure the path is absolute and tilde-expanded.  */
3104b169a6bSchristos       std::string abs = gdb_abspath (xdg_config_home);
3114b169a6bSchristos       return path_join (abs.c_str (), "gdb");
3124b169a6bSchristos     }
3134b169a6bSchristos #endif
3144b169a6bSchristos 
3154b169a6bSchristos   const char *home = getenv ("HOME");
3164b169a6bSchristos   if (home != NULL && home[0] != '\0')
3174b169a6bSchristos     {
3184b169a6bSchristos       /* Make sure the path is absolute and tilde-expanded.  */
3194b169a6bSchristos       std::string abs = gdb_abspath (home);
3204b169a6bSchristos       return path_join (abs.c_str (), HOME_CONFIG_DIR, "gdb");
3214b169a6bSchristos     }
3224b169a6bSchristos 
3234b169a6bSchristos   return {};
3244b169a6bSchristos }
3254b169a6bSchristos 
3264b169a6bSchristos /* See pathstuff.h. */
3274b169a6bSchristos 
3284b169a6bSchristos std::string
3294b169a6bSchristos get_standard_config_filename (const char *filename)
3304b169a6bSchristos {
3314b169a6bSchristos   std::string config_dir = get_standard_config_dir ();
3324b169a6bSchristos   if (config_dir != "")
3334b169a6bSchristos     {
3344b169a6bSchristos       const char *tmp = (*filename == '.') ? (filename + 1) : filename;
3354b169a6bSchristos       std::string path = config_dir + SLASH_STRING + std::string (tmp);
3364b169a6bSchristos       return path;
3374b169a6bSchristos     }
3384b169a6bSchristos 
3394b169a6bSchristos   return {};
3404b169a6bSchristos }
3414b169a6bSchristos 
3424b169a6bSchristos /* See pathstuff.h.  */
3434b169a6bSchristos 
3444b169a6bSchristos std::string
3454b169a6bSchristos find_gdb_home_config_file (const char *name, struct stat *buf)
3464b169a6bSchristos {
3474b169a6bSchristos   gdb_assert (name != nullptr);
3484b169a6bSchristos   gdb_assert (*name != '\0');
3494b169a6bSchristos 
3504b169a6bSchristos   std::string config_dir_file = get_standard_config_filename (name);
3514b169a6bSchristos   if (!config_dir_file.empty ())
3524b169a6bSchristos     {
3534b169a6bSchristos       if (stat (config_dir_file.c_str (), buf) == 0)
3544b169a6bSchristos 	return config_dir_file;
3554b169a6bSchristos     }
3564b169a6bSchristos 
3574b169a6bSchristos   const char *homedir = getenv ("HOME");
3584b169a6bSchristos   if (homedir != nullptr && homedir[0] != '\0')
3594b169a6bSchristos     {
3604b169a6bSchristos       /* Make sure the path is absolute and tilde-expanded.  */
3614b169a6bSchristos       std::string abs = gdb_abspath (homedir);
3624b169a6bSchristos       std::string path = string_printf ("%s/%s", abs.c_str (), name);
3634b169a6bSchristos       if (stat (path.c_str (), buf) == 0)
3644b169a6bSchristos 	return path;
3654b169a6bSchristos     }
3664b169a6bSchristos 
3674b169a6bSchristos   return {};
3684b169a6bSchristos }
3694b169a6bSchristos 
3708dffb485Schristos /* See gdbsupport/pathstuff.h.  */
3718dffb485Schristos 
3728dffb485Schristos const char *
3738dffb485Schristos get_shell ()
3748dffb485Schristos {
3758dffb485Schristos   const char *ret = getenv ("SHELL");
3768dffb485Schristos   if (ret == NULL)
3778dffb485Schristos     ret = "/bin/sh";
3788dffb485Schristos 
3798dffb485Schristos   return ret;
3808dffb485Schristos }
3818dffb485Schristos 
3828dffb485Schristos /* See gdbsupport/pathstuff.h.  */
3838dffb485Schristos 
3848dffb485Schristos gdb::char_vector
3858dffb485Schristos make_temp_filename (const std::string &f)
3868dffb485Schristos {
3878dffb485Schristos   gdb::char_vector filename_temp (f.length () + 8);
3888dffb485Schristos   strcpy (filename_temp.data (), f.c_str ());
3898dffb485Schristos   strcat (filename_temp.data () + f.size (), "-XXXXXX");
3908dffb485Schristos   return filename_temp;
3918dffb485Schristos }
392