]> git.proxmox.com Git - libgit2.git/blobdiff - src/transports/smart.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / src / transports / smart.c
index d0f9c90e89511cfb8811f67e6304ffbaa88afb87..801fcbe53bfa310d858f72d95d1d528eff85bb92 100644 (file)
@@ -4,10 +4,14 @@
  * This file is part of libgit2, distributed under the GNU GPL v2 with
  * a Linking Exception. For full terms see the included COPYING file.
  */
-#include "git2.h"
+
 #include "smart.h"
+
+#include "git2.h"
+#include "git2/sys/remote.h"
 #include "refs.h"
 #include "refspec.h"
+#include "proxy.h"
 
 static int git_smart__recv_cb(gitno_buffer *buf)
 {
@@ -15,7 +19,7 @@ static int git_smart__recv_cb(gitno_buffer *buf)
        size_t old_len, bytes_read;
        int error;
 
-       assert(t->current_stream);
+       GIT_ASSERT(t->current_stream);
 
        old_len = buf->offset;
 
@@ -27,7 +31,7 @@ static int git_smart__recv_cb(gitno_buffer *buf)
        if (t->packetsize_cb && !t->cancelled.val) {
                error = t->packetsize_cb(bytes_read, t->packetsize_payload);
                if (error) {
-                       git_atomic_set(&t->cancelled, 1);
+                       git_atomic32_set(&t->cancelled, 1);
                        return GIT_EUSER;
                }
        }
@@ -42,26 +46,13 @@ GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransp
                t->current_stream = NULL;
        }
 
-       if (close_subtransport &&
-               t->wrapped->close(t->wrapped) < 0)
-               return -1;
-
-       return 0;
-}
-
-static int git_smart__set_callbacks(
-       git_transport *transport,
-       git_transport_message_cb progress_cb,
-       git_transport_message_cb error_cb,
-       git_transport_certificate_check_cb certificate_check_cb,
-       void *message_cb_payload)
-{
-       transport_smart *t = (transport_smart *)transport;
+       if (close_subtransport) {
+               git__free(t->url);
+               t->url = NULL;
 
-       t->progress_cb = progress_cb;
-       t->error_cb = error_cb;
-       t->certificate_check_cb = certificate_check_cb;
-       t->message_cb_payload = message_cb_payload;
+               if (t->wrapped->close(t->wrapped) < 0)
+                       return -1;
+       }
 
        return 0;
 }
@@ -79,18 +70,20 @@ int git_smart__update_heads(transport_smart *t, git_vector *symrefs)
 
                if (symrefs) {
                        git_refspec *spec;
-                       git_buf buf = GIT_BUF_INIT;
+                       git_str buf = GIT_STR_INIT;
                        size_t j;
                        int error = 0;
 
                        git_vector_foreach(symrefs, j, spec) {
-                               git_buf_clear(&buf);
+                               git_str_clear(&buf);
                                if (git_refspec_src_matches(spec, ref->head.name) &&
-                                   !(error = git_refspec_transform(&buf, spec, ref->head.name)))
-                                       ref->head.symref_target = git_buf_detach(&buf);
+                                   !(error = git_refspec__transform(&buf, spec, ref->head.name))) {
+                                       git__free(ref->head.symref_target);
+                                       ref->head.symref_target = git_str_detach(&buf);
+                               }
                        }
 
-                       git_buf_free(&buf);
+                       git_str_dispose(&buf);
 
                        if (error < 0)
                                return error;
@@ -109,7 +102,7 @@ static void free_symrefs(git_vector *symrefs)
        size_t i;
 
        git_vector_foreach(symrefs, i, spec) {
-               git_refspec__free(spec);
+               git_refspec__dispose(spec);
                git__free(spec);
        }
 
