int git_index_write(git_index *index) { git_filebuf file; struct stat indexst; int error; git_vector_sort(&index->entries); if ((error = git_filebuf_open(&file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write index"); if ((error = write_index(index, &file)) < GIT_SUCCESS) { git_filebuf_cleanup(&file); return git__rethrow(error, "Failed to write index"); } if ((error = git_filebuf_commit(&file)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write index"); if (p_stat(index->index_file_path, &indexst) == 0) { index->last_modified = indexst.st_mtime; index->on_disk = 1; } return GIT_SUCCESS; }
int git_filebuf_write(git_filebuf *file, const void *buff, size_t len) { int error; const unsigned char *buf = buff; for (;;) { size_t space_left = file->buf_size - file->buf_pos; /* cache if it's small */ if (space_left > len) { add_to_cache(file, buf, len); return GIT_SUCCESS; } /* flush the cache if it doesn't fit */ if (file->buf_pos > 0) { add_to_cache(file, buf, space_left); if ((error = flush_buffer(file)) < GIT_SUCCESS) return git__rethrow(error, "Failed to write to buffer"); len -= space_left; buf += space_left; } /* write too-large chunks immediately */ if (len > file->buf_size) { error = file->write(file, buf, len); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to write to buffer"); } } }
/* * In this first version, we push all our refs in and start sending * them out. When we get an ACK we hide that commit and continue * traversing until we're done */ int git_fetch_negotiate(git_remote *remote) { int error; git_headarray *list = &remote->refs; git_transport *t = remote->transport; error = filter_wants(remote); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to filter the reference list for wants"); /* Don't try to negotiate when we don't want anything */ if (list->len == 0) return GIT_SUCCESS; if (!remote->need_pack) return GIT_SUCCESS; /* * Now we have everything set up so we can start tell the server * what we want and what we have. */ error = t->send_wants(t, list); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to send want list"); return t->negotiate_fetch(t, remote->repo, &remote->refs); }
static int write_index(git_index *index, git_filebuf *file) { int error = GIT_SUCCESS; git_oid hash_final; struct index_header header; int is_extended; assert(index && file); is_extended = is_index_extended(index); header.signature = htonl(INDEX_HEADER_SIG); header.version = htonl(is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER); header.entry_count = htonl(index->entries.length); git_filebuf_write(file, &header, sizeof(struct index_header)); error = write_entries(index, file); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to write index"); /* TODO: write extensions (tree cache) */ /* get out the hash for all the contents we've appended to the file */ git_filebuf_hash(&hash_final, file); /* write it at the end of the file */ git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write index"); }
static int filter_wants(git_remote *remote) { git_vector list; git_headarray refs; git_transport *t = remote->transport; git_repository *repo = remote->repo; const git_refspec *spec; int error; unsigned int i; error = git_vector_init(&list, 16, NULL); if (error < GIT_SUCCESS) return error; error = t->ls(t, &refs); if (error < GIT_SUCCESS) { error = git__rethrow(error, "Failed to get remote ref list"); goto cleanup; } spec = git_remote_fetchspec(remote); if (spec == NULL) { error = git__throw(GIT_ERROR, "The remote has no fetchspec"); goto cleanup; } for (i = 0; i < refs.len; ++i) { git_remote_head *head = refs.heads[i]; /* If it doesn't match the refpec, we don't want it */ error = git_refspec_src_match(spec, head->name); if (error == GIT_ENOMATCH) continue; if (error < GIT_SUCCESS) { error = git__rethrow(error, "Error matching remote ref name"); goto cleanup; } /* If we have the object, mark it so we don't ask for it */ if (git_odb_exists(repo->db, &head->oid)) head->local = 1; else remote->need_pack = 1; error = git_vector_insert(&list, head); if (error < GIT_SUCCESS) goto cleanup; } remote->refs.len = list.length; remote->refs.heads = (git_remote_head **) list.contents; return GIT_SUCCESS; cleanup: git_vector_free(&list); return error; }
static int pack_entry_find_prefix( struct git_pack_entry *e, struct pack_backend *backend, const git_oid *short_oid, unsigned int len) { int error; size_t i; unsigned found = 0; if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS) return git__rethrow(error, "Failed to find pack entry"); if (backend->last_found) { error = git_pack_entry_find(e, backend->last_found, short_oid, len); if (error == GIT_EAMBIGUOUSOIDPREFIX) { return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix"); } else if (error == GIT_SUCCESS) { found = 1; } } for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p; p = git_vector_get(&backend->packs, i); if (p == backend->last_found) continue; error = git_pack_entry_find(e, p, short_oid, len); if (error == GIT_EAMBIGUOUSOIDPREFIX) { return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix"); } else if (error == GIT_SUCCESS) { found++; if (found > 1) break; backend->last_found = p; } } if (!found) { return git__rethrow(GIT_ENOTFOUND, "Failed to find pack entry"); } else if (found > 1) { return git__rethrow(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find pack entry. Ambiguous sha1 prefix"); } else { return GIT_SUCCESS; } }
int git_config_add_file(git_config *cfg, git_config_file *file, int priority) { file_internal *internal; int error; assert(cfg && file); if ((error = file->open(file)) < GIT_SUCCESS) return git__rethrow(error, "Failed to open config file"); internal = git__malloc(sizeof(file_internal)); if (internal == NULL) return GIT_ENOMEM; internal->file = file; internal->priority = priority; if (git_vector_insert(&cfg->files, internal) < 0) { free(internal); return GIT_ENOMEM; } git_vector_sort(&cfg->files); internal->file->cfg = cfg; return GIT_SUCCESS; }
int git_filebuf_printf(git_filebuf *file, const char *format, ...) { va_list arglist; size_t space_left = file->buf_size - file->buf_pos; int len, error; va_start(arglist, format); len = vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); va_end(arglist); if (len < 0 || (size_t)len >= space_left) { if ((error = flush_buffer(file)) < GIT_SUCCESS) return git__rethrow(error, "Failed to output to buffer"); space_left = file->buf_size - file->buf_pos; va_start(arglist, format); len = vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); va_end(arglist); if (len < 0 || (size_t)len > file->buf_size) return GIT_ENOMEM; } file->buf_pos += len; return GIT_SUCCESS; }
static int packfile_refresh_all(struct pack_backend *backend) { int error; struct stat st; if (backend->pack_folder == NULL) return GIT_SUCCESS; if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) return git__throw(GIT_ENOTFOUND, "Failed to refresh packfiles. Backend not found"); if (st.st_mtime != backend->pack_folder_mtime) { char path[GIT_PATH_MAX]; strcpy(path, backend->pack_folder); /* reload all packs */ error = git_futils_direach(path, GIT_PATH_MAX, packfile_load__cb, (void *)backend); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to refresh packfiles"); git_vector_sort(&backend->packs); backend->pack_folder_mtime = st.st_mtime; } return GIT_SUCCESS; }
int git__percent_decode(git_buf *decoded_out, const char *input) { int len, hi, lo, i, error = GIT_SUCCESS; assert(decoded_out && input); len = strlen(input); git_buf_clear(decoded_out); for(i = 0; i < len; i++) { char c = input[i]; if (c != '%') goto append; if (i >= len - 2) goto append; hi = git__fromhex(input[i + 1]); lo = git__fromhex(input[i + 2]); if (hi < 0 || lo < 0) goto append; c = (char)(hi << 4 | lo); i += 2; append: error = git_buf_putc(decoded_out, c); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to percent decode '%s'.", input); } return error; }
static int packfile_load__cb(void *_data, char *path) { struct pack_backend *backend = (struct pack_backend *)_data; struct git_pack_file *pack; int error; size_t i; if (git__suffixcmp(path, ".idx") != 0) return GIT_SUCCESS; /* not an index */ for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p = git_vector_get(&backend->packs, i); if (memcmp(p->pack_name, path, strlen(path) - strlen(".idx")) == 0) return GIT_SUCCESS; } error = git_packfile_check(&pack, path); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to load packfile"); if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) { free(pack); return GIT_ENOMEM; } return GIT_SUCCESS; }
static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid) { int error; size_t i; if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS) return git__rethrow(error, "Failed to find pack entry"); if (backend->last_found && git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == GIT_SUCCESS) return GIT_SUCCESS; for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p; p = git_vector_get(&backend->packs, i); if (p == backend->last_found) continue; if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == GIT_SUCCESS) { backend->last_found = p; return GIT_SUCCESS; } } return git__throw(GIT_ENOTFOUND, "Failed to find pack entry"); }
int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld) { unsigned int i; int error; git_buf tree = GIT_BUF_INIT; assert(bld); sort_entries(bld); /* Grow the buffer beforehand to an estimated size */ git_buf_grow(&tree, bld->entries.length * 72); for (i = 0; i < bld->entries.length; ++i) { git_tree_entry *entry = bld->entries.contents[i]; if (entry->removed) continue; git_buf_printf(&tree, "%o ", entry->attr); git_buf_put(&tree, entry->filename, entry->filename_len + 1); git_buf_put(&tree, (char *)entry->oid.id, GIT_OID_RAWSZ); } if (git_buf_oom(&tree)) { git_buf_free(&tree); return git__throw(GIT_ENOMEM, "Not enough memory to build the tree data"); } error = git_odb_write(oid, git_repository_database(repo), tree.ptr, tree.size, GIT_OBJ_TREE); git_buf_free(&tree); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write tree"); }
static int filter_ref__cb(git_remote_head *head, void *payload) { struct filter_payload *p = payload; int error; if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) { p->found_head = 1; } else { /* If it doesn't match the refpec, we don't want it */ error = git_refspec_src_match(p->spec, head->name); if (error == GIT_ENOMATCH) return GIT_SUCCESS; if (error < GIT_SUCCESS) return git__rethrow(error, "Error matching remote ref name"); } /* If we have the object, mark it so we don't ask for it */ if (git_odb_exists(p->odb, &head->oid)) head->local = 1; else p->remote->need_pack = 1; return git_vector_insert(&p->remote->refs, head); }
int git_config_get_int64(git_config *cfg, const char *name, int64_t *out) { const char *value, *num_end; int ret; int64_t num; ret = git_config_get_string(cfg, name, &value); if (ret < GIT_SUCCESS) return git__rethrow(ret, "Failed to retrieve value for '%s'", name); ret = git__strtol64(&num, value, &num_end, 0); if (ret < GIT_SUCCESS) return git__rethrow(ret, "Failed to convert value for '%s'", name); switch (*num_end) { case 'g': case 'G': num *= 1024; /* fallthrough */ case 'm': case 'M': num *= 1024; /* fallthrough */ case 'k': case 'K': num *= 1024; /* check that that there are no more characters after the * given modifier suffix */ if (num_end[1] != '\0') return git__throw(GIT_EINVALIDTYPE, "Failed to get value for '%s'. Invalid type suffix", name); /* fallthrough */ case '\0': *out = num; return GIT_SUCCESS; default: return git__throw(GIT_EINVALIDTYPE, "Failed to get value for '%s'. Value is of invalid type", name); } }
int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) { struct git_pack_entry e; git_rawobj raw; int error; if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < GIT_SUCCESS) return git__rethrow(error, "Failed to read pack backend"); if ((error = git_packfile_unpack(&raw, e.p, &e.offset)) < GIT_SUCCESS) return git__rethrow(error, "Failed to read pack backend"); *buffer_p = raw.data; *len_p = raw.len; *type_p = raw.type; return GIT_SUCCESS; }
int git_index_append(git_index *index, const char *path, int stage) { int error; git_index_entry entry; if ((error = index_init_entry(&entry, index, path, stage)) < GIT_SUCCESS) return git__rethrow(error, "Failed to append to index"); return index_insert(index, &entry, 0); }
/* * Based on the Android implementation, BSD licensed. * Check http://android.git.kernel.org/ */ int git_path_dirname_r(git_buf *buffer, const char *path) { const char *endp; int result, len; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { path = "."; len = 1; goto Exit; } /* Strip trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* Find the start of the dir */ while (endp > path && *endp != '/') endp--; /* Either the dir is "/" or there are no slashes */ if (endp == path) { path = (*endp == '/') ? "/" : "."; len = 1; goto Exit; } do { endp--; } while (endp > path && *endp == '/'); len = endp - path +1; #ifdef GIT_WIN32 /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return 'C:/' here */ if (len == 2 && isalpha(path[0]) && path[1] == ':') { len = 3; goto Exit; } #endif Exit: result = len; if (buffer != NULL) { if (git_buf_set(buffer, path, len) < GIT_SUCCESS) return git__rethrow(git_buf_lasterror(buffer), "Could not get dirname of '%s'", path); } return result; }
static int _rmdir_recurs_foreach(void *opaque, char *path) { int error = GIT_SUCCESS; int force = *(int *)opaque; if (git_futils_isdir(path) == GIT_SUCCESS) { size_t root_size = strlen(path); if ((error = git_futils_direach(path, GIT_PATH_MAX, _rmdir_recurs_foreach, opaque)) < GIT_SUCCESS) return git__rethrow(error, "Failed to remove directory `%s`", path); path[root_size] = '\0'; return p_rmdir(path); } else if (force) { return p_unlink(path); } return git__rethrow(error, "Failed to remove directory. `%s` is not empty", path); }
static int local_ls(git_transport *transport, git_headarray *array) { int error; unsigned int i; git_repository *repo; git_vector *vec; git_strarray refs; transport_local *t = (transport_local *) transport; assert(transport && transport->connected); repo = t->repo; error = git_reference_listall(&refs, repo, GIT_REF_LISTALL); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to list remote heads"); vec = git__malloc(sizeof(git_vector)); if (vec == NULL) { error = GIT_ENOMEM; goto out; } error = git_vector_init(vec, refs.count, NULL); if (error < GIT_SUCCESS) return error; /* Sort the references first */ qsort(refs.strings, refs.count, sizeof(char *), cmp_refs); /* Add HEAD */ error = add_ref(GIT_HEAD_FILE, repo, vec); if (error < GIT_SUCCESS) goto out; for (i = 0; i < refs.count; ++i) { error = add_ref(refs.strings[i], repo, vec); if (error < GIT_SUCCESS) goto out; } array->len = vec->length; array->heads = (git_remote_head **)vec->contents; t->refs = vec; out: git_strarray_free(&refs); return error; }
int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset) { int error; git_signature *p = NULL; assert(name && email); *sig_out = NULL; if ((p = git__malloc(sizeof(git_signature))) == NULL) { error = GIT_ENOMEM; goto cleanup; } memset(p, 0x0, sizeof(git_signature)); error = process_trimming(name, &p->name, name + strlen(name), 1); if (error < GIT_SUCCESS) { git__rethrow(GIT_EINVALIDARGS, "Failed to create signature. 'name' argument is invalid"); goto cleanup; } error = process_trimming(email, &p->email, email + strlen(email), 1); if (error < GIT_SUCCESS) { git__rethrow(GIT_EINVALIDARGS, "Failed to create signature. 'email' argument is invalid"); goto cleanup; } p->when.time = time; p->when.offset = offset; *sig_out = p; return error; cleanup: git_signature_free(p); return error; }
int git_index_read(git_index *index) { struct stat indexst; int error = GIT_SUCCESS; assert(index->index_file_path); if (!index->on_disk || git_futils_exists(index->index_file_path) < 0) { git_index_clear(index); index->on_disk = 0; return GIT_SUCCESS; } if (p_stat(index->index_file_path, &indexst) < 0) return git__throw(GIT_EOSERR, "Failed to read index. %s does not exist or is corrupted", index->index_file_path); if (!S_ISREG(indexst.st_mode)) return git__throw(GIT_ENOTFOUND, "Failed to read index. %s is not an index file", index->index_file_path); if (indexst.st_mtime != index->last_modified) { git_fbuffer buffer; if ((error = git_futils_readbuffer(&buffer, index->index_file_path)) < GIT_SUCCESS) return git__rethrow(error, "Failed to read index"); git_index_clear(index); error = parse_index(index, buffer.data, buffer.len); if (error == GIT_SUCCESS) index->last_modified = indexst.st_mtime; git_futils_freebuffer(&buffer); } if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to read index"); return error; }
int pack_backend__read_prefix( git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *short_oid, unsigned int len) { if (len < GIT_OID_MINPREFIXLEN) return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read pack backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); if (len >= GIT_OID_HEXSZ) { /* We can fall back to regular read method */ int error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid); if (error == GIT_SUCCESS) git_oid_cpy(out_oid, short_oid); return error; } else { struct git_pack_entry e; git_rawobj raw; int error; if ((error = pack_entry_find_prefix(&e, (struct pack_backend *)backend, short_oid, len)) < GIT_SUCCESS) return git__rethrow(error, "Failed to read pack backend"); if ((error = git_packfile_unpack(&raw, e.p, &e.offset)) < GIT_SUCCESS) return git__rethrow(error, "Failed to read pack backend"); *buffer_p = raw.data; *len_p = raw.len; *type_p = raw.type; git_oid_cpy(out_oid, &e.sha1); } return GIT_SUCCESS; }
static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buffer_end) { int error = GIT_SUCCESS; if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) return GIT_ENOMEM; while (buffer < buffer_end) { git_tree_entry *entry; int tmp; entry = git__calloc(1, sizeof(git_tree_entry)); if (entry == NULL) { error = GIT_ENOMEM; break; } if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS) return GIT_ENOMEM; if (git__strtol32(&tmp, buffer, &buffer, 8) < GIT_SUCCESS || !buffer || !valid_attributes(tmp)) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Can't parse attributes"); entry->attr = tmp; if (*buffer++ != ' ') { error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted"); break; } if (memchr(buffer, 0, buffer_end - buffer) == NULL) { error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted"); break; } entry->filename = git__strdup(buffer); entry->filename_len = strlen(buffer); while (buffer < buffer_end && *buffer != 0) buffer++; buffer++; git_oid_fromraw(&entry->oid, (const unsigned char *)buffer); buffer += GIT_OID_RAWSZ; } return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse buffer"); }
int git_config_get_bool(git_config *cfg, const char *name, int *out) { const char *value; int error = GIT_SUCCESS; error = git_config_get_string(cfg, name, &value); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to get value for %s", name); /* A missing value means true */ if (value == NULL) { *out = 1; return GIT_SUCCESS; } if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) { *out = 1; return GIT_SUCCESS; } if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) { *out = 0; return GIT_SUCCESS; } /* Try to parse it as an integer */ error = git_config_get_int32(cfg, name, out); if (error == GIT_SUCCESS) *out = !!(*out); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to get value for %s", name); return error; }
int git_filebuf_hash(git_oid *oid, git_filebuf *file) { int error; assert(oid && file && file->digest); if ((error = flush_buffer(file)) < GIT_SUCCESS) return git__rethrow(error, "Failed to get hash for file"); git_hash_final(oid, file->digest); git_hash_free_ctx(file->digest); file->digest = NULL; return GIT_SUCCESS; }
int git_tree_create_fromindex(git_oid *oid, git_index *index) { int error; if (index->repository == NULL) return git__throw(GIT_EBAREINDEX, "Failed to create tree. The index file is not backed up by an existing repository"); if (index->tree != NULL && index->tree->entries >= 0) { git_oid_cpy(oid, &index->tree->oid); return GIT_SUCCESS; } /* The tree cache didn't help us */ error = write_tree(oid, index, "", 0); return (error < GIT_SUCCESS) ? git__rethrow(error, "Failed to create tree") : GIT_SUCCESS; }
int git_config_get_int32(git_config *cfg, const char *name, int32_t *out) { int64_t tmp_long; int32_t tmp_int; int ret; ret = git_config_get_int64(cfg, name, &tmp_long); if (ret < GIT_SUCCESS) return git__rethrow(ret, "Failed to convert value for '%s'", name); tmp_int = tmp_long & 0xFFFFFFFF; if (tmp_int != tmp_long) return git__throw(GIT_EOVERFLOW, "Value for '%s' is too large", name); *out = tmp_int; return ret; }
/* * Based on the Android implementation, BSD licensed. * Check http://android.git.kernel.org/ */ int git_path_basename_r(git_buf *buffer, const char *path) { const char *endp, *startp; int len, result; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { startp = "."; len = 1; goto Exit; } /* Strip trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* All slashes becomes "/" */ if (endp == path && *endp == '/') { startp = "/"; len = 1; goto Exit; } /* Find the start of the base */ startp = endp; while (startp > path && *(startp - 1) != '/') startp--; len = endp - startp +1; Exit: result = len; if (buffer != NULL) { if (git_buf_set(buffer, startp, len) < GIT_SUCCESS) return git__rethrow(git_buf_lasterror(buffer), "Could not get basename of '%s'", path); } return result; }
int git_transport_new(git_transport **out, const char *url) { git_transport_cb fn; git_transport *transport; int error; fn = transport_new_fn(url); error = fn(&transport); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to create new transport"); transport->url = git__strdup(url); if (transport->url == NULL) return GIT_ENOMEM; *out = transport; return GIT_SUCCESS; }