123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- /* Path manipulation routines for GDB and gdbserver.
- Copyright (C) 1986-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "common-defs.h"
- #include "pathstuff.h"
- #include "host-defs.h"
- #include "filenames.h"
- #include "gdb_tilde_expand.h"
- #ifdef USE_WIN32API
- #include <windows.h>
- #endif
- /* See gdbsupport/pathstuff.h. */
- char *current_directory;
- /* See gdbsupport/pathstuff.h. */
- gdb::unique_xmalloc_ptr<char>
- gdb_realpath (const char *filename)
- {
- /* On most hosts, we rely on canonicalize_file_name to compute
- the FILENAME's realpath.
- But the situation is slightly more complex on Windows, due to some
- versions of GCC which were reported to generate paths where
- backlashes (the directory separator) were doubled. For instance:
- c:\\some\\double\\slashes\\dir
- ... instead of ...
- c:\some\double\slashes\dir
- Those double-slashes were getting in the way when comparing paths,
- for instance when trying to insert a breakpoint as follow:
- (gdb) b c:/some/double/slashes/dir/foo.c:4
- No source file named c:/some/double/slashes/dir/foo.c:4.
- (gdb) b c:\some\double\slashes\dir\foo.c:4
- No source file named c:\some\double\slashes\dir\foo.c:4.
- To prevent this from happening, we need this function to always
- strip those extra backslashes. While canonicalize_file_name does
- perform this simplification, it only works when the path is valid.
- Since the simplification would be useful even if the path is not
- valid (one can always set a breakpoint on a file, even if the file
- does not exist locally), we rely instead on GetFullPathName to
- perform the canonicalization. */
- #if defined (_WIN32)
- {
- char buf[MAX_PATH];
- DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL);
- /* The file system is case-insensitive but case-preserving.
- So it is important we do not lowercase the path. Otherwise,
- we might not be able to display the original casing in a given
- path. */
- if (len > 0 && len < MAX_PATH)
- return make_unique_xstrdup (buf);
- }
- #else
- {
- char *rp = canonicalize_file_name (filename);
- if (rp != NULL)
- return gdb::unique_xmalloc_ptr<char> (rp);
- }
- #endif
- /* This system is a lost cause, just dup the buffer. */
- return make_unique_xstrdup (filename);
- }
- /* See gdbsupport/pathstuff.h. */
- gdb::unique_xmalloc_ptr<char>
- gdb_realpath_keepfile (const char *filename)
- {
- const char *base_name = lbasename (filename);
- char *dir_name;
- char *result;
- /* Extract the basename of filename, and return immediately
- a copy of filename if it does not contain any directory prefix. */
- if (base_name == filename)
- return make_unique_xstrdup (filename);
- dir_name = (char *) alloca ((size_t) (base_name - filename + 2));
- /* Allocate enough space to store the dir_name + plus one extra
- character sometimes needed under Windows (see below), and
- then the closing \000 character. */
- strncpy (dir_name, filename, base_name - filename);
- dir_name[base_name - filename] = '\000';
- #ifdef HAVE_DOS_BASED_FILE_SYSTEM
- /* We need to be careful when filename is of the form 'd:foo', which
- is equivalent of d:./foo, which is totally different from d:/foo. */
- if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':')
- {
- dir_name[2] = '.';
- dir_name[3] = '\000';
- }
- #endif
- /* Canonicalize the directory prefix, and build the resulting
- filename. If the dirname realpath already contains an ending
- directory separator, avoid doubling it. */
- gdb::unique_xmalloc_ptr<char> path_storage = gdb_realpath (dir_name);
- const char *real_path = path_storage.get ();
- if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1]))
- result = concat (real_path, base_name, (char *) NULL);
- else
- result = concat (real_path, SLASH_STRING, base_name, (char *) NULL);
- return gdb::unique_xmalloc_ptr<char> (result);
- }
- /* See gdbsupport/pathstuff.h. */
- gdb::unique_xmalloc_ptr<char>
- gdb_abspath (const char *path)
- {
- gdb_assert (path != NULL && path[0] != '\0');
- if (path[0] == '~')
- return gdb_tilde_expand_up (path);
- if (IS_ABSOLUTE_PATH (path) || current_directory == NULL)
- return make_unique_xstrdup (path);
- /* Beware the // my son, the Emacs barfs, the botch that catch... */
- return gdb::unique_xmalloc_ptr<char>
- (concat (current_directory,
- IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1])
- ? "" : SLASH_STRING,
- path, (char *) NULL));
- }
- /* See gdbsupport/pathstuff.h. */
- const char *
- child_path (const char *parent, const char *child)
- {
- /* The child path must start with the parent path. */
- size_t parent_len = strlen (parent);
- if (filename_ncmp (parent, child, parent_len) != 0)
- return NULL;
- /* The parent path must be a directory and the child must contain at
- least one component underneath the parent. */
- const char *child_component;
- if (parent_len > 0 && IS_DIR_SEPARATOR (parent[parent_len - 1]))
- {
- /* The parent path ends in a directory separator, so it is a
- directory. The first child component starts after the common
- prefix. */
- child_component = child + parent_len;
- }
- else
- {
- /* The parent path does not end in a directory separator. The
- first character in the child after the common prefix must be
- a directory separator.
- Note that CHILD must hold at least parent_len characters for
- filename_ncmp to return zero. If the character at parent_len
- is nul due to CHILD containing the same path as PARENT, the
- IS_DIR_SEPARATOR check will fail here. */
- if (!IS_DIR_SEPARATOR (child[parent_len]))
- return NULL;
- /* The first child component starts after the separator after the
- common prefix. */
- child_component = child + parent_len + 1;
- }
- /* The child must contain at least one non-separator character after
- the parent. */
- while (*child_component != '\0')
- {
- if (!IS_DIR_SEPARATOR (*child_component))
- return child_component;
- child_component++;
- }
- return NULL;
- }
- /* See gdbsupport/pathstuff.h. */
- bool
- contains_dir_separator (const char *path)
- {
- for (; *path != '\0'; path++)
- {
- if (IS_DIR_SEPARATOR (*path))
- return true;
- }
- return false;
- }
- /* See gdbsupport/pathstuff.h. */
- std::string
- get_standard_cache_dir ()
- {
- #ifdef __APPLE__
- #define HOME_CACHE_DIR "Library/Caches"
- #else
- #define HOME_CACHE_DIR ".cache"
- #endif
- #ifndef __APPLE__
- const char *xdg_cache_home = getenv ("XDG_CACHE_HOME");
- if (xdg_cache_home != NULL && xdg_cache_home[0] != '\0')
- {
- /* Make sure the path is absolute and tilde-expanded. */
- gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (xdg_cache_home));
- return string_printf ("%s/gdb", abs.get ());
- }
- #endif
- const char *home = getenv ("HOME");
- if (home != NULL && home[0] != '\0')
- {
- /* Make sure the path is absolute and tilde-expanded. */
- gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (home));
- return string_printf ("%s/" HOME_CACHE_DIR "/gdb", abs.get ());
- }
- #ifdef WIN32
- const char *win_home = getenv ("LOCALAPPDATA");
- if (win_home != NULL && win_home[0] != '\0')
- {
- /* Make sure the path is absolute and tilde-expanded. */
- gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (win_home));
- return string_printf ("%s/gdb", abs.get ());
- }
- #endif
- return {};
- }
- /* See gdbsupport/pathstuff.h. */
- std::string
- get_standard_temp_dir ()
- {
- #ifdef WIN32
- const char *tmp = getenv ("TMP");
- if (tmp != nullptr)
- return tmp;
- tmp = getenv ("TEMP");
- if (tmp != nullptr)
- return tmp;
- error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));
- #else
- const char *tmp = getenv ("TMPDIR");
- if (tmp != nullptr)
- return tmp;
- return "/tmp";
- #endif
- }
- /* See pathstuff.h. */
- std::string
- get_standard_config_dir ()
- {
- #ifdef __APPLE__
- #define HOME_CONFIG_DIR "Library/Preferences"
- #else
- #define HOME_CONFIG_DIR ".config"
- #endif
- #ifndef __APPLE__
- const char *xdg_config_home = getenv ("XDG_CONFIG_HOME");
- if (xdg_config_home != NULL && xdg_config_home[0] != '\0')
- {
- /* Make sure the path is absolute and tilde-expanded. */
- gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (xdg_config_home));
- return string_printf ("%s/gdb", abs.get ());
- }
- #endif
- const char *home = getenv ("HOME");
- if (home != NULL && home[0] != '\0')
- {
- /* Make sure the path is absolute and tilde-expanded. */
- gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (home));
- return string_printf ("%s/" HOME_CONFIG_DIR "/gdb", abs.get ());
- }
- return {};
- }
- /* See pathstuff.h. */
- std::string
- get_standard_config_filename (const char *filename)
- {
- std::string config_dir = get_standard_config_dir ();
- if (config_dir != "")
- {
- const char *tmp = (*filename == '.') ? (filename + 1) : filename;
- std::string path = config_dir + SLASH_STRING + std::string (tmp);
- return path;
- }
- return {};
- }
- /* See pathstuff.h. */
- std::string
- find_gdb_home_config_file (const char *name, struct stat *buf)
- {
- gdb_assert (name != nullptr);
- gdb_assert (*name != '\0');
- std::string config_dir_file = get_standard_config_filename (name);
- if (!config_dir_file.empty ())
- {
- if (stat (config_dir_file.c_str (), buf) == 0)
- return config_dir_file;
- }
- const char *homedir = getenv ("HOME");
- if (homedir != nullptr && homedir[0] != '\0')
- {
- /* Make sure the path is absolute and tilde-expanded. */
- gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (homedir));
- std::string path = (std::string (abs.get ()) + SLASH_STRING
- + std::string (name));
- if (stat (path.c_str (), buf) == 0)
- return path;
- }
- return {};
- }
- /* See gdbsupport/pathstuff.h. */
- const char *
- get_shell ()
- {
- const char *ret = getenv ("SHELL");
- if (ret == NULL)
- ret = "/bin/sh";
- return ret;
- }
- /* See gdbsupport/pathstuff.h. */
- gdb::char_vector
- make_temp_filename (const std::string &f)
- {
- gdb::char_vector filename_temp (f.length () + 8);
- strcpy (filename_temp.data (), f.c_str ());
- strcat (filename_temp.data () + f.size (), "-XXXXXX");
- return filename_temp;
- }
|