Move bundle specific stuff into bundle.[ch]
[gitweb.git] / http-push.c
index 47686195cdf41ad58fe66a606033d3156de8fd82..8e1fdfddf5402add6b6ce787647c522c9a0116ae 100644 (file)
@@ -1,7 +1,6 @@
 #include "cache.h"
 #include "commit.h"
 #include "pack.h"
-#include "fetch.h"
 #include "tag.h"
 #include "blob.h"
 #include "http.h"
@@ -9,6 +8,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "exec_cmd.h"
+#include "remote.h"
 
 #include <expat.h>
 
@@ -70,18 +70,18 @@ enum XML_Status {
 /* We allow "recursive" symbolic refs. Only within reason, though */
 #define MAXDEPTH 5
 
-static int pushing = 0;
-static int aborted = 0;
+static int pushing;
+static int aborted;
 static signed char remote_dir_exists[256];
 
 static struct curl_slist *no_pragma_header;
 static struct curl_slist *default_headers;
 
-static int push_verbosely = 0;
-static int push_all = 0;
-static int force_all = 0;
+static int push_verbosely;
+static int push_all;
+static int force_all;
 
-static struct object_list *objects = NULL;
+static struct object_list *objects;
 
 struct repo
 {
@@ -94,7 +94,7 @@ struct repo
        struct remote_lock *locks;
 };
 
-static struct repo *remote = NULL;
+static struct repo *remote;
 
 enum transfer_state {
        NEED_FETCH,
@@ -134,7 +134,7 @@ struct transfer_request
        struct transfer_request *next;
 };
 
-static struct transfer_request *request_queue_head = NULL;
+static struct transfer_request *request_queue_head;
 
 struct xml_ctx
 {
@@ -195,7 +195,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
        int posn = 0;
        struct transfer_request *request = (struct transfer_request *)data;
        do {
-               ssize_t retval = write(request->local_fileno,
+               ssize_t retval = xwrite(request->local_fileno,
                                       (char *) ptr + posn, size - posn);
                if (retval < 0)
                        return posn;
@@ -288,7 +288,7 @@ static void start_fetch_loose(struct transfer_request *request)
        prevlocal = open(prevfile, O_RDONLY);
        if (prevlocal != -1) {
                do {
-                       prev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);
+                       prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
                        if (prev_read>0) {
                                if (fwrite_sha1_file(prev_buf,
                                                     1,
@@ -312,7 +312,7 @@ static void start_fetch_loose(struct transfer_request *request)
                SHA1_Init(&request->c);
                if (prev_posn>0) {
                        prev_posn = 0;
-                       lseek(request->local_fileno, SEEK_SET, 0);
+                       lseek(request->local_fileno, 0, SEEK_SET);
                        ftruncate(request->local_fileno, 0);
                }
        }
@@ -479,7 +479,7 @@ static void start_put(struct transfer_request *request)
        char *hex = sha1_to_hex(request->obj->sha1);
        struct active_request_slot *slot;
        char *posn;
-       char type[20];
+       enum object_type type;
        char hdr[50];
        void *unpacked;
        unsigned long len;
@@ -487,8 +487,8 @@ static void start_put(struct transfer_request *request)
        ssize_t size;
        z_stream stream;
 
-       unpacked = read_sha1_file(request->obj->sha1, type, &len);
-       hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
+       unpacked = read_sha1_file(request->obj->sha1, &type, &len);
+       hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
 
        /* Set it up */
        memset(&stream, 0, sizeof(stream));
@@ -517,7 +517,7 @@ static void start_put(struct transfer_request *request)
        request->buffer.size = stream.total_out;
        request->buffer.posn = 0;
 
-       request->url = xmalloc(strlen(remote->url) + 
+       request->url = xmalloc(strlen(remote->url) +
                               strlen(request->lock->token) + 51);
        strcpy(request->url, remote->url);
        posn = request->url + strlen(remote->url);
@@ -530,7 +530,7 @@ static void start_put(struct transfer_request *request)
        request->dest = xmalloc(strlen(request->url) + 14);
        sprintf(request->dest, "Destination: %s", request->url);
        posn += 38;
-       *(posn++) = '.';
+       *(posn++) = '_';
        strcpy(posn, request->lock->token);
 
        slot = get_active_slot();
@@ -745,7 +745,7 @@ static void finish_request(struct transfer_request *request)
                        SHA1_Final(request->real_sha1, &request->c);
                        if (request->zret != Z_STREAM_END) {
                                unlink(request->tmpfile);
-                       } else if (memcmp(request->obj->sha1, request->real_sha1, 20)) {
+                       } else if (hashcmp(request->obj->sha1, request->real_sha1)) {
                                unlink(request->tmpfile);
                        } else {
                                request->rename =
@@ -770,11 +770,14 @@ static void finish_request(struct transfer_request *request)
                                request->url, curl_errorstr);
                        remote->can_update_info_refs = 0;
                } else {
+                       off_t pack_size = ftell(request->local_stream);
+
                        fclose(request->local_stream);
                        request->local_stream = NULL;
                        if (!move_temp_to_file(request->tmpfile,
                                               request->filename)) {
                                target = (struct packed_git *)request->userData;
+                               target->pack_size = pack_size;
                                lst = &remote->packs;
                                while (*lst != target)
                                        lst = &((*lst)->next);
@@ -791,38 +794,27 @@ static void finish_request(struct transfer_request *request)
 }
 
 #ifdef USE_CURL_MULTI
-void fill_active_slots(void)
+static int fill_active_slot(void *unused)
 {
        struct transfer_request *request = request_queue_head;
-       struct transfer_request *next;
-       struct active_request_slot *slot = active_queue_head;
-       int num_transfers;
 
        if (aborted)
-               return;
+               return 0;
 
-       while (active_requests < max_requests && request != NULL) {
-               next = request->next;
+       for (request = request_queue_head; request; request = request->next) {
                if (request->state == NEED_FETCH) {
                        start_fetch_loose(request);
+                       return 1;
                } else if (pushing && request->state == NEED_PUSH) {
                        if (remote_dir_exists[request->obj->sha1[0]] == 1) {
                                start_put(request);
                        } else {
                                start_mkcol(request);
                        }
-                       curl_multi_perform(curlm, &num_transfers);
-               }
-               request = next;
-       }
-
-       while (slot != NULL) {
-               if (!slot->in_use && slot->curl != NULL) {
-                       curl_easy_cleanup(slot->curl);
-                       slot->curl = NULL;
+                       return 1;
                }
-               slot = slot->next;
        }
+       return 0;
 }
 #endif
 
@@ -1057,8 +1049,8 @@ static int fetch_indices(void)
                case 'P':
                        i++;
                        if (i + 52 < buffer.posn &&
-                           !strncmp(data + i, " pack-", 6) &&
-                           !strncmp(data + i + 46, ".pack\n", 6)) {
+                           !prefixcmp(data + i, " pack-") &&
+                           !prefixcmp(data + i + 46, ".pack\n")) {
                                get_sha1_hex(data + i + 6, sha1);
                                setup_index(sha1);
                                i += 51;
@@ -1203,11 +1195,11 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
                        lock->owner = xmalloc(strlen(ctx->cdata) + 1);
                        strcpy(lock->owner, ctx->cdata);
                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) {
-                       if (!strncmp(ctx->cdata, "Second-", 7))
+                       if (!prefixcmp(ctx->cdata, "Second-"))
                                lock->timeout =
                                        strtol(ctx->cdata + 7, NULL, 10);
                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
-                       if (!strncmp(ctx->cdata, "opaquelocktoken:", 16)) {
+                       if (!prefixcmp(ctx->cdata, "opaquelocktoken:")) {
                                lock->token = xmalloc(strlen(ctx->cdata) - 15);
                                strcpy(lock->token, ctx->cdata + 16);
                        }
@@ -1238,10 +1230,8 @@ xml_start_tag(void *userData, const char *name, const char **atts)
        strcat(ctx->name, ".");
        strcat(ctx->name, c);
 
-       if (ctx->cdata) {
-               free(ctx->cdata);
-               ctx->cdata = NULL;
-       }
+       free(ctx->cdata);
+       ctx->cdata = NULL;
 
        ctx->userFunc(ctx, 0);
 }
@@ -1268,10 +1258,11 @@ static void
 xml_cdata(void *userData, const XML_Char *s, int len)
 {
        struct xml_ctx *ctx = (struct xml_ctx *)userData;
-       if (ctx->cdata)
-               free(ctx->cdata);
+       free(ctx->cdata);
        ctx->cdata = xmalloc(len + 1);
-       strlcpy(ctx->cdata, s, len + 1);
+       /* NB: 's' is not null-terminated, can not use strlcpy here */
+       memcpy(ctx->cdata, s, len);
+       ctx->cdata[len] = '\0';
 }
 
 static struct remote_lock *lock_remote(const char *path, long timeout)
@@ -1295,7 +1286,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
        sprintf(url, "%s%s", remote->url, path);
 
        /* Make sure leading directories exist for the remote ref */
-       ep = strchr(url + strlen(remote->url) + 11, '/');
+       ep = strchr(url + strlen(remote->url) + 1, '/');
        while (ep) {
                *ep = 0;
                slot = get_active_slot();
@@ -1473,7 +1464,8 @@ static void process_ls_object(struct remote_ls_ctx *ls)
                return;
        path += 8;
        obj_hex = xmalloc(strlen(path));
-       strlcpy(obj_hex, path, 3);
+       /* NB: path is not null-terminated, can not use strlcpy here */
+       memcpy(obj_hex, path, 2);
        strcpy(obj_hex + 2, path + 3);
        one_remote_object(obj_hex);
        free(obj_hex);
@@ -1518,9 +1510,7 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
                        ls->dentry_flags |= IS_DIR;
                }
        } else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
-               if (ls->dentry_name) {
-                       free(ls->dentry_name);
-               }
+               free(ls->dentry_name);
                ls->dentry_name = NULL;
                ls->dentry_flags = 0;
        }
@@ -1544,7 +1534,7 @@ static void remote_ls(const char *path, int flags,
        struct remote_ls_ctx ls;
 
        ls.flags = flags;
-       ls.path = strdup(path);
+       ls.path = xstrdup(path);
        ls.dentry_name = NULL;
        ls.dentry_flags = 0;
        ls.userData = userData;
@@ -1700,7 +1690,7 @@ static int locking_available(void)
        return lock_flags;
 }
 
-struct object_list **add_one_object(struct object *obj, struct object_list **p)
+static struct object_list **add_one_object(struct object *obj, struct object_list **p)
 {
        struct object_list *entry = xmalloc(sizeof(struct object_list));
        entry->item = obj;
@@ -1743,14 +1733,13 @@ static struct object_list **process_tree(struct tree *tree,
                die("bad tree object %s", sha1_to_hex(obj->sha1));
 
        obj->flags |= SEEN;
-       name = strdup(name);
+       name = xstrdup(name);
        p = add_one_object(obj, p);
        me.up = path;
        me.elem = name;
        me.elem_len = strlen(name);
 
-       desc.buf = tree->buffer;
-       desc.size = tree->size;
+       init_tree_desc(&desc, tree->buffer, tree->size);
 
        while (tree_entry(&desc, &entry)) {
                if (S_ISDIR(entry.mode))
@@ -1869,12 +1858,12 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
 static struct ref *local_refs, **local_tail;
 static struct ref *remote_refs, **remote_tail;
 
-static int one_local_ref(const char *refname, const unsigned char *sha1)
+static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
        struct ref *ref;
        int len = strlen(refname) + 1;
        ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->new_sha1, sha1, 20);
+       hashcpy(ref->new_sha1, sha1);
        memcpy(ref->name, refname, len);
        *local_tail = ref;
        local_tail = &ref->next;
@@ -1909,7 +1898,7 @@ static void one_remote_ref(char *refname)
        }
 
        ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->old_sha1, remote_sha1, 20);
+       hashcpy(ref->old_sha1, remote_sha1);
        memcpy(ref->name, refname, len);
        *remote_tail = ref;
        remote_tail = &ref->next;
@@ -1918,7 +1907,7 @@ static void one_remote_ref(char *refname)
 static void get_local_heads(void)
 {
        local_tail = &local_refs;
-       for_each_ref(one_local_ref);
+       for_each_ref(one_local_ref, NULL);
 }
 
 static void get_dav_remote_heads(void)
@@ -2164,15 +2153,16 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
        if (*symref != NULL)
                free(*symref);
        *symref = NULL;
-       memset(sha1, 0, 20);
+       hashclr(sha1);
 
        if (buffer.posn == 0)
                return;
 
        /* If it's a symref, set the refname; otherwise try for a sha1 */
-       if (!strncmp((char *)buffer.buffer, "ref: ", 5)) {
+       if (!prefixcmp((char *)buffer.buffer, "ref: ")) {
                *symref = xmalloc(buffer.posn - 5);
-               strlcpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 5);
+               memcpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 6);
+               (*symref)[buffer.posn - 6] = '\0';
        } else {
                get_sha1_hex(buffer.buffer, sha1);
        }
@@ -2182,49 +2172,11 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
 
 static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1)
 {
-       int pipe_fd[2];
-       pid_t merge_base_pid;
-       char line[PATH_MAX + 20];
-       unsigned char merge_sha1[20];
-       int verified = 0;
-
-       if (pipe(pipe_fd) < 0)
-               die("Verify merge base: pipe failed");
-
-       merge_base_pid = fork();
-       if (!merge_base_pid) {
-               static const char *args[] = {
-                       "merge-base",
-                       "-a",
-                       NULL,
-                       NULL,
-                       NULL
-               };
-               args[2] = strdup(sha1_to_hex(head_sha1));
-               args[3] = sha1_to_hex(branch_sha1);
-
-               dup2(pipe_fd[1], 1);
-               close(pipe_fd[0]);
-               close(pipe_fd[1]);
-               execv_git_cmd(args);
-               die("merge-base setup failed");
-       }
-       if (merge_base_pid < 0)
-               die("merge-base fork failed");
-
-       dup2(pipe_fd[0], 0);
-       close(pipe_fd[0]);
-       close(pipe_fd[1]);
-       while (fgets(line, sizeof(line), stdin) != NULL) {
-               if (get_sha1_hex(line, merge_sha1))
-                       die("expected sha1, got garbage:\n %s", line);
-               if (!memcmp(branch_sha1, merge_sha1, 20)) {
-                       verified = 1;
-                       break;
-               }
-       }
+       struct commit *head = lookup_commit(head_sha1);
+       struct commit *branch = lookup_commit(branch_sha1);
+       struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
 
-       return verified;
+       return (merge_bases && !merge_bases->next && merge_bases->item == branch);
 }
 
 static int delete_remote_branch(char *pattern, int force)
@@ -2339,7 +2291,6 @@ int main(int argc, char **argv)
        struct ref *ref;
 
        setup_git_directory();
-       setup_ident();
 
        remote = xcalloc(sizeof(*remote), 1);
 
@@ -2454,7 +2405,7 @@ int main(int argc, char **argv)
 
                if (!ref->peer_ref)
                        continue;
-               if (!memcmp(ref->old_sha1, ref->peer_ref->new_sha1, 20)) {
+               if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
                        if (push_verbosely || 1)
                                fprintf(stderr, "'%s': up-to-date\n", ref->name);
                        continue;
@@ -2483,7 +2434,7 @@ int main(int argc, char **argv)
                                continue;
                        }
                }
-               memcpy(ref->new_sha1, ref->peer_ref->new_sha1, 20);
+               hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
                if (is_zero_sha1(ref->new_sha1)) {
                        error("cannot happen anymore");
                        rc = -3;
@@ -2510,7 +2461,7 @@ int main(int argc, char **argv)
 
                /* Set up revision info for this refspec */
                commit_argc = 3;
-               new_sha1_hex = strdup(sha1_to_hex(ref->new_sha1));
+               new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1));
                old_sha1_hex = NULL;
                commit_argv[1] = "--objects";
                commit_argv[2] = new_sha1_hex;
@@ -2521,7 +2472,7 @@ int main(int argc, char **argv)
                        commit_argv[3] = old_sha1_hex;
                        commit_argc++;
                }
-               init_revisions(&revs);
+               init_revisions(&revs, setup_git_directory());
                setup_revisions(commit_argc, commit_argv, &revs, NULL);
                free(new_sha1_hex);
                if (old_sha1_hex) {
@@ -2544,6 +2495,7 @@ int main(int argc, char **argv)
                                objects_to_send);
 #ifdef USE_CURL_MULTI
                fill_active_slots();
+               add_fill_function(NULL, fill_active_slot);
 #endif
                finish_all_active_slots();