const char *git_commit_summary(git_commit *commit) { git_buf summary = GIT_BUF_INIT; const char *msg, *space; assert(commit); if (!commit->summary) { for (msg = git_commit_message(commit), space = NULL; *msg; ++msg) { if (msg[0] == '\n' && (!msg[1] || msg[1] == '\n')) break; else if (msg[0] == '\n') git_buf_putc(&summary, ' '); else if (git__isspace(msg[0])) space = space ? space : msg; else if (space) { git_buf_put(&summary, space, (msg - space) + 1); space = NULL; } else git_buf_putc(&summary, *msg); } commit->summary = git_buf_detach(&summary); if (!commit->summary) commit->summary = git__strdup(""); } return commit->summary; }
int git_pkt_buffer_wants(const git_vector *refs, git_transport_caps *caps, git_buf *buf) { unsigned int i = 0; git_remote_head *head; if (caps->common) { for (; i < refs->length; ++i) { head = refs->contents[i]; if (!head->local) break; } if (buffer_want_with_caps(refs->contents[i], caps, buf) < 0) return -1; i++; } for (; i < refs->length; ++i) { char oid[GIT_OID_HEXSZ]; head = refs->contents[i]; if (head->local) continue; git_oid_fmt(oid, &head->oid); git_buf_put(buf, pkt_want_prefix, strlen(pkt_want_prefix)); git_buf_put(buf, oid, GIT_OID_HEXSZ); git_buf_putc(buf, '\n'); if (git_buf_oom(buf)) return -1; } return git_pkt_buffer_flush(buf); }
int git__percent_decode(git_buf *decoded_out, const char *input) { int len, hi, lo, i; assert(decoded_out && input); len = (int)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: if (git_buf_putc(decoded_out, c) < 0) return -1; } return 0; }
static int diriter_update_paths(git_path_diriter *diriter) { size_t filename_len, path_len; filename_len = wcslen(diriter->current.cFileName); if (GIT_ADD_SIZET_OVERFLOW(&path_len, diriter->parent_len, filename_len) || GIT_ADD_SIZET_OVERFLOW(&path_len, path_len, 2)) return -1; if (path_len > GIT_WIN_PATH_UTF16) { giterr_set(GITERR_FILESYSTEM, "invalid path '%.*ls\\%ls' (path too long)", diriter->parent_len, diriter->path, diriter->current.cFileName); return -1; } diriter->path[diriter->parent_len] = L'\\'; memcpy(&diriter->path[diriter->parent_len+1], diriter->current.cFileName, filename_len * sizeof(wchar_t)); diriter->path[path_len-1] = L'\0'; git_buf_truncate(&diriter->path_utf8, diriter->parent_utf8_len); git_buf_putc(&diriter->path_utf8, '/'); git_buf_put_w(&diriter->path_utf8, diriter->current.cFileName, filename_len); if (git_buf_oom(&diriter->path_utf8)) return -1; return 0; }
static int write_tag_annotation( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, const git_signature *tagger, const char *message) { git_buf tag = GIT_BUF_INIT; git_odb *odb; git_oid__writebuf(&tag, "object ", git_object_id(target)); git_buf_printf(&tag, "type %s\n", git_object_type2string(git_object_type(target))); git_buf_printf(&tag, "tag %s\n", tag_name); git_signature__writebuf(&tag, "tagger ", tagger); git_buf_putc(&tag, '\n'); if (git_buf_puts(&tag, message) < 0) goto on_error; if (git_repository_odb__weakptr(&odb, repo) < 0) goto on_error; if (git_odb_write(oid, odb, tag.ptr, tag.size, GIT_OBJ_TAG) < 0) goto on_error; git_buf_free(&tag); return 0; on_error: git_buf_free(&tag); giterr_set(GITERR_OBJECT, "Failed to create tag annotation."); return -1; }
static int ident_insert_id( git_buf *to, const git_buf *from, const git_filter_source *src) { char oid[GIT_OID_HEXSZ+1]; const char *id_start, *id_end, *from_end = from->ptr + from->size; size_t need_size; /* replace $Id$ with blob id */ if (!git_filter_source_id(src)) return GIT_PASSTHROUGH; git_oid_tostr(oid, sizeof(oid), git_filter_source_id(src)); if (ident_find_id(&id_start, &id_end, from->ptr, from->size) < 0) return GIT_PASSTHROUGH; need_size = (size_t)(id_start - from->ptr) + 5 /* "$Id: " */ + GIT_OID_HEXSZ + 1 /* "$" */ + (size_t)(from_end - id_end); if (git_buf_grow(to, need_size) < 0) return -1; git_buf_set(to, from->ptr, (size_t)(id_start - from->ptr)); git_buf_put(to, "$Id: ", 5); git_buf_put(to, oid, GIT_OID_HEXSZ); git_buf_putc(to, '$'); git_buf_put(to, id_end, (size_t)(from_end - id_end)); return git_buf_oom(to) ? -1 : 0; }
/* * Create a git protocol request. * * For example: git-upload-pack '/libgit2/libgit2' */ static int gen_proto(git_buf *request, const char *cmd, const char *url) { char *repo; int len; if (!git__prefixcmp(url, prefix_ssh)) { url = url + strlen(prefix_ssh); repo = strchr(url, '/'); } else { repo = strchr(url, ':'); if (repo) repo++; } if (!repo) { giterr_set(GITERR_NET, "Malformed git protocol URL"); return -1; } len = strlen(cmd) + 1 /* Space */ + 1 /* Quote */ + strlen(repo) + 1 /* Quote */ + 1; git_buf_grow(request, len); git_buf_printf(request, "%s '%s'", cmd, repo); git_buf_putc(request, '\0'); if (git_buf_oom(request)) return -1; return 0; }
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; }
/* * Create a git protocol request. * * For example: 0035git-upload-pack /libgit2/libgit2\0host=github.com\0 */ static int gen_proto(git_buf *request, const char *cmd, const char *url) { char *delim, *repo; char host[] = "host="; size_t len; delim = strchr(url, '/'); if (delim == NULL) { giterr_set(GITERR_NET, "Malformed URL"); return -1; } repo = delim; delim = strchr(url, ':'); if (delim == NULL) delim = strchr(url, '/'); len = 4 + strlen(cmd) + 1 + strlen(repo) + 1 + strlen(host) + (delim - url) + 1; git_buf_grow(request, len); git_buf_printf(request, "%04x%s %s%c%s", (unsigned int)(len & 0x0FFFF), cmd, repo, 0, host); git_buf_put(request, url, delim - url); git_buf_putc(request, '\0'); if (git_buf_oom(request)) return -1; return 0; }
static void create_paths(const char *root, int depth) { git_buf fullpath = GIT_BUF_INIT; size_t root_len; int i; cl_git_pass(git_buf_puts(&fullpath, root)); cl_git_pass(git_buf_putc(&fullpath, '/')); root_len = fullpath.size; for (i = 0; i < 8; i++) { bool file = (depth == 0 || (i % 2) == 0); git_buf_truncate(&fullpath, root_len); cl_git_pass(git_buf_printf(&fullpath, "item%d", i)); if (file) { cl_git_rewritefile(fullpath.ptr, "This is a file!\n"); } else { cl_must_pass(p_mkdir(fullpath.ptr, 0777)); if (depth > 0) create_paths(fullpath.ptr, (depth - 1)); } } git_buf_dispose(&fullpath); }
int git_commit_header_field(git_buf *out, const git_commit *commit, const char *field) { const char *eol, *buf = commit->raw_header; git_buf_clear(out); while ((eol = strchr(buf, '\n'))) { /* We can skip continuations here */ if (buf[0] == ' ') { buf = eol + 1; continue; } /* Skip until we find the field we're after */ if (git__prefixcmp(buf, field)) { buf = eol + 1; continue; } buf += strlen(field); /* Check that we're not matching a prefix but the field itself */ if (buf[0] != ' ') { buf = eol + 1; continue; } buf++; /* skip the SP */ git_buf_put(out, buf, eol - buf); if (git_buf_oom(out)) goto oom; /* If the next line starts with SP, it's multi-line, we must continue */ while (eol[1] == ' ') { git_buf_putc(out, '\n'); buf = eol + 2; eol = strchr(buf, '\n'); if (!eol) goto malformed; git_buf_put(out, buf, eol - buf); } if (git_buf_oom(out)) goto oom; return 0; } giterr_set(GITERR_OBJECT, "no such field '%s'", field); return GIT_ENOTFOUND; malformed: giterr_set(GITERR_OBJECT, "malformed header"); return -1; oom: giterr_set_oom(); return -1; }
static int read_variable_cb( git_config_parser *reader, const char *current_section, const char *var_name, const char *var_value, const char *line, size_t line_len, void *payload) { config_memory_parse_data *parse_data = (config_memory_parse_data *) payload; git_buf buf = GIT_BUF_INIT; git_config_entry *entry; const char *c; int result; GIT_UNUSED(reader); GIT_UNUSED(line); GIT_UNUSED(line_len); if (current_section) { /* TODO: Once warnings land, we should likely warn * here. Git appears to warn in most cases if it sees * un-namespaced config options. */ git_buf_puts(&buf, current_section); git_buf_putc(&buf, '.'); } for (c = var_name; *c; c++) git_buf_putc(&buf, git__tolower(*c)); if (git_buf_oom(&buf)) return -1; entry = git__calloc(1, sizeof(git_config_entry)); GITERR_CHECK_ALLOC(entry); entry->name = git_buf_detach(&buf); entry->value = var_value ? git__strdup(var_value) : NULL; entry->level = parse_data->level; entry->include_depth = 0; if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) return result; return result; }
const char* cl_git_path_url(const char *path) { static char url[4096]; const char *in_buf; git_buf path_buf = GIT_BUF_INIT; git_buf url_buf = GIT_BUF_INIT; cl_git_pass(git_path_prettify_dir(&path_buf, path, NULL)); cl_git_pass(git_buf_puts(&url_buf, "file://")); #ifdef GIT_WIN32 /* * A FILE uri matches the following format: file://[host]/path * where "host" can be empty and "path" is an absolute path to the resource. * * In this test, no hostname is used, but we have to ensure the leading triple slashes: * * *nix: file:///usr/home/... * Windows: file:///C:/Users/... */ cl_git_pass(git_buf_putc(&url_buf, '/')); #endif in_buf = git_buf_cstr(&path_buf); /* * A very hacky Url encoding that only takes care of escaping the spaces */ while (*in_buf) { if (*in_buf == ' ') cl_git_pass(git_buf_puts(&url_buf, "%20")); else cl_git_pass(git_buf_putc(&url_buf, *in_buf)); in_buf++; } cl_assert(url_buf.size < 4096); strncpy(url, git_buf_cstr(&url_buf), 4096); git_buf_free(&url_buf); git_buf_free(&path_buf); return url; }
void test_win32_longpath__initialize(void) { #ifdef GIT_WIN32 const char *base = clar_sandbox_path(); size_t base_len = strlen(base); size_t remain = MAX_PATH - base_len; size_t i; git_buf_clear(&path); git_buf_puts(&path, base); git_buf_putc(&path, '/'); cl_assert(remain < (MAX_PATH - 5)); for (i = 0; i < (remain - 5); i++) git_buf_putc(&path, 'a'); #endif }
int git_path_to_dir(git_buf *path) { if (path->asize > 0 && git_buf_len(path) > 0 && path->ptr[git_buf_len(path) - 1] != '/') git_buf_putc(path, '/'); return git_buf_oom(path) ? -1 : 0; }
int git_path_to_dir(git_buf *path) { if (path->asize > 0 && path->size > 0 && path->ptr[path->size - 1] != '/') git_buf_putc(path, '/'); return git_buf_lasterror(path); }
/** * Append to 'out' properly marking continuations when there's a newline in 'content' */ static void format_header_field(git_buf *out, const char *field, const char *content) { const char *lf; assert(out && field && content); git_buf_puts(out, field); git_buf_putc(out, ' '); while ((lf = strchr(content, '\n')) != NULL) { git_buf_put(out, content, lf - content); git_buf_puts(out, "\n "); content = lf + 1; } git_buf_puts(out, content); git_buf_putc(out, '\n'); }
const char *git_commit_summary(git_commit *commit) { git_buf summary = GIT_BUF_INIT; const char *msg, *space; bool space_contains_newline = false; assert(commit); if (!commit->summary) { for (msg = git_commit_message(commit), space = NULL; *msg; ++msg) { char next_character = msg[0]; /* stop processing at the end of the first paragraph */ if (next_character == '\n' && (!msg[1] || msg[1] == '\n')) break; /* record the beginning of contiguous whitespace runs */ else if (git__isspace(next_character)) { if(space == NULL) { space = msg; space_contains_newline = false; } space_contains_newline |= next_character == '\n'; } /* the next character is non-space */ else { /* process any recorded whitespace */ if (space) { if(space_contains_newline) git_buf_putc(&summary, ' '); /* if the space contains a newline, collapse to ' ' */ else git_buf_put(&summary, space, (msg - space)); /* otherwise copy it */ space = NULL; } /* copy the next character */ git_buf_putc(&summary, next_character); } } commit->summary = git_buf_detach(&summary); if (!commit->summary) commit->summary = git__strdup(""); } return commit->summary; }
/* * 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 is_prefix = 0, 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--; if ((len = win32_prefix_length(path, endp - path + 1)) > 0) { is_prefix = 1; goto Exit; } /* 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 == '/'); if ((len = win32_prefix_length(path, endp - path + 1)) > 0) { is_prefix = 1; goto Exit; } /* Cast is safe because max path < max int */ len = (int)(endp - path + 1); Exit: if (buffer) { if (git_buf_set(buffer, path, len) < 0) return -1; if (is_prefix && git_buf_putc(buffer, '/') < 0) return -1; } return len; }
int git_commit_header_field(git_buf *out, const git_commit *commit, const char *field) { const char *buf = commit->raw_header; const char *h, *eol; git_buf_sanitize(out); while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') { h++; if (git__prefixcmp(h, field)) { buf = h; continue; } h += strlen(field); eol = strchr(h, '\n'); if (h[0] != ' ') { buf = h; continue; } if (!eol) goto malformed; h++; /* skip the SP */ git_buf_put(out, h, eol - h); if (git_buf_oom(out)) goto oom; /* If the next line starts with SP, it's multi-line, we must continue */ while (eol[1] == ' ') { git_buf_putc(out, '\n'); h = eol + 2; eol = strchr(h, '\n'); if (!eol) goto malformed; git_buf_put(out, h, eol - h); } if (git_buf_oom(out)) goto oom; return 0; } return GIT_ENOTFOUND; malformed: giterr_set(GITERR_OBJECT, "malformed header"); return -1; oom: giterr_set_oom(); return -1; }
int git_refspec__serialize(git_buf *out, const git_refspec *refspec) { if (refspec->force) git_buf_putc(out, '+'); git_buf_printf(out, "%s:%s", refspec->src != NULL ? refspec->src : "", refspec->dst != NULL ? refspec->dst : ""); return git_buf_oom(out) == false; }
int git_commit_create( git_oid *oid, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_tree *tree, int parent_count, const git_commit *parents[]) { git_buf commit = GIT_BUF_INIT; int i; git_odb *odb; assert(git_object_owner((const git_object *)tree) == repo); git_oid__writebuf(&commit, "tree ", git_object_id((const git_object *)tree)); for (i = 0; i < parent_count; ++i) { assert(git_object_owner((const git_object *)parents[i]) == repo); git_oid__writebuf(&commit, "parent ", git_object_id((const git_object *)parents[i])); } git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); if (message_encoding != NULL) git_buf_printf(&commit, "encoding %s\n", message_encoding); git_buf_putc(&commit, '\n'); if (git_buf_puts(&commit, message) < 0) goto on_error; if (git_repository_odb__weakptr(&odb, repo) < 0) goto on_error; if (git_odb_write(oid, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT) < 0) goto on_error; git_buf_free(&commit); if (update_ref != NULL) return git_reference__update(repo, oid, update_ref); return 0; on_error: git_buf_free(&commit); giterr_set(GITERR_OBJECT, "Failed to create commit."); return -1; }
static void build_local_file_url(git_buf *out, const char *fixture) { const char *in_buf; git_buf path_buf = GIT_BUF_INIT; cl_git_pass(git_path_prettify_dir(&path_buf, fixture, NULL)); cl_git_pass(git_buf_puts(out, "file://")); #ifdef _MSC_VER /* * A FILE uri matches the following format: file://[host]/path * where "host" can be empty and "path" is an absolute path to the resource. * * In this test, no hostname is used, but we have to ensure the leading triple slashes: * * *nix: file:///usr/home/... * Windows: file:///C:/Users/... */ cl_git_pass(git_buf_putc(out, '/')); #endif in_buf = git_buf_cstr(&path_buf); /* * A very hacky Url encoding that only takes care of escaping the spaces */ while (*in_buf) { if (*in_buf == ' ') cl_git_pass(git_buf_puts(out, "%20")); else cl_git_pass(git_buf_putc(out, *in_buf)); in_buf++; } git_buf_free(&path_buf); }
static int user_agent(git_buf *ua) { const char *custom = git_libgit2__user_agent(); git_buf_clear(ua); git_buf_PUTS(ua, "git/1.0 ("); if (custom) git_buf_puts(ua, custom); else git_buf_PUTS(ua, "libgit2 " LIBGIT2_VERSION); return git_buf_putc(ua, ')'); }
static int append_commit_description(git_buf *out, git_commit* commit) { const char *message; size_t pos = 0, len; if (append_abbreviated_oid(out, git_commit_id(commit)) < 0) return -1; message = git_commit_message(commit); len = strlen(message); /* TODO: Replace with proper commit short message * when git_commit_message_short() is implemented. */ while (pos < len && message[pos] != '\n') pos++; git_buf_putc(out, ' '); git_buf_put(out, message, pos); git_buf_putc(out, '\n'); return git_buf_oom(out) ? -1 : 0; }
/* see https://github.com/git/git/blob/497215d8811ac7b8955693ceaad0899ecd894ed2/builtin/stripspace.c#L4-67 */ int git_message__prettify(git_buf *message_out, const char *message, int strip_comments) { const size_t message_len = strlen(message); int consecutive_empty_lines = 0; size_t i, line_length, rtrimmed_line_length; char *next_newline; for (i = 0; i < strlen(message); i += line_length) { next_newline = memchr(message + i, '\n', message_len - i); if (next_newline != NULL) { line_length = next_newline - (message + i) + 1; } else { line_length = message_len - i; } if (strip_comments && line_length && message[i] == '#') continue; rtrimmed_line_length = line_length_without_trailing_spaces(message + i, line_length); if (!rtrimmed_line_length) { consecutive_empty_lines++; continue; } if (consecutive_empty_lines > 0 && message_out->size > 0) git_buf_putc(message_out, '\n'); consecutive_empty_lines = 0; git_buf_put(message_out, message + i, rtrimmed_line_length); git_buf_putc(message_out, '\n'); } return git_buf_oom(message_out) ? -1 : 0; }
static char *tree_iterator__current_filename( tree_iterator *ti, const git_tree_entry *te) { if (!ti->path_has_filename) { if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0) return NULL; if (git_tree_entry__is_tree(te) && git_buf_putc(&ti->path, '/') < 0) return NULL; ti->path_has_filename = true; } return ti->path.ptr; }
int git_path_diriter_next(git_path_diriter *diriter) { struct dirent *de; const char *filename; size_t filename_len; bool skip_dot = !(diriter->flags & GIT_PATH_DIR_INCLUDE_DOT_AND_DOTDOT); int error = 0; assert(diriter); errno = 0; do { if ((de = readdir(diriter->dir)) == NULL) { if (!errno) return GIT_ITEROVER; giterr_set(GITERR_OS, "Could not read directory '%s'", diriter->path); return -1; } } while (skip_dot && git_path_is_dot_or_dotdot(de->d_name)); filename = de->d_name; filename_len = strlen(filename); #ifdef GIT_USE_ICONV if ((diriter->flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0 && (error = git_path_iconv(&diriter->ic, &filename, &filename_len)) < 0) return error; #endif git_buf_truncate(&diriter->path, diriter->parent_len); if (diriter->parent_len > 0 && diriter->path.ptr[diriter->parent_len-1] != '/') git_buf_putc(&diriter->path, '/'); git_buf_put(&diriter->path, filename, filename_len); if (git_buf_oom(&diriter->path)) return -1; return error; }
static int expandPerCentF(git_buf *buf, const char *replaceWith) { ssize_t foundPercentage = git_buf_find(buf, '%'); if (foundPercentage) { git_buf expanded = GIT_BUF_INIT; const char *end = buf->ptr + buf->size; const char *lastPercentage = buf->ptr; const char *idx = buf->ptr + foundPercentage; while (idx < end) { if (*idx == '%') { if (idx + 1 == end || (idx + 1 < end && *(idx + 1) == '%')) { // one '%' is at the end of the string OR "%%" is in the string git_buf_putc(&expanded, '%'); ++idx; ++idx; lastPercentage = idx; continue; } // now we know, that we're not at the end of the string and that the next char is not '%' git_buf_put(&expanded, lastPercentage, idx - lastPercentage); ++idx; if (*idx == 'f') git_buf_printf(&expanded, "\"%s\"", replaceWith); ++idx; lastPercentage = idx; continue; } ++idx; } if (lastPercentage) git_buf_put(&expanded, lastPercentage, idx - lastPercentage); if (git_buf_oom(&expanded)) { giterr_set_oom(); return -1; } git_buf_swap(buf, &expanded); git_buf_free(&expanded); } return 0; }
int create_deletion_refspecs(git_vector *out, const git_remote_head **heads, size_t heads_len) { git_buf del_spec = GIT_BUF_INIT; size_t i; for (i = 0; i < heads_len; i++) { const git_remote_head *head = heads[i]; /* Ignore malformed ref names (which also saves us from tag^{} */ if (!git_reference_is_valid_name(head->name)) return 0; /* Create a refspec that deletes a branch in the remote */ if (strcmp(head->name, "refs/heads/master")) { cl_git_pass(git_buf_putc(&del_spec, ':')); cl_git_pass(git_buf_puts(&del_spec, head->name)); cl_git_pass(git_vector_insert(out, git_buf_detach(&del_spec))); } } return 0; }