ewah: support platforms that require aligned reads
[gitweb.git] / wrapper.c
index 4c147d6c48c000bab636fad3edc2fe7da6670948..9a6aaafaf35bbd6d2a7a97589edfd9b0b12102c7 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -9,6 +9,18 @@ static void do_nothing(size_t size)
 
 static void (*try_to_free_routine)(size_t size) = do_nothing;
 
+static void memory_limit_check(size_t size)
+{
+       static int limit = -1;
+       if (limit == -1) {
+               const char *env = getenv("GIT_ALLOC_LIMIT");
+               limit = env ? atoi(env) * 1024 : 0;
+       }
+       if (limit && size > limit)
+               die("attempting to allocate %"PRIuMAX" over limit %d",
+                   (intmax_t)size, limit);
+}
+
 try_to_free_t set_try_to_free_routine(try_to_free_t routine)
 {
        try_to_free_t old = try_to_free_routine;
@@ -32,7 +44,10 @@ char *xstrdup(const char *str)
 
 void *xmalloc(size_t size)
 {
-       void *ret = malloc(size);
+       void *ret;
+
+       memory_limit_check(size);
+       ret = malloc(size);
        if (!ret && !size)
                ret = malloc(1);
        if (!ret) {
@@ -79,7 +94,10 @@ char *xstrndup(const char *str, size_t len)
 
 void *xrealloc(void *ptr, size_t size)
 {
-       void *ret = realloc(ptr, size);
+       void *ret;
+
+       memory_limit_check(size);
+       ret = realloc(ptr, size);
        if (!ret && !size)
                ret = realloc(ptr, 1);
        if (!ret) {
@@ -95,7 +113,10 @@ void *xrealloc(void *ptr, size_t size)
 
 void *xcalloc(size_t nmemb, size_t size)
 {
-       void *ret = calloc(nmemb, size);
+       void *ret;
+
+       memory_limit_check(size * nmemb);
+       ret = calloc(nmemb, size);
        if (!ret && (!nmemb || !size))
                ret = calloc(1, 1);
        if (!ret) {
@@ -109,6 +130,14 @@ void *xcalloc(size_t nmemb, size_t size)
        return ret;
 }
 
+/*
+ * Limit size of IO chunks, because huge chunks only cause pain.  OS X
+ * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
+ * the absense of bugs, large chunks can result in bad latencies when
+ * you decide to kill the process.
+ */
+#define MAX_IO_SIZE (8*1024*1024)
+
 /*
  * xread() is the same a read(), but it automatically restarts read()
  * operations with a recoverable error (EAGAIN and EINTR). xread()
@@ -117,6 +146,8 @@ void *xcalloc(size_t nmemb, size_t size)
 ssize_t xread(int fd, void *buf, size_t len)
 {
        ssize_t nr;
+       if (len > MAX_IO_SIZE)
+           len = MAX_IO_SIZE;
        while (1) {
                nr = read(fd, buf, len);
                if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
@@ -133,6 +164,8 @@ ssize_t xread(int fd, void *buf, size_t len)
 ssize_t xwrite(int fd, const void *buf, size_t len)
 {
        ssize_t nr;
+       if (len > MAX_IO_SIZE)
+           len = MAX_IO_SIZE;
        while (1) {
                nr = write(fd, buf, len);
                if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
@@ -148,8 +181,10 @@ ssize_t read_in_full(int fd, void *buf, size_t count)
 
        while (count > 0) {
                ssize_t loaded = xread(fd, p, count);
-               if (loaded <= 0)
-                       return total ? total : loaded;
+               if (loaded < 0)
+                       return -1;
+               if (loaded == 0)
+                       return total;
                count -= loaded;
                p += loaded;
                total += loaded;
@@ -206,10 +241,10 @@ int xmkstemp(char *template)
                int saved_errno = errno;
                const char *nonrelative_template;
 
-               if (!template[0])
+               if (strlen(template) != strlen(origtemplate))
                        template = origtemplate;
 
-               nonrelative_template = make_nonrelative_path(template);
+               nonrelative_template = absolute_path(template);
                errno = saved_errno;
                die_errno("Unable to create temporary file '%s'",
                        nonrelative_template);
@@ -299,7 +334,7 @@ int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
                template[5] = letters[v % num_letters]; v /= num_letters;
 
                fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
-               if (fd > 0)
+               if (fd >= 0)
                        return fd;
                /*
                 * Fatal error (EPERM, ENOSPC etc).
@@ -325,10 +360,12 @@ int git_mkstemp_mode(char *pattern, int mode)
        return git_mkstemps_mode(pattern, 0, mode);
 }
 
+#ifdef NO_MKSTEMPS
 int gitmkstemps(char *pattern, int suffix_len)
 {
        return git_mkstemps_mode(pattern, suffix_len, 0600);
 }
+#endif
 
 int xmkstemp_mode(char *template, int mode)
 {
@@ -344,7 +381,7 @@ int xmkstemp_mode(char *template, int mode)
                if (!template[0])
                        template = origtemplate;
 
-               nonrelative_template = make_nonrelative_path(template);
+               nonrelative_template = absolute_path(template);
                errno = saved_errno;
                die_errno("Unable to create temporary file '%s'",
                        nonrelative_template);
@@ -379,3 +416,42 @@ int remove_or_warn(unsigned int mode, const char *file)
 {
        return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
 }
+
+void warn_on_inaccessible(const char *path)
+{
+       warning(_("unable to access '%s': %s"), path, strerror(errno));
+}
+
+static int access_error_is_ok(int err, unsigned flag)
+{
+       return err == ENOENT || err == ENOTDIR ||
+               ((flag & ACCESS_EACCES_OK) && err == EACCES);
+}
+
+int access_or_warn(const char *path, int mode, unsigned flag)
+{
+       int ret = access(path, mode);
+       if (ret && !access_error_is_ok(errno, flag))
+               warn_on_inaccessible(path);
+       return ret;
+}
+
+int access_or_die(const char *path, int mode, unsigned flag)
+{
+       int ret = access(path, mode);
+       if (ret && !access_error_is_ok(errno, flag))
+               die_errno(_("unable to access '%s'"), path);
+       return ret;
+}
+
+struct passwd *xgetpwuid_self(void)
+{
+       struct passwd *pw;
+
+       errno = 0;
+       pw = getpwuid(getuid());
+       if (!pw)
+               die(_("unable to look up current user in the passwd file: %s"),
+                   errno ? strerror(errno) : _("no such user"));
+       return pw;
+}