static int git_futils_find_in_dirlist( git_buf *path, const char *name, git_futils_dir_t which, const char *label) { size_t len; const char *scan, *next = NULL; const git_buf *syspath; GITERR_CHECK_ERROR(git_futils_dirs_get(&syspath, which)); for (scan = git_buf_cstr(syspath); scan; scan = next) { for (next = strchr(scan, GIT_PATH_LIST_SEPARATOR); next && next > scan && next[-1] == '\\'; next = strchr(next + 1, GIT_PATH_LIST_SEPARATOR)) /* find unescaped separator or end of string */; len = next ? (size_t)(next++ - scan) : strlen(scan); if (!len) continue; GITERR_CHECK_ERROR(git_buf_set(path, scan, len)); GITERR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name)); if (git_path_exists(path->ptr)) return 0; } git_buf_clear(path); giterr_set(GITERR_OS, "The %s file '%s' doesn't exist", label, name); return GIT_ENOTFOUND; }
int git_path_make_relative(git_buf *path, const char *parent) { const char *p, *q, *p_dirsep, *q_dirsep; size_t plen = path->size, newlen, alloclen, depth = 1, i, offset; for (p_dirsep = p = path->ptr, q_dirsep = q = parent; *p && *q; p++, q++) { if (*p == '/' && *q == '/') { p_dirsep = p; q_dirsep = q; } else if (*p != *q) break; } /* need at least 1 common path segment */ if ((p_dirsep == path->ptr || q_dirsep == parent) && (*p_dirsep != '/' || *q_dirsep != '/')) { giterr_set(GITERR_INVALID, "%s is not a parent of %s", parent, path->ptr); return GIT_ENOTFOUND; } if (*p == '/' && !*q) p++; else if (!*p && *q == '/') q++; else if (!*p && !*q) return git_buf_clear(path), 0; else { p = p_dirsep + 1; q = q_dirsep + 1; } plen -= (p - path->ptr); if (!*q) return git_buf_set(path, p, plen); for (; (q = strchr(q, '/')) && *(q + 1); q++) depth++; GITERR_CHECK_ALLOC_MULTIPLY(&newlen, depth, 3); GITERR_CHECK_ALLOC_ADD(&newlen, newlen, plen); GITERR_CHECK_ALLOC_ADD(&alloclen, newlen, 1); /* save the offset as we might realllocate the pointer */ offset = p - path->ptr; if (git_buf_try_grow(path, alloclen, 1, 0) < 0) return -1; p = path->ptr + offset; memmove(path->ptr + (depth * 3), p, plen + 1); for (i = 0; i < depth; i++) memcpy(path->ptr + (i * 3), "../", 3); path->size = newlen; return 0; }
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; }
static int tree_reader_read( git_buf *out, git_oid *out_id, git_filemode_t *out_filemode, git_reader *_reader, const char *filename) { tree_reader *reader = (tree_reader *)_reader; git_tree_entry *tree_entry = NULL; git_blob *blob = NULL; int error; if ((error = git_tree_entry_bypath(&tree_entry, reader->tree, filename)) < 0 || (error = git_blob_lookup(&blob, git_tree_owner(reader->tree), git_tree_entry_id(tree_entry))) < 0 || (error = git_buf_set(out, git_blob_rawcontent(blob), git_blob_rawsize(blob))) < 0) goto done; if (out_id) git_oid_cpy(out_id, git_tree_entry_id(tree_entry)); if (out_filemode) *out_filemode = git_tree_entry_filemode(tree_entry); done: git_blob_free(blob); git_tree_entry_free(tree_entry); return error; }
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; }
int git_path_dirload_with_stat( const char *path, size_t prefix_len, unsigned int flags, const char *start_stat, const char *end_stat, git_vector *contents) { int error; unsigned int i; git_path_with_stat *ps; git_buf full = GIT_BUF_INIT; int (*strncomp)(const char *a, const char *b, size_t sz); size_t start_len = start_stat ? strlen(start_stat) : 0; size_t end_len = end_stat ? strlen(end_stat) : 0, cmp_len; if (git_buf_set(&full, path, prefix_len) < 0) return -1; error = git_path_dirload( path, prefix_len, sizeof(git_path_with_stat) + 1, flags, contents); if (error < 0) { git_buf_free(&full); return error; } strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ? git__strncasecmp : git__strncmp; /* stat struct at start of git_path_with_stat, so shift path text */ git_vector_foreach(contents, i, ps) { size_t path_len = strlen((char *)ps); memmove(ps->path, ps, path_len + 1); ps->path_len = path_len; }
int git_blob__getbuf(git_buf *buffer, git_blob *blob) { return git_buf_set( buffer, git_odb_object_data(blob->odb_object), git_odb_object_size(blob->odb_object)); }
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; }
int git_win32__find_system_dirs(git_buf *out, const wchar_t *subdir) { git_buf buf = GIT_BUF_INIT; /* directories where git.exe & git.cmd are found */ if (!win32_find_git_in_path(&buf, L"git.exe", subdir) && buf.size) git_buf_set(out, buf.ptr, buf.size); else git_buf_clear(out); if (!win32_find_git_in_path(&buf, L"git.cmd", subdir) && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); /* directories where git is installed according to registry */ if (!win32_find_git_in_registry( &buf, HKEY_CURRENT_USER, REG_MSYSGIT_INSTALL_LOCAL, subdir) && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); if (!win32_find_git_in_registry( &buf, HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL, subdir) && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); git_buf_free(&buf); return (git_buf_oom(out) ? -1 : 0); }
int git_blob__getbuf(git_buf *buffer, git_blob *blob) { return git_buf_set( buffer, git_blob_rawcontent(blob), git_blob_rawsize(blob)); }
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); }
mrb_value mrb_Git_Buf_replace(mrb_state * mrb, mrb_value self) { giterr_clear(); git_buf * native_self = mruby_unbox_git_buf(self); mrb_value str = mrb_nil_value(); mrb_get_args(mrb, "S", str); int err = git_buf_set(native_self, RSTRING_PTR(str), RSTRING_LEN(str)); RAISE_GIT_ERROR(err); return str; }
/* * 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; }
/* * 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 result, 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--; /* 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 == '/'); len = endp - path +1; #ifdef GIT_WIN32 /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return 'C:/' here */ if (len == 2 && isalpha(path[0]) && path[1] == ':') { len = 3; goto Exit; } #endif Exit: result = len; if (buffer != NULL) { if (git_buf_set(buffer, path, len) < GIT_SUCCESS) return git__rethrow(git_buf_lasterror(buffer), "Could not get dirname of '%s'", path); } return result; }
int git_branch_upstream__name( git_buf *tracking_name, git_repository *repo, const char *canonical_branch_name) { const char *remote_name, *merge_name; git_buf buf = GIT_BUF_INIT; int error = -1; git_remote *remote = NULL; const git_refspec *refspec; assert(tracking_name && canonical_branch_name); if (!git_reference__is_branch(canonical_branch_name)) return not_a_local_branch(canonical_branch_name); if ((error = retrieve_upstream_configuration( &remote_name, repo, canonical_branch_name, "branch.%s.remote")) < 0) goto cleanup; if ((error = retrieve_upstream_configuration( &merge_name, repo, canonical_branch_name, "branch.%s.merge")) < 0) goto cleanup; if (!*remote_name || !*merge_name) { giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream", canonical_branch_name); error = GIT_ENOTFOUND; goto cleanup; } if (strcmp(".", remote_name) != 0) { if ((error = git_remote_load(&remote, repo, remote_name)) < 0) goto cleanup; refspec = git_remote__matching_refspec(remote, merge_name); if (!refspec) { error = GIT_ENOTFOUND; goto cleanup; } if (git_refspec_transform_r(&buf, refspec, merge_name) < 0) goto cleanup; } else if (git_buf_sets(&buf, merge_name) < 0) goto cleanup; error = git_buf_set(tracking_name, git_buf_cstr(&buf), git_buf_len(&buf)); cleanup: git_remote_free(remote); git_buf_free(&buf); return error; }
/* * 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 result, 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--; /* 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 == '/'); /* Cast is safe because max path < max int */ len = (int)(endp - path + 1); #ifdef GIT_WIN32 /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return 'C:/' here */ if (len == 2 && isalpha(path[0]) && path[1] == ':') { len = 3; goto Exit; } #endif Exit: result = len; if (buffer != NULL && git_buf_set(buffer, path, len) < 0) return -1; return result; }
/* let's do some tests with larger buffers to push our limits */ void test_core_buffer__3(void) { git_buf buf = GIT_BUF_INIT; /* set to string */ git_buf_set(&buf, test_4096, 4096); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_4096, git_buf_cstr(&buf)); /* append string */ git_buf_puts(&buf, test_4096); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_8192, git_buf_cstr(&buf)); /* set to string again (should overwrite - not append) */ git_buf_set(&buf, test_4096, 4096); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_4096, git_buf_cstr(&buf)); git_buf_free(&buf); }
mrb_value mrb_Git_Buf_initialize(mrb_state* mrb, mrb_value self) { mrb_value str = mrb_nil_value(); mrb_get_args(mrb, "S", str); git_buf* native_object = (git_buf*)calloc(1, sizeof(git_buf)); mruby_gift_git_buf_data_ptr(self, native_object); if (!mrb_nil_p(str)) { git_buf_set(native_object, RSTRING_PTR(str), RSTRING_LEN(str)); } return self; }
int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src) { const char *scan = src->ptr; const char *scan_end = src->ptr + src->size; const char *next = memchr(scan, '\r', src->size); size_t new_size; char *out; assert(tgt != src); if (!next) return git_buf_set(tgt, src->ptr, src->size); /* reduce reallocs while in the loop */ GITERR_CHECK_ALLOC_ADD(&new_size, src->size, 1); if (git_buf_grow(tgt, new_size) < 0) return -1; out = tgt->ptr; tgt->size = 0; /* Find the next \r and copy whole chunk up to there to tgt */ for (; next; scan = next + 1, next = memchr(scan, '\r', scan_end - scan)) { if (next > scan) { size_t copylen = (size_t)(next - scan); memcpy(out, scan, copylen); out += copylen; } /* Do not drop \r unless it is followed by \n */ if (next + 1 == scan_end || next[1] != '\n') *out++ = '\r'; } /* Copy remaining input into dest */ if (scan < scan_end) { size_t remaining = (size_t)(scan_end - scan); memcpy(out, scan, remaining); out += remaining; } tgt->size = (size_t)(out - tgt->ptr); tgt->ptr[tgt->size] = '\0'; return 0; }
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); }
static int diff_driver_add_patterns( git_diff_driver *drv, const char *regex_str, int regex_flags) { int error = 0; const char *scan, *end; git_diff_driver_pattern *pat = NULL; git_buf buf = GIT_BUF_INIT; for (scan = regex_str; scan; scan = end) { /* get pattern to fill in */ if ((pat = git_array_alloc(drv->fn_patterns)) == NULL) { error = -1; break; } pat->flags = regex_flags; if (*scan == '!') { pat->flags |= REG_NEGATE; ++scan; } if ((end = strchr(scan, '\n')) != NULL) { error = git_buf_set(&buf, scan, end - scan); end++; } else { error = git_buf_sets(&buf, scan); } if (error < 0) break; if ((error = regcomp(&pat->re, buf.ptr, regex_flags)) < 0) { /* if regex fails to compile, warn? fail? */ error = giterr_set_regex(&pat->re, error); regfree(&pat->re); break; } } if (error && pat != NULL) (void)git_array_pop(drv->fn_patterns); /* release last item */ git_buf_free(&buf); return error; }
/* * Based on the Android implementation, BSD licensed. * Check http://android.git.kernel.org/ */ int git_path_basename_r(git_buf *buffer, const char *path) { const char *endp, *startp; int len, result; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { startp = "."; len = 1; goto Exit; } /* Strip trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* All slashes becomes "/" */ if (endp == path && *endp == '/') { startp = "/"; len = 1; goto Exit; } /* Find the start of the base */ startp = endp; while (startp > path && *(startp - 1) != '/') startp--; len = endp - startp +1; Exit: result = len; if (buffer != NULL) { if (git_buf_set(buffer, startp, len) < GIT_SUCCESS) return git__rethrow(git_buf_lasterror(buffer), "Could not get basename of '%s'", path); } return result; }
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 int object_file_name( git_buf *name, const loose_backend *be, const git_oid *id) { size_t alloclen; /* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */ GITERR_CHECK_ALLOC_ADD(&alloclen, be->objects_dirlen, GIT_OID_HEXSZ); GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 3); if (git_buf_grow(name, alloclen) < 0) return -1; git_buf_set(name, be->objects_dir, be->objects_dirlen); git_path_to_dir(name); /* loose object filename: aa/aaa... (41 bytes) */ git_oid_pathfmt(name->ptr + name->size, id); name->size += GIT_OID_HEXSZ + 1; name->ptr[name->size] = '\0'; return 0; }
/* * Based on the Android implementation, BSD licensed. * http://android.git.kernel.org/ * * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ int git_path_basename_r(git_buf *buffer, const char *path) { const char *endp, *startp; int len, result; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { startp = "."; len = 1; goto Exit; } /* Strip trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* All slashes becomes "/" */ if (endp == path && *endp == '/') { startp = "/"; len = 1; goto Exit; } /* Find the start of the base */ startp = endp; while (startp > path && *(startp - 1) != '/') startp--; /* Cast is safe because max path < max int */ len = (int)(endp - startp + 1); Exit: result = len; if (buffer != NULL && git_buf_set(buffer, startp, len) < 0) return -1; return result; }
/* "b=name,t=name", blob_id, tree_id */ static void build_test_tree( git_oid *out, git_repository *repo, const char *fmt, ...) { git_oid *id; git_treebuilder *builder; const char *scan = fmt, *next; char type, delimiter; git_filemode_t mode = GIT_FILEMODE_BLOB; git_buf name = GIT_BUF_INIT; va_list arglist; cl_git_pass(git_treebuilder_new(&builder, repo, NULL)); /* start builder */ va_start(arglist, fmt); while (*scan) { switch (type = *scan++) { case 't': case 'T': mode = GIT_FILEMODE_TREE; break; case 'b': case 'B': mode = GIT_FILEMODE_BLOB; break; default: cl_assert(type == 't' || type == 'T' || type == 'b' || type == 'B'); } delimiter = *scan++; /* read and skip delimiter */ for (next = scan; *next && *next != delimiter; ++next) /* seek end */; cl_git_pass(git_buf_set(&name, scan, (size_t)(next - scan))); for (scan = next; *scan && (*scan == delimiter || *scan == ','); ++scan) /* skip delimiter and optional comma */; id = va_arg(arglist, git_oid *); cl_git_pass(git_treebuilder_insert(NULL, builder, name.ptr, id, mode)); } va_end(arglist); cl_git_pass(git_treebuilder_write(out, builder)); git_treebuilder_free(builder); git_buf_free(&name); }
int git_path_dirload_with_stat( const char *path, size_t prefix_len, git_vector *contents) { int error; unsigned int i; git_path_with_stat *ps; git_buf full = GIT_BUF_INIT; if (git_buf_set(&full, path, prefix_len) < 0) return -1; error = git_path_dirload( path, prefix_len, sizeof(git_path_with_stat) + 1, contents); if (error < 0) { git_buf_free(&full); return error; } git_vector_foreach(contents, i, ps) { size_t path_len = strlen((char *)ps); memmove(ps->path, ps, path_len + 1); ps->path_len = path_len; if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 || (error = git_path_lstat(full.ptr, &ps->st)) < 0) break; git_buf_truncate(&full, prefix_len); if (S_ISDIR(ps->st.st_mode)) { ps->path[path_len] = '/'; ps->path[path_len + 1] = '\0'; } }
int git_futils_dirs_set(git_futils_dir_t which, const char *search_path) { const char *expand_path = NULL; git_buf merge = GIT_BUF_INIT; GITERR_CHECK_ERROR(git_futils_check_selector(which)); if (search_path != NULL) expand_path = strstr(search_path, PATH_MAGIC); /* init with default if not yet done and needed (ignoring error) */ if ((!search_path || expand_path) && !git_buf_len(&git_futils__dirs[which])) git_futils__dir_guess[which](&git_futils__dirs[which]); /* if $PATH is not referenced, then just set the path */ if (!expand_path) return git_buf_sets(&git_futils__dirs[which], search_path); /* otherwise set to join(before $PATH, old value, after $PATH) */ if (expand_path > search_path) git_buf_set(&merge, search_path, expand_path - search_path); if (git_buf_len(&git_futils__dirs[which])) git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, git_futils__dirs[which].ptr); expand_path += strlen(PATH_MAGIC); if (*expand_path) git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path); git_buf_swap(&git_futils__dirs[which], &merge); git_buf_free(&merge); return git_buf_oom(&git_futils__dirs[which]) ? -1 : 0; }
int git_branch_upstream_name( git_buf *out, git_repository *repo, const char *refname) { git_buf remote_name = GIT_BUF_INIT; git_buf merge_name = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT; int error = -1; git_remote *remote = NULL; const git_refspec *refspec; git_config *config; assert(out && refname); git_buf_sanitize(out); if (!git_reference__is_branch(refname)) return not_a_local_branch(refname); if ((error = git_repository_config_snapshot(&config, repo)) < 0) return error; if ((error = retrieve_upstream_configuration( &remote_name, config, refname, "branch.%s.remote")) < 0) goto cleanup; if ((error = retrieve_upstream_configuration( &merge_name, config, refname, "branch.%s.merge")) < 0) goto cleanup; if (git_buf_len(&remote_name) == 0 || git_buf_len(&merge_name) == 0) { giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream", refname); error = GIT_ENOTFOUND; goto cleanup; } if (strcmp(".", git_buf_cstr(&remote_name)) != 0) { if ((error = git_remote_lookup(&remote, repo, git_buf_cstr(&remote_name))) < 0) goto cleanup; refspec = git_remote__matching_refspec(remote, git_buf_cstr(&merge_name)); if (!refspec) { error = GIT_ENOTFOUND; goto cleanup; } if (git_refspec_transform(&buf, refspec, git_buf_cstr(&merge_name)) < 0) goto cleanup; } else if (git_buf_set(&buf, git_buf_cstr(&merge_name), git_buf_len(&merge_name)) < 0) goto cleanup; error = git_buf_set(out, git_buf_cstr(&buf), git_buf_len(&buf)); cleanup: git_config_free(config); git_remote_free(remote); git_buf_free(&remote_name); git_buf_free(&merge_name); git_buf_free(&buf); return error; }
/* * 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 result, 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--; /* 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 == '/'); /* Cast is safe because max path < max int */ len = (int)(endp - path + 1); #ifdef GIT_WIN32 /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return 'C:/' here */ if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path)) { len = 3; goto Exit; } /* Similarly checks if we're dealing with a network computer name '//computername/.git' will return '//computername/' */ if (looks_like_network_computer_name(path, len)) { len++; goto Exit; } #endif Exit: result = len; if (buffer != NULL && git_buf_set(buffer, path, len) < 0) return -1; return result; }