int git_reference__read_head( git_reference **out, git_repository *repo, const char *path) { git_buf reference = GIT_BUF_INIT; char *name = NULL; int error; if ((error = git_futils_readbuffer(&reference, path)) < 0) goto out; git_buf_rtrim(&reference); if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) { git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF)); name = git_path_basename(path); if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) { error = -1; goto out; } } else { if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0) goto out; } out: git__free(name); git_buf_free(&reference); return error; }
static long diff_context_find( const char *line, long line_len, char *out, long out_size, void *payload) { git_diff_find_context_payload *ctxt = payload; if (git_buf_set(&ctxt->line, line, (size_t)line_len) < 0) return -1; git_buf_rtrim(&ctxt->line); if (!ctxt->line.size) return -1; if (!ctxt->match_line || !ctxt->match_line(ctxt->driver, &ctxt->line)) return -1; if (out_size > (long)ctxt->line.size) out_size = (long)ctxt->line.size; memcpy(out, ctxt->line.ptr, (size_t)out_size); return out_size; }
static int diff_context_line__pattern_match( git_diff_driver *driver, git_buf *line) { size_t i, maxi = git_array_size(driver->fn_patterns); regmatch_t pmatch[2]; for (i = 0; i < maxi; ++i) { git_diff_driver_pattern *pat = git_array_get(driver->fn_patterns, i); if (!regexec(&pat->re, line->ptr, 2, pmatch, 0)) { if (pat->flags & REG_NEGATE) return false; /* use pmatch data to trim line data */ i = (pmatch[1].rm_so >= 0) ? 1 : 0; git_buf_consume(line, git_buf_cstr(line) + pmatch[i].rm_so); git_buf_truncate(line, pmatch[i].rm_eo - pmatch[i].rm_so); git_buf_rtrim(line); return true; } } return false; }
/* * Read the contents of `file_path` and set `path_out` to the repo dir that * it points to. Before calling, set `path_out` to the base directory that * should be used if the contents of `file_path` are a relative path. */ static int read_gitfile(git_buf *path_out, const char *file_path) { int error = 0; git_buf file = GIT_BUF_INIT; size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX); assert(path_out && file_path); if (git_futils_readbuffer(&file, file_path) < 0) return -1; git_buf_rtrim(&file); /* apparently on Windows, some people use backslashes in paths */ git_path_mkposix(file.ptr); if (git_buf_len(&file) <= prefix_len || memcmp(git_buf_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0) { giterr_set(GITERR_REPOSITORY, "The `.git` file at '%s' is malformed", file_path); error = -1; } else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) { const char *gitlink = git_buf_cstr(&file) + prefix_len; while (*gitlink && git__isspace(*gitlink)) gitlink++; error = git_path_prettify_dir( path_out, gitlink, git_buf_cstr(path_out)); } git_buf_free(&file); return error; }
/* * Read the contents of `file_path` and set `path_out` to the repo dir that * it points to. Before calling, set `path_out` to the base directory that * should be used if the contents of `file_path` are a relative path. */ static int read_gitfile(git_buf *path_out, const char *file_path) { int error = 0; git_buf file = GIT_BUF_INIT; size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX); assert(path_out && file_path); if (git_futils_readbuffer(&file, file_path) < 0) return -1; git_buf_rtrim(&file); if (file.size <= prefix_len || memcmp(file.ptr, GIT_FILE_CONTENT_PREFIX, prefix_len) != 0) { giterr_set(GITERR_REPOSITORY, "The `.git` file at '%s' is malformed", file_path); error = -1; } else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) { const char *gitlink = ((const char *)file.ptr) + prefix_len; while (*gitlink && git__isspace(*gitlink)) gitlink++; error = git_path_prettify_dir(path_out, gitlink, path_out->ptr); } git_buf_free(&file); return error; }
GIT_INLINE(int) rebase_readfile( git_buf *out, git_buf *state_path, const char *filename) { size_t state_path_len = state_path->size; int error; git_buf_clear(out); if ((error = git_buf_joinpath(state_path, state_path->ptr, filename)) < 0 || (error = git_futils_readbuffer(out, state_path->ptr)) < 0) goto done; git_buf_rtrim(out); done: git_buf_truncate(state_path, state_path_len); return error; }
static int parse_header_path_buf(git_buf *path, git_patch_parse_ctx *ctx, size_t path_len) { int error; if ((error = git_buf_put(path, ctx->parse_ctx.line, path_len)) < 0) goto done; git_parse_advance_chars(&ctx->parse_ctx, path_len); git_buf_rtrim(path); if (path->size > 0 && path->ptr[0] == '"') error = git_buf_unquote(path); if (error < 0) goto done; git_path_squash_slashes(path); done: return error; }
/* rewrite gitmodules -> .gitmodules * rewrite the empty or relative urls inside each module * rename the .gitted directory inside any submodule to .git */ void rewrite_gitmodules(const char *workdir) { git_buf in_f = GIT_BUF_INIT, out_f = GIT_BUF_INIT, path = GIT_BUF_INIT; FILE *in, *out; char line[256]; cl_git_pass(git_buf_joinpath(&in_f, workdir, "gitmodules")); cl_git_pass(git_buf_joinpath(&out_f, workdir, ".gitmodules")); cl_assert((in = fopen(in_f.ptr, "rb")) != NULL); cl_assert((out = fopen(out_f.ptr, "wb")) != NULL); while (fgets(line, sizeof(line), in) != NULL) { char *scan = line; while (*scan == ' ' || *scan == '\t') scan++; /* rename .gitted -> .git in submodule directories */ if (git__prefixcmp(scan, "path =") == 0) { scan += strlen("path ="); while (*scan == ' ') scan++; git_buf_joinpath(&path, workdir, scan); git_buf_rtrim(&path); git_buf_joinpath(&path, path.ptr, ".gitted"); if (!git_buf_oom(&path) && p_access(path.ptr, F_OK) == 0) { git_buf_joinpath(&out_f, workdir, scan); git_buf_rtrim(&out_f); git_buf_joinpath(&out_f, out_f.ptr, ".git"); if (!git_buf_oom(&out_f)) p_rename(path.ptr, out_f.ptr); } } /* copy non-"url =" lines verbatim */ if (git__prefixcmp(scan, "url =") != 0) { fputs(line, out); continue; } /* convert relative URLs in "url =" lines */ scan += strlen("url ="); while (*scan == ' ') scan++; if (*scan == '.') { git_buf_joinpath(&path, workdir, scan); git_buf_rtrim(&path); } else if (!*scan || *scan == '\n') { git_buf_joinpath(&path, workdir, "../testrepo.git"); } else { fputs(line, out); continue; } git_path_prettify(&path, path.ptr, NULL); git_buf_putc(&path, '\n'); cl_assert(!git_buf_oom(&path)); fwrite(line, scan - line, sizeof(char), out); fputs(path.ptr, out); } fclose(in); fclose(out); cl_must_pass(p_unlink(in_f.ptr)); git_buf_free(&in_f); git_buf_free(&out_f); git_buf_free(&path); }
int git_rebase_open( git_rebase **out, git_repository *repo, const git_rebase_options *given_opts) { git_rebase *rebase; git_buf path = GIT_BUF_INIT, orig_head_name = GIT_BUF_INIT, orig_head_id = GIT_BUF_INIT, onto_id = GIT_BUF_INIT; int state_path_len, error; assert(repo); if ((error = rebase_check_versions(given_opts)) < 0) return error; if (rebase_alloc(&rebase, given_opts) < 0) return -1; rebase->repo = repo; if ((error = rebase_state_type(&rebase->type, &rebase->state_path, repo)) < 0) goto done; if (rebase->type == GIT_REBASE_TYPE_NONE) { giterr_set(GITERR_REBASE, "There is no rebase in progress"); error = GIT_ENOTFOUND; goto done; } if ((error = git_buf_puts(&path, rebase->state_path)) < 0) goto done; state_path_len = git_buf_len(&path); if ((error = git_buf_joinpath(&path, path.ptr, HEAD_NAME_FILE)) < 0 || (error = git_futils_readbuffer(&orig_head_name, path.ptr)) < 0) goto done; git_buf_rtrim(&orig_head_name); if (strcmp(ORIG_DETACHED_HEAD, orig_head_name.ptr) == 0) rebase->head_detached = 1; git_buf_truncate(&path, state_path_len); if ((error = git_buf_joinpath(&path, path.ptr, ORIG_HEAD_FILE)) < 0) goto done; if (!git_path_isfile(path.ptr)) { /* Previous versions of git.git used 'head' here; support that. */ git_buf_truncate(&path, state_path_len); if ((error = git_buf_joinpath(&path, path.ptr, HEAD_FILE)) < 0) goto done; } if ((error = git_futils_readbuffer(&orig_head_id, path.ptr)) < 0) goto done; git_buf_rtrim(&orig_head_id); if ((error = git_oid_fromstr(&rebase->orig_head_id, orig_head_id.ptr)) < 0) goto done; git_buf_truncate(&path, state_path_len); if ((error = git_buf_joinpath(&path, path.ptr, ONTO_FILE)) < 0 || (error = git_futils_readbuffer(&onto_id, path.ptr)) < 0) goto done; git_buf_rtrim(&onto_id); if ((error = git_oid_fromstr(&rebase->onto_id, onto_id.ptr)) < 0) goto done; if (!rebase->head_detached) rebase->orig_head_name = git_buf_detach(&orig_head_name); switch (rebase->type) { case GIT_REBASE_TYPE_INTERACTIVE: giterr_set(GITERR_REBASE, "Interactive rebase is not supported"); error = -1; break; case GIT_REBASE_TYPE_MERGE: error = rebase_open_merge(rebase); break; case GIT_REBASE_TYPE_APPLY: giterr_set(GITERR_REBASE, "Patch application rebase is not supported"); error = -1; break; default: abort(); } done: if (error == 0) *out = rebase; else git_rebase_free(rebase); git_buf_free(&path); git_buf_free(&orig_head_name); git_buf_free(&orig_head_id); git_buf_free(&onto_id); return error; }
int git_stash_save( git_oid *out, git_repository *repo, const git_signature *stasher, const char *message, uint32_t flags) { git_index *index = NULL; git_commit *b_commit = NULL, *i_commit = NULL, *u_commit = NULL; git_buf msg = GIT_BUF_INIT; int error; assert(out && repo && stasher); if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0) return error; if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0) goto cleanup; if ((error = ensure_there_are_changes_to_stash( repo, (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0, (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0) goto cleanup; if ((error = git_repository_index(&index, repo)) < 0) goto cleanup; if ((error = commit_index( &i_commit, index, stasher, git_buf_cstr(&msg), b_commit)) < 0) goto cleanup; if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) && (error = commit_untracked( &u_commit, index, stasher, git_buf_cstr(&msg), i_commit, flags)) < 0) goto cleanup; if ((error = prepare_worktree_commit_message(&msg, message)) < 0) goto cleanup; if ((error = commit_worktree( out, index, stasher, git_buf_cstr(&msg), i_commit, b_commit, u_commit)) < 0) goto cleanup; git_buf_rtrim(&msg); if ((error = update_reflog(out, repo, stasher, git_buf_cstr(&msg))) < 0) goto cleanup; if ((error = reset_index_and_workdir( repo, ((flags & GIT_STASH_KEEP_INDEX) != 0) ? i_commit : b_commit, (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0)) < 0) goto cleanup; cleanup: git_buf_free(&msg); git_commit_free(i_commit); git_commit_free(b_commit); git_commit_free(u_commit); git_index_free(index); return error; }