03d284ba8bc76d873d289efbf45404cad58f111a
   1/*
   2 * I'm tired of doing "vsnprintf()" etc just to open a
   3 * file, so here's a "return static buffer with printf"
   4 * interface for paths.
   5 *
   6 * It's obviously not thread-safe. Sue me. But it's quite
   7 * useful for doing things like
   8 *
   9 *   f = open(mkpath("%s/%s.git", base, name), O_RDONLY);
  10 *
  11 * which is what it's designed for.
  12 */
  13#include "cache.h"
  14#include "strbuf.h"
  15
  16static char bad_path[] = "/bad-path/";
  17
  18static char *get_pathname(void)
  19{
  20        static char pathname_array[4][PATH_MAX];
  21        static int index;
  22        return pathname_array[3 & ++index];
  23}
  24
  25static char *cleanup_path(char *path)
  26{
  27        /* Clean it up */
  28        if (!memcmp(path, "./", 2)) {
  29                path += 2;
  30                while (*path == '/')
  31                        path++;
  32        }
  33        return path;
  34}
  35
  36char *mksnpath(char *buf, size_t n, const char *fmt, ...)
  37{
  38        va_list args;
  39        unsigned len;
  40
  41        va_start(args, fmt);
  42        len = vsnprintf(buf, n, fmt, args);
  43        va_end(args);
  44        if (len >= n) {
  45                strlcpy(buf, bad_path, n);
  46                return buf;
  47        }
  48        return cleanup_path(buf);
  49}
  50
  51static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
  52{
  53        const char *git_dir = get_git_dir();
  54        size_t len;
  55
  56        len = strlen(git_dir);
  57        if (n < len + 1)
  58                goto bad;
  59        memcpy(buf, git_dir, len);
  60        if (len && !is_dir_sep(git_dir[len-1]))
  61                buf[len++] = '/';
  62        len += vsnprintf(buf + len, n - len, fmt, args);
  63        if (len >= n)
  64                goto bad;
  65        return cleanup_path(buf);
  66bad:
  67        strlcpy(buf, bad_path, n);
  68        return buf;
  69}
  70
  71char *git_snpath(char *buf, size_t n, const char *fmt, ...)
  72{
  73        va_list args;
  74        va_start(args, fmt);
  75        (void)git_vsnpath(buf, n, fmt, args);
  76        va_end(args);
  77        return buf;
  78}
  79
  80char *git_pathdup(const char *fmt, ...)
  81{
  82        char path[PATH_MAX];
  83        va_list args;
  84        va_start(args, fmt);
  85        (void)git_vsnpath(path, sizeof(path), fmt, args);
  86        va_end(args);
  87        return xstrdup(path);
  88}
  89
  90char *mkpath(const char *fmt, ...)
  91{
  92        va_list args;
  93        unsigned len;
  94        char *pathname = get_pathname();
  95
  96        va_start(args, fmt);
  97        len = vsnprintf(pathname, PATH_MAX, fmt, args);
  98        va_end(args);
  99        if (len >= PATH_MAX)
 100                return bad_path;
 101        return cleanup_path(pathname);
 102}
 103
 104char *git_path(const char *fmt, ...)
 105{
 106        const char *git_dir = get_git_dir();
 107        char *pathname = get_pathname();
 108        va_list args;
 109        unsigned len;
 110
 111        len = strlen(git_dir);
 112        if (len > PATH_MAX-100)
 113                return bad_path;
 114        memcpy(pathname, git_dir, len);
 115        if (len && git_dir[len-1] != '/')
 116                pathname[len++] = '/';
 117        va_start(args, fmt);
 118        len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
 119        va_end(args);
 120        if (len >= PATH_MAX)
 121                return bad_path;
 122        return cleanup_path(pathname);
 123}
 124
 125
 126/* git_mkstemp() - create tmp file honoring TMPDIR variable */
 127int git_mkstemp(char *path, size_t len, const char *template)
 128{
 129        const char *tmp;
 130        size_t n;
 131
 132        tmp = getenv("TMPDIR");
 133        if (!tmp)
 134                tmp = "/tmp";
 135        n = snprintf(path, len, "%s/%s", tmp, template);
 136        if (len <= n) {
 137                errno = ENAMETOOLONG;
 138                return -1;
 139        }
 140        return mkstemp(path);
 141}
 142
 143/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */
 144int git_mkstemps(char *path, size_t len, const char *template, int suffix_len)
 145{
 146        const char *tmp;
 147        size_t n;
 148
 149        tmp = getenv("TMPDIR");
 150        if (!tmp)
 151                tmp = "/tmp";
 152        n = snprintf(path, len, "%s/%s", tmp, template);
 153        if (len <= n) {
 154                errno = ENAMETOOLONG;
 155                return -1;
 156        }
 157        return mkstemps(path, suffix_len);
 158}
 159
 160/* Adapted from libiberty's mkstemp.c. */
 161
 162#undef TMP_MAX
 163#define TMP_MAX 16384
 164
 165int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
 166{
 167        static const char letters[] =
 168                "abcdefghijklmnopqrstuvwxyz"
 169                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 170                "0123456789";
 171        static const int num_letters = 62;
 172        uint64_t value;
 173        struct timeval tv;
 174        char *template;
 175        size_t len;
 176        int fd, count;
 177
 178        len = strlen(pattern);
 179
 180        if (len < 6 + suffix_len) {
 181                errno = EINVAL;
 182                return -1;
 183        }
 184
 185        if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
 186                errno = EINVAL;
 187                return -1;
 188        }
 189
 190        /*
 191         * Replace pattern's XXXXXX characters with randomness.
 192         * Try TMP_MAX different filenames.
 193         */
 194        gettimeofday(&tv, NULL);
 195        value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
 196        template = &pattern[len - 6 - suffix_len];
 197        for (count = 0; count < TMP_MAX; ++count) {
 198                uint64_t v = value;
 199                /* Fill in the random bits. */
 200                template[0] = letters[v % num_letters]; v /= num_letters;
 201                template[1] = letters[v % num_letters]; v /= num_letters;
 202                template[2] = letters[v % num_letters]; v /= num_letters;
 203                template[3] = letters[v % num_letters]; v /= num_letters;
 204                template[4] = letters[v % num_letters]; v /= num_letters;
 205                template[5] = letters[v % num_letters]; v /= num_letters;
 206
 207                fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
 208                if (fd > 0)
 209                        return fd;
 210                /*
 211                 * Fatal error (EPERM, ENOSPC etc).
 212                 * It doesn't make sense to loop.
 213                 */
 214                if (errno != EEXIST)
 215                        break;
 216                /*
 217                 * This is a random value.  It is only necessary that
 218                 * the next TMP_MAX values generated by adding 7777 to
 219                 * VALUE are different with (module 2^32).
 220                 */
 221                value += 7777;
 222        }
 223        /* We return the null string if we can't find a unique file name.  */
 224        pattern[0] = '\0';
 225        errno = EINVAL;
 226        return -1;
 227}
 228
 229int git_mkstemp_mode(char *pattern, int mode)
 230{
 231        /* mkstemp is just mkstemps with no suffix */
 232        return git_mkstemps_mode(pattern, 0, mode);
 233}
 234
 235int gitmkstemps(char *pattern, int suffix_len)
 236{
 237        return git_mkstemps_mode(pattern, suffix_len, 0600);
 238}
 239
 240int validate_headref(const char *path)
 241{
 242        struct stat st;
 243        char *buf, buffer[256];
 244        unsigned char sha1[20];
 245        int fd;
 246        ssize_t len;
 247
 248        if (lstat(path, &st) < 0)
 249                return -1;
 250
 251        /* Make sure it is a "refs/.." symlink */
 252        if (S_ISLNK(st.st_mode)) {
 253                len = readlink(path, buffer, sizeof(buffer)-1);
 254                if (len >= 5 && !memcmp("refs/", buffer, 5))
 255                        return 0;
 256                return -1;
 257        }
 258
 259        /*
 260         * Anything else, just open it and try to see if it is a symbolic ref.
 261         */
 262        fd = open(path, O_RDONLY);
 263        if (fd < 0)
 264                return -1;
 265        len = read_in_full(fd, buffer, sizeof(buffer)-1);
 266        close(fd);
 267
 268        /*
 269         * Is it a symbolic ref?
 270         */
 271        if (len < 4)
 272                return -1;
 273        if (!memcmp("ref:", buffer, 4)) {
 274                buf = buffer + 4;
 275                len -= 4;
 276                while (len && isspace(*buf))
 277                        buf++, len--;
 278                if (len >= 5 && !memcmp("refs/", buf, 5))
 279                        return 0;
 280        }
 281
 282        /*
 283         * Is this a detached HEAD?
 284         */
 285        if (!get_sha1_hex(buffer, sha1))
 286                return 0;
 287
 288        return -1;
 289}
 290
 291static struct passwd *getpw_str(const char *username, size_t len)
 292{
 293        struct passwd *pw;
 294        char *username_z = xmalloc(len + 1);
 295        memcpy(username_z, username, len);
 296        username_z[len] = '\0';
 297        pw = getpwnam(username_z);
 298        free(username_z);
 299        return pw;
 300}
 301
 302/*
 303 * Return a string with ~ and ~user expanded via getpw*.  If buf != NULL,
 304 * then it is a newly allocated string. Returns NULL on getpw failure or
 305 * if path is NULL.
 306 */
 307char *expand_user_path(const char *path)
 308{
 309        struct strbuf user_path = STRBUF_INIT;
 310        const char *first_slash = strchrnul(path, '/');
 311        const char *to_copy = path;
 312
 313        if (path == NULL)
 314                goto return_null;
 315        if (path[0] == '~') {
 316                const char *username = path + 1;
 317                size_t username_len = first_slash - username;
 318                if (username_len == 0) {
 319                        const char *home = getenv("HOME");
 320                        strbuf_add(&user_path, home, strlen(home));
 321                } else {
 322                        struct passwd *pw = getpw_str(username, username_len);
 323                        if (!pw)
 324                                goto return_null;
 325                        strbuf_add(&user_path, pw->pw_dir, strlen(pw->pw_dir));
 326                }
 327                to_copy = first_slash;
 328        }
 329        strbuf_add(&user_path, to_copy, strlen(to_copy));
 330        return strbuf_detach(&user_path, NULL);
 331return_null:
 332        strbuf_release(&user_path);
 333        return NULL;
 334}
 335
 336/*
 337 * First, one directory to try is determined by the following algorithm.
 338 *
 339 * (0) If "strict" is given, the path is used as given and no DWIM is
 340 *     done. Otherwise:
 341 * (1) "~/path" to mean path under the running user's home directory;
 342 * (2) "~user/path" to mean path under named user's home directory;
 343 * (3) "relative/path" to mean cwd relative directory; or
 344 * (4) "/absolute/path" to mean absolute directory.
 345 *
 346 * Unless "strict" is given, we try access() for existence of "%s.git/.git",
 347 * "%s/.git", "%s.git", "%s" in this order.  The first one that exists is
 348 * what we try.
 349 *
 350 * Second, we try chdir() to that.  Upon failure, we return NULL.
 351 *
 352 * Then, we try if the current directory is a valid git repository.
 353 * Upon failure, we return NULL.
 354 *
 355 * If all goes well, we return the directory we used to chdir() (but
 356 * before ~user is expanded), avoiding getcwd() resolving symbolic
 357 * links.  User relative paths are also returned as they are given,
 358 * except DWIM suffixing.
 359 */
 360char *enter_repo(char *path, int strict)
 361{
 362        static char used_path[PATH_MAX];
 363        static char validated_path[PATH_MAX];
 364
 365        if (!path)
 366                return NULL;
 367
 368        if (!strict) {
 369                static const char *suffix[] = {
 370                        ".git/.git", "/.git", ".git", "", NULL,
 371                };
 372                int len = strlen(path);
 373                int i;
 374                while ((1 < len) && (path[len-1] == '/')) {
 375                        path[len-1] = 0;
 376                        len--;
 377                }
 378                if (PATH_MAX <= len)
 379                        return NULL;
 380                if (path[0] == '~') {
 381                        char *newpath = expand_user_path(path);
 382                        if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
 383                                free(newpath);
 384                                return NULL;
 385                        }
 386                        /*
 387                         * Copy back into the static buffer. A pity
 388                         * since newpath was not bounded, but other
 389                         * branches of the if are limited by PATH_MAX
 390                         * anyway.
 391                         */
 392                        strcpy(used_path, newpath); free(newpath);
 393                        strcpy(validated_path, path);
 394                        path = used_path;
 395                }
 396                else if (PATH_MAX - 10 < len)
 397                        return NULL;
 398                else {
 399                        path = strcpy(used_path, path);
 400                        strcpy(validated_path, path);
 401                }
 402                len = strlen(path);
 403                for (i = 0; suffix[i]; i++) {
 404                        strcpy(path + len, suffix[i]);
 405                        if (!access(path, F_OK)) {
 406                                strcat(validated_path, suffix[i]);
 407                                break;
 408                        }
 409                }
 410                if (!suffix[i] || chdir(path))
 411                        return NULL;
 412                path = validated_path;
 413        }
 414        else if (chdir(path))
 415                return NULL;
 416
 417        if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
 418            validate_headref("HEAD") == 0) {
 419                setenv(GIT_DIR_ENVIRONMENT, ".", 1);
 420                check_repository_format();
 421                return path;
 422        }
 423
 424        return NULL;
 425}
 426
 427int set_shared_perm(const char *path, int mode)
 428{
 429        struct stat st;
 430        int tweak, shared, orig_mode;
 431
 432        if (!shared_repository) {
 433                if (mode)
 434                        return chmod(path, mode & ~S_IFMT);
 435                return 0;
 436        }
 437        if (!mode) {
 438                if (lstat(path, &st) < 0)
 439                        return -1;
 440                mode = st.st_mode;
 441                orig_mode = mode;
 442        } else
 443                orig_mode = 0;
 444        if (shared_repository < 0)
 445                shared = -shared_repository;
 446        else
 447                shared = shared_repository;
 448        tweak = shared;
 449
 450        if (!(mode & S_IWUSR))
 451                tweak &= ~0222;
 452        if (mode & S_IXUSR)
 453                /* Copy read bits to execute bits */
 454                tweak |= (tweak & 0444) >> 2;
 455        if (shared_repository < 0)
 456                mode = (mode & ~0777) | tweak;
 457        else
 458                mode |= tweak;
 459
 460        if (S_ISDIR(mode)) {
 461                /* Copy read bits to execute bits */
 462                mode |= (shared & 0444) >> 2;
 463                mode |= FORCE_DIR_SET_GID;
 464        }
 465
 466        if (((shared_repository < 0
 467              ? (orig_mode & (FORCE_DIR_SET_GID | 0777))
 468              : (orig_mode & mode)) != mode) &&
 469            chmod(path, (mode & ~S_IFMT)) < 0)
 470                return -2;
 471        return 0;
 472}
 473
 474const char *make_relative_path(const char *abs, const char *base)
 475{
 476        static char buf[PATH_MAX + 1];
 477        int i = 0, j = 0;
 478
 479        if (!base || !base[0])
 480                return abs;
 481        while (base[i]) {
 482                if (is_dir_sep(base[i])) {
 483                        if (!is_dir_sep(abs[j]))
 484                                return abs;
 485                        while (is_dir_sep(base[i]))
 486                                i++;
 487                        while (is_dir_sep(abs[j]))
 488                                j++;
 489                        continue;
 490                } else if (abs[j] != base[i]) {
 491                        return abs;
 492                }
 493                i++;
 494                j++;
 495        }
 496        if (
 497            /* "/foo" is a prefix of "/foo" */
 498            abs[j] &&
 499            /* "/foo" is not a prefix of "/foobar" */
 500            !is_dir_sep(base[i-1]) && !is_dir_sep(abs[j])
 501           )
 502                return abs;
 503        while (is_dir_sep(abs[j]))
 504                j++;
 505        if (!abs[j])
 506                strcpy(buf, ".");
 507        else
 508                strcpy(buf, abs + j);
 509        return buf;
 510}
 511
 512/*
 513 * It is okay if dst == src, but they should not overlap otherwise.
 514 *
 515 * Performs the following normalizations on src, storing the result in dst:
 516 * - Ensures that components are separated by '/' (Windows only)
 517 * - Squashes sequences of '/'.
 518 * - Removes "." components.
 519 * - Removes ".." components, and the components the precede them.
 520 * Returns failure (non-zero) if a ".." component appears as first path
 521 * component anytime during the normalization. Otherwise, returns success (0).
 522 *
 523 * Note that this function is purely textual.  It does not follow symlinks,
 524 * verify the existence of the path, or make any system calls.
 525 */
 526int normalize_path_copy(char *dst, const char *src)
 527{
 528        char *dst0;
 529
 530        if (has_dos_drive_prefix(src)) {
 531                *dst++ = *src++;
 532                *dst++ = *src++;
 533        }
 534        dst0 = dst;
 535
 536        if (is_dir_sep(*src)) {
 537                *dst++ = '/';
 538                while (is_dir_sep(*src))
 539                        src++;
 540        }
 541
 542        for (;;) {
 543                char c = *src;
 544
 545                /*
 546                 * A path component that begins with . could be
 547                 * special:
 548                 * (1) "." and ends   -- ignore and terminate.
 549                 * (2) "./"           -- ignore them, eat slash and continue.
 550                 * (3) ".." and ends  -- strip one and terminate.
 551                 * (4) "../"          -- strip one, eat slash and continue.
 552                 */
 553                if (c == '.') {
 554                        if (!src[1]) {
 555                                /* (1) */
 556                                src++;
 557                        } else if (is_dir_sep(src[1])) {
 558                                /* (2) */
 559                                src += 2;
 560                                while (is_dir_sep(*src))
 561                                        src++;
 562                                continue;
 563                        } else if (src[1] == '.') {
 564                                if (!src[2]) {
 565                                        /* (3) */
 566                                        src += 2;
 567                                        goto up_one;
 568                                } else if (is_dir_sep(src[2])) {
 569                                        /* (4) */
 570                                        src += 3;
 571                                        while (is_dir_sep(*src))
 572                                                src++;
 573                                        goto up_one;
 574                                }
 575                        }
 576                }
 577
 578                /* copy up to the next '/', and eat all '/' */
 579                while ((c = *src++) != '\0' && !is_dir_sep(c))
 580                        *dst++ = c;
 581                if (is_dir_sep(c)) {
 582                        *dst++ = '/';
 583                        while (is_dir_sep(c))
 584                                c = *src++;
 585                        src--;
 586                } else if (!c)
 587                        break;
 588                continue;
 589
 590        up_one:
 591                /*
 592                 * dst0..dst is prefix portion, and dst[-1] is '/';
 593                 * go up one level.
 594                 */
 595                dst--;  /* go to trailing '/' */
 596                if (dst <= dst0)
 597                        return -1;
 598                /* Windows: dst[-1] cannot be backslash anymore */
 599                while (dst0 < dst && dst[-1] != '/')
 600                        dst--;
 601        }
 602        *dst = '\0';
 603        return 0;
 604}
 605
 606/*
 607 * path = Canonical absolute path
 608 * prefix_list = Colon-separated list of absolute paths
 609 *
 610 * Determines, for each path in prefix_list, whether the "prefix" really
 611 * is an ancestor directory of path.  Returns the length of the longest
 612 * ancestor directory, excluding any trailing slashes, or -1 if no prefix
 613 * is an ancestor.  (Note that this means 0 is returned if prefix_list is
 614 * "/".) "/foo" is not considered an ancestor of "/foobar".  Directories
 615 * are not considered to be their own ancestors.  path must be in a
 616 * canonical form: empty components, or "." or ".." components are not
 617 * allowed.  prefix_list may be null, which is like "".
 618 */
 619int longest_ancestor_length(const char *path, const char *prefix_list)
 620{
 621        char buf[PATH_MAX+1];
 622        const char *ceil, *colon;
 623        int len, max_len = -1;
 624
 625        if (prefix_list == NULL || !strcmp(path, "/"))
 626                return -1;
 627
 628        for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
 629                for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
 630                len = colon - ceil;
 631                if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
 632                        continue;
 633                strlcpy(buf, ceil, len+1);
 634                if (normalize_path_copy(buf, buf) < 0)
 635                        continue;
 636                len = strlen(buf);
 637                if (len > 0 && buf[len-1] == '/')
 638                        buf[--len] = '\0';
 639
 640                if (!strncmp(path, buf, len) &&
 641                    path[len] == '/' &&
 642                    len > max_len) {
 643                        max_len = len;
 644                }
 645        }
 646
 647        return max_len;
 648}
 649
 650/* strip arbitrary amount of directory separators at end of path */
 651static inline int chomp_trailing_dir_sep(const char *path, int len)
 652{
 653        while (len && is_dir_sep(path[len - 1]))
 654                len--;
 655        return len;
 656}
 657
 658/*
 659 * If path ends with suffix (complete path components), returns the
 660 * part before suffix (sans trailing directory separators).
 661 * Otherwise returns NULL.
 662 */
 663char *strip_path_suffix(const char *path, const char *suffix)
 664{
 665        int path_len = strlen(path), suffix_len = strlen(suffix);
 666
 667        while (suffix_len) {
 668                if (!path_len)
 669                        return NULL;
 670
 671                if (is_dir_sep(path[path_len - 1])) {
 672                        if (!is_dir_sep(suffix[suffix_len - 1]))
 673                                return NULL;
 674                        path_len = chomp_trailing_dir_sep(path, path_len);
 675                        suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
 676                }
 677                else if (path[--path_len] != suffix[--suffix_len])
 678                        return NULL;
 679        }
 680
 681        if (path_len && !is_dir_sep(path[path_len - 1]))
 682                return NULL;
 683        return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
 684}
 685
 686int daemon_avoid_alias(const char *p)
 687{
 688        int sl, ndot;
 689
 690        /*
 691         * This resurrects the belts and suspenders paranoia check by HPA
 692         * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
 693         * does not do getcwd() based path canonicalizations.
 694         *
 695         * sl becomes true immediately after seeing '/' and continues to
 696         * be true as long as dots continue after that without intervening
 697         * non-dot character.
 698         */
 699        if (!p || (*p != '/' && *p != '~'))
 700                return -1;
 701        sl = 1; ndot = 0;
 702        p++;
 703
 704        while (1) {
 705                char ch = *p++;
 706                if (sl) {
 707                        if (ch == '.')
 708                                ndot++;
 709                        else if (ch == '/') {
 710                                if (ndot < 3)
 711                                        /* reject //, /./ and /../ */
 712                                        return -1;
 713                                ndot = 0;
 714                        }
 715                        else if (ch == 0) {
 716                                if (0 < ndot && ndot < 3)
 717                                        /* reject /.$ and /..$ */
 718                                        return -1;
 719                                return 0;
 720                        }
 721                        else
 722                                sl = ndot = 0;
 723                }
 724                else if (ch == 0)
 725                        return 0;
 726                else if (ch == '/') {
 727                        sl = 1;
 728                        ndot = 0;
 729                }
 730        }
 731}