t7501-commit.sh: explicitly check that -F prevents invoking the editor
[git/git.git] / symlinks.c
CommitLineData
f859c846
JH
1#include "cache.h"
2
c40641b7
LT
3struct pathname {
4 int len;
f859c846 5 char path[PATH_MAX];
c40641b7
LT
6};
7
8/* Return matching pathname prefix length, or zero if not matching */
9static inline int match_pathname(int len, const char *name, struct pathname *match)
10{
11 int match_len = match->len;
12 return (len > match_len &&
13 name[match_len] == '/' &&
14 !memcmp(name, match->path, match_len)) ? match_len : 0;
15}
16
17static inline void set_pathname(int len, const char *name, struct pathname *match)
18{
19 if (len < PATH_MAX) {
20 match->len = len;
21 memcpy(match->path, name, len);
22 match->path[len] = 0;
f859c846 23 }
c40641b7
LT
24}
25
26int has_symlink_leading_path(int len, const char *name)
27{
28 static struct pathname link, nonlink;
29 char path[PATH_MAX];
30 struct stat st;
31 char *sp;
32 int known_dir;
f859c846 33
c40641b7
LT
34 /*
35 * See if the last known symlink cache matches.
36 */
37 if (match_pathname(len, name, &link))
38 return 1;
f859c846 39
c40641b7
LT
40 /*
41 * Get rid of the last known directory part
42 */
43 known_dir = match_pathname(len, name, &nonlink);
44
45 while ((sp = strchr(name + known_dir + 1, '/')) != NULL) {
46 int thislen = sp - name ;
47 memcpy(path, name, thislen);
48 path[thislen] = 0;
f859c846
JH
49
50 if (lstat(path, &st))
51 return 0;
c40641b7
LT
52 if (S_ISDIR(st.st_mode)) {
53 set_pathname(thislen, path, &nonlink);
54 known_dir = thislen;
55 continue;
56 }
f859c846 57 if (S_ISLNK(st.st_mode)) {
c40641b7 58 set_pathname(thislen, path, &link);
f859c846
JH
59 return 1;
60 }
c40641b7 61 break;
f859c846
JH
62 }
63 return 0;
64}