send-pack: avoid deadlock on git:// push with failed pack-objects
[gitweb.git] / http-backend.c
index 646e9108bddbd538f04fc01129214aa8615d5e5a..f729488fc5f787c0f4997aacdd1bb14732d717f7 100644 (file)
@@ -108,6 +108,7 @@ static const char *get_parameter(const char *name)
        return i ? i->util : NULL;
 }
 
+__attribute__((format (printf, 2, 3)))
 static void format_write(int fd, const char *fmt, ...)
 {
        static char buffer[1024];
@@ -134,7 +135,7 @@ static void hdr_str(const char *name, const char *value)
        format_write(1, "%s: %s\r\n", name, value);
 }
 
-static void hdr_int(const char *name, size_t value)
+static void hdr_int(const char *name, uintmax_t value)
 {
        format_write(1, "%s: %" PRIuMAX "\r\n", name, value);
 }
@@ -165,6 +166,7 @@ static void end_headers(void)
        safe_write(1, "\r\n", 2);
 }
 
+__attribute__((format (printf, 1, 2)))
 static NORETURN void not_found(const char *err, ...)
 {
        va_list params;
@@ -180,6 +182,7 @@ static NORETURN void not_found(const char *err, ...)
        exit(0);
 }
 
+__attribute__((format (printf, 1, 2)))
 static NORETURN void forbidden(const char *err, ...)
 {
        va_list params;
@@ -216,7 +219,6 @@ static void send_local_file(const char *the_type, const char *name)
        char *buf = xmalloc(buf_alloc);
        int fd;
        struct stat sb;
-       size_t size;
 
        fd = open(p, O_RDONLY);
        if (fd < 0)
@@ -224,14 +226,12 @@ static void send_local_file(const char *the_type, const char *name)
        if (fstat(fd, &sb) < 0)
                die_errno("Cannot stat '%s'", p);
 
-       size = xsize_t(sb.st_size);
-
-       hdr_int(content_length, size);
+       hdr_int(content_length, sb.st_size);
        hdr_str(content_type, the_type);
        hdr_date(last_modified, sb.st_mtime);
        end_headers();
 
-       while (size) {
+       for (;;) {
                ssize_t n = xread(fd, buf, buf_alloc);
                if (n < 0)
                        die_errno("Cannot read '%s'", p);
@@ -559,7 +559,13 @@ static char* getdir(void)
        if (root && *root) {
                if (!pathinfo || !*pathinfo)
                        die("GIT_PROJECT_ROOT is set but PATH_INFO is not");
+               if (daemon_avoid_alias(pathinfo))
+                       die("'%s': aliased", pathinfo);
                strbuf_addstr(&buf, root);
+               if (buf.buf[buf.len - 1] != '/')
+                       strbuf_addch(&buf, '/');
+               if (pathinfo[0] == '/')
+                       pathinfo++;
                strbuf_addstr(&buf, pathinfo);
                return strbuf_detach(&buf, NULL);
        } else if (path && *path) {
@@ -612,7 +618,7 @@ int main(int argc, char **argv)
                if (regcomp(&re, c->pattern, REG_EXTENDED))
                        die("Bogus regex in service table: %s", c->pattern);
                if (!regexec(&re, dir, 1, out, 0)) {
-                       size_t n = out[0].rm_eo - out[0].rm_so;
+                       size_t n;
 
                        if (strcmp(method, c->method)) {
                                const char *proto = getenv("SERVER_PROTOCOL");
@@ -626,9 +632,10 @@ int main(int argc, char **argv)
                        }
 
                        cmd = c;
+                       n = out[0].rm_eo - out[0].rm_so;
                        cmd_arg = xmalloc(n);
-                       strncpy(cmd_arg, dir + out[0].rm_so + 1, n);
-                       cmd_arg[n] = '\0';
+                       memcpy(cmd_arg, dir + out[0].rm_so + 1, n-1);
+                       cmd_arg[n-1] = '\0';
                        dir[out[0].rm_so] = 0;
                        break;
                }