diff options
Diffstat (limited to 'wrapper.c')
-rw-r--r-- | wrapper.c | 138 |
1 files changed, 76 insertions, 62 deletions
@@ -152,6 +152,9 @@ void *xcalloc(size_t nmemb, size_t size) { void *ret; + if (unsigned_mult_overflows(nmemb, size)) + die("data too large to fit into virtual memory space"); + memory_limit_check(size * nmemb, 0); ret = calloc(nmemb, size); if (!ret && (!nmemb || !size)) @@ -224,6 +227,24 @@ int xopen(const char *path, int oflag, ...) } } +static int handle_nonblock(int fd, short poll_events, int err) +{ + struct pollfd pfd; + + if (err != EAGAIN && err != EWOULDBLOCK) + return 0; + + pfd.fd = fd; + pfd.events = poll_events; + + /* + * no need to check for errors, here; + * a subsequent read/write will detect unrecoverable errors + */ + poll(&pfd, 1, -1); + return 1; +} + /* * xread() is the same a read(), but it automatically restarts read() * operations with a recoverable error (EAGAIN and EINTR). xread() @@ -236,8 +257,12 @@ ssize_t xread(int fd, void *buf, size_t len) len = MAX_IO_SIZE; while (1) { nr = read(fd, buf, len); - if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) - continue; + if (nr < 0) { + if (errno == EINTR) + continue; + if (handle_nonblock(fd, POLLIN, errno)) + continue; + } return nr; } } @@ -254,8 +279,13 @@ ssize_t xwrite(int fd, const void *buf, size_t len) len = MAX_IO_SIZE; while (1) { nr = write(fd, buf, len); - if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) - continue; + if (nr < 0) { + if (errno == EINTR) + continue; + if (handle_nonblock(fd, POLLOUT, errno)) + continue; + } + return nr; } } @@ -375,6 +405,19 @@ FILE *xfdopen(int fd, const char *mode) return stream; } +FILE *fopen_for_writing(const char *path) +{ + FILE *ret = fopen(path, "w"); + + if (!ret && errno == EPERM) { + if (!unlink(path)) + ret = fopen(path, "w"); + else + errno = EPERM; + } + return ret; +} + int xmkstemp(char *template) { int fd; @@ -414,23 +457,6 @@ int git_mkstemp(char *path, size_t len, const char *template) return mkstemp(path); } -/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */ -int git_mkstemps(char *path, size_t len, const char *template, int suffix_len) -{ - const char *tmp; - size_t n; - - tmp = getenv("TMPDIR"); - if (!tmp) - tmp = "/tmp"; - n = snprintf(path, len, "%s/%s", tmp, template); - if (len <= n) { - errno = ENAMETOOLONG; - return -1; - } - return mkstemps(path, suffix_len); -} - /* Adapted from libiberty's mkstemp.c. */ #undef TMP_MAX @@ -540,7 +566,7 @@ static int warn_if_unremovable(const char *op, const char *file, int rc) if (!rc || errno == ENOENT) return 0; err = errno; - warning("unable to %s %s: %s", op, file, strerror(errno)); + warning_errno("unable to %s %s", op, file); errno = err; return rc; } @@ -576,7 +602,7 @@ int remove_or_warn(unsigned int mode, const char *file) void warn_on_inaccessible(const char *path) { - warning(_("unable to access '%s': %s"), path, strerror(errno)); + warning_errno(_("unable to access '%s'"), path); } static int access_error_is_ok(int err, unsigned flag) @@ -609,56 +635,44 @@ char *xgetcwd(void) return strbuf_detach(&sb, NULL); } -static int write_file_v(const char *path, int fatal, - const char *fmt, va_list params) +int xsnprintf(char *dst, size_t max, const char *fmt, ...) { - 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; + 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; } -int write_file(const char *path, const char *fmt, ...) +void write_file_buf(const char *path, const char *buf, size_t len) { - int status; - va_list params; - - va_start(params, fmt); - status = write_file_v(path, 1, fmt, params); - va_end(params); - return status; + int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (write_in_full(fd, buf, len) != len) + die_errno(_("could not write to %s"), path); + if (close(fd)) + die_errno(_("could not close %s"), path); } -int write_file_gently(const char *path, const char *fmt, ...) +void write_file(const char *path, const char *fmt, ...) { - int status; va_list params; + struct strbuf sb = STRBUF_INIT; va_start(params, fmt); - status = write_file_v(path, 0, fmt, params); + strbuf_vaddf(&sb, fmt, params); va_end(params); - return status; + + strbuf_complete_line(&sb); + + write_file_buf(path, sb.buf, sb.len); + strbuf_release(&sb); } void sleep_millisec(int millisec) |