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