#include "cache.h" struct pathname { int len; char path[PATH_MAX]; }; /* Return matching pathname prefix length, or zero if not matching */ static inline int match_pathname(int len, const char *name, struct pathname *match) { int match_len = match->len; return (len > match_len && name[match_len] == '/' && !memcmp(name, match->path, match_len)) ? match_len : 0; } static inline void set_pathname(int len, const char *name, struct pathname *match) { if (len < PATH_MAX) { match->len = len; memcpy(match->path, name, len); match->path[len] = 0; } } int has_symlink_leading_path(int len, const char *name) { static struct pathname link, nonlink; char path[PATH_MAX]; struct stat st; char *sp; int known_dir; /* * See if the last known symlink cache matches. */ if (match_pathname(len, name, &link)) return 1; /* * Get rid of the last known directory part */ known_dir = match_pathname(len, name, &nonlink); while ((sp = strchr(name + known_dir + 1, '/')) != NULL) { int thislen = sp - name ; memcpy(path, name, thislen); path[thislen] = 0; if (lstat(path, &st)) return 0; if (S_ISDIR(st.st_mode)) { set_pathname(thislen, path, &nonlink); known_dir = thislen; continue; } if (S_ISLNK(st.st_mode)) { set_pathname(thislen, path, &link); return 1; } break; } return 0; }