| /* |
| * Utilities library for libgit2 examples |
| * |
| * Written by the libgit2 contributors |
| * |
| * To the extent possible under law, the author(s) have dedicated all copyright |
| * and related and neighboring rights to this software to the public domain |
| * worldwide. This software is distributed without any warranty. |
| * |
| * You should have received a copy of the CC0 Public Domain Dedication along |
| * with this software. If not, see |
| * <http://creativecommons.org/publicdomain/zero/1.0/>. |
| */ |
| |
| |
| #include "common.h" |
| |
| #ifndef _WIN32 |
| # include <unistd.h> |
| #endif |
| #include <errno.h> |
| |
| void check_lg2(int error, const char *message, const char *extra) |
| { |
| const git_error *lg2err; |
| const char *lg2msg = "", *lg2spacer = ""; |
| |
| if (!error) |
| return; |
| |
| if ((lg2err = git_error_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); |
| |
| exit(1); |
| } |
| |
| void fatal(const char *message, const char *extra) |
| { |
| if (extra) |
| fprintf(stderr, "%s %s\n", message, extra); |
| else |
| fprintf(stderr, "%s\n", message); |
| |
| exit(1); |
| } |
| |
| int diff_output( |
| const git_diff_delta *d, |
| const git_diff_hunk *h, |
| const git_diff_line *l, |
| void *p) |
| { |
| FILE *fp = (FILE*)p; |
| |
| (void)d; (void)h; |
| |
| if (!fp) |
| fp = stdout; |
| |
| if (l->origin == GIT_DIFF_LINE_CONTEXT || |
| l->origin == GIT_DIFF_LINE_ADDITION || |
| l->origin == GIT_DIFF_LINE_DELETION) |
| fputc(l->origin, fp); |
| |
| fwrite(l->content, 1, l->content_len, fp); |
| |
| return 0; |
| } |
| |
| void treeish_to_tree( |
| git_tree **out, git_repository *repo, const char *treeish) |
| { |
| git_object *obj = NULL; |
| |
| check_lg2( |
| git_revparse_single(&obj, repo, treeish), |
| "looking up object", treeish); |
| |
| check_lg2( |
| git_object_peel((git_object **)out, obj, GIT_OBJECT_TREE), |
| "resolving object to tree", treeish); |
| |
| git_object_free(obj); |
| } |
| |
| void *xrealloc(void *oldp, size_t newsz) |
| { |
| void *p = realloc(oldp, newsz); |
| if (p == NULL) { |
| fprintf(stderr, "Cannot allocate memory, exiting.\n"); |
| exit(1); |
| } |
| return p; |
| } |
| |
| int resolve_refish(git_annotated_commit **commit, git_repository *repo, const char *refish) |
| { |
| git_reference *ref; |
| git_object *obj; |
| int err = 0; |
| |
| assert(commit != NULL); |
| |
| err = git_reference_dwim(&ref, repo, refish); |
| if (err == GIT_OK) { |
| git_annotated_commit_from_ref(commit, repo, ref); |
| git_reference_free(ref); |
| return 0; |
| } |
| |
| err = git_revparse_single(&obj, repo, refish); |
| if (err == GIT_OK) { |
| err = git_annotated_commit_lookup(commit, repo, git_object_id(obj)); |
| git_object_free(obj); |
| } |
| |
| return err; |
| } |
| |
| static int readline(char **out) |
| { |
| int c, error = 0, length = 0, allocated = 0; |
| char *line = NULL; |
| |
| errno = 0; |
| |
| while ((c = getchar()) != EOF) { |
| if (length == allocated) { |
| allocated += 16; |
| |
| if ((line = realloc(line, allocated)) == NULL) { |
| error = -1; |
| goto error; |
| } |
| } |
| |
| if (c == '\n') |
| break; |
| |
| line[length++] = c; |
| } |
| |
| if (errno != 0) { |
| error = -1; |
| goto error; |
| } |
| |
| line[length] = '\0'; |
| *out = line; |
| line = NULL; |
| error = length; |
| error: |
| free(line); |
| return error; |
| } |
| |
| static int ask(char **out, const char *prompt, char optional) |
| { |
| printf("%s ", prompt); |
| fflush(stdout); |
| |
| if (!readline(out) && !optional) { |
| fprintf(stderr, "Could not read response: %s", strerror(errno)); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int cred_acquire_cb(git_credential **out, |
| const char *url, |
| const char *username_from_url, |
| unsigned int allowed_types, |
| void *payload) |
| { |
| char *username = NULL, *password = NULL, *privkey = NULL, *pubkey = NULL; |
| int error = 1; |
| |
| UNUSED(url); |
| UNUSED(payload); |
| |
| if (username_from_url) { |
| if ((username = strdup(username_from_url)) == NULL) |
| goto out; |
| } else if ((error = ask(&username, "Username:", 0)) < 0) { |
| goto out; |
| } |
| |
| if (allowed_types & GIT_CREDENTIAL_SSH_KEY) { |
| int n; |
| |
| if ((error = ask(&privkey, "SSH Key:", 0)) < 0 || |
| (error = ask(&password, "Password:", 1)) < 0) |
| goto out; |
| |
| if ((n = snprintf(NULL, 0, "%s.pub", privkey)) < 0 || |
| (pubkey = malloc(n + 1)) == NULL || |
| (n = snprintf(pubkey, n + 1, "%s.pub", privkey)) < 0) |
| goto out; |
| |
| error = git_credential_ssh_key_new(out, username, pubkey, privkey, password); |
| } else if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) { |
| if ((error = ask(&password, "Password:", 1)) < 0) |
| goto out; |
| |
| error = git_credential_userpass_plaintext_new(out, username, password); |
| } else if (allowed_types & GIT_CREDENTIAL_USERNAME) { |
| error = git_credential_username_new(out, username); |
| } |
| |
| out: |
| free(username); |
| free(password); |
| free(privkey); |
| free(pubkey); |
| return error; |
| } |
| |
| char *read_file(const char *path) |
| { |
| ssize_t total = 0; |
| char *buf = NULL; |
| struct stat st; |
| int fd = -1; |
| |
| if ((fd = open(path, O_RDONLY)) < 0 || fstat(fd, &st) < 0) |
| goto out; |
| |
| if ((buf = malloc(st.st_size + 1)) == NULL) |
| goto out; |
| |
| while (total < st.st_size) { |
| ssize_t bytes = read(fd, buf + total, st.st_size - total); |
| if (bytes <= 0) { |
| if (errno == EAGAIN || errno == EINTR) |
| continue; |
| free(buf); |
| buf = NULL; |
| goto out; |
| } |
| total += bytes; |
| } |
| |
| buf[total] = '\0'; |
| |
| out: |
| if (fd >= 0) |
| close(fd); |
| return buf; |
| } |
| |