diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/blame.c | 18 | ||||
| -rw-r--r-- | src/clone.c | 41 | ||||
| -rw-r--r-- | src/config_file.c | 26 | ||||
| -rw-r--r-- | src/fetch.c | 59 | ||||
| -rw-r--r-- | src/fetchhead.c | 6 | ||||
| -rw-r--r-- | src/indexer.c | 7 | ||||
| -rw-r--r-- | src/merge.c | 4 | ||||
| -rw-r--r-- | src/netops.c | 99 | ||||
| -rw-r--r-- | src/netops.h | 1 | ||||
| -rw-r--r-- | src/odb_pack.c | 2 | ||||
| -rw-r--r-- | src/pack-objects.c | 17 | ||||
| -rw-r--r-- | src/push.c | 20 | ||||
| -rw-r--r-- | src/refspec.c | 68 | ||||
| -rw-r--r-- | src/refspec.h | 8 | ||||
| -rw-r--r-- | src/remote.c | 205 | ||||
| -rw-r--r-- | src/remote.h | 1 | ||||
| -rw-r--r-- | src/signature.c | 6 | ||||
| -rw-r--r-- | src/transports/git.c | 72 | ||||
| -rw-r--r-- | src/transports/local.c | 10 | ||||
| -rw-r--r-- | src/transports/smart.c | 44 | ||||
| -rw-r--r-- | src/transports/smart.h | 3 | ||||
| -rw-r--r-- | src/transports/smart_protocol.c | 26 | ||||
| -rw-r--r-- | src/transports/ssh.c | 6 |
23 files changed, 465 insertions, 284 deletions
diff --git a/src/blame.c b/src/blame.c index 01d3fc03c..219a6bfe4 100644 --- a/src/blame.c +++ b/src/blame.c @@ -75,6 +75,9 @@ static git_blame_hunk* dup_hunk(git_blame_hunk *hunk) hunk->orig_path); git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id); git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id); + newhunk->boundary = hunk->boundary; + newhunk->final_signature = git_signature_dup(hunk->final_signature); + newhunk->orig_signature = git_signature_dup(hunk->orig_signature); return newhunk; } @@ -381,9 +384,13 @@ static int buffer_hunk_cb( wedge_line = (hunk->old_lines == 0) ? hunk->new_start : hunk->old_start; blame->current_diff_line = wedge_line; - /* If this hunk doesn't start between existing hunks, split a hunk up so it does */ blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byline(blame, wedge_line); - if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){ + if (!blame->current_hunk) { + /* Line added at the end of the file */ + blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, blame->path); + git_vector_insert(&blame->hunks, blame->current_hunk); + } else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){ + /* If this hunk doesn't start between existing hunks, split a hunk up so it does */ blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk, wedge_line - blame->current_hunk->orig_start_line_number, true); } @@ -404,13 +411,6 @@ static int buffer_line_cb( GIT_UNUSED(hunk); GIT_UNUSED(line); -#ifdef DO_DEBUG - { - char *str = git__substrdup(content, content_len); - git__free(str); - } -#endif - if (line->origin == GIT_DIFF_LINE_ADDITION) { if (hunk_is_bufferblame(blame->current_hunk) && hunk_ends_at_or_before_line(blame->current_hunk, blame->current_diff_line)) { diff --git a/src/clone.c b/src/clone.c index 657243945..23aacd478 100644 --- a/src/clone.c +++ b/src/clone.c @@ -176,25 +176,20 @@ static int update_head_to_new_branch( return error; } -static int get_head_callback(git_remote_head *head, void *payload) -{ - git_remote_head **destination = (git_remote_head **)payload; - - /* Save the first entry, and terminate the enumeration */ - *destination = head; - return 1; -} - static int update_head_to_remote(git_repository *repo, git_remote *remote) { int retcode = -1; + size_t refs_len; git_refspec dummy_spec; - git_remote_head *remote_head; + const git_remote_head *remote_head, **refs; struct head_info head_info; git_buf remote_master_name = GIT_BUF_INIT; + if (git_remote_ls(&refs, &refs_len, remote) < 0) + return -1; + /* Did we just clone an empty repository? */ - if (remote->refs.length == 0) { + if (refs_len == 0) { return setup_tracking_config( repo, "master", @@ -202,12 +197,8 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote) GIT_REFS_HEADS_MASTER_FILE); } - /* Get the remote's HEAD. This is always the first ref in remote->refs. */ - remote_head = NULL; - - if (!remote->transport->ls(remote->transport, get_head_callback, &remote_head)) - return -1; - + /* Get the remote's HEAD. This is always the first ref in the list. */ + remote_head = refs[0]; assert(remote_head); git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid); @@ -349,7 +340,7 @@ static bool should_checkout( int git_clone_into(git_repository *repo, git_remote *remote, const git_checkout_opts *co_opts, const char *branch) { int error = 0, old_fetchhead; - size_t nspecs; + git_strarray refspecs; assert(repo && remote); @@ -358,6 +349,10 @@ int git_clone_into(git_repository *repo, git_remote *remote, const git_checkout_ return -1; } + + if ((error = git_remote_get_fetch_refspecs(&refspecs, remote)) < 0) + return error; + if ((error = git_remote_add_fetch(remote, "refs/tags/*:refs/tags/*")) < 0) return error; @@ -378,9 +373,13 @@ int git_clone_into(git_repository *repo, git_remote *remote, const git_checkout_ cleanup: git_remote_set_update_fetchhead(remote, old_fetchhead); - /* Remove the tags refspec */ - nspecs = git_remote_refspec_count(remote); - git_remote_remove_refspec(remote, nspecs); + /* Go back to the original refspecs */ + if (git_remote_set_fetch_refspecs(remote, &refspecs) < 0) { + git_strarray_free(&refspecs); + return -1; + } + + git_strarray_free(&refspecs); return error; } diff --git a/src/config_file.c b/src/config_file.c index 0bd4e4ece..15c8de49c 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -1178,6 +1178,24 @@ static int write_section(git_filebuf *file, const char *key) return result; } +static const char *quotes_for_value(const char *value) +{ + const char *ptr; + + if (value[0] == ' ' || value[0] == '\0') + return "\""; + + for (ptr = value; *ptr; ++ptr) { + if (*ptr == ';' || *ptr == '#') + return "\""; + } + + if (ptr[-1] == ' ') + return "\""; + + return ""; +} + /* * This is pretty much the parsing, except we write out anything we don't have */ @@ -1302,7 +1320,8 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p /* Then replace the variable. If the value is NULL, it * means we want to delete it, so don't write anything. */ if (value != NULL) { - git_filebuf_printf(&file, "\t%s = %s\n", name, value); + const char *q = quotes_for_value(value); + git_filebuf_printf(&file, "\t%s = %s%s%s\n", name, q, value, q); } /* @@ -1343,6 +1362,8 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p if (preg_replaced) { git_filebuf_printf(&file, "\n%s", write_start); } else { + const char *q; + git_filebuf_write(&file, reader->buffer.ptr, reader->buffer.size); /* And now if we just need to add a variable */ @@ -1362,7 +1383,8 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p if (reader->buffer.size > 0 && *(reader->buffer.ptr + reader->buffer.size - 1) != '\n') git_filebuf_write(&file, "\n", 1); - git_filebuf_printf(&file, "\t%s = %s\n", name, value); + q = quotes_for_value(value); + git_filebuf_printf(&file, "\t%s = %s%s%s\n", name, q, value, q); } } diff --git a/src/fetch.c b/src/fetch.c index 5d97913e8..276591821 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -19,55 +19,47 @@ #include "repository.h" #include "refs.h" -struct filter_payload { - git_remote *remote; - const git_refspec *spec, *tagspec; - git_odb *odb; - int found_head; -}; - -static int filter_ref__cb(git_remote_head *head, void *payload) +static int maybe_want(git_remote *remote, git_remote_head *head, git_odb *odb, git_refspec *tagspec) { - struct filter_payload *p = payload; int match = 0; if (!git_reference_is_valid_name(head->name)) return 0; - if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) - p->found_head = 1; - else if (p->remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { + if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { /* * If tagopt is --tags, then we only use the default * tags refspec and ignore the remote's */ - if (git_refspec_src_matches(p->tagspec, head->name)) + if (git_refspec_src_matches(tagspec, head->name)) match = 1; else return 0; - } else if (git_remote__matching_refspec(p->remote, head->name)) + } else if (git_remote__matching_refspec(remote, head->name)) match = 1; if (!match) return 0; /* If we have the object, mark it so we don't ask for it */ - if (git_odb_exists(p->odb, &head->oid)) + if (git_odb_exists(odb, &head->oid)) head->local = 1; else - p->remote->need_pack = 1; + remote->need_pack = 1; - return git_vector_insert(&p->remote->refs, head); + return git_vector_insert(&remote->refs, head); } static int filter_wants(git_remote *remote) { - struct filter_payload p; - git_refspec tagspec; - int error = -1; + git_remote_head **heads; + git_refspec tagspec, head; + int error = 0; + git_odb *odb; + size_t i, heads_len; git_vector_clear(&remote->refs); - if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) + if ((error = git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true)) < 0) return error; /* @@ -76,14 +68,27 @@ static int filter_wants(git_remote *remote) * not interested in any particular branch but just the remote's * HEAD, which will be stored in FETCH_HEAD after the fetch. */ - p.tagspec = &tagspec; - p.found_head = 0; - p.remote = remote; + if (remote->active_refspecs.length == 0) { + if ((error = git_refspec__parse(&head, "HEAD", true)) < 0) + goto cleanup; - if (git_repository_odb__weakptr(&p.odb, remote->repo) < 0) + error = git_refspec__dwim_one(&remote->active_refspecs, &head, &remote->refs); + git_refspec__free(&head); + + if (error < 0) + goto cleanup; + } + + if (git_repository_odb__weakptr(&odb, remote->repo) < 0) + goto cleanup; + + if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0) goto cleanup; - error = git_remote_ls(remote, filter_ref__cb, &p); + for (i = 0; i < heads_len; i++) { + if ((error = maybe_want(remote, heads[i], odb, &tagspec)) < 0) + break; + } cleanup: git_refspec__free(&tagspec); @@ -106,7 +111,7 @@ int git_fetch_negotiate(git_remote *remote) } /* Don't try to negotiate when we don't want anything */ - if (remote->refs.length == 0 || !remote->need_pack) + if (!remote->need_pack) return 0; /* diff --git a/src/fetchhead.c b/src/fetchhead.c index 9672623ff..67089d13d 100644 --- a/src/fetchhead.c +++ b/src/fetchhead.c @@ -74,6 +74,7 @@ static int fetchhead_ref_write( { char oid[GIT_OID_HEXSZ + 1]; const char *type, *name; + int head = 0; assert(file && fetchhead_ref); @@ -87,11 +88,16 @@ static int fetchhead_ref_write( GIT_REFS_TAGS_DIR) == 0) { type = "tag "; name = fetchhead_ref->ref_name + strlen(GIT_REFS_TAGS_DIR); + } else if (!git__strcmp(fetchhead_ref->ref_name, GIT_HEAD_FILE)) { + head = 1; } else { type = ""; name = fetchhead_ref->ref_name; } + if (head) + return git_filebuf_printf(file, "%s\t\t%s\n", oid, fetchhead_ref->remote_url); + return git_filebuf_printf(file, "%s\t%s\t%s'%s' of %s\n", oid, (fetchhead_ref->is_merge) ? "" : "not-for-merge", diff --git a/src/indexer.c b/src/indexer.c index 90fb52187..df1ce7cfb 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -37,6 +37,7 @@ struct git_indexer { struct git_pack_header hdr; struct git_pack_file *pack; git_filebuf pack_file; + unsigned int mode; git_off_t off; git_off_t entry_start; git_packfile_stream stream; @@ -119,6 +120,7 @@ static int objects_cmp(const void *a, const void *b) int git_indexer_new( git_indexer **out, const char *prefix, + unsigned int mode, git_odb *odb, git_transfer_progress_callback progress_cb, void *progress_payload) @@ -133,6 +135,7 @@ int git_indexer_new( idx->odb = odb; idx->progress_cb = progress_cb; idx->progress_payload = progress_payload; + idx->mode = mode ? mode : GIT_PACK_FILE_MODE; git_hash_ctx_init(&idx->trailer); error = git_buf_joinpath(&path, prefix, suff); @@ -141,7 +144,7 @@ int git_indexer_new( error = git_filebuf_open(&idx->pack_file, path.ptr, GIT_FILEBUF_TEMPORARY | GIT_FILEBUF_DO_NOT_BUFFER, - GIT_PACK_FILE_MODE); + idx->mode); git_buf_free(&path); if (error < 0) goto cleanup; @@ -905,7 +908,7 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) return -1; if (git_filebuf_open(&index_file, filename.ptr, - GIT_FILEBUF_HASH_CONTENTS, GIT_PACK_FILE_MODE) < 0) + GIT_FILEBUF_HASH_CONTENTS, idx->mode) < 0) goto on_error; /* Write out the header */ diff --git a/src/merge.c b/src/merge.c index 2cbf531f9..115867971 100644 --- a/src/merge.c +++ b/src/merge.c @@ -1649,7 +1649,7 @@ static int write_merge_head( goto cleanup; for (i = 0; i < heads_len; i++) { - if ((error = git_filebuf_printf(&file, "%s\n", &heads[i]->oid_str)) < 0) + if ((error = git_filebuf_printf(&file, "%s\n", heads[i]->oid_str)) < 0) goto cleanup; } @@ -2240,6 +2240,8 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde git_diff_options opts = GIT_DIFF_OPTIONS_INIT; int error = 0; + GIT_UNUSED(index_new); + *conflicts = 0; opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED; diff --git a/src/netops.c b/src/netops.c index 7e13f12e7..15ed0fc26 100644 --- a/src/netops.c +++ b/src/netops.c @@ -32,6 +32,7 @@ #include "netops.h" #include "posix.h" #include "buffer.h" +#include "http_parser.h" #ifdef GIT_WIN32 static void net_set_error(const char *str) @@ -582,7 +583,7 @@ int gitno_connection_data_from_url( const char *service_suffix) { int error = -1; - const char *default_port = NULL; + const char *default_port = NULL, *path_search_start = NULL; char *original_host = NULL; /* service_suffix is optional */ @@ -594,22 +595,18 @@ int gitno_connection_data_from_url( gitno_connection_data_free_ptrs(data); if (!git__prefixcmp(url, prefix_http)) { - url = url + strlen(prefix_http); + path_search_start = url + strlen(prefix_http); default_port = "80"; if (data->use_ssl) { giterr_set(GITERR_NET, "Redirect from HTTPS to HTTP is not allowed"); goto cleanup; } - } - - if (!git__prefixcmp(url, prefix_https)) { - url += strlen(prefix_https); + } else if (!git__prefixcmp(url, prefix_https)) { + path_search_start = url + strlen(prefix_https); default_port = "443"; data->use_ssl = true; - } - - if (url[0] == '/') + } else if (url[0] == '/') default_port = data->use_ssl ? "443" : "80"; if (!default_port) { @@ -618,18 +615,19 @@ int gitno_connection_data_from_url( } error = gitno_extract_url_parts( - &data->host, &data->port, &data->user, &data->pass, + &data->host, &data->port, &data->path, &data->user, &data->pass, url, default_port); if (url[0] == '/') { /* Relative redirect; reuse original host name and port */ + path_search_start = url; git__free(data->host); data->host = original_host; original_host = NULL; } if (!error) { - const char *path = strchr(url, '/'); + const char *path = strchr(path_search_start, '/'); size_t pathlen = strlen(path); size_t suffixlen = service_suffix ? strlen(service_suffix) : 0; @@ -660,55 +658,74 @@ void gitno_connection_data_free_ptrs(gitno_connection_data *d) git__free(d->pass); d->pass = NULL; } +#define hex2c(c) ((c | 32) % 39 - 9) +static char* unescape(char *str) +{ + int x, y; + int len = (int)strlen(str); + + for (x=y=0; str[y]; ++x, ++y) { + if ((str[x] = str[y]) == '%') { + if (y < len-2 && isxdigit(str[y+1]) && isxdigit(str[y+2])) { + str[x] = (hex2c(str[y+1]) << 4) + hex2c(str[y+2]); + y += 2; + } + } + } + str[x] = '\0'; + return str; +} + int gitno_extract_url_parts( char **host, char **port, + char **path, char **username, char **password, const char *url, const char *default_port) { - char *colon, *slash, *at, *end; - const char *start; - - /* - * ==> [user[:pass]@]hostname.tld[:port]/resource - */ - - colon = strchr(url, ':'); - slash = strchr(url, '/'); - at = strchr(url, '@'); + struct http_parser_url u = {0}; + const char *_host, *_port, *_path, *_userinfo; - if (!slash || - (colon && (slash < colon))) { - giterr_set(GITERR_NET, "Malformed URL"); + if (http_parser_parse_url(url, strlen(url), false, &u)) { + giterr_set(GITERR_NET, "Malformed URL '%s'", url); return GIT_EINVALIDSPEC; } - start = url; - if (at && at < slash) { - start = at+1; - *username = git__substrdup(url, at - url); - } + _host = url+u.field_data[UF_HOST].off; + _port = url+u.field_data[UF_PORT].off; + _path = url+u.field_data[UF_PATH].off; + _userinfo = url+u.field_data[UF_USERINFO].off; - if (colon && colon < at) { - git__free(*username); - *username = git__substrdup(url, colon-url); - *password = git__substrdup(colon+1, at-colon-1); - colon = strchr(at, ':'); + if (u.field_set & (1 << UF_HOST)) { + *host = git__substrdup(_host, u.field_data[UF_HOST].len); + GITERR_CHECK_ALLOC(*host); } - if (colon == NULL) { + if (u.field_set & (1 << UF_PORT)) + *port = git__substrdup(_port, u.field_data[UF_PORT].len); + else *port = git__strdup(default_port); - } else { - *port = git__substrdup(colon + 1, slash - colon - 1); - } GITERR_CHECK_ALLOC(*port); - end = colon == NULL ? slash : colon; + if (u.field_set & (1 << UF_PATH)) { + *path = git__substrdup(_path, u.field_data[UF_PATH].len); + GITERR_CHECK_ALLOC(*path); + } - *host = git__substrdup(start, end - start); - GITERR_CHECK_ALLOC(*host); + if (u.field_set & (1 << UF_USERINFO)) { + const char *colon = memchr(_userinfo, ':', u.field_data[UF_USERINFO].len); + if (colon) { + *username = unescape(git__substrdup(_userinfo, colon - _userinfo)); + *password = unescape(git__substrdup(colon+1, u.field_data[UF_USERINFO].len - (colon+1-_userinfo))); + GITERR_CHECK_ALLOC(*password); + } else { + *username = git__substrdup(_userinfo, u.field_data[UF_USERINFO].len); + } + GITERR_CHECK_ALLOC(*username); + + } return 0; } diff --git a/src/netops.h b/src/netops.h index 5c105d6e3..666d66b12 100644 --- a/src/netops.h +++ b/src/netops.h @@ -92,6 +92,7 @@ void gitno_connection_data_free_ptrs(gitno_connection_data *data); int gitno_extract_url_parts( char **host, char **port, + char **path, char **username, char **password, const char *url, diff --git a/src/odb_pack.c b/src/odb_pack.c index 12f4591ec..fd2ca0fd8 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -558,7 +558,7 @@ static int pack_backend__writepack(struct git_odb_writepack **out, GITERR_CHECK_ALLOC(writepack); if (git_indexer_new(&writepack->indexer, - backend->pack_folder, odb, progress_cb, progress_payload) < 0) { + backend->pack_folder, 0, odb, progress_cb, progress_payload) < 0) { git__free(writepack); return -1; } diff --git a/src/pack-objects.c b/src/pack-objects.c index 9ea7c659a..2d62507f2 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -272,7 +272,7 @@ static int write_object(git_buf *buf, git_packbuilder *pb, git_pobject *po) git_buf zbuf = GIT_BUF_INIT; git_otype type; unsigned char hdr[10]; - unsigned int hdr_len; + size_t hdr_len; unsigned long size; void *data; @@ -560,6 +560,7 @@ static int write_pack(git_packbuilder *pb, git_buf buf = GIT_BUF_INIT; enum write_one_status status; struct git_pack_header ph; + git_oid entry_oid; unsigned int i = 0; int error = 0; @@ -596,10 +597,10 @@ static int write_pack(git_packbuilder *pb, } while (pb->nr_remaining && i < pb->nr_objects); - if ((error = git_hash_final(&pb->pack_oid, &pb->ctx)) < 0) + if ((error = git_hash_final(&entry_oid, &pb->ctx)) < 0) goto done; - error = cb(pb->pack_oid.id, GIT_OID_RAWSZ, data); + error = cb(entry_oid.id, GIT_OID_RAWSZ, data); done: git__free(write_order); @@ -1247,6 +1248,7 @@ static int write_cb(void *buf, size_t len, void *payload) int git_packbuilder_write( git_packbuilder *pb, const char *path, + unsigned int mode, git_transfer_progress_callback progress_cb, void *progress_cb_payload) { @@ -1257,7 +1259,7 @@ int git_packbuilder_write( PREPARE_PACK; if (git_indexer_new( - &indexer, path, pb->odb, progress_cb, progress_cb_payload) < 0) + &indexer, path, mode, pb->odb, progress_cb, progress_cb_payload) < 0) return -1; ctx.indexer = indexer; @@ -1269,12 +1271,19 @@ int git_packbuilder_write( return -1; } + git_oid_cpy(&pb->pack_oid, git_indexer_hash(indexer)); + git_indexer_free(indexer); return 0; } #undef PREPARE_PACK +const git_oid *git_packbuilder_hash(git_packbuilder *pb) +{ + return &pb->pack_oid; +} + static int cb_tree_walk(const char *root, const git_tree_entry *entry, void *payload) { struct tree_walk_context *ctx = payload; diff --git a/src/push.c b/src/push.c index a799db8d0..3c9d5bb35 100644 --- a/src/push.c +++ b/src/push.c @@ -616,16 +616,22 @@ on_error: return error; } -static int cb_filter_refs(git_remote_head *ref, void *data) -{ - git_remote *remote = (git_remote *) data; - return git_vector_insert(&remote->refs, ref); -} - static int filter_refs(git_remote *remote) { + const git_remote_head **heads; + size_t heads_len, i; + git_vector_clear(&remote->refs); - return git_remote_ls(remote, cb_filter_refs, remote); + + if (git_remote_ls(&heads, &heads_len, remote) < 0) + return -1; + + for (i = 0; i < heads_len; i++) { + if (git_vector_insert(&remote->refs, (void *)heads[i]) < 0) + return -1; + } + + return 0; } int git_push_finish(git_push *push) diff --git a/src/refspec.c b/src/refspec.c index 492c6ed3f..a97340071 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -12,6 +12,7 @@ #include "util.h" #include "posix.h" #include "refs.h" +#include "vector.h" int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) { @@ -287,3 +288,70 @@ git_direction git_refspec_direction(const git_refspec *spec) return spec->push; } + +int git_refspec__dwim_one(git_vector *out, git_refspec *spec, git_vector *refs) +{ + git_buf buf = GIT_BUF_INIT; + size_t j, pos; + git_remote_head key; + + const char* formatters[] = { + GIT_REFS_DIR "%s", + GIT_REFS_TAGS_DIR "%s", + GIT_REFS_HEADS_DIR "%s", + NULL + }; + + git_refspec *cur = git__calloc(1, sizeof(git_refspec)); + GITERR_CHECK_ALLOC(cur); + + cur->force = spec->force; + cur->push = spec->push; + cur->pattern = spec->pattern; + cur->matching = spec->matching; + cur->string = git__strdup(spec->string); + + /* shorthand on the lhs */ + if (git__prefixcmp(spec->src, GIT_REFS_DIR)) { + for (j = 0; formatters[j]; j++) { + git_buf_clear(&buf); + if (git_buf_printf(&buf, formatters[j], spec->src) < 0) + return -1; + + key.name = (char *) git_buf_cstr(&buf); + if (!git_vector_search(&pos, refs, &key)) { + /* we found something to match the shorthand, set src to that */ + cur->src = git_buf_detach(&buf); + } + } + } + + /* No shorthands found, copy over the name */ + if (cur->src == NULL && spec->src != NULL) { + cur->src = git__strdup(spec->src); + GITERR_CHECK_ALLOC(cur->src); + } + + if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) { + /* if it starts with "remotes" then we just prepend "refs/" */ + if (!git__prefixcmp(spec->dst, "remotes/")) { + git_buf_puts(&buf, GIT_REFS_DIR); + } else { + git_buf_puts(&buf, GIT_REFS_HEADS_DIR); + } + + if (git_buf_puts(&buf, spec->dst) < 0) + return -1; + + cur->dst = git_buf_detach(&buf); + } + + git_buf_free(&buf); + + if (cur->dst == NULL && spec->dst != NULL) { + cur->dst = git__strdup(spec->dst); + GITERR_CHECK_ALLOC(cur->dst); + } + + return git_vector_insert(out, cur); +} diff --git a/src/refspec.h b/src/refspec.h index 44d484c7b..51b7bfee9 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -9,6 +9,7 @@ #include "git2/refspec.h" #include "buffer.h" +#include "vector.h" struct git_refspec { char *string; @@ -17,7 +18,6 @@ struct git_refspec { unsigned int force :1, push : 1, pattern :1, - dwim :1, matching :1; }; @@ -63,4 +63,10 @@ int git_refspec__serialize(git_buf *out, const git_refspec *refspec); */ int git_refspec_is_wildcard(const git_refspec *spec); +/** + * DWIM `spec` with `refs` existing on the remote, append the dwim'ed + * result in `out`. + */ +int git_refspec__dwim_one(git_vector *out, git_refspec *spec, git_vector *refs); + #endif diff --git a/src/remote.c b/src/remote.c index b97cc9e79..c0f35e5ea 100644 --- a/src/remote.c +++ b/src/remote.c @@ -19,6 +19,8 @@ #include "refspec.h" #include "fetchhead.h" +static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs); + static int add_refspec(git_remote *remote, const char *string, bool is_fetch) { git_refspec *spec; @@ -318,7 +320,8 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) GITERR_CHECK_ALLOC(remote->name); if ((git_vector_init(&remote->refs, 32, NULL) < 0) || - (git_vector_init(&remote->refspecs, 2, NULL))) { + (git_vector_init(&remote->refspecs, 2, NULL) < 0) || + (git_vector_init(&remote->active_refspecs, 2, NULL) < 0)) { error = -1; goto cleanup; } @@ -377,6 +380,10 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) if (download_tags_value(remote, config) < 0) goto cleanup; + /* Move the data over to where the matching functions can find them */ + if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0) + goto cleanup; + *out = remote; cleanup: @@ -643,11 +650,11 @@ on_error: return -1; } -int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) +int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote) { assert(remote); - return remote->transport->ls(remote->transport, list_cb, payload); + return remote->transport->ls(out, size, remote->transport); } int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url) @@ -707,67 +714,31 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur return 0; } -static int store_refs(git_remote_head *head, void *payload) -{ - git_vector *refs = (git_vector *)payload; - - return git_vector_insert(refs, head); -} - -static int dwim_refspecs(git_vector *refspecs, git_vector *refs) +/* DWIM `refspecs` based on `refs` and append the output to `out` */ +static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs) { - git_buf buf = GIT_BUF_INIT; + size_t i; git_refspec *spec; - size_t i, j, pos; - git_remote_head key; - - const char* formatters[] = { - GIT_REFS_DIR "%s", - GIT_REFS_TAGS_DIR "%s", - GIT_REFS_HEADS_DIR "%s", - NULL - }; git_vector_foreach(refspecs, i, spec) { - if (spec->dwim) - continue; - - /* shorthand on the lhs */ - if (git__prefixcmp(spec->src, GIT_REFS_DIR)) { - for (j = 0; formatters[j]; j++) { - git_buf_clear(&buf); - if (git_buf_printf(&buf, formatters[j], spec->src) < 0) - return -1; - - key.name = (char *) git_buf_cstr(&buf); - if (!git_vector_search(&pos, refs, &key)) { - /* we found something to match the shorthand, set src to that */ - git__free(spec->src); - spec->src = git_buf_detach(&buf); - } - } - } - - if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) { - /* if it starts with "remotes" then we just prepend "refs/" */ - if (!git__prefixcmp(spec->dst, "remotes/")) { - git_buf_puts(&buf, GIT_REFS_DIR); - } else { - git_buf_puts(&buf, GIT_REFS_HEADS_DIR); - } + if (git_refspec__dwim_one(out, spec, refs) < 0) + return -1; + } - if (git_buf_puts(&buf, spec->dst) < 0) - return -1; + return 0; +} - git__free(spec->dst); - spec->dst = git_buf_detach(&buf); - } +static void free_refspecs(git_vector *vec) +{ + size_t i; + git_refspec *spec; - spec->dwim = 1; + git_vector_foreach(vec, i, spec) { + git_refspec__free(spec); + git__free(spec); } - git_buf_free(&buf); - return 0; + git_vector_clear(vec); } static int remote_head_cmp(const void *_a, const void *_b) @@ -778,6 +749,25 @@ static int remote_head_cmp(const void *_a, const void *_b) return git__strcmp_cb(a->name, b->name); } +static int ls_to_vector(git_vector *out, git_remote *remote) +{ + git_remote_head **heads; + size_t heads_len, i; + + if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0) + return -1; + + if (git_vector_init(out, heads_len, remote_head_cmp) < 0) + return -1; + + for (i = 0; i < heads_len; i++) { + if (git_vector_insert(out, heads[i]) < 0) + return -1; + } + + return 0; +} + int git_remote_download(git_remote *remote) { int error; @@ -785,15 +775,14 @@ int git_remote_download(git_remote *remote) assert(remote); - if (git_vector_init(&refs, 16, remote_head_cmp) < 0) + if (ls_to_vector(&refs, remote) < 0) return -1; - if (git_remote_ls(remote, store_refs, &refs) < 0) { - return -1; - } + free_refspecs(&remote->active_refspecs); - error = dwim_refspecs(&remote->refspecs, &refs); + error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &refs); git_vector_free(&refs); + if (error < 0) return -1; @@ -1043,10 +1032,8 @@ int git_remote_update_tips(git_remote *remote) if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) return -1; - if (git_vector_init(&refs, 16, NULL) < 0) - return -1; - if ((error = git_remote_ls(remote, store_refs, &refs)) < 0) + if ((error = ls_to_vector(&refs, remote)) < 0) goto out; if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { @@ -1054,7 +1041,7 @@ int git_remote_update_tips(git_remote *remote) goto out; } - git_vector_foreach(&remote->refspecs, i, spec) { + git_vector_foreach(&remote->active_refspecs, i, spec) { if (spec->push) continue; @@ -1063,8 +1050,8 @@ int git_remote_update_tips(git_remote *remote) } out: - git_refspec__free(&tagspec); git_vector_free(&refs); + git_refspec__free(&tagspec); return error; } @@ -1097,9 +1084,6 @@ void git_remote_disconnect(git_remote *remote) void git_remote_free(git_remote *remote) { - git_refspec *spec; - size_t i; - if (remote == NULL) return; @@ -1112,12 +1096,12 @@ void git_remote_free(git_remote *remote) git_vector_free(&remote->refs); - git_vector_foreach(&remote->refspecs, i, spec) { - git_refspec__free(spec); - git__free(spec); - } + free_refspecs(&remote->refspecs); git_vector_free(&remote->refspecs); + free_refspecs(&remote->active_refspecs); + git_vector_free(&remote->active_refspecs); + git__free(remote->url); git__free(remote->pushurl); git__free(remote->name); @@ -1526,7 +1510,7 @@ git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refnam git_refspec *spec; size_t i; - git_vector_foreach(&remote->refspecs, i, spec) { + git_vector_foreach(&remote->active_refspecs, i, spec) { if (spec->push) continue; @@ -1542,7 +1526,7 @@ git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *re git_refspec *spec; size_t i; - git_vector_foreach(&remote->refspecs, i, spec) { + git_vector_foreach(&remote->active_refspecs, i, spec) { if (spec->push) continue; @@ -1565,14 +1549,68 @@ void git_remote_clear_refspecs(git_remote *remote) git_vector_clear(&remote->refspecs); } +static int add_and_dwim(git_remote *remote, const char *str, int push) +{ + git_refspec *spec; + git_vector *vec; + + if (add_refspec(remote, str, !push) < 0) + return -1; + + vec = &remote->refspecs; + spec = git_vector_get(vec, vec->length - 1); + return git_refspec__dwim_one(&remote->active_refspecs, spec, &remote->refs); +} + int git_remote_add_fetch(git_remote *remote, const char *refspec) { - return add_refspec(remote, refspec, true); + return add_and_dwim(remote, refspec, false); } int git_remote_add_push(git_remote *remote, const char *refspec) { - return add_refspec(remote, refspec, false); + return add_and_dwim(remote, refspec, true); +} + +static int set_refspecs(git_remote *remote, git_strarray *array, int push) +{ + git_vector *vec = &remote->refspecs; + git_refspec *spec; + size_t i; + + /* Start by removing any refspecs of the same type */ + for (i = 0; i < vec->length; i++) { + spec = git_vector_get(vec, i); + if (spec->push != push) + continue; + + git_refspec__free(spec); + git__free(spec); + git_vector_remove(vec, i); + i--; + } + + /* And now we add the new ones */ + + for (i = 0; i < array->count; i++) { + if (add_refspec(remote, array->strings[i], !push) < 0) + return -1; + } + + free_refspecs(&remote->active_refspecs); + git_vector_clear(&remote->active_refspecs); + + return dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs); +} + +int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array) +{ + return set_refspecs(remote, array, false); +} + +int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array) +{ + return set_refspecs(remote, array, true); } static int copy_refspecs(git_strarray *array, git_remote *remote, unsigned int push) @@ -1630,18 +1668,3 @@ const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n) { return git_vector_get(&remote->refspecs, n); } - -int git_remote_remove_refspec(git_remote *remote, size_t n) -{ - git_refspec *spec; - - assert(remote); - - spec = git_vector_get(&remote->refspecs, n); - if (spec) { - git_refspec__free(spec); - git__free(spec); - } - - return git_vector_remove(&remote->refspecs, n); -} diff --git a/src/remote.h b/src/remote.h index 269584d96..33e4d68f8 100644 --- a/src/remote.h +++ b/src/remote.h @@ -21,6 +21,7 @@ struct git_remote { char *pushurl; git_vector refs; git_vector refspecs; + git_vector active_refspecs; git_transport *transport; git_repository *repo; git_remote_callbacks callbacks; diff --git a/src/signature.c b/src/signature.c index 52ca2b375..ec51a42e9 100644 --- a/src/signature.c +++ b/src/signature.c @@ -84,8 +84,12 @@ int git_signature_new(git_signature **sig_out, const char *name, const char *ema git_signature *git_signature_dup(const git_signature *sig) { - git_signature *new = git__calloc(1, sizeof(git_signature)); + git_signature *new; + if (sig == NULL) + return NULL; + + new = git__calloc(1, sizeof(git_signature)); if (new == NULL) return NULL; diff --git a/src/transports/git.c b/src/transports/git.c index 79a9e7dd4..5dcd4eff7 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -179,39 +179,33 @@ static int _git_uploadpack_ls( const char *url, git_smart_subtransport_stream **stream) { - char *host=NULL, *port=NULL, *user=NULL, *pass=NULL; + char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL; + const char *stream_url = url; git_stream *s; + int error = -1; *stream = NULL; - if (!git__prefixcmp(url, prefix_git)) - url += strlen(prefix_git); + stream_url += strlen(prefix_git); - if (git_stream_alloc(t, url, cmd_uploadpack, stream) < 0) + if (git_stream_alloc(t, stream_url, cmd_uploadpack, stream) < 0) return -1; s = (git_stream *)*stream; - if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) - goto on_error; - - if (gitno_connect(&s->socket, host, port, 0) < 0) - goto on_error; - - t->current_stream = s; - git__free(host); - git__free(port); - git__free(user); - git__free(pass); - return 0; + if (!(error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, GIT_DEFAULT_PORT))) { + if (!(error = gitno_connect(&s->socket, host, port, 0))) + t->current_stream = s; -on_error: - if (*stream) + git__free(host); + git__free(port); + git__free(path); + git__free(user); + git__free(pass); + } else if (*stream) git_stream_free(*stream); - git__free(host); - git__free(port); - return -1; + return error; } static int _git_uploadpack( @@ -235,39 +229,33 @@ static int _git_receivepack_ls( const char *url, git_smart_subtransport_stream **stream) { - char *host=NULL, *port=NULL, *user=NULL, *pass=NULL; + char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL; + const char *stream_url = url; git_stream *s; + int error; *stream = NULL; - if (!git__prefixcmp(url, prefix_git)) - url += strlen(prefix_git); + stream_url += strlen(prefix_git); - if (git_stream_alloc(t, url, cmd_receivepack, stream) < 0) + if (git_stream_alloc(t, stream_url, cmd_receivepack, stream) < 0) return -1; s = (git_stream *)*stream; - if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) - goto on_error; - - if (gitno_connect(&s->socket, host, port, 0) < 0) - goto on_error; - - t->current_stream = s; - git__free(host); - git__free(port); - git__free(user); - git__free(pass); - return 0; + if (!(error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, GIT_DEFAULT_PORT))) { + if (!(error = gitno_connect(&s->socket, host, port, 0))) + t->current_stream = s; -on_error: - if (*stream) + git__free(host); + git__free(port); + git__free(path); + git__free(user); + git__free(pass); + } else if (*stream) git_stream_free(*stream); - git__free(host); - git__free(port); - return -1; + return error; } static int _git_receivepack( diff --git a/src/transports/local.c b/src/transports/local.c index 3163d2eac..4502f0202 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -213,21 +213,17 @@ static int local_connect( return 0; } -static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *payload) +static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport) { transport_local *t = (transport_local *)transport; - unsigned int i; - git_remote_head *head = NULL; if (!t->have_refs) { giterr_set(GITERR_NET, "The transport has not yet loaded the refs"); return -1; } - git_vector_foreach(&t->refs, i, head) { - if (list_cb(head, payload)) - return GIT_EUSER; - } + *out = (const git_remote_head **) t->refs.contents; + *size = t->refs.length; return 0; } diff --git a/src/transports/smart.c b/src/transports/smart.c index a681d5f40..5242beb65 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -63,6 +63,24 @@ static int git_smart__set_callbacks( return 0; } +int git_smart__update_heads(transport_smart *t) +{ + size_t i; + git_pkt *pkt; + + git_vector_clear(&t->heads); + git_vector_foreach(&t->refs, i, pkt) { + git_pkt_ref *ref = (git_pkt_ref *) pkt; + if (pkt->type != GIT_PKT_REF) + continue; + + if (git_vector_insert(&t->heads, &ref->head) < 0) + return -1; + } + + return 0; +} + static int git_smart__connect( git_transport *transport, const char *url, @@ -140,6 +158,9 @@ static int git_smart__connect( git_pkt_free((git_pkt *)first); } + /* Keep a list of heads for _ls */ + git_smart__update_heads(t); + if (t->rpc && git_smart__reset_stream(t, false) < 0) return -1; @@ -149,28 +170,17 @@ static int git_smart__connect( return 0; } -static int git_smart__ls(git_transport *transport, git_headlist_cb list_cb, void *payload) +static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport) { transport_smart *t = (transport_smart *)transport; - unsigned int i; - git_pkt *p = NULL; if (!t->have_refs) { giterr_set(GITERR_NET, "The transport has not yet loaded the refs"); return -1; } - git_vector_foreach(&t->refs, i, p) { - git_pkt_ref *pkt = NULL; - - if (p->type != GIT_PKT_REF) - continue; - - pkt = (git_pkt_ref *)p; - - if (list_cb(&pkt->head, payload)) - return GIT_EUSER; - } + *out = (const git_remote_head **) t->heads.contents; + *size = t->heads.length; return 0; } @@ -293,6 +303,7 @@ static void git_smart__free(git_transport *transport) /* Free the subtransport */ t->wrapped->free(t->wrapped); + git_vector_free(&t->heads); git_vector_foreach(refs, i, p) git_pkt_free(p); @@ -340,6 +351,11 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) return -1; } + if (git_vector_init(&t->heads, 16, ref_name_cmp) < 0) { + git__free(t); + return -1; + } + if (definition->callback(&t->wrapped, &t->parent) < 0) { git__free(t); return -1; diff --git a/src/transports/smart.h b/src/transports/smart.h index 5232e54de..32f0be7f2 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -140,6 +140,7 @@ typedef struct { git_smart_subtransport_stream *current_stream; transport_smart_caps caps; git_vector refs; + git_vector heads; git_vector common; git_atomic cancelled; packetsize_cb packetsize_cb; @@ -173,6 +174,8 @@ int git_smart__download_pack( int git_smart__negotiation_step(git_transport *transport, void *data, size_t len); int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream **out); +int git_smart__update_heads(transport_smart *t); + /* smart_pkt.c */ int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len); int git_pkt_buffer_flush(git_buf *buf); diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 4e9e112f4..7288a4820 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -269,7 +269,7 @@ static int wait_while_ack(gitno_buffer *buf) return 0; } -int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count) +int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *wants, size_t count) { transport_smart *t = (transport_smart *)transport; gitno_buffer *buf = &t->buffer; @@ -279,19 +279,20 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c unsigned int i; git_oid oid; - /* No own logic, do our thing */ - if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0) + if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) return error; if ((error = fetch_setup_walk(&walk, repo)) < 0) goto on_error; + /* - * We don't support any kind of ACK extensions, so the negotiation - * boils down to sending what we have and listening for an ACK - * every once in a while. + * Our support for ACK extensions is simply to parse them. On + * the first ACK we will accept that as enough common + * objects. We give up if we haven't found an answer in the + * first 256 we send. */ i = 0; - while (true) { + while (i < 256) { error = git_revwalk_next(&oid, walk); if (error < 0) { @@ -349,7 +350,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c git_pkt_ack *pkt; unsigned int i; - if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0) + if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) goto on_error; git_vector_foreach(&t->common, i, pkt) { @@ -369,7 +370,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c git_pkt_ack *pkt; unsigned int i; - if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0) + if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) goto on_error; git_vector_foreach(&t->common, i, pkt) { @@ -943,8 +944,13 @@ int git_smart__push(git_transport *transport, git_push *push) push->transfer_progress_cb(push->pb->nr_written, push->pb->nr_objects, packbuilder_payload.last_bytes, push->transfer_progress_cb_payload); } - if (push->status.length) + if (push->status.length) { error = update_refs_from_report(&t->refs, &push->specs, &push->status); + if (error < 0) + goto done; + + error = git_smart__update_heads(t); + } done: git_buf_free(&pktline); diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 4e2834b49..4a905e3c9 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -317,7 +317,7 @@ static int _git_ssh_setup_conn( const char *cmd, git_smart_subtransport_stream **stream) { - char *host=NULL, *port=NULL, *user=NULL, *pass=NULL; + char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL; const char *default_port="22"; ssh_stream *s; LIBSSH2_SESSION* session=NULL; @@ -330,8 +330,7 @@ static int _git_ssh_setup_conn( s = (ssh_stream *)*stream; if (!git__prefixcmp(url, prefix_ssh)) { - url = url + strlen(prefix_ssh); - if (gitno_extract_url_parts(&host, &port, &user, &pass, url, default_port) < 0) + if (gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port) < 0) goto on_error; } else { if (git_ssh_extract_url_parts(&host, &user, url) < 0) @@ -390,6 +389,7 @@ static int _git_ssh_setup_conn( t->current_stream = s; git__free(host); git__free(port); + git__free(path); git__free(user); git__free(pass); |
