]>
Commit | Line | Data |
---|---|---|
5b8e6f85 DP |
1 | #include "cache.h" |
2 | ||
90b4a71c JH |
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 | ||
05b458c1 BW |
14 | /* removes the last path component from 'path' except if 'path' is root */ |
15 | static void strip_last_component(struct strbuf *path) | |
16 | { | |
17 | size_t offset = offset_1st_component(path->buf); | |
18 | size_t len = path->len; | |
19 | ||
20 | /* Find start of the last component */ | |
21 | while (offset < len && !is_dir_sep(path->buf[len - 1])) | |
22 | len--; | |
23 | /* Skip sequences of multiple path-separators */ | |
24 | while (offset < len && is_dir_sep(path->buf[len - 1])) | |
25 | len--; | |
26 | ||
27 | strbuf_setlen(path, len); | |
28 | } | |
29 | ||
30 | /* get (and remove) the next component in 'remaining' and place it in 'next' */ | |
31 | static void get_next_component(struct strbuf *next, struct strbuf *remaining) | |
32 | { | |
33 | char *start = NULL; | |
34 | char *end = NULL; | |
35 | ||
36 | strbuf_reset(next); | |
37 | ||
38 | /* look for the next component */ | |
39 | /* Skip sequences of multiple path-separators */ | |
40 | for (start = remaining->buf; is_dir_sep(*start); start++) | |
41 | ; /* nothing */ | |
42 | /* Find end of the path component */ | |
43 | for (end = start; *end && !is_dir_sep(*end); end++) | |
44 | ; /* nothing */ | |
45 | ||
46 | strbuf_add(next, start, end - start); | |
47 | /* remove the component from 'remaining' */ | |
48 | strbuf_remove(remaining, 0, end - remaining->buf); | |
49 | } | |
50 | ||
5b8e6f85 | 51 | /* We allow "recursive" symbolic links. Only within reason, though. */ |
05b458c1 | 52 | #define MAXSYMLINKS 5 |
5b8e6f85 | 53 | |
e2a57aac | 54 | /* |
038e55fe MH |
55 | * Return the real path (i.e., absolute path, with symlinks resolved |
56 | * and extra slashes removed) equivalent to the specified path. (If | |
57 | * you want an absolute path but don't mind links, use | |
a1ae4841 | 58 | * absolute_path().) Places the resolved realpath in the provided strbuf. |
038e55fe | 59 | * |
038e55fe MH |
60 | * The directory part of path (i.e., everything up to the last |
61 | * dir_sep) must denote a valid, existing directory, but the last | |
62 | * component need not exist. If die_on_error is set, then die with an | |
63 | * informative error message if there is a problem. Otherwise, return | |
64 | * NULL on errors (without generating any output). | |
e2a57aac | 65 | */ |
a1ae4841 BW |
66 | char *strbuf_realpath(struct strbuf *resolved, const char *path, |
67 | int die_on_error) | |
5b8e6f85 | 68 | { |
05b458c1 BW |
69 | struct strbuf remaining = STRBUF_INIT; |
70 | struct strbuf next = STRBUF_INIT; | |
71 | struct strbuf symlink = STRBUF_INIT; | |
038e55fe | 72 | char *retval = NULL; |
05b458c1 | 73 | int num_symlinks = 0; |
5b8e6f85 DP |
74 | struct stat st; |
75 | ||
038e55fe MH |
76 | if (!*path) { |
77 | if (die_on_error) | |
78 | die("The empty string is not a valid path"); | |
79 | else | |
80 | goto error_out; | |
81 | } | |
3efe5d1d | 82 | |
a1ae4841 | 83 | strbuf_reset(resolved); |
5b8e6f85 | 84 | |
05b458c1 BW |
85 | if (is_absolute_path(path)) { |
86 | /* absolute path; start with only root as being resolved */ | |
87 | int offset = offset_1st_component(path); | |
a1ae4841 | 88 | strbuf_add(resolved, path, offset); |
05b458c1 BW |
89 | strbuf_addstr(&remaining, path + offset); |
90 | } else { | |
91 | /* relative path; can use CWD as the initial resolved path */ | |
a1ae4841 | 92 | if (strbuf_getcwd(resolved)) { |
05b458c1 BW |
93 | if (die_on_error) |
94 | die_errno("unable to get current working directory"); | |
95 | else | |
96 | goto error_out; | |
97 | } | |
98 | strbuf_addstr(&remaining, path); | |
99 | } | |
100 | ||
101 | /* Iterate over the remaining path components */ | |
102 | while (remaining.len > 0) { | |
103 | get_next_component(&next, &remaining); | |
104 | ||
105 | if (next.len == 0) { | |
106 | continue; /* empty component */ | |
107 | } else if (next.len == 1 && !strcmp(next.buf, ".")) { | |
108 | continue; /* '.' component */ | |
109 | } else if (next.len == 2 && !strcmp(next.buf, "..")) { | |
110 | /* '..' component; strip the last path component */ | |
a1ae4841 | 111 | strip_last_component(resolved); |
05b458c1 | 112 | continue; |
5b8e6f85 DP |
113 | } |
114 | ||
05b458c1 | 115 | /* append the next component and resolve resultant path */ |
a1ae4841 BW |
116 | if (!is_dir_sep(resolved->buf[resolved->len - 1])) |
117 | strbuf_addch(resolved, '/'); | |
118 | strbuf_addbuf(resolved, &next); | |
05b458c1 | 119 | |
a1ae4841 | 120 | if (lstat(resolved->buf, &st)) { |
05b458c1 BW |
121 | /* error out unless this was the last component */ |
122 | if (errno != ENOENT || remaining.len) { | |
038e55fe | 123 | if (die_on_error) |
05b458c1 | 124 | die_errno("Invalid path '%s'", |
a1ae4841 | 125 | resolved->buf); |
038e55fe MH |
126 | else |
127 | goto error_out; | |
128 | } | |
05b458c1 BW |
129 | } else if (S_ISLNK(st.st_mode)) { |
130 | ssize_t len; | |
131 | strbuf_reset(&symlink); | |
5b8e6f85 | 132 | |
05b458c1 | 133 | if (num_symlinks++ > MAXSYMLINKS) { |
038e55fe | 134 | if (die_on_error) |
05b458c1 BW |
135 | die("More than %d nested symlinks " |
136 | "on path '%s'", MAXSYMLINKS, path); | |
038e55fe MH |
137 | else |
138 | goto error_out; | |
139 | } | |
5b8e6f85 | 140 | |
a1ae4841 | 141 | len = strbuf_readlink(&symlink, resolved->buf, |
05b458c1 | 142 | st.st_size); |
038e55fe MH |
143 | if (len < 0) { |
144 | if (die_on_error) | |
2fdb9ce0 | 145 | die_errno("Invalid symlink '%s'", |
a1ae4841 | 146 | resolved->buf); |
038e55fe MH |
147 | else |
148 | goto error_out; | |
149 | } | |
05b458c1 BW |
150 | |
151 | if (is_absolute_path(symlink.buf)) { | |
152 | /* absolute symlink; set resolved to root */ | |
153 | int offset = offset_1st_component(symlink.buf); | |
a1ae4841 BW |
154 | strbuf_reset(resolved); |
155 | strbuf_add(resolved, symlink.buf, offset); | |
05b458c1 BW |
156 | strbuf_remove(&symlink, 0, offset); |
157 | } else { | |
158 | /* | |
159 | * relative symlink | |
160 | * strip off the last component since it will | |
161 | * be replaced with the contents of the symlink | |
162 | */ | |
a1ae4841 | 163 | strip_last_component(resolved); |
05b458c1 BW |
164 | } |
165 | ||
166 | /* | |
167 | * if there are still remaining components to resolve | |
168 | * then append them to symlink | |
169 | */ | |
170 | if (remaining.len) { | |
171 | strbuf_addch(&symlink, '/'); | |
172 | strbuf_addbuf(&symlink, &remaining); | |
173 | } | |
174 | ||
175 | /* | |
176 | * use the symlink as the remaining components that | |
177 | * need to be resloved | |
178 | */ | |
179 | strbuf_swap(&symlink, &remaining); | |
180 | } | |
5b8e6f85 DP |
181 | } |
182 | ||
a1ae4841 | 183 | retval = resolved->buf; |
05b458c1 | 184 | |
038e55fe | 185 | error_out: |
05b458c1 BW |
186 | strbuf_release(&remaining); |
187 | strbuf_release(&next); | |
188 | strbuf_release(&symlink); | |
5b8e6f85 | 189 | |
a1ae4841 BW |
190 | if (!retval) |
191 | strbuf_reset(resolved); | |
192 | ||
038e55fe MH |
193 | return retval; |
194 | } | |
195 | ||
196 | const char *real_path(const char *path) | |
197 | { | |
a1ae4841 BW |
198 | static struct strbuf realpath = STRBUF_INIT; |
199 | return strbuf_realpath(&realpath, path, 1); | |
5b8e6f85 | 200 | } |
10c4c881 | 201 | |
e3e46cdb MH |
202 | const char *real_path_if_valid(const char *path) |
203 | { | |
a1ae4841 BW |
204 | static struct strbuf realpath = STRBUF_INIT; |
205 | return strbuf_realpath(&realpath, path, 0); | |
e3e46cdb MH |
206 | } |
207 | ||
72417640 BW |
208 | char *real_pathdup(const char *path) |
209 | { | |
210 | struct strbuf realpath = STRBUF_INIT; | |
211 | char *retval = NULL; | |
212 | ||
213 | if (strbuf_realpath(&realpath, path, 0)) | |
214 | retval = strbuf_detach(&realpath, NULL); | |
215 | ||
216 | strbuf_release(&realpath); | |
217 | ||
218 | return retval; | |
219 | } | |
220 | ||
e2a57aac CMN |
221 | /* |
222 | * Use this to get an absolute path from a relative one. If you want | |
223 | * to resolve links, you should use real_path. | |
e2a57aac CMN |
224 | */ |
225 | const char *absolute_path(const char *path) | |
10c4c881 | 226 | { |
679eebe2 RS |
227 | static struct strbuf sb = STRBUF_INIT; |
228 | strbuf_reset(&sb); | |
229 | strbuf_add_absolute_path(&sb, path); | |
230 | return sb.buf; | |
10c4c881 | 231 | } |
06876284 DI |
232 | |
233 | /* | |
234 | * Unlike prefix_path, this should be used if the named file does | |
235 | * not have to interact with index entry; i.e. name of a random file | |
236 | * on the filesystem. | |
237 | */ | |
238 | const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) | |
239 | { | |
fc2b6214 | 240 | static struct strbuf path = STRBUF_INIT; |
380395d0 | 241 | #ifndef GIT_WINDOWS_NATIVE |
06876284 DI |
242 | if (!pfx_len || is_absolute_path(arg)) |
243 | return arg; | |
fc2b6214 AP |
244 | strbuf_reset(&path); |
245 | strbuf_add(&path, pfx, pfx_len); | |
246 | strbuf_addstr(&path, arg); | |
06876284 | 247 | #else |
06876284 | 248 | /* don't add prefix to absolute paths, but still replace '\' by '/' */ |
fc2b6214 | 249 | strbuf_reset(&path); |
06876284 DI |
250 | if (is_absolute_path(arg)) |
251 | pfx_len = 0; | |
252 | else if (pfx_len) | |
fc2b6214 AP |
253 | strbuf_add(&path, pfx, pfx_len); |
254 | strbuf_addstr(&path, arg); | |
8e9b2080 | 255 | convert_slashes(path.buf + pfx_len); |
06876284 | 256 | #endif |
fc2b6214 | 257 | return path.buf; |
06876284 | 258 | } |