Line | Count | Source (jump to first uncovered line) |
1 | | #include "git-compat-util.h" |
2 | | #include "abspath.h" |
3 | | #include "strbuf.h" |
4 | | |
5 | | /* |
6 | | * Do not use this for inspecting *tracked* content. When path is a |
7 | | * symlink to a directory, we do not want to say it is a directory when |
8 | | * dealing with tracked content in the working tree. |
9 | | */ |
10 | | int is_directory(const char *path) |
11 | 7.22k | { |
12 | 7.22k | struct stat st; |
13 | 7.22k | return (!stat(path, &st) && S_ISDIR(st.st_mode)); |
14 | 7.22k | } |
15 | | |
16 | | /* removes the last path component from 'path' except if 'path' is root */ |
17 | | static void strip_last_component(struct strbuf *path) |
18 | 0 | { |
19 | 0 | size_t offset = offset_1st_component(path->buf); |
20 | 0 | size_t len = path->len; |
21 | | |
22 | | /* Find start of the last component */ |
23 | 0 | while (offset < len && !is_dir_sep(path->buf[len - 1])) |
24 | 0 | len--; |
25 | | /* Skip sequences of multiple path-separators */ |
26 | 0 | while (offset < len && is_dir_sep(path->buf[len - 1])) |
27 | 0 | len--; |
28 | |
|
29 | 0 | strbuf_setlen(path, len); |
30 | 0 | } |
31 | | |
32 | | /* get (and remove) the next component in 'remaining' and place it in 'next' */ |
33 | | static void get_next_component(struct strbuf *next, struct strbuf *remaining) |
34 | 47.4k | { |
35 | 47.4k | char *start = NULL; |
36 | 47.4k | char *end = NULL; |
37 | | |
38 | 47.4k | strbuf_reset(next); |
39 | | |
40 | | /* look for the next component */ |
41 | | /* Skip sequences of multiple path-separators */ |
42 | 79.9k | for (start = remaining->buf; is_dir_sep(*start); start++) |
43 | 32.4k | ; /* nothing */ |
44 | | /* Find end of the path component */ |
45 | 612k | for (end = start; *end && !is_dir_sep(*end); end++) |
46 | 564k | ; /* nothing */ |
47 | | |
48 | 47.4k | strbuf_add(next, start, end - start); |
49 | | /* remove the component from 'remaining' */ |
50 | 47.4k | strbuf_remove(remaining, 0, end - remaining->buf); |
51 | 47.4k | } |
52 | | |
53 | | /* copies root part from remaining to resolved, canonicalizing it on the way */ |
54 | | static void get_root_part(struct strbuf *resolved, struct strbuf *remaining) |
55 | 15.0k | { |
56 | 15.0k | int offset = offset_1st_component(remaining->buf); |
57 | | |
58 | 15.0k | strbuf_reset(resolved); |
59 | 15.0k | strbuf_add(resolved, remaining->buf, offset); |
60 | | #ifdef GIT_WINDOWS_NATIVE |
61 | | convert_slashes(resolved->buf); |
62 | | #endif |
63 | 15.0k | strbuf_remove(remaining, 0, offset); |
64 | 15.0k | } |
65 | | |
66 | | /* We allow "recursive" symbolic links. Only within reason, though. */ |
67 | | #ifndef MAXSYMLINKS |
68 | 0 | #define MAXSYMLINKS 32 |
69 | | #endif |
70 | | |
71 | | /* |
72 | | * If set, any number of trailing components may be missing; otherwise, only one |
73 | | * may be. |
74 | | */ |
75 | 2.44k | #define REALPATH_MANY_MISSING (1 << 0) |
76 | | /* Should we die if there's an error? */ |
77 | 15.0k | #define REALPATH_DIE_ON_ERROR (1 << 1) |
78 | | |
79 | | static char *strbuf_realpath_1(struct strbuf *resolved, const char *path, |
80 | | int flags) |
81 | 15.0k | { |
82 | 15.0k | struct strbuf remaining = STRBUF_INIT; |
83 | 15.0k | struct strbuf next = STRBUF_INIT; |
84 | 15.0k | struct strbuf symlink = STRBUF_INIT; |
85 | 15.0k | char *retval = NULL; |
86 | 15.0k | int num_symlinks = 0; |
87 | 15.0k | struct stat st; |
88 | | |
89 | 15.0k | if (!*path) { |
90 | 0 | if (flags & REALPATH_DIE_ON_ERROR) |
91 | 0 | die("The empty string is not a valid path"); |
92 | 0 | else |
93 | 0 | goto error_out; |
94 | 0 | } |
95 | | |
96 | 15.0k | strbuf_addstr(&remaining, path); |
97 | 15.0k | get_root_part(resolved, &remaining); |
98 | | |
99 | 15.0k | if (!resolved->len) { |
100 | | /* relative path; can use CWD as the initial resolved path */ |
101 | 2 | if (strbuf_getcwd(resolved)) { |
102 | 0 | if (flags & REALPATH_DIE_ON_ERROR) |
103 | 0 | die_errno("unable to get current working directory"); |
104 | 0 | else |
105 | 0 | goto error_out; |
106 | 0 | } |
107 | 2 | } |
108 | | |
109 | | /* Iterate over the remaining path components */ |
110 | 62.4k | while (remaining.len > 0) { |
111 | 47.4k | get_next_component(&next, &remaining); |
112 | | |
113 | 47.4k | if (next.len == 0) { |
114 | 0 | continue; /* empty component */ |
115 | 47.4k | } else if (next.len == 1 && !strcmp(next.buf, ".")) { |
116 | 0 | continue; /* '.' component */ |
117 | 47.4k | } else if (next.len == 2 && !strcmp(next.buf, "..")) { |
118 | | /* '..' component; strip the last path component */ |
119 | 0 | strip_last_component(resolved); |
120 | 0 | continue; |
121 | 0 | } |
122 | | |
123 | | /* append the next component and resolve resultant path */ |
124 | 47.4k | if (!is_dir_sep(resolved->buf[resolved->len - 1])) |
125 | 32.4k | strbuf_addch(resolved, '/'); |
126 | 47.4k | strbuf_addbuf(resolved, &next); |
127 | | |
128 | 47.4k | if (lstat(resolved->buf, &st)) { |
129 | | /* error out unless this was the last component */ |
130 | 2.44k | if (errno != ENOENT || |
131 | 2.44k | (!(flags & REALPATH_MANY_MISSING) && remaining.len)) { |
132 | 0 | if (flags & REALPATH_DIE_ON_ERROR) |
133 | 0 | die_errno("Invalid path '%s'", |
134 | 0 | resolved->buf); |
135 | 0 | else |
136 | 0 | goto error_out; |
137 | 0 | } |
138 | 45.0k | } else if (S_ISLNK(st.st_mode)) { |
139 | 0 | ssize_t len; |
140 | 0 | strbuf_reset(&symlink); |
141 | |
|
142 | 0 | if (num_symlinks++ > MAXSYMLINKS) { |
143 | 0 | errno = ELOOP; |
144 | |
|
145 | 0 | if (flags & REALPATH_DIE_ON_ERROR) |
146 | 0 | die("More than %d nested symlinks " |
147 | 0 | "on path '%s'", MAXSYMLINKS, path); |
148 | 0 | else |
149 | 0 | goto error_out; |
150 | 0 | } |
151 | | |
152 | 0 | len = strbuf_readlink(&symlink, resolved->buf, |
153 | 0 | st.st_size); |
154 | 0 | if (len < 0) { |
155 | 0 | if (flags & REALPATH_DIE_ON_ERROR) |
156 | 0 | die_errno("Invalid symlink '%s'", |
157 | 0 | resolved->buf); |
158 | 0 | else |
159 | 0 | goto error_out; |
160 | 0 | } |
161 | | |
162 | 0 | if (is_absolute_path(symlink.buf)) { |
163 | | /* absolute symlink; set resolved to root */ |
164 | 0 | get_root_part(resolved, &symlink); |
165 | 0 | } else { |
166 | | /* |
167 | | * relative symlink |
168 | | * strip off the last component since it will |
169 | | * be replaced with the contents of the symlink |
170 | | */ |
171 | 0 | strip_last_component(resolved); |
172 | 0 | } |
173 | | |
174 | | /* |
175 | | * if there are still remaining components to resolve |
176 | | * then append them to symlink |
177 | | */ |
178 | 0 | if (remaining.len) { |
179 | 0 | strbuf_addch(&symlink, '/'); |
180 | 0 | strbuf_addbuf(&symlink, &remaining); |
181 | 0 | } |
182 | | |
183 | | /* |
184 | | * use the symlink as the remaining components that |
185 | | * need to be resolved |
186 | | */ |
187 | 0 | strbuf_swap(&symlink, &remaining); |
188 | 0 | } |
189 | 47.4k | } |
190 | | |
191 | 15.0k | retval = resolved->buf; |
192 | | |
193 | 15.0k | error_out: |
194 | 15.0k | strbuf_release(&remaining); |
195 | 15.0k | strbuf_release(&next); |
196 | 15.0k | strbuf_release(&symlink); |
197 | | |
198 | 15.0k | if (!retval) |
199 | 0 | strbuf_reset(resolved); |
200 | | |
201 | 15.0k | return retval; |
202 | 15.0k | } |
203 | | |
204 | | /* |
205 | | * Return the real path (i.e., absolute path, with symlinks resolved |
206 | | * and extra slashes removed) equivalent to the specified path. (If |
207 | | * you want an absolute path but don't mind links, use |
208 | | * absolute_path().) Places the resolved realpath in the provided strbuf. |
209 | | * |
210 | | * The directory part of path (i.e., everything up to the last |
211 | | * dir_sep) must denote a valid, existing directory, but the last |
212 | | * component need not exist. If die_on_error is set, then die with an |
213 | | * informative error message if there is a problem. Otherwise, return |
214 | | * NULL on errors (without generating any output). |
215 | | */ |
216 | | char *strbuf_realpath(struct strbuf *resolved, const char *path, |
217 | | int die_on_error) |
218 | 15.0k | { |
219 | 15.0k | return strbuf_realpath_1(resolved, path, |
220 | 15.0k | die_on_error ? REALPATH_DIE_ON_ERROR : 0); |
221 | 15.0k | } |
222 | | |
223 | | /* |
224 | | * Just like strbuf_realpath, but allows an arbitrary number of path |
225 | | * components to be missing. |
226 | | */ |
227 | | char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path, |
228 | | int die_on_error) |
229 | 0 | { |
230 | 0 | return strbuf_realpath_1(resolved, path, |
231 | 0 | ((die_on_error ? REALPATH_DIE_ON_ERROR : 0) | |
232 | 0 | REALPATH_MANY_MISSING)); |
233 | 0 | } |
234 | | |
235 | | char *real_pathdup(const char *path, int die_on_error) |
236 | 13.7k | { |
237 | 13.7k | struct strbuf realpath = STRBUF_INIT; |
238 | 13.7k | char *retval = NULL; |
239 | | |
240 | 13.7k | if (strbuf_realpath(&realpath, path, die_on_error)) |
241 | 13.7k | retval = strbuf_detach(&realpath, NULL); |
242 | | |
243 | 13.7k | strbuf_release(&realpath); |
244 | | |
245 | 13.7k | return retval; |
246 | 13.7k | } |
247 | | |
248 | | /* |
249 | | * Use this to get an absolute path from a relative one. If you want |
250 | | * to resolve links, you should use strbuf_realpath. |
251 | | */ |
252 | | const char *absolute_path(const char *path) |
253 | 0 | { |
254 | 0 | static struct strbuf sb = STRBUF_INIT; |
255 | 0 | strbuf_reset(&sb); |
256 | 0 | strbuf_add_absolute_path(&sb, path); |
257 | 0 | return sb.buf; |
258 | 0 | } |
259 | | |
260 | | char *absolute_pathdup(const char *path) |
261 | 0 | { |
262 | 0 | struct strbuf sb = STRBUF_INIT; |
263 | 0 | strbuf_add_absolute_path(&sb, path); |
264 | 0 | return strbuf_detach(&sb, NULL); |
265 | 0 | } |
266 | | |
267 | | char *prefix_filename(const char *pfx, const char *arg) |
268 | 3.37k | { |
269 | 3.37k | struct strbuf path = STRBUF_INIT; |
270 | 3.37k | size_t pfx_len = pfx ? strlen(pfx) : 0; |
271 | | |
272 | 3.37k | if (!pfx_len) |
273 | 3.37k | ; /* nothing to prefix */ |
274 | 0 | else if (is_absolute_path(arg)) |
275 | 0 | pfx_len = 0; |
276 | 0 | else |
277 | 0 | strbuf_add(&path, pfx, pfx_len); |
278 | | |
279 | 3.37k | strbuf_addstr(&path, arg); |
280 | | #ifdef GIT_WINDOWS_NATIVE |
281 | | convert_slashes(path.buf + pfx_len); |
282 | | #endif |
283 | 3.37k | return strbuf_detach(&path, NULL); |
284 | 3.37k | } |
285 | | |
286 | | char *prefix_filename_except_for_dash(const char *pfx, const char *arg) |
287 | 0 | { |
288 | 0 | if (!strcmp(arg, "-")) |
289 | 0 | return xstrdup(arg); |
290 | 0 | return prefix_filename(pfx, arg); |
291 | 0 | } |
292 | | |
293 | | void strbuf_add_absolute_path(struct strbuf *sb, const char *path) |
294 | 35.1k | { |
295 | 35.1k | if (!*path) |
296 | 0 | die("The empty string is not a valid path"); |
297 | 35.1k | if (!is_absolute_path(path)) { |
298 | 0 | struct stat cwd_stat, pwd_stat; |
299 | 0 | size_t orig_len = sb->len; |
300 | 0 | char *cwd = xgetcwd(); |
301 | 0 | char *pwd = getenv("PWD"); |
302 | 0 | if (pwd && strcmp(pwd, cwd) && |
303 | 0 | !stat(cwd, &cwd_stat) && |
304 | 0 | (cwd_stat.st_dev || cwd_stat.st_ino) && |
305 | 0 | !stat(pwd, &pwd_stat) && |
306 | 0 | pwd_stat.st_dev == cwd_stat.st_dev && |
307 | 0 | pwd_stat.st_ino == cwd_stat.st_ino) |
308 | 0 | strbuf_addstr(sb, pwd); |
309 | 0 | else |
310 | 0 | strbuf_addstr(sb, cwd); |
311 | 0 | if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1])) |
312 | 0 | strbuf_addch(sb, '/'); |
313 | 0 | free(cwd); |
314 | 0 | } |
315 | 35.1k | strbuf_addstr(sb, path); |
316 | 35.1k | } |
317 | | |
318 | | void strbuf_add_real_path(struct strbuf *sb, const char *path) |
319 | 0 | { |
320 | 0 | if (sb->len) { |
321 | 0 | struct strbuf resolved = STRBUF_INIT; |
322 | 0 | strbuf_realpath(&resolved, path, 1); |
323 | 0 | strbuf_addbuf(sb, &resolved); |
324 | 0 | strbuf_release(&resolved); |
325 | 0 | } else |
326 | 0 | strbuf_realpath(sb, path, 1); |
327 | 0 | } |