| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 1 | #include "cache.h" |
| 2 | |
| Junio C Hamano | 90b4a71 | 2008-09-09 08:27:07 | [diff] [blame] | 3 | /* |
| 4 | * Do not use this for inspecting *tracked* content. When path is a |
| 5 | * symlink to a directory, we do not want to say it is a directory when |
| 6 | * dealing with tracked content in the working tree. |
| 7 | */ |
| 8 | int is_directory(const char *path) |
| 9 | { |
| 10 | struct stat st; |
| 11 | return (!stat(path, &st) && S_ISDIR(st.st_mode)); |
| 12 | } |
| 13 | |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 14 | /* We allow "recursive" symbolic links. Only within reason, though. */ |
| 15 | #define MAXDEPTH 5 |
| 16 | |
| Carlos Martín Nieto | e2a57aa | 2011-03-17 11:26:46 | [diff] [blame] | 17 | /* |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 18 | * Return the real path (i.e., absolute path, with symlinks resolved |
| 19 | * and extra slashes removed) equivalent to the specified path. (If |
| 20 | * you want an absolute path but don't mind links, use |
| 21 | * absolute_path().) The return value is a pointer to a static |
| 22 | * buffer. |
| 23 | * |
| 24 | * The input and all intermediate paths must be shorter than MAX_PATH. |
| 25 | * The directory part of path (i.e., everything up to the last |
| 26 | * dir_sep) must denote a valid, existing directory, but the last |
| 27 | * component need not exist. If die_on_error is set, then die with an |
| 28 | * informative error message if there is a problem. Otherwise, return |
| 29 | * NULL on errors (without generating any output). |
| Carlos Martín Nieto | e2a57aa | 2011-03-17 11:26:46 | [diff] [blame] | 30 | * |
| 31 | * If path is our buffer, then return path, as it's already what the |
| 32 | * user wants. |
| 33 | */ |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 34 | static const char *real_path_internal(const char *path, int die_on_error) |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 35 | { |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 36 | static struct strbuf sb = STRBUF_INIT; |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 37 | char *retval = NULL; |
| Michael Haggerty | d6052ab | 2012-10-28 16:16:21 | [diff] [blame] | 38 | |
| 39 | /* |
| 40 | * If we have to temporarily chdir(), store the original CWD |
| 41 | * here so that we can chdir() back to it at the end of the |
| 42 | * function: |
| 43 | */ |
| René Scharfe | 251277a | 2014-07-28 18:27:34 | [diff] [blame] | 44 | struct strbuf cwd = STRBUF_INIT; |
| Michael Haggerty | d6052ab | 2012-10-28 16:16:21 | [diff] [blame] | 45 | |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 46 | int depth = MAXDEPTH; |
| 47 | char *last_elem = NULL; |
| 48 | struct stat st; |
| 49 | |
| Carlos Martín Nieto | 1d679de | 2011-03-16 16:06:17 | [diff] [blame] | 50 | /* We've already done it */ |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 51 | if (path == sb.buf) |
| Carlos Martín Nieto | 1d679de | 2011-03-16 16:06:17 | [diff] [blame] | 52 | return path; |
| 53 | |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 54 | if (!*path) { |
| 55 | if (die_on_error) |
| 56 | die("The empty string is not a valid path"); |
| 57 | else |
| 58 | goto error_out; |
| 59 | } |
| Michael Haggerty | 3efe5d1 | 2012-09-06 22:41:01 | [diff] [blame] | 60 | |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 61 | strbuf_reset(&sb); |
| 62 | strbuf_addstr(&sb, path); |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 63 | |
| 64 | while (depth--) { |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 65 | if (!is_directory(sb.buf)) { |
| 66 | char *last_slash = find_last_dir_sep(sb.buf); |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 67 | if (last_slash) { |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 68 | last_elem = xstrdup(last_slash + 1); |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 69 | strbuf_setlen(&sb, last_slash - sb.buf + 1); |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 70 | } else { |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 71 | last_elem = xmemdupz(sb.buf, sb.len); |
| 72 | strbuf_reset(&sb); |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 73 | } |
| 74 | } |
| 75 | |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 76 | if (sb.len) { |
| René Scharfe | 251277a | 2014-07-28 18:27:34 | [diff] [blame] | 77 | if (!cwd.len && strbuf_getcwd(&cwd)) { |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 78 | if (die_on_error) |
| 79 | die_errno("Could not get current working directory"); |
| 80 | else |
| 81 | goto error_out; |
| 82 | } |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 83 | |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 84 | if (chdir(sb.buf)) { |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 85 | if (die_on_error) |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 86 | die_errno("Could not switch to '%s'", |
| 87 | sb.buf); |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 88 | else |
| 89 | goto error_out; |
| 90 | } |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 91 | } |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 92 | if (strbuf_getcwd(&sb)) { |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 93 | if (die_on_error) |
| 94 | die_errno("Could not get current working directory"); |
| 95 | else |
| 96 | goto error_out; |
| 97 | } |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 98 | |
| 99 | if (last_elem) { |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 100 | if (sb.len && !is_dir_sep(sb.buf[sb.len - 1])) |
| 101 | strbuf_addch(&sb, '/'); |
| 102 | strbuf_addstr(&sb, last_elem); |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 103 | free(last_elem); |
| 104 | last_elem = NULL; |
| 105 | } |
| 106 | |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 107 | if (!lstat(sb.buf, &st) && S_ISLNK(st.st_mode)) { |
| 108 | struct strbuf next_sb = STRBUF_INIT; |
| 109 | ssize_t len = strbuf_readlink(&next_sb, sb.buf, 0); |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 110 | if (len < 0) { |
| 111 | if (die_on_error) |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 112 | die_errno("Invalid symlink '%s'", |
| 113 | sb.buf); |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 114 | else |
| 115 | goto error_out; |
| 116 | } |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 117 | strbuf_swap(&sb, &next_sb); |
| 118 | strbuf_release(&next_sb); |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 119 | } else |
| 120 | break; |
| 121 | } |
| 122 | |
| René Scharfe | 2fdb9ce | 2014-07-28 18:28:30 | [diff] [blame] | 123 | retval = sb.buf; |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 124 | error_out: |
| 125 | free(last_elem); |
| René Scharfe | 251277a | 2014-07-28 18:27:34 | [diff] [blame] | 126 | if (cwd.len && chdir(cwd.buf)) |
| 127 | die_errno("Could not change back to '%s'", cwd.buf); |
| 128 | strbuf_release(&cwd); |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 129 | |
| Michael Haggerty | 038e55f | 2012-10-28 16:16:20 | [diff] [blame] | 130 | return retval; |
| 131 | } |
| 132 | |
| 133 | const char *real_path(const char *path) |
| 134 | { |
| 135 | return real_path_internal(path, 1); |
| Dmitry Potapov | 5b8e6f8 | 2008-06-27 20:46:42 | [diff] [blame] | 136 | } |
| Johannes Sixt | 10c4c88 | 2008-07-21 19:19:55 | [diff] [blame] | 137 | |
| Michael Haggerty | e3e46cd | 2012-10-28 16:16:22 | [diff] [blame] | 138 | const char *real_path_if_valid(const char *path) |
| 139 | { |
| 140 | return real_path_internal(path, 0); |
| 141 | } |
| 142 | |
| Carlos Martín Nieto | e2a57aa | 2011-03-17 11:26:46 | [diff] [blame] | 143 | /* |
| 144 | * Use this to get an absolute path from a relative one. If you want |
| 145 | * to resolve links, you should use real_path. |
| Carlos Martín Nieto | e2a57aa | 2011-03-17 11:26:46 | [diff] [blame] | 146 | */ |
| 147 | const char *absolute_path(const char *path) |
| Johannes Sixt | 10c4c88 | 2008-07-21 19:19:55 | [diff] [blame] | 148 | { |
| René Scharfe | 679eebe | 2014-07-28 18:33:55 | [diff] [blame] | 149 | static struct strbuf sb = STRBUF_INIT; |
| 150 | strbuf_reset(&sb); |
| 151 | strbuf_add_absolute_path(&sb, path); |
| 152 | return sb.buf; |
| Johannes Sixt | 10c4c88 | 2008-07-21 19:19:55 | [diff] [blame] | 153 | } |
| Dmitry Ivankov | 0687628 | 2011-08-11 09:15:38 | [diff] [blame] | 154 | |
| 155 | /* |
| 156 | * Unlike prefix_path, this should be used if the named file does |
| 157 | * not have to interact with index entry; i.e. name of a random file |
| 158 | * on the filesystem. |
| 159 | */ |
| 160 | const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) |
| 161 | { |
| Antoine Pelisse | fc2b621 | 2013-12-14 11:31:16 | [diff] [blame] | 162 | static struct strbuf path = STRBUF_INIT; |
| Jonathan Nieder | 380395d | 2013-05-02 19:26:08 | [diff] [blame] | 163 | #ifndef GIT_WINDOWS_NATIVE |
| Dmitry Ivankov | 0687628 | 2011-08-11 09:15:38 | [diff] [blame] | 164 | if (!pfx_len || is_absolute_path(arg)) |
| 165 | return arg; |
| Antoine Pelisse | fc2b621 | 2013-12-14 11:31:16 | [diff] [blame] | 166 | strbuf_reset(&path); |
| 167 | strbuf_add(&path, pfx, pfx_len); |
| 168 | strbuf_addstr(&path, arg); |
| Dmitry Ivankov | 0687628 | 2011-08-11 09:15:38 | [diff] [blame] | 169 | #else |
| 170 | char *p; |
| 171 | /* don't add prefix to absolute paths, but still replace '\' by '/' */ |
| Antoine Pelisse | fc2b621 | 2013-12-14 11:31:16 | [diff] [blame] | 172 | strbuf_reset(&path); |
| Dmitry Ivankov | 0687628 | 2011-08-11 09:15:38 | [diff] [blame] | 173 | if (is_absolute_path(arg)) |
| 174 | pfx_len = 0; |
| 175 | else if (pfx_len) |
| Antoine Pelisse | fc2b621 | 2013-12-14 11:31:16 | [diff] [blame] | 176 | strbuf_add(&path, pfx, pfx_len); |
| 177 | strbuf_addstr(&path, arg); |
| 178 | for (p = path.buf + pfx_len; *p; p++) |
| Dmitry Ivankov | 0687628 | 2011-08-11 09:15:38 | [diff] [blame] | 179 | if (*p == '\\') |
| 180 | *p = '/'; |
| 181 | #endif |
| Antoine Pelisse | fc2b621 | 2013-12-14 11:31:16 | [diff] [blame] | 182 | return path.buf; |
| Dmitry Ivankov | 0687628 | 2011-08-11 09:15:38 | [diff] [blame] | 183 | } |