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_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 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; }
static int refspec_transform( git_buf *out, const char *from, const char *to, const char *name) { const char *from_star, *to_star; size_t replacement_len, star_offset; git_buf_sanitize(out); git_buf_clear(out); /* * There are two parts to each side of a refspec, the bit * before the star and the bit after it. The star can be in * the middle of the pattern, so we need to look at each bit * individually. */ from_star = strchr(from, '*'); to_star = strchr(to, '*'); assert(from_star && to_star); /* star offset, both in 'from' and in 'name' */ star_offset = from_star - from; /* the first half is copied over */ git_buf_put(out, to, to_star - to); /* * Copy over the name, but exclude the trailing part in "from" starting * after the glob */ replacement_len = strlen(name + star_offset) - strlen(from_star + 1); git_buf_put(out, name + star_offset, replacement_len); return git_buf_puts(out, to_star + 1); }
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; }
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; }
static int prepare_worktree_commit_message( git_buf* msg, const char *user_message) { git_buf buf = GIT_BUF_INIT; int error; if ((error = git_buf_set(&buf, git_buf_cstr(msg), git_buf_len(msg))) < 0) return error; git_buf_clear(msg); if (!user_message) git_buf_printf(msg, "WIP on %s", git_buf_cstr(&buf)); else { const char *colon; if ((colon = strchr(git_buf_cstr(&buf), ':')) == NULL) goto cleanup; git_buf_puts(msg, "On "); git_buf_put(msg, git_buf_cstr(&buf), colon - buf.ptr); git_buf_printf(msg, ": %s\n", user_message); } error = (git_buf_oom(msg) || git_buf_oom(&buf)) ? -1 : 0; cleanup: git_buf_free(&buf); return error; }
int git_futils_cleanupdir_r(const char *path) { int error; git_buf fullpath = GIT_BUF_INIT; futils__rmdir_data data; if ((error = git_buf_put(&fullpath, path, strlen(path))) < 0) goto clean_up; data.base = ""; data.baselen = 0; data.flags = GIT_RMDIR_REMOVE_FILES; data.error = 0; if (!git_path_exists(path)) { giterr_set(GITERR_OS, "Path does not exist: %s" , path); error = GIT_ERROR; goto clean_up; } if (!git_path_isdir(path)) { giterr_set(GITERR_OS, "Path is not a directory: %s" , path); error = GIT_ERROR; goto clean_up; } error = git_path_direach(&fullpath, futils__rmdir_recurs_foreach, &data); if (error == GIT_EUSER) error = data.error; clean_up: git_buf_free(&fullpath); return error; }
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; }
/* * 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 int refspec_transform( git_buf *out, const char *from, const char *to, const char *name) { size_t to_len = to ? strlen(to) : 0; size_t from_len = from ? strlen(from) : 0; size_t name_len = name ? strlen(name) : 0; git_buf_sanitize(out); if (git_buf_set(out, to, to_len) < 0) return -1; if (to_len > 0) { /* No '*' at the end of 'to' means that refspec is mapped to one * specific branch, so no actual transformation is needed. */ if (out->ptr[to_len - 1] != '*') return 0; git_buf_shorten(out, 1); /* remove trailing '*' copied from 'to' */ } if (from_len > 0) /* ignore trailing '*' from 'from' */ from_len--; if (from_len > name_len) from_len = name_len; return git_buf_put(out, name + from_len, name_len - from_len); }
void test_clone_nonetwork__do_not_clean_existing_directory(void) { git_buf path_buf = GIT_BUF_INIT; git_buf_put(&path_buf, "./foo", 5); /* Clone should not remove the directory if it already exists, but * Should clean up entries it creates. */ p_mkdir("./foo", GIT_DIR_MODE); cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options)); cl_assert(git_path_exists("./foo")); /* Make sure the directory is empty. */ cl_git_pass(git_path_direach(&path_buf, dont_call_me, NULL)); /* Try again with a bare repository. */ g_options.bare = true; cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options)); cl_assert(git_path_exists("./foo")); /* Make sure the directory is empty. */ cl_git_pass(git_path_direach(&path_buf, dont_call_me, NULL)); git_buf_free(&path_buf); }
void test_repo_init__at_filesystem_root(void) { git_repository *repo; const char *sandbox = clar_sandbox_path(); git_buf root = GIT_BUF_INIT; int root_len; if (!cl_is_env_set("GITTEST_INVASIVE_FS_STRUCTURE")) cl_skip(); root_len = git_path_root(sandbox); cl_assert(root_len >= 0); git_buf_put(&root, sandbox, root_len+1); git_buf_joinpath(&root, root.ptr, "libgit2_test_dir"); cl_assert(!git_path_exists(root.ptr)); cl_git_pass(git_repository_init(&repo, root.ptr, 0)); cl_assert(git_path_isdir(root.ptr)); cl_git_pass(git_futils_rmdir_r(root.ptr, NULL, GIT_RMDIR_REMOVE_FILES)); git_buf_free(&root); git_repository_free(repo); }
static int on_header_field(http_parser *parser, const char *str, size_t len) { transport_http *t = (transport_http *) parser->data; git_buf *buf = &t->buf; if (t->last_cb == VALUE && t->ct_found) { t->ct_finished = 1; t->ct_found = 0; t->content_type = git__strdup(git_buf_cstr(buf)); GITERR_CHECK_ALLOC(t->content_type); git_buf_clear(buf); } if (t->ct_found) { t->last_cb = FIELD; return 0; } if (t->last_cb != FIELD) git_buf_clear(buf); git_buf_put(buf, str, len); t->last_cb = FIELD; return git_buf_oom(buf); }
static int ensure_base_rev_loaded(git_object **object, git_reference **reference, const char *spec, size_t identifier_len, git_repository *repo, bool allow_empty_identifier) { int error; git_buf identifier = GIT_BUF_INIT; if (*object != NULL) return 0; if (*reference != NULL) { if ((error = object_from_reference(object, *reference)) < 0) return error; git_reference_free(*reference); *reference = NULL; return 0; } if (!allow_empty_identifier && identifier_len == 0) return revspec_error(spec); if (git_buf_put(&identifier, spec, identifier_len) < 0) return -1; error = revparse_lookup_object(object, repo, git_buf_cstr(&identifier)); git_buf_free(&identifier); return error; }
static int print_cb( const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, void *payload) { git_buf *buf = (git_buf *)payload; GIT_UNUSED(delta); if (hunk) git_buf_put(buf, hunk->header, hunk->header_len); if (line) git_buf_put(buf, line->content, line->content_len); return git_buf_oom(buf) ? -1 : 0; }
static int on_body_parse_response(http_parser *parser, const char *str, size_t len) { transport_http *t = (transport_http *) parser->data; git_buf *buf = &t->buf; git_vector *common = &t->common; int error; const char *line_end, *ptr; if (len == 0) { /* EOF */ if (git_buf_len(buf) != 0) { giterr_set(GITERR_NET, "Unexpected EOF"); return t->error = -1; } else { return 0; } } git_buf_put(buf, str, len); ptr = buf->ptr; while (1) { git_pkt *pkt; if (git_buf_len(buf) == 0) return 0; error = git_pkt_parse_line(&pkt, ptr, &line_end, git_buf_len(buf)); if (error == GIT_EBUFS) { return 0; /* Ask for more */ } if (error < 0) return t->error = -1; git_buf_consume(buf, line_end); if (pkt->type == GIT_PKT_PACK) { git__free(pkt); t->pack_ready = 1; return 0; } if (pkt->type == GIT_PKT_NAK) { git__free(pkt); return 0; } if (pkt->type != GIT_PKT_ACK) { git__free(pkt); continue; } if (git_vector_insert(common, pkt) < 0) return -1; } return error; }
static int on_body_store_refs(http_parser *parser, const char *str, size_t len) { transport_http *t = (transport_http *) parser->data; if (parser->status_code == 404) { return git_buf_put(&t->buf, str, len); } return git_protocol_store_refs(&t->proto, str, len); }
static int refspec_transform( git_buf *out, const char *from, const char *to, const char *name) { const char *from_star, *to_star; const char *name_slash, *from_slash; size_t replacement_len, star_offset; git_buf_sanitize(out); git_buf_clear(out); /* * There are two parts to each side of a refspec, the bit * before the star and the bit after it. The star can be in * the middle of the pattern, so we need to look at each bit * individually. */ from_star = strchr(from, '*'); to_star = strchr(to, '*'); assert(from_star && to_star); /* star offset, both in 'from' and in 'name' */ star_offset = from_star - from; /* the first half is copied over */ git_buf_put(out, to, to_star - to); /* then we copy over the replacement, from the star's offset to the next slash in 'name' */ name_slash = strchr(name + star_offset, '/'); if (!name_slash) name_slash = strrchr(name, '\0'); /* if there is no slash after the star in 'from', we want to copy everything over */ from_slash = strchr(from + star_offset, '/'); if (!from_slash) name_slash = strrchr(name, '\0'); replacement_len = (name_slash - name) - star_offset; git_buf_put(out, name + star_offset, replacement_len); return git_buf_puts(out, to_star + 1); }
static int command_readall(HANDLE handle, git_buf *buf) { size_t bytes_read = 0; do { char buffer[65536]; command_read(handle, buffer, sizeof(buffer), &bytes_read); git_buf_put(buf, buffer, bytes_read); } while (bytes_read); return 0; }
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; }
static int append_abbreviated_oid(git_buf *out, const git_oid *b_commit) { char *formatted_oid; formatted_oid = git_oid_allocfmt(b_commit); GITERR_CHECK_ALLOC(formatted_oid); git_buf_put(out, formatted_oid, 7); git__free(formatted_oid); return git_buf_oom(out) ? -1 : 0; }
static int ident_remove_id( git_buf *to, const git_buf *from) { const char *id_start, *id_end, *from_end = from->ptr + from->size; size_t need_size; if (ident_find_id(&id_start, &id_end, from->ptr, from->size) < 0) return GIT_PASSTHROUGH; need_size = (size_t)(id_start - from->ptr) + 4 /* "$Id$" */ + (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$", 4); git_buf_put(to, id_end, (size_t)(from_end - id_end)); return git_buf_oom(to) ? -1 : 0; }
static void write_tree(git_buf *out, git_tree_cache *tree) { size_t i; git_buf_printf(out, "%s%c%"PRIdZ" %"PRIuZ"\n", tree->name, 0, tree->entry_count, tree->children_count); if (tree->entry_count != -1) git_buf_put(out, (const char *) &tree->oid, GIT_OID_RAWSZ); for (i = 0; i < tree->children_count; i++) write_tree(out, tree->children[i]); }
static int diff_print_to_buffer_cb( const git_diff_delta *delta, const git_diff_range *range, char line_origin, const char *content, size_t content_len, void *payload) { git_buf *output = payload; GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(line_origin); return git_buf_put(output, content, content_len); }
static int on_header_value(http_parser *parser, const char *str, size_t len) { transport_http *t = (transport_http *) parser->data; git_buf *buf = &t->buf; if (t->ct_finished) { t->last_cb = VALUE; return 0; } if (t->last_cb == VALUE) git_buf_put(buf, str, len); if (t->last_cb == FIELD && !strcmp(git_buf_cstr(buf), typestr)) { t->ct_found = 1; git_buf_clear(buf); git_buf_put(buf, str, len); } t->last_cb = VALUE; return git_buf_oom(buf); }
static int on_header_value(http_parser *parser, const char *str, size_t len) { parser_context *ctx = (parser_context *) parser->data; http_subtransport *t = ctx->t; assert(NONE != t->last_cb); if (FIELD == t->last_cb) git_buf_clear(&t->parse_header_value); if (git_buf_put(&t->parse_header_value, str, len) < 0) return t->parse_error = PARSE_ERROR_GENERIC; t->last_cb = VALUE; return 0; }
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; }
int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) { const char *start = src->ptr; const char *end = start + src->size; const char *scan = start; const char *next = memchr(scan, '\n', src->size); size_t alloclen; assert(tgt != src); if (!next) return git_buf_set(tgt, src->ptr, src->size); /* attempt to reduce reallocs while in the loop */ GITERR_CHECK_ALLOC_ADD(&alloclen, src->size, src->size >> 4); GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); if (git_buf_grow(tgt, alloclen) < 0) return -1; tgt->size = 0; for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) { size_t copylen = next - scan; /* if we find mixed line endings, bail */ if (next > start && next[-1] == '\r') { git_buf_free(tgt); return GIT_PASSTHROUGH; } GITERR_CHECK_ALLOC_ADD(&alloclen, copylen, 3); if (git_buf_grow_by(tgt, alloclen) < 0) return -1; if (next > scan) { memcpy(tgt->ptr + tgt->size, scan, copylen); tgt->size += copylen; } tgt->ptr[tgt->size++] = '\r'; tgt->ptr[tgt->size++] = '\n'; } tgt->ptr[tgt->size] = '\0'; return git_buf_put(tgt, scan, end - scan); }
/** * 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'); }