path.con commit path.c: remove home_config_paths() (846e5df)
   1/*
   2 * Utilities for paths and pathnames
   3 */
   4#include "cache.h"
   5#include "strbuf.h"
   6#include "string-list.h"
   7
   8static int get_st_mode_bits(const char *path, int *mode)
   9{
  10        struct stat st;
  11        if (lstat(path, &st) < 0)
  12                return -1;
  13        *mode = st.st_mode;
  14        return 0;
  15}
  16
  17static char bad_path[] = "/bad-path/";
  18
  19static char *get_pathname(void)
  20{
  21        static char pathname_array[4][PATH_MAX];
  22        static int index;
  23        return pathname_array[3 & ++index];
  24}
  25
  26static char *cleanup_path(char *path)
  27{
  28        /* Clean it up */
  29        if (!memcmp(path, "./", 2)) {
  30                path += 2;
  31                while (*path == '/')
  32                        path++;
  33        }
  34        return path;
  35}
  36
  37char *mksnpath(char *buf, size_t n, const char *fmt, ...)
  38{
  39        va_list args;
  40        unsigned len;
  41
  42        va_start(args, fmt);
  43        len = vsnprintf(buf, n, fmt, args);
  44        va_end(args);
  45        if (len >= n) {
  46                strlcpy(buf, bad_path, n);
  47                return buf;
  48        }
  49        return cleanup_path(buf);
  50}
  51
  52static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args)
  53{
  54        const char *git_dir = get_git_dir();
  55        size_t len;
  56
  57        len = strlen(git_dir);
  58        if (n < len + 1)
  59                goto bad;
  60        memcpy(buf, git_dir, len);
  61        if (len && !is_dir_sep(git_dir[len-1]))
  62                buf[len++] = '/';
  63        len += vsnprintf(buf + len, n - len, fmt, args);
  64        if (len >= n)
  65                goto bad;
  66        return cleanup_path(buf);
  67bad:
  68        strlcpy(buf, bad_path, n);
  69        return buf;
  70}
  71
  72char *git_snpath(char *buf, size_t n, const char *fmt, ...)
  73{
  74        char *ret;
  75        va_list args;
  76        va_start(args, fmt);
  77        ret = vsnpath(buf, n, fmt, args);
  78        va_end(args);
  79        return ret;
  80}
  81
  82char *git_pathdup(const char *fmt, ...)
  83{
  84        char path[PATH_MAX], *ret;
  85        va_list args;
  86        va_start(args, fmt);
  87        ret = vsnpath(path, sizeof(path), fmt, args);
  88        va_end(args);
  89        return xstrdup(ret);
  90}
  91
  92char *mkpathdup(const char *fmt, ...)
  93{
  94        char *path;
  95        struct strbuf sb = STRBUF_INIT;
  96        va_list args;
  97
  98        va_start(args, fmt);
  99        strbuf_vaddf(&sb, fmt, args);
 100        va_end(args);
 101        path = xstrdup(cleanup_path(sb.buf));
 102
 103        strbuf_release(&sb);
 104        return path;
 105}
 106
 107char *mkpath(const char *fmt, ...)
 108{
 109        va_list args;
 110        unsigned len;
 111        char *pathname = get_pathname();
 112
 113        va_start(args, fmt);
 114        len = vsnprintf(pathname, PATH_MAX, fmt, args);
 115        va_end(args);
 116        if (len >= PATH_MAX)
 117                return bad_path;
 118        return cleanup_path(pathname);
 119}
 120
 121char *git_path(const char *fmt, ...)
 122{
 123        char *pathname = get_pathname();
 124        va_list args;
 125        char *ret;
 126
 127        va_start(args, fmt);
 128        ret = vsnpath(pathname, PATH_MAX, fmt, args);
 129        va_end(args);
 130        return ret;
 131}
 132
 133char *git_path_submodule(const char *path, const char *fmt, ...)
 134{
 135        char *pathname = get_pathname();
 136        struct strbuf buf = STRBUF_INIT;
 137        const char *git_dir;
 138        va_list args;
 139        unsigned len;
 140
 141        len = strlen(path);
 142        if (len > PATH_MAX-100)
 143                return bad_path;
 144
 145        strbuf_addstr(&buf, path);
 146        if (len && path[len-1] != '/')
 147                strbuf_addch(&buf, '/');
 148        strbuf_addstr(&buf, ".git");
 149
 150        git_dir = read_gitfile(buf.buf);
 151        if (git_dir) {
 152                strbuf_reset(&buf);
 153                strbuf_addstr(&buf, git_dir);
 154        }
 155        strbuf_addch(&buf, '/');
 156
 157        if (buf.len >= PATH_MAX)
 158                return bad_path;
 159        memcpy(pathname, buf.buf, buf.len + 1);
 160
 161        strbuf_release(&buf);
 162        len = strlen(pathname);
 163
 164        va_start(args, fmt);
 165        len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
 166        va_end(args);
 167        if (len >= PATH_MAX)
 168                return bad_path;
 169        return cleanup_path(pathname);
 170}
 171
 172int validate_headref(const char *path)
 173{
 174        struct stat st;
 175        char *buf, buffer[256];
 176        unsigned char sha1[20];
 177        int fd;
 178        ssize_t len;
 179
 180        if (lstat(path, &st) < 0)
 181                return -1;
 182
 183        /* Make sure it is a "refs/.." symlink */
 184        if (S_ISLNK(st.st_mode)) {
 185                len = readlink(path, buffer, sizeof(buffer)-1);
 186                if (len >= 5 && !memcmp("refs/", buffer, 5))
 187                        return 0;
 188                return -1;
 189        }
 190
 191        /*
 192         * Anything else, just open it and try to see if it is a symbolic ref.
 193         */
 194        fd = open(path, O_RDONLY);
 195        if (fd < 0)
 196                return -1;
 197        len = read_in_full(fd, buffer, sizeof(buffer)-1);
 198        close(fd);
 199
 200        /*
 201         * Is it a symbolic ref?
 202         */
 203        if (len < 4)
 204                return -1;
 205        if (!memcmp("ref:", buffer, 4)) {
 206                buf = buffer + 4;
 207                len -= 4;
 208                while (len && isspace(*buf))
 209                        buf++, len--;
 210                if (len >= 5 && !memcmp("refs/", buf, 5))
 211                        return 0;
 212        }
 213
 214        /*
 215         * Is this a detached HEAD?
 216         */
 217        if (!get_sha1_hex(buffer, sha1))
 218                return 0;
 219
 220        return -1;
 221}
 222
 223static struct passwd *getpw_str(const char *username, size_t len)
 224{
 225        struct passwd *pw;
 226        char *username_z = xmemdupz(username, len);
 227        pw = getpwnam(username_z);
 228        free(username_z);
 229        return pw;
 230}
 231
 232/*
 233 * Return a string with ~ and ~user expanded via getpw*.  If buf != NULL,
 234 * then it is a newly allocated string. Returns NULL on getpw failure or
 235 * if path is NULL.
 236 */
 237char *expand_user_path(const char *path)
 238{
 239        struct strbuf user_path = STRBUF_INIT;
 240        const char *to_copy = path;
 241
 242        if (path == NULL)
 243                goto return_null;
 244        if (path[0] == '~') {
 245                const char *first_slash = strchrnul(path, '/');
 246                const char *username = path + 1;
 247                size_t username_len = first_slash - username;
 248                if (username_len == 0) {
 249                        const char *home = getenv("HOME");
 250                        if (!home)
 251                                goto return_null;
 252                        strbuf_addstr(&user_path, home);
 253                } else {
 254                        struct passwd *pw = getpw_str(username, username_len);
 255                        if (!pw)
 256                                goto return_null;
 257                        strbuf_addstr(&user_path, pw->pw_dir);
 258                }
 259                to_copy = first_slash;
 260        }
 261        strbuf_addstr(&user_path, to_copy);
 262        return strbuf_detach(&user_path, NULL);
 263return_null:
 264        strbuf_release(&user_path);
 265        return NULL;
 266}
 267
 268/*
 269 * First, one directory to try is determined by the following algorithm.
 270 *
 271 * (0) If "strict" is given, the path is used as given and no DWIM is
 272 *     done. Otherwise:
 273 * (1) "~/path" to mean path under the running user's home directory;
 274 * (2) "~user/path" to mean path under named user's home directory;
 275 * (3) "relative/path" to mean cwd relative directory; or
 276 * (4) "/absolute/path" to mean absolute directory.
 277 *
 278 * Unless "strict" is given, we try access() for existence of "%s.git/.git",
 279 * "%s/.git", "%s.git", "%s" in this order.  The first one that exists is
 280 * what we try.
 281 *
 282 * Second, we try chdir() to that.  Upon failure, we return NULL.
 283 *
 284 * Then, we try if the current directory is a valid git repository.
 285 * Upon failure, we return NULL.
 286 *
 287 * If all goes well, we return the directory we used to chdir() (but
 288 * before ~user is expanded), avoiding getcwd() resolving symbolic
 289 * links.  User relative paths are also returned as they are given,
 290 * except DWIM suffixing.
 291 */
 292const char *enter_repo(const char *path, int strict)
 293{
 294        static char used_path[PATH_MAX];
 295        static char validated_path[PATH_MAX];
 296
 297        if (!path)
 298                return NULL;
 299
 300        if (!strict) {
 301                static const char *suffix[] = {
 302                        "/.git", "", ".git/.git", ".git", NULL,
 303                };
 304                const char *gitfile;
 305                int len = strlen(path);
 306                int i;
 307                while ((1 < len) && (path[len-1] == '/'))
 308                        len--;
 309
 310                if (PATH_MAX <= len)
 311                        return NULL;
 312                strncpy(used_path, path, len); used_path[len] = 0 ;
 313                strcpy(validated_path, used_path);
 314
 315                if (used_path[0] == '~') {
 316                        char *newpath = expand_user_path(used_path);
 317                        if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
 318                                free(newpath);
 319                                return NULL;
 320                        }
 321                        /*
 322                         * Copy back into the static buffer. A pity
 323                         * since newpath was not bounded, but other
 324                         * branches of the if are limited by PATH_MAX
 325                         * anyway.
 326                         */
 327                        strcpy(used_path, newpath); free(newpath);
 328                }
 329                else if (PATH_MAX - 10 < len)
 330                        return NULL;
 331                len = strlen(used_path);
 332                for (i = 0; suffix[i]; i++) {
 333                        struct stat st;
 334                        strcpy(used_path + len, suffix[i]);
 335                        if (!stat(used_path, &st) &&
 336                            (S_ISREG(st.st_mode) ||
 337                            (S_ISDIR(st.st_mode) && is_git_directory(used_path)))) {
 338                                strcat(validated_path, suffix[i]);
 339                                break;
 340                        }
 341                }
 342                if (!suffix[i])
 343                        return NULL;
 344                gitfile = read_gitfile(used_path) ;
 345                if (gitfile)
 346                        strcpy(used_path, gitfile);
 347                if (chdir(used_path))
 348                        return NULL;
 349                path = validated_path;
 350        }
 351        else if (chdir(path))
 352                return NULL;
 353
 354        if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
 355            validate_headref("HEAD") == 0) {
 356                set_git_dir(".");
 357                check_repository_format();
 358                return path;
 359        }
 360
 361        return NULL;
 362}
 363
 364static int calc_shared_perm(int mode)
 365{
 366        int tweak;
 367
 368        if (shared_repository < 0)
 369                tweak = -shared_repository;
 370        else
 371                tweak = shared_repository;
 372
 373        if (!(mode & S_IWUSR))
 374                tweak &= ~0222;
 375        if (mode & S_IXUSR)
 376                /* Copy read bits to execute bits */
 377                tweak |= (tweak & 0444) >> 2;
 378        if (shared_repository < 0)
 379                mode = (mode & ~0777) | tweak;
 380        else
 381                mode |= tweak;
 382
 383        return mode;
 384}
 385
 386
 387int adjust_shared_perm(const char *path)
 388{
 389        int old_mode, new_mode;
 390
 391        if (!shared_repository)
 392                return 0;
 393        if (get_st_mode_bits(path, &old_mode) < 0)
 394                return -1;
 395
 396        new_mode = calc_shared_perm(old_mode);
 397        if (S_ISDIR(old_mode)) {
 398                /* Copy read bits to execute bits */
 399                new_mode |= (new_mode & 0444) >> 2;
 400                new_mode |= FORCE_DIR_SET_GID;
 401        }
 402
 403        if (((old_mode ^ new_mode) & ~S_IFMT) &&
 404                        chmod(path, (new_mode & ~S_IFMT)) < 0)
 405                return -2;
 406        return 0;
 407}
 408
 409static int have_same_root(const char *path1, const char *path2)
 410{
 411        int is_abs1, is_abs2;
 412
 413        is_abs1 = is_absolute_path(path1);
 414        is_abs2 = is_absolute_path(path2);
 415        return (is_abs1 && is_abs2 && tolower(path1[0]) == tolower(path2[0])) ||
 416               (!is_abs1 && !is_abs2);
 417}
 418
 419/*
 420 * Give path as relative to prefix.
 421 *
 422 * The strbuf may or may not be used, so do not assume it contains the
 423 * returned path.
 424 */
 425const char *relative_path(const char *in, const char *prefix,
 426                          struct strbuf *sb)
 427{
 428        int in_len = in ? strlen(in) : 0;
 429        int prefix_len = prefix ? strlen(prefix) : 0;
 430        int in_off = 0;
 431        int prefix_off = 0;
 432        int i = 0, j = 0;
 433
 434        if (!in_len)
 435                return "./";
 436        else if (!prefix_len)
 437                return in;
 438
 439        if (have_same_root(in, prefix)) {
 440                /* bypass dos_drive, for "c:" is identical to "C:" */
 441                if (has_dos_drive_prefix(in)) {
 442                        i = 2;
 443                        j = 2;
 444                }
 445        } else {
 446                return in;
 447        }
 448
 449        while (i < prefix_len && j < in_len && prefix[i] == in[j]) {
 450                if (is_dir_sep(prefix[i])) {
 451                        while (is_dir_sep(prefix[i]))
 452                                i++;
 453                        while (is_dir_sep(in[j]))
 454                                j++;
 455                        prefix_off = i;
 456                        in_off = j;
 457                } else {
 458                        i++;
 459                        j++;
 460                }
 461        }
 462
 463        if (
 464            /* "prefix" seems like prefix of "in" */
 465            i >= prefix_len &&
 466            /*
 467             * but "/foo" is not a prefix of "/foobar"
 468             * (i.e. prefix not end with '/')
 469             */
 470            prefix_off < prefix_len) {
 471                if (j >= in_len) {
 472                        /* in="/a/b", prefix="/a/b" */
 473                        in_off = in_len;
 474                } else if (is_dir_sep(in[j])) {
 475                        /* in="/a/b/c", prefix="/a/b" */
 476                        while (is_dir_sep(in[j]))
 477                                j++;
 478                        in_off = j;
 479                } else {
 480                        /* in="/a/bbb/c", prefix="/a/b" */
 481                        i = prefix_off;
 482                }
 483        } else if (
 484                   /* "in" is short than "prefix" */
 485                   j >= in_len &&
 486                   /* "in" not end with '/' */
 487                   in_off < in_len) {
 488                if (is_dir_sep(prefix[i])) {
 489                        /* in="/a/b", prefix="/a/b/c/" */
 490                        while (is_dir_sep(prefix[i]))
 491                                i++;
 492                        in_off = in_len;
 493                }
 494        }
 495        in += in_off;
 496        in_len -= in_off;
 497
 498        if (i >= prefix_len) {
 499                if (!in_len)
 500                        return "./";
 501                else
 502                        return in;
 503        }
 504
 505        strbuf_reset(sb);
 506        strbuf_grow(sb, in_len);
 507
 508        while (i < prefix_len) {
 509                if (is_dir_sep(prefix[i])) {
 510                        strbuf_addstr(sb, "../");
 511                        while (is_dir_sep(prefix[i]))
 512                                i++;
 513                        continue;
 514                }
 515                i++;
 516        }
 517        if (!is_dir_sep(prefix[prefix_len - 1]))
 518                strbuf_addstr(sb, "../");
 519
 520        strbuf_addstr(sb, in);
 521
 522        return sb->buf;
 523}
 524
 525/*
 526 * A simpler implementation of relative_path
 527 *
 528 * Get relative path by removing "prefix" from "in". This function
 529 * first appears in v1.5.6-1-g044bbbc, and makes git_dir shorter
 530 * to increase performance when traversing the path to work_tree.
 531 */
 532const char *remove_leading_path(const char *in, const char *prefix)
 533{
 534        static char buf[PATH_MAX + 1];
 535        int i = 0, j = 0;
 536
 537        if (!prefix || !prefix[0])
 538                return in;
 539        while (prefix[i]) {
 540                if (is_dir_sep(prefix[i])) {
 541                        if (!is_dir_sep(in[j]))
 542                                return in;
 543                        while (is_dir_sep(prefix[i]))
 544                                i++;
 545                        while (is_dir_sep(in[j]))
 546                                j++;
 547                        continue;
 548                } else if (in[j] != prefix[i]) {
 549                        return in;
 550                }
 551                i++;
 552                j++;
 553        }
 554        if (
 555            /* "/foo" is a prefix of "/foo" */
 556            in[j] &&
 557            /* "/foo" is not a prefix of "/foobar" */
 558            !is_dir_sep(prefix[i-1]) && !is_dir_sep(in[j])
 559           )
 560                return in;
 561        while (is_dir_sep(in[j]))
 562                j++;
 563        if (!in[j])
 564                strcpy(buf, ".");
 565        else
 566                strcpy(buf, in + j);
 567        return buf;
 568}
 569
 570/*
 571 * It is okay if dst == src, but they should not overlap otherwise.
 572 *
 573 * Performs the following normalizations on src, storing the result in dst:
 574 * - Ensures that components are separated by '/' (Windows only)
 575 * - Squashes sequences of '/'.
 576 * - Removes "." components.
 577 * - Removes ".." components, and the components the precede them.
 578 * Returns failure (non-zero) if a ".." component appears as first path
 579 * component anytime during the normalization. Otherwise, returns success (0).
 580 *
 581 * Note that this function is purely textual.  It does not follow symlinks,
 582 * verify the existence of the path, or make any system calls.
 583 *
 584 * prefix_len != NULL is for a specific case of prefix_pathspec():
 585 * assume that src == dst and src[0..prefix_len-1] is already
 586 * normalized, any time "../" eats up to the prefix_len part,
 587 * prefix_len is reduced. In the end prefix_len is the remaining
 588 * prefix that has not been overridden by user pathspec.
 589 */
 590int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
 591{
 592        char *dst0;
 593
 594        if (has_dos_drive_prefix(src)) {
 595                *dst++ = *src++;
 596                *dst++ = *src++;
 597        }
 598        dst0 = dst;
 599
 600        if (is_dir_sep(*src)) {
 601                *dst++ = '/';
 602                while (is_dir_sep(*src))
 603                        src++;
 604        }
 605
 606        for (;;) {
 607                char c = *src;
 608
 609                /*
 610                 * A path component that begins with . could be
 611                 * special:
 612                 * (1) "." and ends   -- ignore and terminate.
 613                 * (2) "./"           -- ignore them, eat slash and continue.
 614                 * (3) ".." and ends  -- strip one and terminate.
 615                 * (4) "../"          -- strip one, eat slash and continue.
 616                 */
 617                if (c == '.') {
 618                        if (!src[1]) {
 619                                /* (1) */
 620                                src++;
 621                        } else if (is_dir_sep(src[1])) {
 622                                /* (2) */
 623                                src += 2;
 624                                while (is_dir_sep(*src))
 625                                        src++;
 626                                continue;
 627                        } else if (src[1] == '.') {
 628                                if (!src[2]) {
 629                                        /* (3) */
 630                                        src += 2;
 631                                        goto up_one;
 632                                } else if (is_dir_sep(src[2])) {
 633                                        /* (4) */
 634                                        src += 3;
 635                                        while (is_dir_sep(*src))
 636                                                src++;
 637                                        goto up_one;
 638                                }
 639                        }
 640                }
 641
 642                /* copy up to the next '/', and eat all '/' */
 643                while ((c = *src++) != '\0' && !is_dir_sep(c))
 644                        *dst++ = c;
 645                if (is_dir_sep(c)) {
 646                        *dst++ = '/';
 647                        while (is_dir_sep(c))
 648                                c = *src++;
 649                        src--;
 650                } else if (!c)
 651                        break;
 652                continue;
 653
 654        up_one:
 655                /*
 656                 * dst0..dst is prefix portion, and dst[-1] is '/';
 657                 * go up one level.
 658                 */
 659                dst--;  /* go to trailing '/' */
 660                if (dst <= dst0)
 661                        return -1;
 662                /* Windows: dst[-1] cannot be backslash anymore */
 663                while (dst0 < dst && dst[-1] != '/')
 664                        dst--;
 665                if (prefix_len && *prefix_len > dst - dst0)
 666                        *prefix_len = dst - dst0;
 667        }
 668        *dst = '\0';
 669        return 0;
 670}
 671
 672int normalize_path_copy(char *dst, const char *src)
 673{
 674        return normalize_path_copy_len(dst, src, NULL);
 675}
 676
 677/*
 678 * path = Canonical absolute path
 679 * prefixes = string_list containing normalized, absolute paths without
 680 * trailing slashes (except for the root directory, which is denoted by "/").
 681 *
 682 * Determines, for each path in prefixes, whether the "prefix"
 683 * is an ancestor directory of path.  Returns the length of the longest
 684 * ancestor directory, excluding any trailing slashes, or -1 if no prefix
 685 * is an ancestor.  (Note that this means 0 is returned if prefixes is
 686 * ["/"].) "/foo" is not considered an ancestor of "/foobar".  Directories
 687 * are not considered to be their own ancestors.  path must be in a
 688 * canonical form: empty components, or "." or ".." components are not
 689 * allowed.
 690 */
 691int longest_ancestor_length(const char *path, struct string_list *prefixes)
 692{
 693        int i, max_len = -1;
 694
 695        if (!strcmp(path, "/"))
 696                return -1;
 697
 698        for (i = 0; i < prefixes->nr; i++) {
 699                const char *ceil = prefixes->items[i].string;
 700                int len = strlen(ceil);
 701
 702                if (len == 1 && ceil[0] == '/')
 703                        len = 0; /* root matches anything, with length 0 */
 704                else if (!strncmp(path, ceil, len) && path[len] == '/')
 705                        ; /* match of length len */
 706                else
 707                        continue; /* no match */
 708
 709                if (len > max_len)
 710                        max_len = len;
 711        }
 712
 713        return max_len;
 714}
 715
 716/* strip arbitrary amount of directory separators at end of path */
 717static inline int chomp_trailing_dir_sep(const char *path, int len)
 718{
 719        while (len && is_dir_sep(path[len - 1]))
 720                len--;
 721        return len;
 722}
 723
 724/*
 725 * If path ends with suffix (complete path components), returns the
 726 * part before suffix (sans trailing directory separators).
 727 * Otherwise returns NULL.
 728 */
 729char *strip_path_suffix(const char *path, const char *suffix)
 730{
 731        int path_len = strlen(path), suffix_len = strlen(suffix);
 732
 733        while (suffix_len) {
 734                if (!path_len)
 735                        return NULL;
 736
 737                if (is_dir_sep(path[path_len - 1])) {
 738                        if (!is_dir_sep(suffix[suffix_len - 1]))
 739                                return NULL;
 740                        path_len = chomp_trailing_dir_sep(path, path_len);
 741                        suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
 742                }
 743                else if (path[--path_len] != suffix[--suffix_len])
 744                        return NULL;
 745        }
 746
 747        if (path_len && !is_dir_sep(path[path_len - 1]))
 748                return NULL;
 749        return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
 750}
 751
 752int daemon_avoid_alias(const char *p)
 753{
 754        int sl, ndot;
 755
 756        /*
 757         * This resurrects the belts and suspenders paranoia check by HPA
 758         * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
 759         * does not do getcwd() based path canonicalization.
 760         *
 761         * sl becomes true immediately after seeing '/' and continues to
 762         * be true as long as dots continue after that without intervening
 763         * non-dot character.
 764         */
 765        if (!p || (*p != '/' && *p != '~'))
 766                return -1;
 767        sl = 1; ndot = 0;
 768        p++;
 769
 770        while (1) {
 771                char ch = *p++;
 772                if (sl) {
 773                        if (ch == '.')
 774                                ndot++;
 775                        else if (ch == '/') {
 776                                if (ndot < 3)
 777                                        /* reject //, /./ and /../ */
 778                                        return -1;
 779                                ndot = 0;
 780                        }
 781                        else if (ch == 0) {
 782                                if (0 < ndot && ndot < 3)
 783                                        /* reject /.$ and /..$ */
 784                                        return -1;
 785                                return 0;
 786                        }
 787                        else
 788                                sl = ndot = 0;
 789                }
 790                else if (ch == 0)
 791                        return 0;
 792                else if (ch == '/') {
 793                        sl = 1;
 794                        ndot = 0;
 795                }
 796        }
 797}
 798
 799static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
 800{
 801        if (len < skip)
 802                return 0;
 803        len -= skip;
 804        path += skip;
 805        while (len-- > 0) {
 806                char c = *(path++);
 807                if (c != ' ' && c != '.')
 808                        return 0;
 809        }
 810        return 1;
 811}
 812
 813int is_ntfs_dotgit(const char *name)
 814{
 815        int len;
 816
 817        for (len = 0; ; len++)
 818                if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
 819                        if (only_spaces_and_periods(name, len, 4) &&
 820                                        !strncasecmp(name, ".git", 4))
 821                                return 1;
 822                        if (only_spaces_and_periods(name, len, 5) &&
 823                                        !strncasecmp(name, "git~1", 5))
 824                                return 1;
 825                        if (name[len] != '\\')
 826                                return 0;
 827                        name += len + 1;
 828                        len = -1;
 829                }
 830}
 831
 832char *xdg_config_home(const char *filename)
 833{
 834        const char *home, *config_home;
 835
 836        assert(filename);
 837        config_home = getenv("XDG_CONFIG_HOME");
 838        if (config_home && *config_home)
 839                return mkpathdup("%s/git/%s", config_home, filename);
 840
 841        home = getenv("HOME");
 842        if (home)
 843                return mkpathdup("%s/.config/git/%s", home, filename);
 844        return NULL;
 845}