| #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; | 
 | } |