@@ -119,12 +112,10 @@ static void free_symrefs(git_vector *symrefs)
 static int git_smart__connect(
        git_transport *transport,
        const char *url,
-       git_cred_acquire_cb cred_acquire_cb,
-       void *cred_acquire_payload,
        int direction,
-       int flags)
+       const git_remote_connect_options *connect_opts)
 {
-       transport_smart *t = (transport_smart *)transport;
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
        git_smart_subtransport_stream *stream;
        int error;
        git_pkt *pkt;
@@ -135,20 +126,20 @@ static int git_smart__connect(
        if (git_smart__reset_stream(t, true) < 0)
                return -1;
 
+       if (git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, connect_opts) < 0)
+               return -1;
+
        t->url = git__strdup(url);
-       GITERR_CHECK_ALLOC(t->url);
+       GIT_ERROR_CHECK_ALLOC(t->url);
 
        t->direction = direction;
-       t->flags = flags;
-       t->cred_acquire_cb = cred_acquire_cb;
-       t->cred_acquire_payload = cred_acquire_payload;
 
-       if (GIT_DIRECTION_FETCH == t->direction)
+       if (GIT_DIRECTION_FETCH == t->direction) {
                service = GIT_SERVICE_UPLOADPACK_LS;
-       else if (GIT_DIRECTION_PUSH == t->direction)
+       } else if (GIT_DIRECTION_PUSH == t->direction) {
                service = GIT_SERVICE_RECEIVEPACK_LS;
-       else {
-               giterr_set(GITERR_NET, "Invalid direction");
+       else {
+               git_error_set(GIT_ERROR_NET, "invalid direction");
                return -1;
        }
 
@@ -158,7 +149,7 @@ static int git_smart__connect(
        /* Save off the current stream (i.e. socket) that we are working with */
        t->current_stream = stream;
 
-       gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
+       gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
 
        /* 2 flushes for RPC; 1 for stateful */
        if ((error = git_smart__store_refs(t, t->rpc ? 2 : 1)) < 0)
@@ -169,7 +160,7 @@ static int git_smart__connect(
                pkt = (git_pkt *)git_vector_get(&t->refs, 0);
 
                if (!pkt || GIT_PKT_COMMENT != pkt->type) {
-                       giterr_set(GITERR_NET, "Invalid response");
+                       git_error_set(GIT_ERROR_NET, "invalid response");
                        return -1;
                } else {
                        /* Remove the comment pkt from the list */
@@ -181,42 +172,82 @@ static int git_smart__connect(
        /* We now have loaded the refs. */
        t->have_refs = 1;
 
-       first = (git_pkt_ref *)git_vector_get(&t->refs, 0);
+       pkt = (git_pkt *)git_vector_get(&t->refs, 0);
+       if (pkt && GIT_PKT_REF != pkt->type) {
+               git_error_set(GIT_ERROR_NET, "invalid response");
+               return -1;
+       }
+       first = (git_pkt_ref *)pkt;
 
        if ((error = git_vector_init(&symrefs, 1, NULL)) < 0)
                return error;
 
        /* Detect capabilities */
-       if (git_smart__detect_caps(first, &t->caps, &symrefs) < 0)
-               return -1;
+       if ((error = git_smart__detect_caps(first, &t->caps, &symrefs)) == 0) {
+               /* If the only ref in the list is capabilities^{} with OID_ZERO, remove it */
+               if (1 == t->refs.length && !strcmp(first->head.name, "capabilities^{}") &&
+                       git_oid_is_zero(&first->head.oid)) {
+                       git_vector_clear(&t->refs);
+                       git_pkt_free((git_pkt *)first);
+               }
 
-       /* If the only ref in the list is capabilities^{} with OID_ZERO, remove it */
-       if (1 == t->refs.length && !strcmp(first->head.name, "capabilities^{}") &&
-               git_oid_iszero(&first->head.oid)) {
-               git_vector_clear(&t->refs);
-               git_pkt_free((git_pkt *)first);
+               /* Keep a list of heads for _ls */
+               git_smart__update_heads(t, &symrefs);
+       } else if (error == GIT_ENOTFOUND) {
+               /* There was no ref packet received, or the cap list was empty */
+               error = 0;
+       } else {
+               git_error_set(GIT_ERROR_NET, "invalid response");
+               goto cleanup;
        }
 
-       /* Keep a list of heads for _ls */
-       git_smart__update_heads(t, &symrefs);
+       if (t->rpc && (error = git_smart__reset_stream(t, false)) < 0)
+               goto cleanup;
+
+       /* We're now logically connected. */
+       t->connected = 1;
 
+cleanup:
        free_symrefs(&symrefs);
 
-       if (t->rpc && git_smart__reset_stream(t, false) < 0)
+       return error;
+}
+
+static int git_smart__set_connect_opts(
+       git_transport *transport,
+       const git_remote_connect_options *opts)
+{
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
+
+       if (!t->connected) {
+               git_error_set(GIT_ERROR_NET, "cannot reconfigure a transport that is not connected");
                return -1;
+       }
 
-       /* We're now logically connected. */
-       t->connected = 1;
+       return git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, opts);
+}
+
+static int git_smart__capabilities(unsigned int *capabilities, git_transport *transport)
+{
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
+
+       *capabilities = 0;
+
+       if (t->caps.want_tip_sha1)
+               *capabilities |= GIT_REMOTE_CAPABILITY_TIP_OID;
+
+       if (t->caps.want_reachable_sha1)
+               *capabilities |= GIT_REMOTE_CAPABILITY_REACHABLE_OID;
 
        return 0;
 }
 
 static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport)
 {
-       transport_smart *t = (transport_smart *)transport;
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
 
        if (!t->have_refs) {
-               giterr_set(GITERR_NET, "The transport has not yet loaded the refs");
+               git_error_set(GIT_ERROR_NET, "the transport has not yet loaded the refs");
                return -1;
        }
 
@@ -228,7 +259,7 @@ static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transpo
 
 int git_smart__negotiation_step(git_transport *transport, void *data, size_t len)
 {
-       transport_smart *t = (transport_smart *)transport;
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
        git_smart_subtransport_stream *stream;
        int error;
 
@@ -236,7 +267,7 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len
                return -1;
 
        if (GIT_DIRECTION_FETCH != t->direction) {
-               giterr_set(GITERR_NET, "This operation is only valid for fetch");
+               git_error_set(GIT_ERROR_NET, "this operation is only valid for fetch");
                return -1;
        }
 
@@ -244,7 +275,7 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len
                return error;
 
        /* If this is a stateful implementation, the stream we get back should be the same */
-       assert(t->rpc || t->current_stream == stream);
+       GIT_ASSERT(t->rpc || t->current_stream == stream);
 
        /* Save off the current stream (i.e. socket) that we are working with */
        t->current_stream = stream;
@@ -252,7 +283,7 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len
        if ((error = stream->write(stream, (const char *)data, len)) < 0)
                return error;
 
-       gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
+       gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
 
        return 0;
 }
@@ -265,7 +296,7 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
                return -1;
 
        if (GIT_DIRECTION_PUSH != t->direction) {
-               giterr_set(GITERR_NET, "This operation is only valid for push");
+               git_error_set(GIT_ERROR_NET, "this operation is only valid for push");
                return -1;
        }
 
@@ -273,42 +304,33 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
                return error;
 
        /* If this is a stateful implementation, the stream we get back should be the same */
-       assert(t->rpc || t->current_stream == *stream);
+       GIT_ASSERT(t->rpc || t->current_stream == *stream);
 
        /* Save off the current stream (i.e. socket) that we are working with */
        t->current_stream = *stream;
 
-       gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
+       gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
 
        return 0;
 }
 
 static void git_smart__cancel(git_transport *transport)
 {
-       transport_smart *t = (transport_smart *)transport;
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
 
-       git_atomic_set(&t->cancelled, 1);
+       git_atomic32_set(&t->cancelled, 1);
 }
 
 static int git_smart__is_connected(git_transport *transport)
 {
-       transport_smart *t = (transport_smart *)transport;
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
 
        return t->connected;
 }
 
-static int git_smart__read_flags(git_transport *transport, int *flags)
-{
-       transport_smart *t = (transport_smart *)transport;
-
-       *flags = t->flags;
-
-       return 0;
-}
-
 static int git_smart__close(git_transport *transport)
 {
-       transport_smart *t = (transport_smart *)transport;
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
        git_vector *common = &t->common;
        unsigned int i;
        git_pkt *p;
@@ -345,7 +367,7 @@ static int git_smart__close(git_transport *transport)
 
 static void git_smart__free(git_transport *transport)
 {
-       transport_smart *t = (transport_smart *)transport;
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
        git_vector *refs = &t->refs;
        unsigned int i;
        git_pkt *p;
@@ -362,6 +384,8 @@ static void git_smart__free(git_transport *transport)
 
        git_vector_free(refs);
 
+       git_remote_connect_options_dispose(&t->connect_opts);
+
        git__free(t);
 }
 
@@ -372,6 +396,35 @@ static int ref_name_cmp(const void *a, const void *b)
        return strcmp(ref_a->head.name, ref_b->head.name);
 }
 
+int git_transport_smart_certificate_check(git_transport *transport, git_cert *cert, int valid, const char *hostname)
+{
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
+       git_remote_connect_options *connect_opts = &t->connect_opts;
+
+       GIT_ASSERT_ARG(transport);
+       GIT_ASSERT_ARG(cert);
+       GIT_ASSERT_ARG(hostname);
+
+       if (!connect_opts->callbacks.certificate_check)
+               return GIT_PASSTHROUGH;
+
+       return connect_opts->callbacks.certificate_check(cert, valid, hostname, connect_opts->callbacks.payload);
+}
+
+int git_transport_smart_credentials(git_credential **out, git_transport *transport, const char *user, int methods)
+{
+       transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
+       git_remote_connect_options *connect_opts = &t->connect_opts;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(transport);
+
+       if (!connect_opts->callbacks.credentials)
+               return GIT_PASSTHROUGH;
+
+       return connect_opts->callbacks.credentials(out, t->url, user, methods, connect_opts->callbacks.payload);
+}
+
 int git_transport_smart(git_transport **out, git_remote *owner, void *param)
 {
        transport_smart *t;
@@ -380,12 +433,13 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
        if (!param)
                return -1;
 
-       t = git__calloc(sizeof(transport_smart), 1);
-       GITERR_CHECK_ALLOC(t);
+       t = git__calloc(1, sizeof(transport_smart));
+       GIT_ERROR_CHECK_ALLOC(t);
 
        t->parent.version = GIT_TRANSPORT_VERSION;
-       t->parent.set_callbacks = git_smart__set_callbacks;
        t->parent.connect = git_smart__connect;
+       t->parent.set_connect_opts = git_smart__set_connect_opts;
+       t->parent.capabilities = git_smart__capabilities;
        t->parent.close = git_smart__close;
        t->parent.free = git_smart__free;
        t->parent.negotiate_fetch = git_smart__negotiate_fetch;
@@ -393,7 +447,6 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
        t->parent.push = git_smart__push;
        t->parent.ls = git_smart__ls;
        t->parent.is_connected = git_smart__is_connected;
-       t->parent.read_flags = git_smart__read_flags;
        t->parent.cancel = git_smart__cancel;
 
        t->owner = owner;
@@ -409,7 +462,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
                return -1;
        }
 
-       if (definition->callback(&t->wrapped, &t->parent) < 0) {
+       if (definition->callback(&t->wrapped, &t->parent, definition->param) < 0) {
                git__free(t);
                return -1;
        }