symlinks.con commit Merge git://git.kernel.org/pub/scm/gitk/gitk (35d2f73)
   1#include "cache.h"
   2
   3struct pathname {
   4        int len;
   5        char path[PATH_MAX];
   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;
  23        }
  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;
  33
  34        /*
  35         * See if the last known symlink cache matches.
  36         */
  37        if (match_pathname(len, name, &link))
  38                return 1;
  39
  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;
  49
  50                if (lstat(path, &st))
  51                        return 0;
  52                if (S_ISDIR(st.st_mode)) {
  53                        set_pathname(thislen, path, &nonlink);
  54                        known_dir = thislen;
  55                        continue;
  56                }
  57                if (S_ISLNK(st.st_mode)) {
  58                        set_pathname(thislen, path, &link);
  59                        return 1;
  60                }
  61                break;
  62        }
  63        return 0;
  64}