static struct origin *make_origin(struct commit *commit, const char *path)
{
struct origin *o;
- size_t pathlen = strlen(path) + 1;
- o = xcalloc(1, sizeof(*o) + pathlen);
+ FLEX_ALLOC_STR(o, path, path);
o->commit = commit;
o->refcnt = 1;
o->next = commit->util;
commit->util = o;
- memcpy(o->path, path, pathlen); /* includes NUL */
return o;
}
for (p = buf; p < end; p = get_next_line(p, end))
num++;
- sb->lineno = lineno = xmalloc(sizeof(*sb->lineno) * (num + 1));
+ ALLOC_ARRAY(sb->lineno, num + 1);
+ lineno = sb->lineno;
for (p = buf; p < end; p = get_next_line(p, end))
*lineno++ = p - buf;
ce->ce_mode = create_ce_mode(mode);
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
- /*
- * We are not going to write this out, so this does not matter
- * right now, but someday we might optimize diff-index --cached
- * with cache-tree information.
- */
cache_tree_invalidate_path(&the_index, path);
return commit;
static void run_pager(struct grep_opt *opt, const char *prefix)
{
struct string_list *path_list = opt->output_priv;
- const char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1));
+ struct child_process child = CHILD_PROCESS_INIT;
int i, status;
for (i = 0; i < path_list->nr; i++)
- argv[i] = path_list->items[i].string;
- argv[path_list->nr] = NULL;
+ argv_array_push(&child.args, path_list->items[i].string);
+ child.dir = prefix;
+ child.use_shell = 1;
- status = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, prefix, NULL);
+ status = run_command(&child);
if (status)
exit(status);
- free(argv);
}
static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
for (nr = 0; nr < active_nr; nr++) {
const struct cache_entry *ce = active_cache[nr];
- if (!S_ISREG(ce->ce_mode))
+ if (!S_ISREG(ce->ce_mode) || ce_intent_to_add(ce))
continue;
if (!ce_path_match(ce, pathspec, NULL))
continue;
ALLOC_GROW(it->down, it->subtree_nr + 1, it->subtree_alloc);
it->subtree_nr++;
- down = xmalloc(sizeof(*down) + pathlen + 1);
+ FLEX_ALLOC_MEM(down, name, path, pathlen);
down->cache_tree = NULL;
down->namelen = pathlen;
- memcpy(down->name, path, pathlen);
- down->name[pathlen] = 0;
if (pos < it->subtree_nr)
memmove(it->down + pos + 1,
* they are not part of generated trees. Invalidate up
* to root to force cache-tree users to read elsewhere.
*/
- if (ce->ce_flags & CE_INTENT_TO_ADD) {
+ if (ce_intent_to_add(ce)) {
to_invalidate = 1;
continue;
}
return offset;
}
-int git_config_set_in_file(const char *config_filename,
- const char *key, const char *value)
+int git_config_set_in_file_gently(const char *config_filename,
+ const char *key, const char *value)
{
- return git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
+ return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
}
-int git_config_set(const char *key, const char *value)
+void git_config_set_in_file(const char *config_filename,
+ const char *key, const char *value)
{
- return git_config_set_multivar(key, value, NULL, 0);
+ git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
+}
+
+int git_config_set_gently(const char *key, const char *value)
+{
+ return git_config_set_multivar_gently(key, value, NULL, 0);
+}
+
+void git_config_set(const char *key, const char *value)
+{
+ git_config_set_multivar(key, value, NULL, 0);
}
/*
* Validate the key and while at it, lower case it for matching.
*/
if (store_key)
- *store_key = xmalloc(strlen(key) + 1);
+ *store_key = xmallocz(strlen(key));
dot = 0;
for (i = 0; key[i]; i++) {
if (store_key)
(*store_key)[i] = c;
}
- if (store_key)
- (*store_key)[i] = 0;
return 0;
* - the config file is removed and the lock file rename()d to it.
*
*/
-int git_config_set_multivar_in_file(const char *config_filename,
- const char *key, const char *value,
- const char *value_regex, int multi_replace)
+int git_config_set_multivar_in_file_gently(const char *config_filename,
+ const char *key, const char *value,
+ const char *value_regex,
+ int multi_replace)
{
int fd = -1, in_fd = -1;
int ret;
}
-int git_config_set_multivar(const char *key, const char *value,
- const char *value_regex, int multi_replace)
+void git_config_set_multivar_in_file(const char *config_filename,
+ const char *key, const char *value,
+ const char *value_regex, int multi_replace)
+{
+ if (git_config_set_multivar_in_file_gently(config_filename, key, value,
+ value_regex, multi_replace) < 0)
+ die(_("Could not set '%s' to '%s'"), key, value);
+}
+
+int git_config_set_multivar_gently(const char *key, const char *value,
+ const char *value_regex, int multi_replace)
+{
+ return git_config_set_multivar_in_file_gently(NULL, key, value, value_regex,
+ multi_replace);
+}
+
+void git_config_set_multivar(const char *key, const char *value,
+ const char *value_regex, int multi_replace)
{
- return git_config_set_multivar_in_file(NULL, key, value, value_regex,
- multi_replace);
+ git_config_set_multivar_in_file(NULL, key, value, value_regex,
+ multi_replace);
}
static int section_name_match (const char *buf, const char *name)
struct diff_filespec *alloc_filespec(const char *path)
{
- int namelen = strlen(path);
- struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
+ struct diff_filespec *spec;
- memset(spec, 0, sizeof(*spec));
- spec->path = (char *)(spec + 1);
- memcpy(spec->path, path, namelen+1);
+ FLEXPTR_ALLOC_STR(spec, path, path);
spec->count = 1;
spec->is_binary = -1;
return spec;
static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
{
- int len;
- char *data = xmalloc(100), *dirty = "";
+ struct strbuf buf = STRBUF_INIT;
+ char *dirty = "";
/* Are we looking at the work tree? */
if (s->dirty_submodule)
dirty = "-dirty";
- len = snprintf(data, 100,
- "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty);
- s->data = data;
- s->size = len;
- s->should_free = 1;
+ strbuf_addf(&buf, "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty);
+ s->size = buf.len;
if (size_only) {
s->data = NULL;
- free(data);
+ strbuf_release(&buf);
+ } else {
+ s->data = strbuf_detach(&buf, NULL);
+ s->should_free = 1;
}
return 0;
}
{
size_t size;
- if (!driver || !driver->textconv) {
+ if (!driver) {
if (!DIFF_FILE_VALID(df)) {
*outbuf = "";
return 0;
return df->size;
}
+ if (!driver->textconv)
+ die("BUG: fill_textconv called with non-textconv driver");
+
if (driver->textconv_cache && df->sha1_valid) {
*outbuf = notes_cache_get(driver->textconv_cache, df->sha1,
&size);
} parent[FLEX_ARRAY];
};
#define combine_diff_path_size(n, l) \
- (sizeof(struct combine_diff_path) + \
- sizeof(struct combine_diff_parent) * (n) + (l) + 1)
+ st_add4(sizeof(struct combine_diff_path), (l), 1, \
+ st_mult(sizeof(struct combine_diff_parent), (n)))
extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
int dense, struct rev_info *);
extern int index_differs_from(const char *def, int diff_flags);
+/*
+ * Fill the contents of the filespec "df", respecting any textconv defined by
+ * its userdiff driver. The "driver" parameter must come from a
+ * previous call to get_textconv(), and therefore should either be NULL or have
+ * textconv enabled.
+ *
+ * Note that the memory ownership of the resulting buffer depends on whether
+ * the driver field is NULL. If it is, then the memory belongs to the filespec
+ * struct. If it is non-NULL, then "outbuf" points to a newly allocated buffer
+ * that should be freed by the caller.
+ */
extern size_t fill_textconv(struct userdiff_driver *driver,
struct diff_filespec *df,
char **outbuf);
+/*
+ * Look up the userdiff driver for the given filespec, and return it if
+ * and only if it has textconv enabled (otherwise return NULL). The result
+ * can be passed to fill_textconv().
+ */
extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
extern int parse_rename_score(const char **cp_p);
err = run_one_slot(slot, results);
if (err != HTTP_OK && err != HTTP_REAUTH) {
- error("RPC failed; result=%d, HTTP code = %ld",
- results->curl_result, results->http_code);
+ struct strbuf msg = STRBUF_INIT;
+ if (results->http_code && results->http_code != 200)
+ strbuf_addf(&msg, "HTTP %ld", results->http_code);
+ if (results->curl_result != CURLE_OK) {
+ if (msg.len)
+ strbuf_addch(&msg, ' ');
+ strbuf_addf(&msg, "curl %d", results->curl_result);
+ if (curl_errorstr[0]) {
+ strbuf_addch(&msg, ' ');
+ strbuf_addstr(&msg, curl_errorstr);
+ }
+ }
+ error("RPC failed; %s", msg.buf);
+ strbuf_release(&msg);
}
return err;
static int fetch_dumb(int nr_heads, struct ref **to_fetch)
{
struct walker *walker;
- char **targets = xmalloc(nr_heads * sizeof(char*));
+ char **targets;
int ret, i;
+ ALLOC_ARRAY(targets, nr_heads);
if (options.depth)
die("dumb http transport does not support --depth");
for (i = 0; i < nr_heads; i++)
static int push_dav(int nr_spec, char **specs)
{
- const char **argv = xmalloc((10 + nr_spec) * sizeof(char*));
- int argc = 0, i;
+ struct child_process child = CHILD_PROCESS_INIT;
+ size_t i;
- argv[argc++] = "http-push";
- argv[argc++] = "--helper-status";
+ child.git_cmd = 1;
+ argv_array_push(&child.args, "http-push");
+ argv_array_push(&child.args, "--helper-status");
if (options.dry_run)
- argv[argc++] = "--dry-run";
+ argv_array_push(&child.args, "--dry-run");
if (options.verbosity > 1)
- argv[argc++] = "--verbose";
- argv[argc++] = url.buf;
+ argv_array_push(&child.args, "--verbose");
+ argv_array_push(&child.args, url.buf);
for (i = 0; i < nr_spec; i++)
- argv[argc++] = specs[i];
- argv[argc++] = NULL;
+ argv_array_push(&child.args, specs[i]);
- if (run_command_v_opt(argv, RUN_GIT_CMD))
- die("git-%s failed", argv[0]);
- free(argv);
+ if (run_command(&child))
+ die("git-http-push failed");
return 0;
}
const char *name)
{
size_t len = strlen(name);
- struct ref *ref = xcalloc(1, sizeof(struct ref) + prefixlen + len + 1);
+ struct ref *ref = xcalloc(1, st_add4(sizeof(*ref), prefixlen, len, 1));
memcpy(ref->name, prefix, prefixlen);
memcpy(ref->name + prefixlen, name, len);
return ref;
size_t len;
if (!ref)
return NULL;
- len = strlen(ref->name);
- cpy = xmalloc(sizeof(struct ref) + len + 1);
- memcpy(cpy, ref, sizeof(struct ref) + len + 1);
+ len = st_add3(sizeof(struct ref), strlen(ref->name), 1);
+ cpy = xmalloc(len);
+ memcpy(cpy, ref, len);
cpy->next = NULL;
cpy->symref = xstrdup_or_null(ref->symref);
cpy->remote_status = xstrdup_or_null(ref->remote_status);
}
/*
- * Bypass the usual "must fast-forward" check but
- * replace it with a weaker "the old value must be
- * this value we observed". If the remote ref has
- * moved and is now different from what we expect,
- * reject any push.
+ * If the remote ref has moved and is now different
+ * from what we expect, reject any push.
*
* It also is an error if the user told us to check
* with the remote-tracking branch to find the value
if (ref->expect_old_no_trackback ||
oidcmp(&ref->old_oid, &ref->old_oid_expect))
reject_reason = REF_STATUS_REJECT_STALE;
+ else
+ /* If the ref isn't stale then force the update. */
+ force_ref_update = 1;
}
/*
- * The usual "must fast-forward" rules.
+ * If the update isn't already rejected then check
+ * the usual "must fast-forward" rules.
*
* Decide whether an individual refspec A:B can be
* pushed. The push will succeed if any of the
* passing the --force argument
*/
- else if (!ref->deletion && !is_null_oid(&ref->old_oid)) {
+ if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) {
if (starts_with(ref->name, "refs/tags/"))
reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
else if (!has_object_file(&ref->old_oid))
{
struct ref ***local_tail = cb_data;
struct ref *ref;
- int len;
/* we already know it starts with refs/ to get here */
if (check_refname_format(refname + 5, 0))
return 0;
- len = strlen(refname) + 1;
- ref = xcalloc(1, sizeof(*ref) + len);
+ ref = alloc_ref(refname);
oidcpy(&ref->new_oid, oid);
- memcpy(ref->name, refname, len);
**local_tail = ref;
*local_tail = &ref->next;
return 0;
return -1;
}
- static const char **prepare_shell_cmd(const char **argv)
+ static const char **prepare_shell_cmd(struct argv_array *out, const char **argv)
{
- int argc, nargc = 0;
- const char **nargv;
-
- for (argc = 0; argv[argc]; argc++)
- ; /* just counting */
- /* +1 for NULL, +3 for "sh -c" plus extra $0 */
- nargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3));
-
- if (argc < 1)
+ if (!argv[0])
die("BUG: shell command is empty");
if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
#ifndef GIT_WINDOWS_NATIVE
- nargv[nargc++] = SHELL_PATH;
+ argv_array_push(out, SHELL_PATH);
#else
- nargv[nargc++] = "sh";
+ argv_array_push(out, "sh");
#endif
- nargv[nargc++] = "-c";
-
- if (argc < 2)
- nargv[nargc++] = argv[0];
- else {
- struct strbuf arg0 = STRBUF_INIT;
- strbuf_addf(&arg0, "%s \"$@\"", argv[0]);
- nargv[nargc++] = strbuf_detach(&arg0, NULL);
- }
- }
+ argv_array_push(out, "-c");
- for (argc = 0; argv[argc]; argc++)
- nargv[nargc++] = argv[argc];
- nargv[nargc] = NULL;
+ /*
+ * If we have no extra arguments, we do not even need to
+ * bother with the "$@" magic.
+ */
+ if (!argv[1])
+ argv_array_push(out, argv[0]);
+ else
+ argv_array_pushf(out, "%s \"$@\"", argv[0]);
+ }
- return nargv;
+ argv_array_pushv(out, argv);
+ return out->argv;
}
#ifndef GIT_WINDOWS_NATIVE
static int execv_shell_cmd(const char **argv)
{
- const char **nargv = prepare_shell_cmd(argv);
- trace_argv_printf(nargv, "trace: exec:");
- sane_execvp(nargv[0], (char **)nargv);
- free(nargv);
+ struct argv_array nargv = ARGV_ARRAY_INIT;
+ prepare_shell_cmd(&nargv, argv);
+ trace_argv_printf(nargv.argv, "trace: exec:");
+ sane_execvp(nargv.argv[0], (char **)nargv.argv);
+ argv_array_clear(&nargv);
return -1;
}
#endif
{
int fhin = 0, fhout = 1, fherr = 2;
const char **sargv = cmd->argv;
+ struct argv_array nargv = ARGV_ARRAY_INIT;
if (cmd->no_stdin)
fhin = open("/dev/null", O_RDWR);
fhout = dup(cmd->out);
if (cmd->git_cmd)
- cmd->argv = prepare_git_cmd(cmd->argv);
+ cmd->argv = prepare_git_cmd(&nargv, cmd->argv);
else if (cmd->use_shell)
- cmd->argv = prepare_shell_cmd(cmd->argv);
+ cmd->argv = prepare_shell_cmd(&nargv, cmd->argv);
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
cmd->dir, fhin, fhout, fherr);
if (cmd->clean_on_exit && cmd->pid >= 0)
mark_child_for_cleanup(cmd->pid);
- if (cmd->git_cmd)
- free(cmd->argv);
-
+ argv_array_clear(&nargv);
cmd->argv = sargv;
if (fhin != 0)
close(fhin);
return !pthread_equal(main_thread, pthread_self());
}
+void NORETURN async_exit(int code)
+{
+ pthread_exit((void *)(intptr_t)code);
+}
+
#else
static struct {
return process_is_async;
}
+void NORETURN async_exit(int code)
+{
+ exit(code);
+}
+
#endif
int start_async(struct async *async)
const char *orig = path;
char *sanitized;
if (is_absolute_path(orig)) {
- sanitized = xmalloc(strlen(path) + 1);
+ sanitized = xmallocz(strlen(path));
if (remaining_prefix)
*remaining_prefix = 0;
if (normalize_path_copy_len(sanitized, path, remaining_prefix)) {
if (arg[2] == '\0') /* ":/" is root dir, always exists */
return 1;
name = arg + 2;
- } else if (!no_wildcard(arg))
- return 1;
- else if (prefix)
+ } else if (prefix)
name = prefix_filename(prefix, strlen(prefix), arg);
else
name = arg;
{
if (*arg == '-')
die("bad flag '%s' used after filename", arg);
- if (check_filename(prefix, arg))
+ if (check_filename(prefix, arg) || !no_wildcard(arg))
return;
die_verify_filename(prefix, arg, diagnose_misspelt_rev);
}
return ret;
}
-static void update_linked_gitdir(const char *gitfile, const char *gitdir)
-{
- struct strbuf path = STRBUF_INIT;
- struct stat st;
-
- strbuf_addf(&path, "%s/gitdir", gitdir);
- if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
- write_file(path.buf, "%s", gitfile);
- strbuf_release(&path);
-}
-
/*
* Try to read the location of the git directory from the .git file,
* return path to git directory if found.
error_code = READ_GITFILE_ERR_OPEN_FAILED;
goto cleanup_return;
}
- buf = xmalloc(st.st_size + 1);
+ buf = xmallocz(st.st_size);
len = read_in_full(fd, buf, st.st_size);
close(fd);
if (len != st.st_size) {
error_code = READ_GITFILE_ERR_READ_FAILED;
goto cleanup_return;
}
- buf[len] = '\0';
if (!starts_with(buf, "gitdir: ")) {
error_code = READ_GITFILE_ERR_INVALID_FORMAT;
goto cleanup_return;
error_code = READ_GITFILE_ERR_NOT_A_REPO;
goto cleanup_return;
}
- update_linked_gitdir(path, dir);
path = real_path(dir);
cleanup_return:
* object databases including our own.
*/
const char *objdir = get_object_directory();
- int objdir_len = strlen(objdir);
- int entlen = objdir_len + 43;
- fakeent = xmalloc(sizeof(*fakeent) + entlen);
+ size_t objdir_len = strlen(objdir);
+ fakeent = xmalloc(st_add3(sizeof(*fakeent), objdir_len, 43));
memcpy(fakeent->base, objdir, objdir_len);
fakeent->name = fakeent->base + objdir_len + 1;
fakeent->name[-1] = '/';
if (prefix[0] == '!') {
if (prefix[1] != '!')
- die ("Invalid search pattern: %s", prefix);
+ return -1;
prefix++;
}
if (regcomp(®ex, prefix, REG_EXTENDED))
- die("Invalid search pattern: %s", prefix);
+ return -1;
for (l = list; l; l = l->next) {
l->item->object.flags |= ONELINE_SEEN;
strbuf_addstr(&entry, "submodule.");
strbuf_addstr(&entry, submodule->name);
strbuf_addstr(&entry, ".path");
- if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
+ if (git_config_set_in_file_gently(".gitmodules", entry.buf, newpath) < 0) {
/* Maybe the user already did that, don't error out here */
warning(_("Could not update .gitmodules entry %s"), entry.buf);
strbuf_release(&entry);
struct strbuf objects_directory = STRBUF_INIT;
struct alternate_object_database *alt_odb;
int ret = 0;
- int alloc;
+ size_t alloc;
strbuf_git_path_submodule(&objects_directory, path, "objects/");
if (!is_directory(objects_directory.buf)) {
objects_directory.len))
goto done;
- alloc = objects_directory.len + 42; /* for "12/345..." sha1 */
- alt_odb = xmalloc(sizeof(*alt_odb) + alloc);
+ alloc = st_add(objects_directory.len, 42); /* for "12/345..." sha1 */
+ alt_odb = xmalloc(st_add(sizeof(*alt_odb), alloc));
alt_odb->next = alt_odb_list;
xsnprintf(alt_odb->base, alloc, "%s", objects_directory.buf);
alt_odb->name = alt_odb->base + objects_directory.len;
/* Update core.worktree setting */
strbuf_reset(&file_name);
strbuf_addf(&file_name, "%s/config", git_dir);
- if (git_config_set_in_file(file_name.buf, "core.worktree",
- relative_path(real_work_tree, git_dir,
- &rel_path)))
- die(_("Could not set core.worktree in %s"),
- file_name.buf);
+ git_config_set_in_file(file_name.buf, "core.worktree",
+ relative_path(real_work_tree, git_dir,
+ &rel_path));
strbuf_release(&file_name);
strbuf_release(&rel_path);