]>
Commit | Line | Data |
---|---|---|
f859c846 JH |
1 | #include "cache.h" |
2 | ||
c40641b7 LT |
3 | struct 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 */ | |
9 | static 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 | ||
17 | static 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 | ||
26 | int 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 | } |