static git_repository *update_local_repo(const char *localdir, const char *remote, const char *branch, enum remote_transport rt) { int error; git_repository *repo = NULL; if (verbose) fprintf(stderr, "git storage: update local repo\n"); error = git_repository_open(&repo, localdir); if (error) { if (is_subsurface_cloud) (void)cleanup_local_cache(remote, branch); else report_error("Unable to open git cache repository at %s: %s", localdir, giterr_last()->message); return NULL; } sync_with_remote(repo, remote, branch, rt); return repo; }
void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error(void) { git_reflog *reflog; const git_error *error; const char *refname = "refs/heads/newline"; const char *refmessage = "Reflog*message with a newline and enough content after it to pass the GIT_REFLOG_SIZE_MIN check inside reflog_parse."; git_reference *ref; git_oid id; git_buf logpath = GIT_BUF_INIT, logcontents = GIT_BUF_INIT; char *star; git_oid_fromstr(&id, current_master_tip); /* create a new branch */ cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, refmessage)); /* corrupt the branch reflog by introducing a newline inside the reflog message (we replace '*' with '\n') */ git_buf_join_n(&logpath, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname); cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath))); cl_assert((star = strchr(git_buf_cstr(&logcontents), '*')) != NULL); *star = '\n'; cl_git_rewritefile(git_buf_cstr(&logpath), git_buf_cstr(&logcontents)); /* confirm that the file was rewritten successfully and now contains a '\n' in the expected location */ cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath))); cl_assert(strstr(git_buf_cstr(&logcontents), "Reflog\nmessage") != NULL); /* clear the error state so we can capture the error generated by git_reflog_read */ giterr_clear(); cl_git_fail(git_reflog_read(&reflog, g_repo, refname)); error = giterr_last(); cl_assert(error != NULL); cl_assert_equal_s("unable to parse OID - contains invalid characters", error->message); git_reference_free(ref); git_buf_dispose(&logpath); git_buf_dispose(&logcontents); }
int luagi_clone( lua_State *L ) { const char *url = luaL_checkstring( L, 1 ); const char *local_path = luaL_checkstring( L, 2 ); git_clone_options options; parse_options( &options, L, 3 ); git_repository **repo = (git_repository **) lua_newuserdata( L, sizeof(git_repository *) ); if( git_clone( repo, url, local_path, &options) ) { const git_error* err = giterr_last(); lua_pushnil( L ); lua_pushfstring( L, "unable to clone repository from %s to %s --> %s", url, local_path, err->message ); return 2; } ltk_setmetatable( L, REPO_NAME ); return 1; }
void rugged_exception_raise(void) { VALUE err_klass, err_obj; const git_error *error; const char *err_message; error = giterr_last(); if (error && error->klass > 0 && error->klass < RUGGED_ERROR_COUNT) { err_klass = rb_eRuggedErrors[error->klass]; err_message = error->message; } else { err_klass = rb_eRuntimeError; err_message = "Rugged operation failed"; } err_obj = rb_exc_new2(err_klass, err_message); giterr_clear(); rb_exc_raise(err_obj); }
int main(int argc, char **argv) { if (argc < 2) { printf("Usage: %s <repo url>\n", argv[0]); return 1; } git_libgit2_init(); git_repository *repo = NULL; git_clone_options opts = GIT_CLONE_OPTIONS_INIT; opts.repository_cb = repository_create_memory_cb; const char *url = argv[1]; const char *path = "repo"; int error = git_clone(&repo, url, path, &opts); if (error) { fprintf(stderr, "%s\n", giterr_last()->message); } git_libgit2_shutdown(); return 0; }
void rugged_exception_raise(void) { VALUE err_klass, err_obj; const git_error *error; const char *err_message; error = giterr_last(); if (error && error->klass >= 0 && error->klass < RUGGED_ERROR_COUNT) { err_klass = rb_eRuggedErrors[error->klass]; err_message = error->message; } else { err_klass = rb_eRuggedErrors[2]; /* InvalidError */ err_message = "Unknown Error"; } err_obj = rb_exc_new2(err_klass, err_message); giterr_clear(); rb_exc_raise(err_obj); }
static int send_request(winhttp_stream *s, size_t len, int ignore_length) { int request_failed = 0, cert_valid = 1, error = 0; DWORD ignore_flags; if ((error = do_send_request(s, len, ignore_length)) < 0) request_failed = 1; if (request_failed) { if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) { giterr_set(GITERR_OS, "failed to send request"); return -1; } else { cert_valid = 0; } } giterr_clear(); if ((error = certificate_check(s, cert_valid)) < 0) { if (!giterr_last()) giterr_set(GITERR_OS, "user cancelled certificate check"); return error; } /* if neither the request nor the certificate check returned errors, we're done */ if (!request_failed) return 0; ignore_flags = no_check_cert_flags; if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) { giterr_set(GITERR_OS, "failed to set security options"); return -1; } if ((error = do_send_request(s, len, ignore_length)) < 0) giterr_set(GITERR_OS, "failed to send request"); return error; }
// Copied from libgit2 examples static int log_lg2(int error, const char *message, const char *extra){ const git_error *lg2err; const char *lg2msg = "", *lg2spacer = ""; if (!error) return error; if ((lg2err = giterr_last()) != NULL && lg2err->message != NULL) { lg2msg = lg2err->message; lg2spacer = " - "; } if (extra) fprintf(stderr, "%s '%s' [%d]%s%s\n", message, extra, error, lg2spacer, lg2msg); else fprintf(stderr, "%s [%d]%s%s\n", message, error, lg2spacer, lg2msg); return error; }
static int update_remote(git_repository *repo, git_remote *origin, git_reference *local, git_reference *remote, enum remote_transport rt) { git_push_options opts = GIT_PUSH_OPTIONS_INIT; git_strarray refspec; const char *name = git_reference_name(local); refspec.count = 1; refspec.strings = (char **)&name; #if USE_LIBGIT23_API if (rt == RT_SSH) opts.callbacks.credentials = credential_ssh_cb; else if (rt == RT_HTTPS) opts.callbacks.credentials = credential_https_cb; opts.callbacks.certificate_check = certificate_check_cb; #endif if (git_remote_push(origin, &refspec, &opts)) return report_error("Unable to update remote with current local cache state (%s)", giterr_last()->message); return 0; }
/** * Make the repository HEAD directly point to the commit. * * @param commit S4 class git_commit * @return R_NilValue */ SEXP git2r_repository_set_head_detached(SEXP commit) { int err; SEXP sha; git_oid oid; git_commit *treeish = NULL; git_repository *repository = NULL; if (git2r_arg_check_commit(commit)) git2r_error(git2r_err_commit_arg, __func__, "commit"); repository = git2r_repository_open(GET_SLOT(commit, Rf_install("repo"))); if (!repository) git2r_error(git2r_err_invalid_repository, __func__, NULL); sha = GET_SLOT(commit, Rf_install("sha")); err = git_oid_fromstr(&oid, CHAR(STRING_ELT(sha, 0))); if (GIT_OK != err) goto cleanup; err = git_commit_lookup(&treeish, repository, &oid); if (GIT_OK != err) goto cleanup; err = git_repository_set_head_detached( repository, git_commit_id(treeish)); cleanup: if (treeish) git_commit_free(treeish); if (repository) git_repository_free(repository); if (GIT_OK != err) git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message); return R_NilValue; }
void test_filter_crlf__with_safecrlf(void) { git_filter_list *fl; git_filter *crlf; git_buf in = {0}, out = GIT_BUF_INIT; cl_repo_set_bool(g_repo, "core.safecrlf", true); cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_ODB, 0)); crlf = git_filter_lookup(GIT_FILTER_CRLF); cl_assert(crlf != NULL); cl_git_pass(git_filter_list_push(fl, crlf, NULL)); /* Normalized \r\n succeeds with safecrlf */ in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr); /* Mix of line endings fails with safecrlf */ in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_fail(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_i(giterr_last()->klass, GITERR_FILTER); /* Normalized \n is reversible, so does not fail with safecrlf */ in.ptr = "Normal\nLF\nonly\nline-endings.\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s(in.ptr, out.ptr); git_filter_list_free(fl); git_buf_free(&out); }
int luagi_diff_index_to_workdir( lua_State *L ) { git_repository **repo = checkrepo( L, 1 ); git_index **index = checkindex_at( L, 2 ); git_diff_options opts; luagi_diff_init_options( L, 3, &opts ); git_diff **diff = (git_diff **) lua_newuserdata( L, sizeof( git_diff *) ); if( git_diff_index_to_workdir( diff, *repo, *index, &opts ) ) { const git_error *err = giterr_last(); lua_pushnil( L ); lua_pushstring( L, err->message ); return 2; } ltk_setmetatable( L, LUAGI_DIFF_FUNCS ); return 1; }
int do_clone(git_repository *repo, int argc, char **argv) { progress_data pd = {{0}}; git_repository *cloned_repo = NULL; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; const char *url = argv[1]; const char *path = argv[2]; int error; (void)repo; // unused // Validate args if (argc < 3) { printf ("USAGE: %s <url> <path>\n", argv[0]); return -1; } // Set up options checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; checkout_opts.progress_cb = checkout_progress; checkout_opts.progress_payload = &pd; clone_opts.checkout_opts = checkout_opts; clone_opts.fetch_opts.callbacks.sideband_progress = sideband_progress; clone_opts.fetch_opts.callbacks.transfer_progress = &fetch_progress; clone_opts.fetch_opts.callbacks.credentials = cred_acquire_cb; clone_opts.fetch_opts.callbacks.payload = &pd; // Do the clone error = git_clone(&cloned_repo, url, path, &clone_opts); printf("\n"); if (error != 0) { const git_error *err = giterr_last(); if (err) printf("ERROR %d: %s\n", err->klass, err->message); else printf("ERROR %d: no detailed info\n", error); } else if (cloned_repo) git_repository_free(cloned_repo); return error; }
/** * Make the repository HEAD point to the specified reference. * * @param repo S4 class git_repository * @param ref_name Canonical name of the reference the HEAD should point at * @return R_NilValue */ SEXP git2r_repository_set_head(SEXP repo, SEXP ref_name) { int err; git_repository *repository = NULL; if (git2r_arg_check_string(ref_name)) git2r_error(git2r_err_string_arg, __func__, "ref_name"); repository = git2r_repository_open(repo); if (!repository) git2r_error(git2r_err_invalid_repository, __func__, NULL); err = git_repository_set_head(repository, CHAR(STRING_ELT(ref_name, 0))); if (repository) git_repository_free(repository); if (GIT_OK != err) git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message); return R_NilValue; }
/* * call-seq: * Commit.extract_signature(repo, commit, field_name) -> [str, str] * * Returns +commit+'s signature in 'field' and the signed data * * The signature is done over the contents of the commit without the * signature block in the header, which is the data in the second * element in the return array. */ static VALUE rb_git_commit_extract_signature(int argc, VALUE *argv, VALUE self) { int error; VALUE ret; git_oid commit_id; const char *field; git_repository *repo; git_buf signature = {0}, signed_data = {0}; VALUE rb_repo, rb_commit, rb_field = Qnil; rb_scan_args(argc, argv, "21", &rb_repo, &rb_commit, &rb_field); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = git_oid_fromstr(&commit_id, StringValueCStr(rb_commit)); rugged_exception_check(error); field = NIL_P(rb_field) ? NULL : StringValueCStr(rb_field); error = git_commit_extract_signature(&signature, &signed_data, repo, &commit_id, field); if (error < 0) { git_buf_free(&signature); git_buf_free(&signed_data); } if (error == GIT_ENOTFOUND && giterr_last()->klass == GITERR_OBJECT ) { ret = Qnil; } else { rugged_exception_check(error); ret = rb_ary_new3(2, rb_str_new(signature.ptr, signature.size), rb_str_new(signed_data.ptr, signed_data.size)); } git_buf_free(&signature); git_buf_free(&signed_data); return ret; }
static git_repository *create_local_repo(const char *localdir, const char *remote, const char *branch, enum remote_transport rt) { int error; git_repository *cloned_repo = NULL; git_clone_options opts = GIT_CLONE_OPTIONS_INIT; #if USE_LIBGIT23_API opts.fetch_opts.callbacks.transfer_progress = &transfer_progress_cb; if (rt == RT_SSH) opts.fetch_opts.callbacks.credentials = credential_ssh_cb; else if (rt == RT_HTTPS) opts.fetch_opts.callbacks.credentials = credential_https_cb; opts.repository_cb = repository_create_cb; opts.fetch_opts.callbacks.certificate_check = certificate_check_cb; #endif opts.checkout_branch = branch; if (rt == RT_HTTPS && !canReachCloudServer()) return 0; error = git_clone(&cloned_repo, remote, localdir, &opts); if (error) { char *msg = giterr_last()->message; int len = sizeof("Reference 'refs/remotes/origin/' not found") + strlen(branch); char *pattern = malloc(len); snprintf(pattern, len, "Reference 'refs/remotes/origin/%s' not found", branch); if (strstr(remote, prefs.cloud_git_url) && strstr(msg, pattern)) { /* we're trying to open the remote branch that corresponds * to our cloud storage and the branch doesn't exist. * So we need to create the branch and push it to the remote */ cloned_repo = create_and_push_remote(localdir, remote, branch); #if !defined(DEBUG) } else if (strstr(remote, prefs.cloud_git_url)) { report_error(translate("gettextFromC", "Error connecting to Subsurface cloud storage")); #endif } else { report_error(translate("gettextFromC", "git clone of %s failed (%s)"), remote, msg); } free(pattern); } return cloned_repo; }
/** * Remove an existing remote * * All remote-tracking branches and configuration settings for the * remote will be removed. * @param repo S4 class git_repository * @param name The name of the remote to remove * @return R_NilValue */ SEXP git2r_remote_remove(SEXP repo, SEXP name) { int err; git_repository *repository = NULL; if (git2r_arg_check_string(name)) git2r_error(__func__, NULL, "'name'", git2r_err_string_arg); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); err = git_remote_delete(repository, CHAR(STRING_ELT(name, 0))); if (repository) git_repository_free(repository); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return R_NilValue; }
void GitWrapper::initializeGitRepository(QString folder) { GIT_RETURN_IF_DISABLED() QMutexLocker l(&gitMutex); // this is not thread safe, we use locking elsewhere git_repository *repo = NULL; QByteArray ba = folder.toUtf8(); const char *cString = ba.data(); int error = git_repository_init(&repo, cString, false); if (error < 0) { const git_error *e = giterr_last(); kDebug() << e->message; } git_signature *sig = NULL; git_index *index = NULL; git_oid tree_id; git_oid commit_id; git_tree *tree = NULL; // no error handling at the moment git_signature_now(&sig, "AutoGit", "auto@localhost"); git_repository_index(&index, repo); git_index_write_tree(&tree_id, index); git_tree_lookup(&tree, repo, &tree_id); git_commit_create_v(&commit_id, repo, "HEAD", sig, sig, NULL, "Initial commit", tree, 0); git_signature_free(sig); git_index_free(index); git_tree_free(tree); //first commit commitPattern(repo, "*", "Initial full commit"); git_repository_free(repo); }
int luagi_diff_tree_to_tree( lua_State *L ) { git_repository **repo = checkrepo( L, 1 ); git_tree **old_tree = checktree_at( L, 2 ); git_tree **new_tree = checktree_at( L, 3 ); git_diff_options opts; luagi_diff_init_options( L, 4, &opts ); git_diff **diff = (git_diff **) lua_newuserdata( L, sizeof( git_diff *) ); if( git_diff_tree_to_tree( diff, *repo, *old_tree, *new_tree, &opts ) ) { const git_error *err = giterr_last(); lua_pushnil( L ); lua_pushstring( L, err->message ); return 2; } ltk_setmetatable( L, LUAGI_DIFF_FUNCS ); return 1; }
/** * Find repository base path for given path * * @param path A character vector specifying the path to a file or folder * @return R_NilValue if repository cannot be found or * a character vector of length one with path to repository's git dir * e.g. /path/to/my/repo/.git */ SEXP git2r_repository_discover(SEXP path) { int err; SEXP result = R_NilValue; git_buf buf = GIT_BUF_INIT; if (git2r_arg_check_string(path)) git2r_error(git2r_err_string_arg, __func__, "path"); /* note that across_fs (arg #3) is set to 0 so this will stop when * a filesystem device change is detected while exploring parent * directories */ err = git_repository_discover(&buf, CHAR(STRING_ELT(path, 0)), 0, /* const char *ceiling_dirs */ NULL); if (GIT_OK != err) { /* NB just return R_NilValue if we can't discover the repo */ if (GIT_ENOTFOUND == err) err = GIT_OK; goto cleanup; } PROTECT(result = allocVector(STRSXP, 1)); SET_STRING_ELT(result, 0, mkChar(buf.ptr)); cleanup: git_buf_free(&buf); if (R_NilValue != result) UNPROTECT(1); if (GIT_OK != err) git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message); return result; }
void PhysiomeModelRepositoryWindowWindow::cloneWorkspace(const QString &pWorkspace) { // Retrieve the name of an empty directory QString dirName = Core::getExistingDirectory(tr("Select Empty Directory"), QString(), true); if (!dirName.isEmpty()) { // We have got a directory name where we can clone the workspace, so // clone it git_libgit2_init(); git_repository *gitRepository = 0; QByteArray workspaceByteArray = pWorkspace.toUtf8(); QByteArray dirNameByteArray = dirName.toUtf8(); int res = git_clone(&gitRepository, workspaceByteArray.constData(), dirNameByteArray.constData(), 0); if (res) { const git_error *gitError = giterr_last(); QMessageBox::warning(qApp->activeWindow(), tr("Clone Workspace"), gitError? tr("Error %1: %2.").arg(QString::number(gitError->klass), Core::formatMessage(gitError->message)): tr("An error occurred while trying to clone the workspace."), QMessageBox::Ok); } else if (gitRepository) { git_repository_free(gitRepository); } git_libgit2_shutdown(); } }
/** * Check if head of repository is detached * * @param repo S4 class git_repository * @return TRUE if detached else FALSE */ SEXP git2r_repository_head_detached(SEXP repo) { SEXP result; int head_detached; git_repository *repository; repository= git2r_repository_open(repo); if (!repository) git2r_error(git2r_err_invalid_repository, __func__, NULL); head_detached = git_repository_head_detached(repository); git_repository_free(repository); if (head_detached < 0) git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message); PROTECT(result = allocVector(LGLSXP, 1)); if (1 == head_detached) LOGICAL(result)[0] = 1; else LOGICAL(result)[0] = 0; UNPROTECT(1); return result; }
/** * Check if repository is empty. * * @param repo S4 class git_repository * @return TRUE if empty else FALSE */ SEXP git2r_repository_is_empty(SEXP repo) { SEXP result; int is_empty; git_repository *repository; repository= git2r_repository_open(repo); if (!repository) git2r_error(git2r_err_invalid_repository, __func__, NULL); is_empty = git_repository_is_empty(repository); git_repository_free(repository); if (is_empty < 0) git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message); PROTECT(result = allocVector(LGLSXP, 1)); if (1 == is_empty) LOGICAL(result)[0] = 1; else LOGICAL(result)[0] = 0; UNPROTECT(1); return result; }
/** * Find a merge base between two commits * * @param one One of the commits * @param two The other commit * @return The commit of a merge base between 'one' and 'two' * or NULL if not found */ SEXP git2r_merge_base(SEXP one, SEXP two) { int err; SEXP result = R_NilValue; SEXP repo; SEXP sha; git_oid oid; git_oid oid_one; git_oid oid_two; git_commit *commit = NULL; git_repository *repository = NULL; if (git2r_arg_check_commit(one)) git2r_error(__func__, NULL, "'one'", git2r_err_commit_arg); if (git2r_arg_check_commit(two)) git2r_error(__func__, NULL, "'two'", git2r_err_commit_arg); repo = GET_SLOT(one, Rf_install("repo")); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); sha = GET_SLOT(one, Rf_install("sha")); err = git_oid_fromstr(&oid_one, CHAR(STRING_ELT(sha, 0))); if (err) goto cleanup; sha = GET_SLOT(two, Rf_install("sha")); err = git_oid_fromstr(&oid_two, CHAR(STRING_ELT(sha, 0))); if (err) goto cleanup; err = git_merge_base(&oid, repository, &oid_one, &oid_two); if (err) { if (GIT_ENOTFOUND == err) err = GIT_OK; goto cleanup; } err = git_commit_lookup(&commit, repository, &oid); if (err) goto cleanup; PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_commit"))); git2r_commit_init(commit, repo, result); cleanup: if (commit) git_commit_free(commit); if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return result; }
/** * Get the remote's url * * Based on https://github.com/libgit2/libgit2/blob/babdc376c7/examples/network/ls-remote.c * @param repo S4 class git_repository * @param name Character vector with URL of remote. * @return Character vector for each reference with the associated commit IDs. */ SEXP git2r_remote_ls(SEXP name, SEXP repo, SEXP credentials) { const char *name_ = NULL; SEXP result = R_NilValue; SEXP names = R_NilValue; git_remote *remote = NULL; int err; const git_remote_head **refs; size_t refs_len, i; git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; git2r_transfer_data payload = GIT2R_TRANSFER_DATA_INIT; git_repository *repository = NULL; if (git2r_arg_check_string(name)) git2r_error(__func__, NULL, "'name'", git2r_err_string_arg); if (git2r_arg_check_credentials(credentials)) git2r_error(__func__, NULL, "'credentials'", git2r_err_credentials_arg); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); name_ = CHAR(STRING_ELT(name, 0)); err = git_remote_lookup(&remote, repository, name_); if (err) { err = git_remote_create_anonymous(&remote, repository, name_); if (err) goto cleanup; } payload.credentials = credentials; callbacks.payload = &payload; callbacks.credentials = &git2r_cred_acquire_cb; err = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL, NULL); if (err) goto cleanup; err = git_remote_ls(&refs, &refs_len, remote); if (err) goto cleanup; PROTECT(result = allocVector(STRSXP, refs_len)); setAttrib(result, R_NamesSymbol, names = allocVector(STRSXP, refs_len)); for (i = 0; i < refs_len; i++) { char oid[GIT_OID_HEXSZ + 1] = {0}; git_oid_fmt(oid, &refs[i]->oid); SET_STRING_ELT(result, i, mkChar(oid)); SET_STRING_ELT(names, i, mkChar(refs[i]->name)); } cleanup: if (repository) git_repository_free(repository); if (result != R_NilValue) UNPROTECT(1); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return(result); }
/** * Fetch new data and update tips * * @param repo S4 class git_repository * @param name The name of the remote to fetch from * @param credentials The credentials for remote repository access. * @param msg The one line long message to be appended to the reflog * @param verbose Print information each time a reference is updated locally. * @param refspecs The refspecs to use for this fetch. Pass R_NilValue * to use the base refspecs. * @return R_NilValue */ SEXP git2r_remote_fetch( SEXP repo, SEXP name, SEXP credentials, SEXP msg, SEXP verbose, SEXP refspecs) { int err; SEXP result = R_NilValue; const git_transfer_progress *stats; git_remote *remote = NULL; git_repository *repository = NULL; git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; git2r_transfer_data payload = GIT2R_TRANSFER_DATA_INIT; git_strarray refs = {0}; if (git2r_arg_check_string(name)) git2r_error(__func__, NULL, "'name'", git2r_err_string_arg); if (git2r_arg_check_credentials(credentials)) git2r_error(__func__, NULL, "'credentials'", git2r_err_credentials_arg); if (git2r_arg_check_string(msg)) git2r_error(__func__, NULL, "'msg'", git2r_err_string_arg); if (git2r_arg_check_logical(verbose)) git2r_error(__func__, NULL, "'verbose'", git2r_err_logical_arg); if (refspecs != R_NilValue && git2r_arg_check_string_vec(refspecs)) git2r_error(__func__, NULL, "'refspecs'", git2r_err_string_vec_arg); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); err = git_remote_lookup(&remote, repository, CHAR(STRING_ELT(name, 0))); if (err) goto cleanup; if (refspecs != R_NilValue) { size_t i, len; /* Count number of non NA values */ len = length(refspecs); for (i = 0; i < len; i++) if (NA_STRING != STRING_ELT(refspecs, i)) refs.count++; if (refs.count) { /* Allocate the strings in refs */ refs.strings = malloc(refs.count * sizeof(char*)); if (!refs.strings) { giterr_set_str(GITERR_NONE, git2r_err_alloc_memory_buffer); err = GIT_ERROR; goto cleanup; } /* Populate the strings in refs */ for (i = 0; i < refs.count; i++) if (NA_STRING != STRING_ELT(refspecs, i)) refs.strings[i] = (char *)CHAR(STRING_ELT(refspecs, i)); } } if (LOGICAL(verbose)[0]) payload.verbose = 1; payload.credentials = credentials; fetch_opts.callbacks.payload = &payload; fetch_opts.callbacks.credentials = &git2r_cred_acquire_cb; fetch_opts.callbacks.update_tips = &git2r_update_tips_cb; err = git_remote_fetch(remote, &refs, &fetch_opts, CHAR(STRING_ELT(msg, 0))); if (err) goto cleanup; stats = git_remote_stats(remote); PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_transfer_progress"))); git2r_transfer_progress_init(stats, result); cleanup: if (refs.strings) free(refs.strings); if (remote) { if (git_remote_connected(remote)) git_remote_disconnect(remote); git_remote_free(remote); } if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err) git2r_error( __func__, giterr_last(), git2r_err_unable_to_authenticate, NULL); return result; }
int git_path_direach( git_buf *path, uint32_t flags, int (*fn)(void *, git_buf *), void *arg) { int error = 0; ssize_t wd_len; DIR *dir; struct dirent *de; #ifdef GIT_USE_ICONV git_path_iconv_t ic = GIT_PATH_ICONV_INIT; #endif GIT_UNUSED(flags); if (git_path_to_dir(path) < 0) return -1; wd_len = git_buf_len(path); if ((dir = opendir(path->ptr)) == NULL) { giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr); if (errno == ENOENT) return GIT_ENOTFOUND; return -1; } #ifdef GIT_USE_ICONV if ((flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0) (void)git_path_iconv_init_precompose(&ic); #endif while ((de = readdir(dir)) != NULL) { char *de_path = de->d_name; size_t de_len = strlen(de_path); if (git_path_is_dot_or_dotdot(de_path)) continue; #ifdef GIT_USE_ICONV if ((error = git_path_iconv(&ic, &de_path, &de_len)) < 0) break; #endif if ((error = git_buf_put(path, de_path, de_len)) < 0) break; giterr_clear(); error = fn(arg, path); git_buf_truncate(path, wd_len); /* restore path */ /* Only set our own error if the callback did not set one already */ if (error != 0) { if (!giterr_last()) giterr_set_after_callback(error); break; } } closedir(dir); #ifdef GIT_USE_ICONV git_path_iconv_clear(&ic); #endif return error; }
static int _git_ssh_setup_conn( ssh_subtransport *t, const char *url, const char *cmd, git_smart_subtransport_stream **stream) { char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL; const char *default_port="22"; int auth_methods, error = 0; size_t i; ssh_stream *s; git_cred *cred = NULL; LIBSSH2_SESSION* session=NULL; LIBSSH2_CHANNEL* channel=NULL; t->current_stream = NULL; *stream = NULL; if (ssh_stream_alloc(t, url, cmd, stream) < 0) return -1; s = (ssh_stream *)*stream; s->session = NULL; s->channel = NULL; for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) { const char *p = ssh_prefixes[i]; if (!git__prefixcmp(url, p)) { if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0) goto done; goto post_extract; } } if ((error = git_ssh_extract_url_parts(&host, &user, url)) < 0) goto done; port = git__strdup(default_port); GITERR_CHECK_ALLOC(port); post_extract: if ((error = git_socket_stream_new(&s->io, host, port)) < 0 || (error = git_stream_connect(s->io)) < 0) goto done; if ((error = _git_ssh_session_create(&session, s->io)) < 0) goto done; if (t->owner->certificate_check_cb != NULL) { git_cert_hostkey cert = {{ 0 }}, *cert_ptr; const char *key; cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2; key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); if (key != NULL) { cert.type |= GIT_CERT_SSH_SHA1; memcpy(&cert.hash_sha1, key, 20); } key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); if (key != NULL) { cert.type |= GIT_CERT_SSH_MD5; memcpy(&cert.hash_md5, key, 16); } if (cert.type == 0) { giterr_set(GITERR_SSH, "unable to get the host key"); error = -1; goto done; } /* We don't currently trust any hostkeys */ giterr_clear(); cert_ptr = &cert; error = t->owner->certificate_check_cb((git_cert *) cert_ptr, 0, host, t->owner->message_cb_payload); if (error < 0) { if (!giterr_last()) giterr_set(GITERR_NET, "user cancelled hostkey check"); goto done; } } /* we need the username to ask for auth methods */ if (!user) { if ((error = request_creds(&cred, t, NULL, GIT_CREDTYPE_USERNAME)) < 0) goto done; user = git__strdup(((git_cred_username *) cred)->username); cred->free(cred); cred = NULL; if (!user) goto done; } else if (user && pass) { if ((error = git_cred_userpass_plaintext_new(&cred, user, pass)) < 0) goto done; } if ((error = list_auth_methods(&auth_methods, session, user)) < 0) goto done; error = GIT_EAUTH; /* if we already have something to try */ if (cred && auth_methods & cred->credtype) error = _git_ssh_authenticate_session(session, cred); while (error == GIT_EAUTH) { if (cred) { cred->free(cred); cred = NULL; } if ((error = request_creds(&cred, t, user, auth_methods)) < 0) goto done; if (strcmp(user, git_cred__username(cred))) { giterr_set(GITERR_SSH, "username does not match previous request"); error = -1; goto done; } error = _git_ssh_authenticate_session(session, cred); } if (error < 0) goto done; channel = libssh2_channel_open_session(session); if (!channel) { error = -1; ssh_error(session, "Failed to open SSH channel"); goto done; } libssh2_channel_set_blocking(channel, 1); s->session = session; s->channel = channel; t->current_stream = s; done: if (error < 0) { ssh_stream_free(*stream); if (session) libssh2_session_free(session); } if (cred) cred->free(cred); git__free(host); git__free(port); git__free(path); git__free(user); git__free(pass); return error; }
static int _git_ssh_authenticate_session( LIBSSH2_SESSION* session, git_cred* cred) { int rc; do { giterr_clear(); switch (cred->credtype) { case GIT_CREDTYPE_USERPASS_PLAINTEXT: { git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; rc = libssh2_userauth_password(session, c->username, c->password); break; } case GIT_CREDTYPE_SSH_KEY: { git_cred_ssh_key *c = (git_cred_ssh_key *)cred; if (c->privatekey) rc = libssh2_userauth_publickey_fromfile( session, c->username, c->publickey, c->privatekey, c->passphrase); else rc = ssh_agent_auth(session, c); break; } case GIT_CREDTYPE_SSH_CUSTOM: { git_cred_ssh_custom *c = (git_cred_ssh_custom *)cred; rc = libssh2_userauth_publickey( session, c->username, (const unsigned char *)c->publickey, c->publickey_len, c->sign_callback, &c->payload); break; } case GIT_CREDTYPE_SSH_INTERACTIVE: { void **abstract = libssh2_session_abstract(session); git_cred_ssh_interactive *c = (git_cred_ssh_interactive *)cred; /* ideally, we should be able to set this by calling * libssh2_session_init_ex() instead of libssh2_session_init(). * libssh2's API is inconsistent here i.e. libssh2_userauth_publickey() * allows you to pass the `abstract` as part of the call, whereas * libssh2_userauth_keyboard_interactive() does not! * * The only way to set the `abstract` pointer is by calling * libssh2_session_abstract(), which will replace the existing * pointer as is done below. This is safe for now (at time of writing), * but may not be valid in future. */ *abstract = c->payload; rc = libssh2_userauth_keyboard_interactive( session, c->username, c->prompt_callback); break; } #ifdef GIT_SSH_MEMORY_CREDENTIALS case GIT_CREDTYPE_SSH_MEMORY: { git_cred_ssh_key *c = (git_cred_ssh_key *)cred; assert(c->username); assert(c->privatekey); rc = libssh2_userauth_publickey_frommemory( session, c->username, strlen(c->username), c->publickey, c->publickey ? strlen(c->publickey) : 0, c->privatekey, strlen(c->privatekey), c->passphrase); break; } #endif default: rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; } } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); if (rc == LIBSSH2_ERROR_PASSWORD_EXPIRED || rc == LIBSSH2_ERROR_AUTHENTICATION_FAILED) return GIT_EAUTH; if (rc != LIBSSH2_ERROR_NONE) { if (!giterr_last()) ssh_error(session, "Failed to authenticate SSH session"); return -1; } return 0; }
/** * Merge the given fetch head data into HEAD * * @param fetch_heads List of S4 class git_fetch_head objects. * @param merger Who made the merge, if the merge is non-fast forward * merge that creates a merge commit. * @return List of git_annotated_commit objects. */ SEXP git2r_merge_fetch_heads(SEXP fetch_heads, SEXP merger) { int err; size_t n; SEXP result = R_NilValue; git_annotated_commit **merge_heads = NULL; git_repository *repository = NULL; git_signature *who = NULL; if (git2r_arg_check_fetch_heads(fetch_heads)) git2r_error(__func__, NULL, "'fetch_heads'", git2r_err_fetch_heads_arg); if (git2r_arg_check_signature(merger)) git2r_error(__func__, NULL, "'merger'", git2r_err_signature_arg); err = git2r_signature_from_arg(&who, merger); if (err) goto cleanup; n = LENGTH(fetch_heads); if (n) { SEXP repo = GET_SLOT(VECTOR_ELT(fetch_heads, 0), Rf_install("repo")); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); } err = git2r_merge_heads_from_fetch_heads( &merge_heads, repository, fetch_heads, n); if (err) goto cleanup; PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_merge_result"))); err = git2r_merge( result, repository, (const git_annotated_commit **)merge_heads, n, GIT_MERGE_PREFERENCE_NONE, "pull", who, 1); /* Commit on success */ if (err) goto cleanup; cleanup: if (who) git_signature_free(who); if (merge_heads) git2r_merge_heads_free(merge_heads, n); if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return result; }