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