Code

Avoid segfault with 'git branch' when the HEAD is detached
[git.git] / http-push.c
index 7d5c23edc4b864958671a26bde64ce21e54924bc..a8ae545dfb952b9108ef679a176d57eb2216d622 100644 (file)
@@ -178,6 +178,47 @@ struct remote_ls_ctx
        struct remote_ls_ctx *parent;
 };
 
+/* get_dav_token_headers options */
+enum dav_header_flag {
+       DAV_HEADER_IF = (1u << 0),
+       DAV_HEADER_LOCK = (1u << 1),
+       DAV_HEADER_TIMEOUT = (1u << 2)
+};
+
+static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options)
+{
+       struct strbuf buf = STRBUF_INIT;
+       struct curl_slist *dav_headers = NULL;
+
+       if (options & DAV_HEADER_IF) {
+               strbuf_addf(&buf, "If: (<%s>)", lock->token);
+               dav_headers = curl_slist_append(dav_headers, buf.buf);
+               strbuf_reset(&buf);
+       }
+       if (options & DAV_HEADER_LOCK) {
+               strbuf_addf(&buf, "Lock-Token: <%s>", lock->token);
+               dav_headers = curl_slist_append(dav_headers, buf.buf);
+               strbuf_reset(&buf);
+       }
+       if (options & DAV_HEADER_TIMEOUT) {
+               strbuf_addf(&buf, "Timeout: Second-%ld", lock->timeout);
+               dav_headers = curl_slist_append(dav_headers, buf.buf);
+               strbuf_reset(&buf);
+       }
+       strbuf_release(&buf);
+
+       return dav_headers;
+}
+
+static void append_remote_object_url(struct strbuf *buf, const char *url,
+                                    const char *hex,
+                                    int only_two_digit_prefix)
+{
+       strbuf_addf(buf, "%sobjects/%.*s/", url, 2, hex);
+       if (!only_two_digit_prefix)
+               strbuf_addf(buf, "%s", hex+2);
+}
+
 static void finish_request(struct transfer_request *request);
 static void release_request(struct transfer_request *request);
 
@@ -190,6 +231,15 @@ static void process_response(void *callback_data)
 }
 
 #ifdef USE_CURL_MULTI
