summaryrefslogtreecommitdiff
path: root/wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'wrapper.c')
-rw-r--r--wrapper.c138
1 files changed, 76 insertions, 62 deletions
diff --git a/wrapper.c b/wrapper.c
index dae5675a96..e7f1979968 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -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)