wrapper.con commit graph: simplify graph_padding_line() (0176e7a)
   1/*
   2 * Various trivial helper wrappers around standard functions
   3 */
   4#include "cache.h"
   5
   6static void do_nothing(size_t size)
   7{
   8}
   9
  10static void (*try_to_free_routine)(size_t size) = do_nothing;
  11
  12static int memory_limit_check(size_t size, int gentle)
  13{
  14        static int limit = -1;
  15        if (limit == -1) {
  16                const char *env = getenv("GIT_ALLOC_LIMIT");
  17                limit = env ? atoi(env) * 1024 : 0;
  18        }
  19        if (limit && size > limit) {
  20                if (gentle) {
  21                        error("attempting to allocate %"PRIuMAX" over limit %d",
  22                              (intmax_t)size, limit);
  23                        return -1;
  24                } else
  25                        die("attempting to allocate %"PRIuMAX" over limit %d",
  26                            (intmax_t)size, limit);
  27        }
  28        return 0;
  29}
  30
  31try_to_free_t set_try_to_free_routine(try_to_free_t routine)
  32{
  33        try_to_free_t old = try_to_free_routine;
  34        if (!routine)
  35                routine = do_nothing;
  36        try_to_free_routine = routine;
  37        return old;
  38}
  39
  40char *xstrdup(const char *str)
  41{
  42        char *ret = strdup(str);
  43        if (!ret) {
  44                try_to_free_routine(strlen(str) + 1);
  45                ret = strdup(str);
  46                if (!ret)
  47                        die("Out of memory, strdup failed");
  48        }
  49        return ret;
  50}
  51
  52static void *do_xmalloc(size_t size, int gentle)
  53{
  54        void *ret;
  55
  56        if (memory_limit_check(size, gentle))
  57                return NULL;
  58        ret = malloc(size);
  59        if (!ret && !size)
  60                ret = malloc(1);
  61        if (!ret) {
  62                try_to_free_routine(size);
  63                ret = malloc(size);
  64                if (!ret && !size)
  65                        ret = malloc(1);
  66                if (!ret) {
  67                        if (!gentle)
  68                                die("Out of memory, malloc failed (tried to allocate %lu bytes)",
  69                                    (unsigned long)size);
  70                        else {
  71                                error("Out of memory, malloc failed (tried to allocate %lu bytes)",
  72                                      (unsigned long)size);
  73                                return NULL;
  74                        }
  75                }
  76        }
  77#ifdef XMALLOC_POISON
  78        memset(ret, 0xA5, size);
  79#endif
  80        return ret;
  81}
  82
  83void *xmalloc(size_t size)
  84{
  85        return do_xmalloc(size, 0);
  86}
  87
  88static void *do_xmallocz(size_t size, int gentle)
  89{
  90        void *ret;
  91        if (unsigned_add_overflows(size, 1)) {
  92                if (gentle) {
  93                        error("Data too large to fit into virtual memory space.");
  94                        return NULL;
  95                } else
  96                        die("Data too large to fit into virtual memory space.");
  97        }
  98        ret = do_xmalloc(size + 1, gentle);
  99        if (ret)
 100                ((char*)ret)[size] = 0;
 101        return ret;
 102}
 103
 104void *xmallocz(size_t size)
 105{
 106        return do_xmallocz(size, 0);
 107}
 108
 109void *xmallocz_gently(size_t size)
 110{
 111        return do_xmallocz(size, 1);
 112}
 113
 114/*
 115 * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
 116 * "data" to the allocated memory, zero terminates the allocated memory,
 117 * and returns a pointer to the allocated memory. If the allocation fails,
 118 * the program dies.
 119 */
 120void *xmemdupz(const void *data, size_t len)
 121{
 122        return memcpy(xmallocz(len), data, len);
 123}
 124
 125char *xstrndup(const char *str, size_t len)
 126{
 127        char *p = memchr(str, '\0', len);
 128        return xmemdupz(str, p ? p - str : len);
 129}
 130
 131void *xrealloc(void *ptr, size_t size)
 132{
 133        void *ret;
 134
 135        memory_limit_check(size, 0);
 136        ret = realloc(ptr, size);
 137        if (!ret && !size)
 138                ret = realloc(ptr, 1);
 139        if (!ret) {
 140                try_to_free_routine(size);
 141                ret = realloc(ptr, size);
 142                if (!ret && !size)
 143                        ret = realloc(ptr, 1);
 144                if (!ret)
 145                        die("Out of memory, realloc failed");
 146        }
 147        return ret;
 148}
 149
 150void *xcalloc(size_t nmemb, size_t size)
 151{
 152        void *ret;
 153
 154        memory_limit_check(size * nmemb, 0);
 155        ret = calloc(nmemb, size);
 156        if (!ret && (!nmemb || !size))
 157                ret = calloc(1, 1);
 158        if (!ret) {
 159                try_to_free_routine(nmemb * size);
 160                ret = calloc(nmemb, size);
 161                if (!ret && (!nmemb || !size))
 162                        ret = calloc(1, 1);
 163                if (!ret)
 164                        die("Out of memory, calloc failed");
 165        }
 166        return ret;
 167}
 168
 169/*
 170 * Limit size of IO chunks, because huge chunks only cause pain.  OS X
 171 * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
 172 * the absence of bugs, large chunks can result in bad latencies when
 173 * you decide to kill the process.
 174 */
 175#define MAX_IO_SIZE (8*1024*1024)
 176
 177/*
 178 * xread() is the same a read(), but it automatically restarts read()
 179 * operations with a recoverable error (EAGAIN and EINTR). xread()
 180 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
 181 */
 182ssize_t xread(int fd, void *buf, size_t len)
 183{
 184        ssize_t nr;
 185        if (len > MAX_IO_SIZE)
 186            len = MAX_IO_SIZE;
 187        while (1) {
 188                nr = read(fd, buf, len);
 189                if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
 190                        continue;
 191                return nr;
 192        }
 193}
 194
 195/*
 196 * xwrite() is the same a write(), but it automatically restarts write()
 197 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
 198 * GUARANTEE that "len" bytes is written even if the operation is successful.
 199 */
 200ssize_t xwrite(int fd, const void *buf, size_t len)
 201{
 202        ssize_t nr;
 203        if (len > MAX_IO_SIZE)
 204            len = MAX_IO_SIZE;
 205        while (1) {
 206                nr = write(fd, buf, len);
 207                if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
 208                        continue;
 209                return nr;
 210        }
 211}
 212
 213/*
 214 * xpread() is the same as pread(), but it automatically restarts pread()
 215 * operations with a recoverable error (EAGAIN and EINTR). xpread() DOES
 216 * NOT GUARANTEE that "len" bytes is read even if the data is available.
 217 */
 218ssize_t xpread(int fd, void *buf, size_t len, off_t offset)
 219{
 220        ssize_t nr;
 221        if (len > MAX_IO_SIZE)
 222                len = MAX_IO_SIZE;
 223        while (1) {
 224                nr = pread(fd, buf, len, offset);
 225                if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
 226                        continue;
 227                return nr;
 228        }
 229}
 230
 231ssize_t read_in_full(int fd, void *buf, size_t count)
 232{
 233        char *p = buf;
 234        ssize_t total = 0;
 235
 236        while (count > 0) {
 237                ssize_t loaded = xread(fd, p, count);
 238                if (loaded < 0)
 239                        return -1;
 240                if (loaded == 0)
 241                        return total;
 242                count -= loaded;
 243                p += loaded;
 244                total += loaded;
 245        }
 246
 247        return total;
 248}
 249
 250ssize_t write_in_full(int fd, const void *buf, size_t count)
 251{
 252        const char *p = buf;
 253        ssize_t total = 0;
 254
 255        while (count > 0) {
 256                ssize_t written = xwrite(fd, p, count);
 257                if (written < 0)
 258                        return -1;
 259                if (!written) {
 260                        errno = ENOSPC;
 261                        return -1;
 262                }
 263                count -= written;
 264                p += written;
 265                total += written;
 266        }
 267
 268        return total;
 269}
 270
 271ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
 272{
 273        char *p = buf;
 274        ssize_t total = 0;
 275
 276        while (count > 0) {
 277                ssize_t loaded = xpread(fd, p, count, offset);
 278                if (loaded < 0)
 279                        return -1;
 280                if (loaded == 0)
 281                        return total;
 282                count -= loaded;
 283                p += loaded;
 284                total += loaded;
 285                offset += loaded;
 286        }
 287
 288        return total;
 289}
 290
 291int xdup(int fd)
 292{
 293        int ret = dup(fd);
 294        if (ret < 0)
 295                die_errno("dup failed");
 296        return ret;
 297}
 298
 299FILE *xfdopen(int fd, const char *mode)
 300{
 301        FILE *stream = fdopen(fd, mode);
 302        if (stream == NULL)
 303                die_errno("Out of memory? fdopen failed");
 304        return stream;
 305}
 306
 307int xmkstemp(char *template)
 308{
 309        int fd;
 310        char origtemplate[PATH_MAX];
 311        strlcpy(origtemplate, template, sizeof(origtemplate));
 312
 313        fd = mkstemp(template);
 314        if (fd < 0) {
 315                int saved_errno = errno;
 316                const char *nonrelative_template;
 317
 318                if (strlen(template) != strlen(origtemplate))
 319                        template = origtemplate;
 320
 321                nonrelative_template = absolute_path(template);
 322                errno = saved_errno;
 323                die_errno("Unable to create temporary file '%s'",
 324                        nonrelative_template);
 325        }
 326        return fd;
 327}
 328
 329/* git_mkstemp() - create tmp file honoring TMPDIR variable */
 330int git_mkstemp(char *path, size_t len, const char *template)
 331{
 332        const char *tmp;
 333        size_t n;
 334
 335        tmp = getenv("TMPDIR");
 336        if (!tmp)
 337                tmp = "/tmp";
 338        n = snprintf(path, len, "%s/%s", tmp, template);
 339        if (len <= n) {
 340                errno = ENAMETOOLONG;
 341                return -1;
 342        }
 343        return mkstemp(path);
 344}
 345
 346/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */
 347int git_mkstemps(char *path, size_t len, const char *template, int suffix_len)
 348{
 349        const char *tmp;
 350        size_t n;
 351
 352        tmp = getenv("TMPDIR");
 353        if (!tmp)
 354                tmp = "/tmp";
 355        n = snprintf(path, len, "%s/%s", tmp, template);
 356        if (len <= n) {
 357                errno = ENAMETOOLONG;
 358                return -1;
 359        }
 360        return mkstemps(path, suffix_len);
 361}
 362
 363/* Adapted from libiberty's mkstemp.c. */
 364
 365#undef TMP_MAX
 366#define TMP_MAX 16384
 367
 368int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
 369{
 370        static const char letters[] =
 371                "abcdefghijklmnopqrstuvwxyz"
 372                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 373                "0123456789";
 374        static const int num_letters = 62;
 375        uint64_t value;
 376        struct timeval tv;
 377        char *template;
 378        size_t len;
 379        int fd, count;
 380
 381        len = strlen(pattern);
 382
 383        if (len < 6 + suffix_len) {
 384                errno = EINVAL;
 385                return -1;
 386        }
 387
 388        if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
 389                errno = EINVAL;
 390                return -1;
 391        }
 392
 393        /*
 394         * Replace pattern's XXXXXX characters with randomness.
 395         * Try TMP_MAX different filenames.
 396         */
 397        gettimeofday(&tv, NULL);
 398        value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
 399        template = &pattern[len - 6 - suffix_len];
 400        for (count = 0; count < TMP_MAX; ++count) {
 401                uint64_t v = value;
 402                /* Fill in the random bits. */
 403                template[0] = letters[v % num_letters]; v /= num_letters;
 404                template[1] = letters[v % num_letters]; v /= num_letters;
 405                template[2] = letters[v % num_letters]; v /= num_letters;
 406                template[3] = letters[v % num_letters]; v /= num_letters;
 407                template[4] = letters[v % num_letters]; v /= num_letters;
 408                template[5] = letters[v % num_letters]; v /= num_letters;
 409
 410                fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
 411                if (fd >= 0)
 412                        return fd;
 413                /*
 414                 * Fatal error (EPERM, ENOSPC etc).
 415                 * It doesn't make sense to loop.
 416                 */
 417                if (errno != EEXIST)
 418                        break;
 419                /*
 420                 * This is a random value.  It is only necessary that
 421                 * the next TMP_MAX values generated by adding 7777 to
 422                 * VALUE are different with (module 2^32).
 423                 */
 424                value += 7777;
 425        }
 426        /* We return the null string if we can't find a unique file name.  */
 427        pattern[0] = '\0';
 428        return -1;
 429}
 430
 431int git_mkstemp_mode(char *pattern, int mode)
 432{
 433        /* mkstemp is just mkstemps with no suffix */
 434        return git_mkstemps_mode(pattern, 0, mode);
 435}
 436
 437#ifdef NO_MKSTEMPS
 438int gitmkstemps(char *pattern, int suffix_len)
 439{
 440        return git_mkstemps_mode(pattern, suffix_len, 0600);
 441}
 442#endif
 443
 444int xmkstemp_mode(char *template, int mode)
 445{
 446        int fd;
 447        char origtemplate[PATH_MAX];
 448        strlcpy(origtemplate, template, sizeof(origtemplate));
 449
 450        fd = git_mkstemp_mode(template, mode);
 451        if (fd < 0) {
 452                int saved_errno = errno;
 453                const char *nonrelative_template;
 454
 455                if (!template[0])
 456                        template = origtemplate;
 457
 458                nonrelative_template = absolute_path(template);
 459                errno = saved_errno;
 460                die_errno("Unable to create temporary file '%s'",
 461                        nonrelative_template);
 462        }
 463        return fd;
 464}
 465
 466static int warn_if_unremovable(const char *op, const char *file, int rc)
 467{
 468        if (rc < 0) {
 469                int err = errno;
 470                if (ENOENT != err) {
 471                        warning("unable to %s %s: %s",
 472                                op, file, strerror(errno));
 473                        errno = err;
 474                }
 475        }
 476        return rc;
 477}
 478
 479int unlink_or_warn(const char *file)
 480{
 481        return warn_if_unremovable("unlink", file, unlink(file));
 482}
 483
 484int rmdir_or_warn(const char *file)
 485{
 486        return warn_if_unremovable("rmdir", file, rmdir(file));
 487}
 488
 489int remove_or_warn(unsigned int mode, const char *file)
 490{
 491        return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
 492}
 493
 494void warn_on_inaccessible(const char *path)
 495{
 496        warning(_("unable to access '%s': %s"), path, strerror(errno));
 497}
 498
 499static int access_error_is_ok(int err, unsigned flag)
 500{
 501        return err == ENOENT || err == ENOTDIR ||
 502                ((flag & ACCESS_EACCES_OK) && err == EACCES);
 503}
 504
 505int access_or_warn(const char *path, int mode, unsigned flag)
 506{
 507        int ret = access(path, mode);
 508        if (ret && !access_error_is_ok(errno, flag))
 509                warn_on_inaccessible(path);
 510        return ret;
 511}
 512
 513int access_or_die(const char *path, int mode, unsigned flag)
 514{
 515        int ret = access(path, mode);
 516        if (ret && !access_error_is_ok(errno, flag))
 517                die_errno(_("unable to access '%s'"), path);
 518        return ret;
 519}
 520
 521struct passwd *xgetpwuid_self(void)
 522{
 523        struct passwd *pw;
 524
 525        errno = 0;
 526        pw = getpwuid(getuid());
 527        if (!pw)
 528                die(_("unable to look up current user in the passwd file: %s"),
 529                    errno ? strerror(errno) : _("no such user"));
 530        return pw;
 531}
 532
 533char *xgetcwd(void)
 534{
 535        struct strbuf sb = STRBUF_INIT;
 536        if (strbuf_getcwd(&sb))
 537                die_errno(_("unable to get current working directory"));
 538        return strbuf_detach(&sb, NULL);
 539}