+
+static char *get_remote_object_url(const char *url, const char *hex,
+                                  int only_two_digit_prefix)
+{
+       struct strbuf buf = STRBUF_INIT;
+       append_remote_object_url(&buf, url, hex, only_two_digit_prefix);
+       return strbuf_detach(&buf, NULL);
+}
+
 static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
                               void *data)
 {
@@ -210,7 +260,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
        do {
                request->stream.next_out = expn;
                request->stream.avail_out = sizeof(expn);
-               request->zret = inflate(&request->stream, Z_SYNC_FLUSH);
+               request->zret = git_inflate(&request->stream, Z_SYNC_FLUSH);
                git_SHA1_Update(&request->c, expn,
                            sizeof(expn) - request->stream.avail_out);
        } while (request->stream.avail_in && request->zret == Z_OK);
@@ -224,7 +274,6 @@ static void start_fetch_loose(struct transfer_request *request)
        char *filename;
        char prevfile[PATH_MAX];
        char *url;
-       char *posn;
        int prevlocal;
        unsigned char prev_buf[PREV_BUF_SIZE];
        ssize_t prev_read = 0;
@@ -270,21 +319,12 @@ static void start_fetch_loose(struct transfer_request *request)
 
        memset(&request->stream, 0, sizeof(request->stream));
 
-       inflateInit(&request->stream);
+       git_inflate_init(&request->stream);
 
        git_SHA1_Init(&request->c);
 
-       url = xmalloc(strlen(remote->url) + 50);
-       request->url = xmalloc(strlen(remote->url) + 50);
-       strcpy(url, remote->url);
-       posn = url + strlen(remote->url);
-       strcpy(posn, "objects/");
-       posn += 8;
-       memcpy(posn, hex, 2);
-       posn += 2;
-       *(posn++) = '/';
-       strcpy(posn, hex + 2);
-       strcpy(request->url, url);
+       url = get_remote_object_url(remote->url, hex, 0);
+       request->url = xstrdup(url);
 
        /* If a previous temp file is present, process what was already
           fetched. */
@@ -311,7 +351,7 @@ static void start_fetch_loose(struct transfer_request *request)
           file; also rewind to the beginning of the local file. */
        if (prev_read == -1) {
                memset(&request->stream, 0, sizeof(request->stream));
-               inflateInit(&request->stream);
+               git_inflate_init(&request->stream);
                git_SHA1_Init(&request->c);
                if (prev_posn>0) {
                        prev_posn = 0;
@@ -357,16 +397,8 @@ static void start_mkcol(struct transfer_request *request)
 {
        char *hex = sha1_to_hex(request->obj->sha1);
        struct active_request_slot *slot;
-       char *posn;
 
-       request->url = xmalloc(strlen(remote->url) + 13);
-       strcpy(request->url, remote->url);
-       posn = request->url + strlen(remote->url);
-       strcpy(posn, "objects/");
-       posn += 8;
-       memcpy(posn, hex, 2);
-       posn += 2;
-       strcpy(posn, "/");
+       request->url = get_remote_object_url(remote->url, hex, 1);
 
        slot = get_active_slot();
        slot->callback_func = process_response;
@@ -481,7 +513,7 @@ static void start_put(struct transfer_request *request)
 {
        char *hex = sha1_to_hex(request->obj->sha1);
        struct active_request_slot *slot;
-       char *posn;
+       struct strbuf buf = STRBUF_INIT;
        enum object_type type;
        char hdr[50];
        void *unpacked;
@@ -520,21 +552,14 @@ static void start_put(struct transfer_request *request)
 
        request->buffer.buf.len = stream.total_out;
 
-       request->url = xmalloc(strlen(remote->url) +
-                              strlen(request->lock->token) + 51);
-       strcpy(request->url, remote->url);
-       posn = request->url + strlen(remote->url);
-       strcpy(posn, "objects/");
-       posn += 8;
-       memcpy(posn, hex, 2);
-       posn += 2;
-       *(posn++) = '/';
-       strcpy(posn, hex + 2);
-       request->dest = xmalloc(strlen(request->url) + 14);
-       sprintf(request->dest, "Destination: %s", request->url);
-       posn += 38;
-       *(posn++) = '_';
-       strcpy(posn, request->lock->token);
+       strbuf_addstr(&buf, "Destination: ");
+       append_remote_object_url(&buf, remote->url, hex, 0);
+       request->dest = strbuf_detach(&buf, NULL);
+
+       append_remote_object_url(&buf, remote->url, hex, 0);
+       strbuf_addstr(&buf, "_");
+       strbuf_addstr(&buf, request->lock->token);
+       request->url = strbuf_detach(&buf, NULL);
 
        slot = get_active_slot();
        slot->callback_func = process_response;
@@ -589,18 +614,12 @@ static int refresh_lock(struct remote_lock *lock)
 {
        struct active_request_slot *slot;
        struct slot_results results;
-       char *if_header;
-       char timeout_header[25];
-       struct curl_slist *dav_headers = NULL;
+       struct curl_slist *dav_headers;
        int rc = 0;
 
        lock->refreshing = 1;
 
-       if_header = xmalloc(strlen(lock->token) + 25);
-       sprintf(if_header, "If: (<%s>)", lock->token);
-       sprintf(timeout_header, "Timeout: Second-%ld", lock->timeout);
-       dav_headers = curl_slist_append(dav_headers, if_header);
-       dav_headers = curl_slist_append(dav_headers, timeout_header);
+       dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF | DAV_HEADER_TIMEOUT);
 
        slot = get_active_slot();
        slot->results = &results;
@@ -623,7 +642,6 @@ static int refresh_lock(struct remote_lock *lock)
 
        lock->refreshing = 0;
        curl_slist_free_all(dav_headers);
-       free(if_header);
 
        return rc;
 }
@@ -743,7 +761,7 @@ static void finish_request(struct transfer_request *request)
                        if (request->http_code == 416)
                                fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
 
-                       inflateEnd(&request->stream);
+                       git_inflate_end(&request->stream);
                        git_SHA1_Final(request->real_sha1, &request->c);
                        if (request->zret != Z_STREAM_END) {
                                unlink(request->tmpfile);
@@ -1202,7 +1220,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
        /* Make sure leading directories exist for the remote ref */
        ep = strchr(url + strlen(remote->url) + 1, '/');
        while (ep) {
-               *ep = 0;
+               char saved_character = ep[1];
+               ep[1] = '\0';
                slot = get_active_slot();
                slot->results = &results;
                curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
@@ -1224,7 +1243,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
                        free(url);
                        return NULL;
                }
-               *ep = '/';
+               ep[1] = saved_character;
                ep = strchr(ep + 1, '/');
        }
 
@@ -1303,14 +1322,10 @@ static int unlock_remote(struct remote_lock *lock)
        struct active_request_slot *slot;
        struct slot_results results;
        struct remote_lock *prev = remote->locks;
-       char *lock_token_header;
-       struct curl_slist *dav_headers = NULL;
+       struct curl_slist *dav_headers;
        int rc = 0;
 
-       lock_token_header = xmalloc(strlen(lock->token) + 31);
-       sprintf(lock_token_header, "Lock-Token: <%s>",
-               lock->token);
-       dav_headers = curl_slist_append(dav_headers, lock_token_header);
+       dav_headers = get_dav_token_headers(lock, DAV_HEADER_LOCK);
 
        slot = get_active_slot();
        slot->results = &results;
@@ -1331,7 +1346,6 @@ static int unlock_remote(struct remote_lock *lock)
        }
 
        curl_slist_free_all(dav_headers);
-       free(lock_token_header);
 
        if (remote->locks == lock) {
                remote->locks = lock->next;
@@ -1435,10 +1449,8 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
                        }
                        if (path) {
                                path += remote->path_len;
+                               ls->dentry_name = xstrdup(path);
                        }
-                       ls->dentry_name = xmalloc(strlen(path) -
-                                                 remote->path_len + 1);
-                       strcpy(ls->dentry_name, path + remote->path_len);
                } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
                        ls->dentry_flags |= IS_DIR;
                }
@@ -1449,6 +1461,12 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
        }
 }
 
