diff options
Diffstat (limited to 'wrapper.c')
-rw-r--r-- | wrapper.c | 192 |
1 files changed, 174 insertions, 18 deletions
@@ -11,19 +11,20 @@ static void (*try_to_free_routine)(size_t size) = do_nothing; static int memory_limit_check(size_t size, int gentle) { - static int limit = -1; - if (limit == -1) { - const char *env = getenv("GIT_ALLOC_LIMIT"); - limit = env ? atoi(env) * 1024 : 0; + static size_t limit = 0; + if (!limit) { + limit = git_env_ulong("GIT_ALLOC_LIMIT", 0); + if (!limit) + limit = SIZE_MAX; } - if (limit && size > limit) { + if (size > limit) { if (gentle) { - error("attempting to allocate %"PRIuMAX" over limit %d", - (intmax_t)size, limit); + error("attempting to allocate %"PRIuMAX" over limit %"PRIuMAX, + (uintmax_t)size, (uintmax_t)limit); return -1; } else - die("attempting to allocate %"PRIuMAX" over limit %d", - (intmax_t)size, limit); + die("attempting to allocate %"PRIuMAX" over limit %"PRIuMAX, + (uintmax_t)size, (uintmax_t)limit); } return 0; } @@ -171,8 +172,57 @@ void *xcalloc(size_t nmemb, size_t size) * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in * the absence of bugs, large chunks can result in bad latencies when * you decide to kill the process. + * + * We pick 8 MiB as our default, but if the platform defines SSIZE_MAX + * that is smaller than that, clip it to SSIZE_MAX, as a call to + * read(2) or write(2) larger than that is allowed to fail. As the last + * resort, we allow a port to pass via CFLAGS e.g. "-DMAX_IO_SIZE=value" + * to override this, if the definition of SSIZE_MAX given by the platform + * is broken. */ -#define MAX_IO_SIZE (8*1024*1024) +#ifndef MAX_IO_SIZE +# define MAX_IO_SIZE_DEFAULT (8*1024*1024) +# if defined(SSIZE_MAX) && (SSIZE_MAX < MAX_IO_SIZE_DEFAULT) +# define MAX_IO_SIZE SSIZE_MAX +# else +# define MAX_IO_SIZE MAX_IO_SIZE_DEFAULT +# endif +#endif + +/** + * xopen() is the same as open(), but it die()s if the open() fails. + */ +int xopen(const char *path, int oflag, ...) +{ + mode_t mode = 0; + va_list ap; + + /* + * va_arg() will have undefined behavior if the specified type is not + * compatible with the argument type. Since integers are promoted to + * ints, we fetch the next argument as an int, and then cast it to a + * mode_t to avoid undefined behavior. + */ + va_start(ap, oflag); + if (oflag & O_CREAT) + mode = va_arg(ap, int); + va_end(ap); + + for (;;) { + int fd = open(path, oflag, mode); + if (fd >= 0) + return fd; + if (errno == EINTR) + continue; + + if ((oflag & O_RDWR) == O_RDWR) + die_errno(_("could not open '%s' for reading and writing"), path); + else if ((oflag & O_WRONLY) == O_WRONLY) + die_errno(_("could not open '%s' for writing"), path); + else + die_errno(_("could not open '%s' for reading"), path); + } +} /* * xread() is the same a read(), but it automatically restarts read() @@ -296,6 +346,27 @@ int xdup(int fd) return ret; } +/** + * xfopen() is the same as fopen(), but it die()s if the fopen() fails. + */ +FILE *xfopen(const char *path, const char *mode) +{ + for (;;) { + FILE *fp = fopen(path, mode); + if (fp) + return fp; + if (errno == EINTR) + continue; + + if (*mode && mode[1] == '+') + die_errno(_("could not open '%s' for reading and writing"), path); + else if (*mode == 'w' || *mode == 'a') + die_errno(_("could not open '%s' for writing"), path); + else + die_errno(_("could not open '%s' for reading"), path); + } +} + FILE *xfdopen(int fd, const char *mode) { FILE *stream = fdopen(fd, mode); @@ -465,17 +536,29 @@ int xmkstemp_mode(char *template, int mode) static int warn_if_unremovable(const char *op, const char *file, int rc) { - if (rc < 0) { - int err = errno; - if (ENOENT != err) { - warning("unable to %s %s: %s", - op, file, strerror(errno)); - errno = err; - } - } + int err; + if (!rc || errno == ENOENT) + return 0; + err = errno; + warning("unable to %s %s: %s", op, file, strerror(errno)); + errno = err; return rc; } +int unlink_or_msg(const char *file, struct strbuf *err) +{ + int rc = unlink(file); + + assert(err); + + if (!rc || errno == ENOENT) + return 0; + + strbuf_addf(err, "unable to unlink %s: %s", + file, strerror(errno)); + return -1; +} + int unlink_or_warn(const char *file) { return warn_if_unremovable("unlink", file, unlink(file)); @@ -537,3 +620,76 @@ char *xgetcwd(void) die_errno(_("unable to get current working directory")); return strbuf_detach(&sb, NULL); } + +int xsnprintf(char *dst, size_t max, const char *fmt, ...) +{ + va_list ap; + int len; + + va_start(ap, fmt); + len = vsnprintf(dst, max, fmt, ap); + va_end(ap); + + if (len < 0) + die("BUG: your snprintf is broken"); + if (len >= max) + die("BUG: attempt to snprintf into too-small buffer"); + return len; +} + +static int write_file_v(const char *path, int fatal, + const char *fmt, va_list params) +{ + struct strbuf sb = STRBUF_INIT; + int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + if (fatal) + die_errno(_("could not open %s for writing"), path); + return -1; + } + strbuf_vaddf(&sb, fmt, params); + strbuf_complete_line(&sb); + if (write_in_full(fd, sb.buf, sb.len) != sb.len) { + int err = errno; + close(fd); + strbuf_release(&sb); + errno = err; + if (fatal) + die_errno(_("could not write to %s"), path); + return -1; + } + strbuf_release(&sb); + if (close(fd)) { + if (fatal) + die_errno(_("could not close %s"), path); + return -1; + } + return 0; +} + +int write_file(const char *path, const char *fmt, ...) +{ + int status; + va_list params; + + va_start(params, fmt); + status = write_file_v(path, 1, fmt, params); + va_end(params); + return status; +} + +int write_file_gently(const char *path, const char *fmt, ...) +{ + int status; + va_list params; + + va_start(params, fmt); + status = write_file_v(path, 0, fmt, params); + va_end(params); + return status; +} + +void sleep_millisec(int millisec) +{ + poll(NULL, 0, millisec); +} |