path.con commit push: support signing pushes iff the server supports it (3026109)
   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 check "%s/.git", "%s", "%s.git/.git", "%s.git"
 279 * in this order. We select the first one that is a valid git repository, and
 280 * chdir() to it. If none match, or we fail to chdir, we return NULL.
 281 *
 282 * If all goes well, we return the directory we used to chdir() (but
 283 * before ~user is expanded), avoiding getcwd() resolving symbolic
 284 * links.  User relative paths are also returned as they are given,
 285 * except DWIM suffixing.
 286 */
 287const char *enter_repo(const char *path, int strict)
 288{
 289        static char used_path[PATH_MAX];
 290        static char validated_path[PATH_MAX];
 291
 292        if (!path)
 293                return NULL;
 294
 295        if (!strict) {
 296                static const char *suffix[] = {
 297                        "/.git", "", ".git/.git", ".git", NULL,
 298                };
 299                const char *gitfile;
 300                int len = strlen(path);
 301                int i;
 302                while ((1 < len) && (path[len-1] == '/'))
 303                        len--;
 304
 305                if (PATH_MAX <= len)
 306                        return NULL;
 307                strncpy(used_path, path, len); used_path[len] = 0 ;
 308                strcpy(validated_path, used_path);
 309
 310                if (used_path[0] == '~') {
 311                        char *newpath = expand_user_path(used_path);
 312                        if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
 313                                free(newpath);
 314                                return NULL;
 315                        }
 316                        /*
 317                         * Copy back into the static buffer. A pity
 318                         * since newpath was not bounded, but other
 319                         * branches of the if are limited by PATH_MAX
 320                         * anyway.
 321                         */
 322                        strcpy(used_path, newpath); free(newpath);
 323                }
 324                else if (PATH_MAX - 10 < len)
 325                        return NULL;
 326                len = strlen(used_path);
 327                for (i = 0; suffix[i]; i++) {
 328                        struct stat st;
 329                        strcpy(used_path + len, suffix[i]);
 330                        if (!stat(used_path, &st) &&
 331                            (S_ISREG(st.st_mode) ||
 332                            (S_ISDIR(st.st_mode) && is_git_directory(used_path)))) {
 333                                strcat(validated_path, suffix[i]);
 334                                break;
 335                        }
 336                }
 337                if (!suffix[i])
 338                        return NULL;
 339                gitfile = read_gitfile(used_path) ;
 340                if (gitfile)
 341                        strcpy(used_path, gitfile);
 342                if (chdir(used_path))
 343                        return NULL;
 344                path = validated_path;
 345        }
 346        else if (chdir(path))
 347                return NULL;
 348
 349        if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
 350            validate_headref("HEAD") == 0) {
 351                set_git_dir(".");
 352                check_repository_format();
 353                return path;
 354        }
 355
 356        return NULL;
 357}
 358
 359static int calc_shared_perm(int mode)
 360{
 361        int tweak;
 362
 363        if (shared_repository < 0)
 364                tweak = -shared_repository;
 365        else
 366                tweak = shared_repository;
 367
 368        if (!(mode & S_IWUSR))
 369                tweak &= ~0222;
 370        if (mode & S_IXUSR)
 371                /* Copy read bits to execute bits */
 372                tweak |= (tweak & 0444) >> 2;
 373        if (shared_repository < 0)
 374                mode = (mode & ~0777) | tweak;
 375        else
 376                mode |= tweak;
 377
 378        return mode;
 379}
 380
 381
 382int adjust_shared_perm(const char *path)
 383{
 384        int old_mode, new_mode;
 385
 386        if (!shared_repository)
 387                return 0;
 388        if (get_st_mode_bits(path, &old_mode) < 0)
 389                return -1;
 390
 391        new_mode = calc_shared_perm(old_mode);
 392        if (S_ISDIR(old_mode)) {
 393                /* Copy read bits to execute bits */
 394                new_mode |= (new_mode & 0444) >> 2;
 395                new_mode |= FORCE_DIR_SET_GID;
 396        }
 397
 398        if (((old_mode ^ new_mode) & ~S_IFMT) &&
 399                        chmod(path, (new_mode & ~S_IFMT)) < 0)
 400                return -2;
 401        return 0;
 402}
 403
 404static int have_same_root(const char *path1, const char *path2)
 405{
 406        int is_abs1, is_abs2;
 407
 408        is_abs1 = is_absolute_path(path1);
 409        is_abs2 = is_absolute_path(path2);
 410        return (is_abs1 && is_abs2 && tolower(path1[0]) == tolower(path2[0])) ||
 411               (!is_abs1 && !is_abs2);
 412}
 413
 414/*
 415 * Give path as relative to prefix.
 416 *
 417 * The strbuf may or may not be used, so do not assume it contains the
 418 * returned path.
 419 */
 420const char *relative_path(const char *in, const char *prefix,
 421                          struct strbuf *sb)
 422{
 423        int in_len = in ? strlen(in) : 0;
 424        int prefix_len = prefix ? strlen(prefix) : 0;
 425        int in_off = 0;
 426        int prefix_off = 0;
 427        int i = 0, j = 0;
 428
 429        if (!in_len)
 430                return "./";
 431        else if (!prefix_len)
 432                return in;
 433
 434        if (have_same_root(in, prefix)) {
 435                /* bypass dos_drive, for "c:" is identical to "C:" */
 436                if (has_dos_drive_prefix(in)) {
 437                        i = 2;
 438                        j = 2;
 439                }
 440        } else {
 441                return in;
 442        }
 443
 444        while (i < prefix_len && j < in_len && prefix[i] == in[j]) {
 445                if (is_dir_sep(prefix[i])) {
 446                        while (is_dir_sep(prefix[i]))
 447                                i++;
 448                        while (is_dir_sep(in[j]))
 449                                j++;
 450                        prefix_off = i;
 451                        in_off = j;
 452                } else {
 453                        i++;
 454                        j++;
 455                }
 456        }
 457
 458        if (
 459            /* "prefix" seems like prefix of "in" */
 460            i >= prefix_len &&
 461            /*
 462             * but "/foo" is not a prefix of "/foobar"
 463             * (i.e. prefix not end with '/')
 464             */
 465            prefix_off < prefix_len) {
 466                if (j >= in_len) {
 467                        /* in="/a/b", prefix="/a/b" */
 468                        in_off = in_len;
 469                } else if (is_dir_sep(in[j])) {
 470                        /* in="/a/b/c", prefix="/a/b" */
 471                        while (is_dir_sep(in[j]))
 472                                j++;
 473                        in_off = j;
 474                } else {
 475                        /* in="/a/bbb/c", prefix="/a/b" */
 476                        i = prefix_off;
 477                }
 478        } else if (
 479                   /* "in" is short than "prefix" */
 480                   j >= in_len &&
 481                   /* "in" not end with '/' */
 482                   in_off < in_len) {
 483                if (is_dir_sep(prefix[i])) {
 484                        /* in="/a/b", prefix="/a/b/c/" */
 485                        while (is_dir_sep(prefix[i]))
 486                                i++;
 487                        in_off = in_len;
 488                }
 489        }
 490        in += in_off;
 491        in_len -= in_off;
 492
 493        if (i >= prefix_len) {
 494                if (!in_len)
 495                        return "./";
 496                else
 497                        return in;
 498        }
 499
 500        strbuf_reset(sb);
 501        strbuf_grow(sb, in_len);
 502
 503        while (i < prefix_len) {
 504                if (is_dir_sep(prefix[i])) {
 505                        strbuf_addstr(sb, "../");
 506                        while (is_dir_sep(prefix[i]))
 507                                i++;
 508                        continue;
 509                }
 510                i++;
 511        }
 512        if (!is_dir_sep(prefix[prefix_len - 1]))
 513                strbuf_addstr(sb, "../");
 514
 515        strbuf_addstr(sb, in);
 516
 517        return sb->buf;
 518}
 519
 520/*
 521 * A simpler implementation of relative_path
 522 *
 523 * Get relative path by removing "prefix" from "in". This function
 524 * first appears in v1.5.6-1-g044bbbc, and makes git_dir shorter
 525 * to increase performance when traversing the path to work_tree.
 526 */
 527const char *remove_leading_path(const char *in, const char *prefix)
 528{
 529        static char buf[PATH_MAX + 1];
 530        int i = 0, j = 0;
 531
 532        if (!prefix || !prefix[0])
 533                return in;
 534        while (prefix[i]) {
 535                if (is_dir_sep(prefix[i])) {
 536                        if (!is_dir_sep(in[j]))
 537                                return in;
 538                        while (is_dir_sep(prefix[i]))
 539                                i++;
 540                        while (is_dir_sep(in[j]))
 541                                j++;
 542                        continue;
 543                } else if (in[j] != prefix[i]) {
 544                        return in;
 545                }
 546                i++;
 547                j++;
 548        }
 549        if (
 550            /* "/foo" is a prefix of "/foo" */
 551            in[j] &&
 552            /* "/foo" is not a prefix of "/foobar" */
 553            !is_dir_sep(prefix[i-1]) && !is_dir_sep(in[j])
 554           )
 555                return in;
 556        while (is_dir_sep(in[j]))
 557                j++;
 558        if (!in[j])
 559                strcpy(buf, ".");
 560        else
 561                strcpy(buf, in + j);
 562        return buf;
 563}
 564
 565/*
 566 * It is okay if dst == src, but they should not overlap otherwise.
 567 *
 568 * Performs the following normalizations on src, storing the result in dst:
 569 * - Ensures that components are separated by '/' (Windows only)
 570 * - Squashes sequences of '/'.
 571 * - Removes "." components.
 572 * - Removes ".." components, and the components the precede them.
 573 * Returns failure (non-zero) if a ".." component appears as first path
 574 * component anytime during the normalization. Otherwise, returns success (0).
 575 *
 576 * Note that this function is purely textual.  It does not follow symlinks,
 577 * verify the existence of the path, or make any system calls.
 578 *
 579 * prefix_len != NULL is for a specific case of prefix_pathspec():
 580 * assume that src == dst and src[0..prefix_len-1] is already
 581 * normalized, any time "../" eats up to the prefix_len part,
 582 * prefix_len is reduced. In the end prefix_len is the remaining
 583 * prefix that has not been overridden by user pathspec.
 584 */
 585int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
 586{
 587        char *dst0;
 588
 589        if (has_dos_drive_prefix(src)) {
 590                *dst++ = *src++;
 591                *dst++ = *src++;
 592        }
 593        dst0 = dst;
 594
 595        if (is_dir_sep(*src)) {
 596                *dst++ = '/';
 597                while (is_dir_sep(*src))
 598                        src++;
 599        }
 600
 601        for (;;) {
 602                char c = *src;
 603
 604                /*
 605                 * A path component that begins with . could be
 606                 * special:
 607                 * (1) "." and ends   -- ignore and terminate.
 608                 * (2) "./"           -- ignore them, eat slash and continue.
 609                 * (3) ".." and ends  -- strip one and terminate.
 610                 * (4) "../"          -- strip one, eat slash and continue.
 611                 */
 612                if (c == '.') {
 613                        if (!src[1]) {
 614                                /* (1) */
 615                                src++;
 616                        } else if (is_dir_sep(src[1])) {
 617                                /* (2) */
 618                                src += 2;
 619                                while (is_dir_sep(*src))
 620                                        src++;
 621                                continue;
 622                        } else if (src[1] == '.') {
 623                                if (!src[2]) {
 624                                        /* (3) */
 625                                        src += 2;
 626                                        goto up_one;
 627                                } else if (is_dir_sep(src[2])) {
 628                                        /* (4) */
 629                                        src += 3;
 630                                        while (is_dir_sep(*src))
 631                                                src++;
 632                                        goto up_one;
 633                                }
 634                        }
 635                }
 636
 637                /* copy up to the next '/', and eat all '/' */
 638                while ((c = *src++) != '\0' && !is_dir_sep(c))
 639                        *dst++ = c;
 640                if (is_dir_sep(c)) {
 641                        *dst++ = '/';
 642                        while (is_dir_sep(c))
 643                                c = *src++;
 644                        src--;
 645                } else if (!c)
 646                        break;
 647                continue;
 648
 649        up_one:
 650                /*
 651                 * dst0..dst is prefix portion, and dst[-1] is '/';
 652                 * go up one level.
 653                 */
 654                dst--;  /* go to trailing '/' */
 655                if (dst <= dst0)
 656                        return -1;
 657                /* Windows: dst[-1] cannot be backslash anymore */
 658                while (dst0 < dst && dst[-1] != '/')
 659                        dst--;
 660                if (prefix_len && *prefix_len > dst - dst0)
 661                        *prefix_len = dst - dst0;
 662        }
 663        *dst = '\0';
 664        return 0;
 665}
 666
 667int normalize_path_copy(char *dst, const char *src)
 668{
 669        return normalize_path_copy_len(dst, src, NULL);
 670}
 671
 672/*
 673 * path = Canonical absolute path
 674 * prefixes = string_list containing normalized, absolute paths without
 675 * trailing slashes (except for the root directory, which is denoted by "/").
 676 *
 677 * Determines, for each path in prefixes, whether the "prefix"
 678 * is an ancestor directory of path.  Returns the length of the longest
 679 * ancestor directory, excluding any trailing slashes, or -1 if no prefix
 680 * is an ancestor.  (Note that this means 0 is returned if prefixes is
 681 * ["/"].) "/foo" is not considered an ancestor of "/foobar".  Directories
 682 * are not considered to be their own ancestors.  path must be in a
 683 * canonical form: empty components, or "." or ".." components are not
 684 * allowed.
 685 */
 686int longest_ancestor_length(const char *path, struct string_list *prefixes)
 687{
 688        int i, max_len = -1;
 689
 690        if (!strcmp(path, "/"))
 691                return -1;
 692
 693        for (i = 0; i < prefixes->nr; i++) {
 694                const char *ceil = prefixes->items[i].string;
 695                int len = strlen(ceil);
 696
 697                if (len == 1 && ceil[0] == '/')
 698                        len = 0; /* root matches anything, with length 0 */
 699                else if (!strncmp(path, ceil, len) && path[len] == '/')
 700                        ; /* match of length len */
 701                else
 702                        continue; /* no match */
 703
 704                if (len > max_len)
 705                        max_len = len;
 706        }
 707
 708        return max_len;
 709}
 710
 711/* strip arbitrary amount of directory separators at end of path */
 712static inline int chomp_trailing_dir_sep(const char *path, int len)
 713{
 714        while (len && is_dir_sep(path[len - 1]))
 715                len--;
 716        return len;
 717}
 718
 719/*
 720 * If path ends with suffix (complete path components), returns the
 721 * part before suffix (sans trailing directory separators).
 722 * Otherwise returns NULL.
 723 */
 724char *strip_path_suffix(const char *path, const char *suffix)
 725{
 726        int path_len = strlen(path), suffix_len = strlen(suffix);
 727
 728        while (suffix_len) {
 729                if (!path_len)
 730                        return NULL;
 731
 732                if (is_dir_sep(path[path_len - 1])) {
 733                        if (!is_dir_sep(suffix[suffix_len - 1]))
 734                                return NULL;
 735                        path_len = chomp_trailing_dir_sep(path, path_len);
 736                        suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
 737                }
 738                else if (path[--path_len] != suffix[--suffix_len])
 739                        return NULL;
 740        }
 741
 742        if (path_len && !is_dir_sep(path[path_len - 1]))
 743                return NULL;
 744        return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
 745}
 746
 747int daemon_avoid_alias(const char *p)
 748{
 749        int sl, ndot;
 750
 751        /*
 752         * This resurrects the belts and suspenders paranoia check by HPA
 753         * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
 754         * does not do getcwd() based path canonicalization.
 755         *
 756         * sl becomes true immediately after seeing '/' and continues to
 757         * be true as long as dots continue after that without intervening
 758         * non-dot character.
 759         */
 760        if (!p || (*p != '/' && *p != '~'))
 761                return -1;
 762        sl = 1; ndot = 0;
 763        p++;
 764
 765        while (1) {
 766                char ch = *p++;
 767                if (sl) {
 768                        if (ch == '.')
 769                                ndot++;
 770                        else if (ch == '/') {
 771                                if (ndot < 3)
 772                                        /* reject //, /./ and /../ */
 773                                        return -1;
 774                                ndot = 0;
 775                        }
 776                        else if (ch == 0) {
 777                                if (0 < ndot && ndot < 3)
 778                                        /* reject /.$ and /..$ */
 779                                        return -1;
 780                                return 0;
 781                        }
 782                        else
 783                                sl = ndot = 0;
 784                }
 785                else if (ch == 0)
 786                        return 0;
 787                else if (ch == '/') {
 788                        sl = 1;
 789                        ndot = 0;
 790                }
 791        }
 792}
 793
 794static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
 795{
 796        if (len < skip)
 797                return 0;
 798        len -= skip;
 799        path += skip;
 800        while (len-- > 0) {
 801                char c = *(path++);
 802                if (c != ' ' && c != '.')
 803                        return 0;
 804        }
 805        return 1;
 806}
 807
 808int is_ntfs_dotgit(const char *name)
 809{
 810        int len;
 811
 812        for (len = 0; ; len++)
 813                if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
 814                        if (only_spaces_and_periods(name, len, 4) &&
 815                                        !strncasecmp(name, ".git", 4))
 816                                return 1;
 817                        if (only_spaces_and_periods(name, len, 5) &&
 818                                        !strncasecmp(name, "git~1", 5))
 819                                return 1;
 820                        if (name[len] != '\\')
 821                                return 0;
 822                        name += len + 1;
 823                        len = -1;
 824                }
 825}
 826
 827char *xdg_config_home(const char *filename)
 828{
 829        const char *home, *config_home;
 830
 831        assert(filename);
 832        config_home = getenv("XDG_CONFIG_HOME");
 833        if (config_home && *config_home)
 834                return mkpathdup("%s/git/%s", config_home, filename);
 835
 836        home = getenv("HOME");
 837        if (home)
 838                return mkpathdup("%s/.config/git/%s", home, filename);
 839        return NULL;
 840}