+/*
+ * NEEDSWORK: remote_ls() ignores info/refs on the remote side.  But it
+ * should _only_ heed the information from that file, instead of trying to
+ * determine the refs from the remote file system (badly: it does not even
+ * know about packed-refs).
+ */
 static void remote_ls(const char *path, int flags,
                      void (*userFunc)(struct remote_ls_ctx *ls),
                      void *userData)
@@ -1727,13 +1745,10 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
 {
        struct active_request_slot *slot;
        struct slot_results results;
-       char *if_header;
        struct buffer out_buffer = { STRBUF_INIT, 0 };
-       struct curl_slist *dav_headers = NULL;
+       struct curl_slist *dav_headers;
 
-       if_header = xmalloc(strlen(lock->token) + 25);
-       sprintf(if_header, "If: (<%s>)", lock->token);
-       dav_headers = curl_slist_append(dav_headers, if_header);
+       dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
 
        strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
 
@@ -1752,7 +1767,6 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
        if (start_active_slot(slot)) {
                run_active_slot(slot);
                strbuf_release(&out_buffer.buf);
-               free(if_header);
                if (results.curl_result != CURLE_OK) {
                        fprintf(stderr,
                                "PUT error: curl result=%d, HTTP code=%ld\n",
@@ -1762,7 +1776,6 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
                }
        } else {
                strbuf_release(&out_buffer.buf);
-               free(if_header);
                fprintf(stderr, "Unable to start PUT request\n");
                return 0;
        }
@@ -1944,15 +1957,12 @@ static void update_remote_info_refs(struct remote_lock *lock)
        struct buffer buffer = { STRBUF_INIT, 0 };
        struct active_request_slot *slot;
        struct slot_results results;
-       char *if_header;
-       struct curl_slist *dav_headers = NULL;
+       struct curl_slist *dav_headers;
 
        remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
                  add_remote_info_ref, &buffer.buf);
        if (!aborted) {
-               if_header = xmalloc(strlen(lock->token) + 25);
-               sprintf(if_header, "If: (<%s>)", lock->token);
-               dav_headers = curl_slist_append(dav_headers, if_header);
+               dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
 
                slot = get_active_slot();
                slot->results = &results;
@@ -1974,7 +1984,6 @@ static void update_remote_info_refs(struct remote_lock *lock)
                                        results.curl_result, results.http_code);
                        }
                }
-               free(if_header);
        }
        strbuf_release(&buffer.buf);
 }
@@ -2180,6 +2189,8 @@ int main(int argc, char **argv)
        struct ref *ref;
        char *rewritten_url = NULL;
 
+       git_extract_argv0_path(argv[0]);
+
        setup_git_directory();
 
        remote = xcalloc(sizeof(*remote), 1);