#include "quote.h"
#include "sha1-lookup.h"
#include "run-command.h"
+#include "log-tree.h"
#include "bisect.h"
struct sha1_array {
int argv_alloc;
};
-static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL};
static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
return for_each_ref_in("refs/bisect/", register_ref, NULL);
}
-void read_bisect_paths(struct argv_array *array)
+static void read_bisect_paths(struct argv_array *array)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path("BISECT_NAMES");
FILE *fp = fopen(filename, "r");
if (!fp)
- die("Could not open file '%s': %s", filename, strerror(errno));
+ die_errno("Could not open file '%s'", filename);
while (strbuf_getline(&str, fp, '\n') != EOF) {
char *quoted;
return strbuf_detach(&joined_hexs, NULL);
}
+/*
+ * In this function, passing a not NULL skipped_first is very special.
+ * It means that we want to know if the first commit in the list is
+ * skipped because we will want to test a commit away from it if it is
+ * indeed skipped.
+ * So if the first commit is skipped, we cannot take the shortcut to
+ * just "return list" when we find the first non skipped commit, we
+ * have to return a fully filtered list.
+ *
+ * We use (*skipped_first == -1) to mean "it has been found that the
+ * first commit is not skipped". In this case *skipped_first is set back
+ * to 0 just before the function returns.
+ */
struct commit_list *filter_skipped(struct commit_list *list,
struct commit_list **tried,
- int show_all)
+ int show_all,
+ int *count,
+ int *skipped_first)
{
struct commit_list *filtered = NULL, **f = &filtered;
*tried = NULL;
+ if (skipped_first)
+ *skipped_first = 0;
+ if (count)
+ *count = 0;
+
if (!skipped_revs.sha1_nr)
return list;
list->next = NULL;
if (0 <= lookup_sha1_array(&skipped_revs,
list->item->object.sha1)) {
+ if (skipped_first && !*skipped_first)
+ *skipped_first = 1;
/* Move current to tried list */
*tried = list;
tried = &list->next;
} else {
- if (!show_all)
- return list;
+ if (!show_all) {
+ if (!skipped_first || !*skipped_first)
+ return list;
+ } else if (skipped_first && !*skipped_first) {
+ /* This means we know it's not skipped */
+ *skipped_first = -1;
+ }
/* Move current to filtered list */
*f = list;
f = &list->next;
+ if (count)
+ (*count)++;
}
list = next;
}
+ if (skipped_first && *skipped_first == -1)
+ *skipped_first = 0;
+
return filtered;
}
+#define PRN_MODULO 32768
+
+/*
+ * This is a pseudo random number generator based on "man 3 rand".
+ * It is not used properly because the seed is the argument and it
+ * is increased by one between each call, but that should not matter
+ * for this application.
+ */
+int get_prn(int count) {
+ count = count * 1103515245 + 12345;
+ return ((unsigned)(count/65536) % PRN_MODULO);
+}
+
+/*
+ * Custom integer square root from
+ * http://en.wikipedia.org/wiki/Integer_square_root
+ */
+static int sqrti(int val)
+{
+ float d, x = val;
+
+ if (val == 0)
+ return 0;
+
+ do {
+ float y = (x + (float)val / x) / 2;
+ d = (y > x) ? y - x : x - y;
+ x = y;
+ } while (d >= 0.5);
+
+ return (int)x;
+}
+
+static struct commit_list *skip_away(struct commit_list *list, int count)
+{
+ struct commit_list *cur, *previous;
+ int prn, index, i;
+
+ prn = get_prn(count);
+ index = (count * prn / PRN_MODULO) * sqrti(prn) / sqrti(PRN_MODULO);
+
+ cur = list;
+ previous = NULL;
+
+ for (i = 0; cur; cur = cur->next, i++) {
+ if (i == index) {
+ if (hashcmp(cur->item->object.sha1, current_bad_sha1))
+ return cur;
+ if (previous)
+ return previous;
+ return list;
+ }
+ previous = cur;
+ }
+
+ return list;
+}
+
+static struct commit_list *managed_skipped(struct commit_list *list,
+ struct commit_list **tried)
+{
+ int count, skipped_first;
+
+ *tried = NULL;
+
+ if (!skipped_revs.sha1_nr)
+ return list;
+
+ list = filter_skipped(list, tried, 0, &count, &skipped_first);
+
+ if (!skipped_first)
+ return list;
+
+ return skip_away(list, count);
+}
+
static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
const char *bad_format, const char *good_format,
int read_paths)
int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
- die("could not create file '%s': %s",
- filename, strerror(errno));
+ die_errno("could not create file '%s'", filename);
bisect_rev_hex[len] = '\n';
write_or_die(fd, bisect_rev_hex, len + 1);
exit(1);
}
-void handle_skipped_merge_base(const unsigned char *mb)
+static void handle_skipped_merge_base(const unsigned char *mb)
{
char *mb_hex = sha1_to_hex(mb);
char *bad_hex = sha1_to_hex(current_bad_sha1);
/* Clean up objects used, as they will be reused. */
for (i = 0; i < pending_copy.nr; i++) {
struct object *o = pending_copy.objects[i].item;
- unparse_commit((struct commit *)o);
+ clear_commit_marks((struct commit *)o, ALL_REV_FLAGS);
}
return res;
close(fd);
}
+/*
+ * This does "git diff-tree --pretty COMMIT" without one fork+exec.
+ */
+static void show_diff_tree(const char *prefix, struct commit *commit)
+{
+ struct rev_info opt;
+
+ /* diff-tree init */
+ init_revisions(&opt, prefix);
+ git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+ opt.abbrev = 0;
+ opt.diff = 1;
+
+ /* This is what "--pretty" does */
+ opt.verbose_header = 1;
+ opt.use_terminator = 0;
+ opt.commit_format = CMIT_FMT_DEFAULT;
+
+ /* diff-tree init */
+ if (!opt.diffopt.output_format)
+ opt.diffopt.output_format = DIFF_FORMAT_RAW;
+
+ log_tree_commit(&opt, commit);
+}
+
/*
* We use the convention that exiting with an exit code 10 means that
* the bisection process finished successfully.
revs.commits = find_bisection(revs.commits, &reaches, &all,
!!skipped_revs.sha1_nr);
- revs.commits = filter_skipped(revs.commits, &tried, 0);
+ revs.commits = managed_skipped(revs.commits, &tried);
if (!revs.commits) {
/*
if (!hashcmp(bisect_rev, current_bad_sha1)) {
exit_if_skipped_commits(tried, current_bad_sha1);
printf("%s is first bad commit\n", bisect_rev_hex);
- argv_diff_tree[2] = bisect_rev_hex;
- run_command_v_opt(argv_diff_tree, RUN_GIT_CMD);
+ show_diff_tree(prefix, revs.commits->item);
/* This means the bisection process succeeded. */
exit(10);
}
return status;
}
-int edit_patch(int argc, const char **argv, const char *prefix)
+static int edit_patch(int argc, const char **argv, const char *prefix)
{
char *file = xstrdup(git_path("ADD_EDIT.patch"));
const char *apply_argv[] = { "apply", "--recount", "--cached",
launch_editor(file, NULL, NULL);
if (stat(file, &st))
- die("Could not stat '%s'", file);
+ die_errno("Could not stat '%s'", file);
if (!st.st_size)
die("Empty patch. Aborted.");
int add_new_files;
int require_pathspec;
+ git_config(add_config, NULL);
+
argc = parse_options(argc, argv, prefix, builtin_add_options,
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive)
if (add_interactive)
exit(interactive_add(argc - 1, argv + 1, prefix));
- git_config(add_config, NULL);
-
if (edit_interactive)
return(edit_patch(argc, argv, prefix));
argc--;
static void read_patch_file(struct strbuf *sb, int fd)
{
if (strbuf_read(sb, fd, 0) < 0)
- die("git apply: read returned %s", strerror(errno));
+ die_errno("git apply: failed to read");
/*
* Make sure that we have some slop in the buffer
static void build_fake_ancestor(struct patch *list, const char *filename)
{
struct patch *patch;
- struct index_state result = { 0 };
+ struct index_state result = { NULL };
int fd;
/* Once we start supporting the reverse patch, it may be
} else {
if (!cached) {
if (lstat(path, &st) < 0)
- die("unable to stat newly created file %s",
- path);
+ die_errno("unable to stat newly created file '%s'",
+ path);
fill_stat_cache_info(ce, &st);
}
if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
strbuf_release(&nbuf);
if (close(fd) < 0)
- die("closing file %s: %s", path, strerror(errno));
+ die_errno("closing file '%s'", path);
return 0;
}
++nr;
}
}
- die("unable to write file %s mode %o", path, mode);
+ die_errno("unable to write file '%s' mode %o", path, mode);
}
static void create_file(struct patch *patch)
OPT_BOOLEAN(0, "stat", &diffstat,
"instead of applying the patch, output diffstat for the input"),
{ OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary,
- NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
+ NULL, "old option, now no-op",
+ PARSE_OPT_HIDDEN | PARSE_OPT_NOARG },
{ OPTION_BOOLEAN, 0, "binary", &binary,
- NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
+ NULL, "old option, now no-op",
+ PARSE_OPT_HIDDEN | PARSE_OPT_NOARG },
OPT_BOOLEAN(0, "numstat", &numstat,
"shows number of added and deleted lines in decimal notation"),
OPT_BOOLEAN(0, "summary", &summary,
fd = open(arg, O_RDONLY);
if (fd < 0)
- die("can't open patch '%s': %s", arg, strerror(errno));
+ die_errno("can't open patch '%s'", arg);
read_stdin = 0;
set_default_whitespace_mode(whitespace_option);
errs |= apply_patch(fd, arg, options);
if (is_bare) {
struct strbuf result = STRBUF_INIT;
strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
- dir = strbuf_detach(&result, 0);
+ dir = strbuf_detach(&result, NULL);
} else
dir = xstrndup(start, end - start);
/*
dir = opendir(src->buf);
if (!dir)
- die("failed to open %s", src->buf);
+ die_errno("failed to open '%s'", src->buf);
if (mkdir(dest->buf, 0777)) {
if (errno != EEXIST)
- die("failed to create directory %s", dest->buf);
+ die_errno("failed to create directory '%s'", dest->buf);
else if (stat(dest->buf, &buf))
- die("failed to stat %s", dest->buf);
+ die_errno("failed to stat '%s'", dest->buf);
else if (!S_ISDIR(buf.st_mode))
die("%s exists and is not a directory", dest->buf);
}
}
if (unlink(dest->buf) && errno != ENOENT)
- die("failed to unlink %s: %s",
- dest->buf, strerror(errno));
+ die_errno("failed to unlink '%s'", dest->buf);
if (!option_no_hardlinks) {
if (!link(src->buf, dest->buf))
continue;
if (option_local)
- die("failed to create link %s", dest->buf);
+ die_errno("failed to create link '%s'", dest->buf);
option_no_hardlinks = 1;
}
if (copy_file(dest->buf, src->buf, 0666))
- die("failed to copy file to %s", dest->buf);
+ die_errno("failed to copy file to '%s'", dest->buf);
}
closedir(dir);
}
if (!option_bare) {
junk_work_tree = work_tree;
if (safe_create_leading_directories_const(work_tree) < 0)
- die("could not create leading directories of '%s': %s",
- work_tree, strerror(errno));
+ die_errno("could not create leading directories of '%s'",
+ work_tree);
if (!dest_exists && mkdir(work_tree, 0755))
- die("could not create work tree dir '%s': %s.",
- work_tree, strerror(errno));
+ die_errno("could not create work tree dir '%s'.",
+ work_tree);
set_git_work_tree(work_tree);
}
junk_git_dir = git_dir;
static void mark_object_reachable(struct object *obj)
{
- mark_object(obj, OBJ_ANY, 0);
+ mark_object(obj, OBJ_ANY, NULL);
}
static int traverse_one_object(struct object *obj, struct object *parent)
return;
}
if (!(f = fopen(filename, "w")))
- die("Could not open %s", filename);
+ die_errno("Could not open '%s'", filename);
if (obj->type == OBJ_BLOB) {
enum object_type type;
unsigned long size;
&type, &size);
if (buf) {
if (fwrite(buf, size, 1, f) != 1)
- die("Could not write %s: %s",
- filename, strerror(errno));
+ die_errno("Could not write '%s'",
+ filename);
free(buf);
}
} else
fprintf(f, "%s\n", sha1_to_hex(obj->sha1));
if (fclose(f))
- die("Could not finish %s: %s",
- filename, strerror(errno));
+ die_errno("Could not finish '%s'",
+ filename);
}
return;
}
fprintf(stderr, "Checking %s %s\n",
typename(obj->type), sha1_to_hex(obj->sha1));
- if (fsck_walk(obj, mark_used, 0))
+ if (fsck_walk(obj, mark_used, NULL))
objerror(obj, "broken links");
if (fsck_object(obj, check_strict, fsck_error_func))
return -1;
printf("Final output: %d %s\n", nr, stage);
}
-struct itimerval early_output_timer;
+static struct itimerval early_output_timer;
static void log_show_early(struct rev_info *revs, struct commit_list *list)
{
strbuf_addch(&buf, '\n');
}
- rev.extra_headers = strbuf_detach(&buf, 0);
+ rev.extra_headers = strbuf_detach(&buf, NULL);
if (start_number < 0)
start_number = 1;
if (use_stdout)
die("standard output, or directory, which one?");
if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
- die("Could not create directory %s",
- output_directory);
+ die_errno("Could not create directory '%s'",
+ output_directory);
}
if (rev.pending.nr == 1) {
printf("Squash commit -- not updating HEAD\n");
fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
if (fd < 0)
- die("Could not write to %s", git_path("SQUASH_MSG"));
+ die_errno("Could not write to '%s'", git_path("SQUASH_MSG"));
init_revisions(&rev, NULL);
rev.ignore_merges = 1;
NULL, NULL, rev.date_mode, 0);
}
if (write(fd, out.buf, out.len) < 0)
- die("Writing SQUASH_MSG: %s", strerror(errno));
+ die_errno("Writing SQUASH_MSG");
if (close(fd))
- die("Finishing SQUASH_MSG: %s", strerror(errno));
+ die_errno("Finishing SQUASH_MSG");
strbuf_release(&out);
}
strbuf_addstr(&buf, "refs/heads/");
strbuf_addstr(&buf, remote);
- resolve_ref(buf.buf, branch_head, 0, 0);
+ resolve_ref(buf.buf, branch_head, 0, NULL);
if (!hashcmp(remote_head->sha1, branch_head)) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
strbuf_addstr(&truname, "refs/heads/");
strbuf_addstr(&truname, remote);
strbuf_setlen(&truname, truname.len - len);
- if (resolve_ref(truname.buf, buf_sha, 0, 0)) {
+ if (resolve_ref(truname.buf, buf_sha, 0, NULL)) {
strbuf_addf(msg,
"%s\t\tbranch '%s'%s of .\n",
sha1_to_hex(remote_head->sha1),
fp = fopen(git_path("FETCH_HEAD"), "r");
if (!fp)
- die("could not open %s for reading: %s",
- git_path("FETCH_HEAD"), strerror(errno));
+ die_errno("could not open '%s' for reading",
+ git_path("FETCH_HEAD"));
strbuf_getline(&line, fp, '\n');
fclose(fp);
ptr = strstr(line.buf, "\tnot-for-merge\t");
fp = fopen(git_path("MERGE_MSG"), "a");
if (!fp)
- die("Could not open %s for writing", git_path("MERGE_MSG"));
+ die_errno("Could not open '%s' for writing",
+ git_path("MERGE_MSG"));
fprintf(fp, "\nConflicts:\n");
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
struct commit_list **remotes = &remoteheads;
setup_work_tree();
+ if (file_exists(git_path("MERGE_HEAD")))
+ die("You have not concluded your merge. (MERGE_HEAD exists)");
if (read_cache_unmerged())
- die("You are in the middle of a conflicted merge.");
+ die("You are in the middle of a conflicted merge."
+ " (index unmerged)");
/*
* Check if we are _not_ on a detached HEAD, i.e. if there is a
sha1_to_hex(j->item->object.sha1));
fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
if (fd < 0)
- die("Could open %s for writing",
- git_path("MERGE_HEAD"));
+ die_errno("Could not open '%s' for writing",
+ git_path("MERGE_HEAD"));
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
- die("Could not write to %s", git_path("MERGE_HEAD"));
+ die_errno("Could not write to '%s'", git_path("MERGE_HEAD"));
close(fd);
strbuf_addch(&merge_msg, '\n');
fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
if (fd < 0)
- die("Could open %s for writing", git_path("MERGE_MSG"));
+ die_errno("Could not open '%s' for writing",
+ git_path("MERGE_MSG"));
if (write_in_full(fd, merge_msg.buf, merge_msg.len) !=
merge_msg.len)
- die("Could not write to %s", git_path("MERGE_MSG"));
+ die_errno("Could not write to '%s'", git_path("MERGE_MSG"));
close(fd);
fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
- die("Could open %s for writing", git_path("MERGE_MODE"));
+ die_errno("Could not open '%s' for writing",
+ git_path("MERGE_MODE"));
strbuf_reset(&buf);
if (!allow_fast_forward)
strbuf_addf(&buf, "no-ff");
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
- die("Could not write to %s", git_path("MERGE_MODE"));
+ die_errno("Could not write to '%s'", git_path("MERGE_MODE"));
close(fd);
}
result[count] = NULL;
for (i = 0; i < count; i++) {
int length = strlen(result[i]);
- if (length > 0 && result[i][length - 1] == '/') {
+ if (length > 0 && is_dir_sep(result[i][length - 1]))
result[i] = xmemdupz(result[i], length - 1);
- }
- if (base_name) {
- const char *last_slash = strrchr(result[i], '/');
- if (last_slash)
- result[i] = last_slash + 1;
- }
+ if (base_name)
+ result[i] = basename((char *)result[i]);
}
return get_pathspec(prefix, result);
}
printf("Renaming %s to %s\n", src, dst);
if (!show_only && mode != INDEX &&
rename(src, dst) < 0 && !ignore_errors)
- die ("renaming %s failed: %s", src, strerror(errno));
+ die_errno ("renaming '%s' failed", src);
if (mode == WORKING_DIRECTORY)
continue;
base_name, sha1_to_hex(sha1));
free_pack_by_name(tmpname);
if (adjust_perm(pack_tmp_name, mode))
- die("unable to make temporary pack file readable: %s",
- strerror(errno));
+ die_errno("unable to make temporary pack file readable");
if (rename(pack_tmp_name, tmpname))
- die("unable to rename temporary pack file: %s",
- strerror(errno));
+ die_errno("unable to rename temporary pack file");
/*
* Packs are runtime accessed in their mtime
snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
base_name, sha1_to_hex(sha1));
if (adjust_perm(idx_tmp_name, mode))
- die("unable to make temporary index file readable: %s",
- strerror(errno));
+ die_errno("unable to make temporary index file readable");
if (rename(idx_tmp_name, tmpname))
- die("unable to rename temporary index file: %s",
- strerror(errno));
+ die_errno("unable to rename temporary index file");
free(idx_tmp_name);
free(pack_tmp_name);
static unsigned name_hash(const char *name)
{
- unsigned char c;
- unsigned hash = 0;
+ unsigned c, hash = 0;
if (!name)
return 0;
if (!ferror(stdin))
die("fgets returned NULL, not EOF, not error!");
if (errno != EINTR)
- die("fgets: %s", strerror(errno));
+ die_errno("fgets");
clearerr(stdin);
continue;
}
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
{
- static int keep_dashdash = 0;
+ static int keep_dashdash = 0, stop_at_non_option = 0;
static char const * const parseopt_usage[] = {
"git rev-parse --parseopt [options] -- [<args>...]",
NULL
static struct option parseopt_opts[] = {
OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
"keep the `--` passed as an arg"),
+ OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
+ "stop parsing after the "
+ "first non-option argument"),
OPT_END(),
};
ALLOC_GROW(opts, onb + 1, osz);
memset(opts + onb, 0, sizeof(opts[onb]));
argc = parse_options(argc, argv, prefix, opts, usage,
- keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
+ keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0 |
+ stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0);
strbuf_addf(&parsed, " --");
sq_quote_argv(&parsed, argv, 0);
continue;
}
if (!getcwd(cwd, PATH_MAX))
- die("unable to get current working directory");
+ die_errno("unable to get current working directory");
printf("%s/.git\n", cwd);
continue;
}
po.out = fd;
po.git_cmd = 1;
if (start_command(&po))
- die("git pack-objects failed (%s)", strerror(errno));
+ die_errno("git pack-objects failed");
/*
* We feed the pack-objects we just spawned with revision
int fd[2];
struct child_process *conn;
struct extra_have_objects extra_have;
- struct ref *remote_refs, **remote_tail, *local_refs;
+ struct ref *remote_refs, *local_refs;
int ret;
int send_all = 0;
const char *receivepack = "git-receive-pack";
flags |= MATCH_REFS_MIRROR;
/* match them up */
- remote_tail = &remote_refs;
- while (*remote_tail)
- remote_tail = &((*remote_tail)->next);
- if (match_refs(local_refs, remote_refs, &remote_tail,
- nr_refspecs, refspecs, flags)) {
+ if (match_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
return -1;
- }
ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
path = git_pathdup("TAG_EDITMSG");
fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
- die("could not create file '%s': %s",
- path, strerror(errno));
+ die_errno("could not create file '%s'", path);
if (!is_null_sha1(prev))
write_tag_body(fd, prev);
struct commit_list *with_commit = NULL;
struct option options[] = {
OPT_BOOLEAN('l', NULL, &list, "list tag names"),
- { OPTION_INTEGER, 'n', NULL, &lines, NULL,
- "print n lines of each tag message",
+ { OPTION_INTEGER, 'n', NULL, &lines, "n",
+ "print <n> lines of each tag message",
PARSE_OPT_OPTARG, NULL, 1 },
OPT_BOOLEAN('d', NULL, &delete, "delete tags"),
OPT_BOOLEAN('v', NULL, &verify, "verify tags"),
else {
if (!strcmp(msgfile, "-")) {
if (strbuf_read(&buf, 0, 1024) < 0)
- die("cannot read %s", msgfile);
+ die_errno("cannot read '%s'", msgfile);
} else {
if (strbuf_read_file(&buf, msgfile, 1024) < 0)
- die("could not open or read '%s': %s",
- msgfile, strerror(errno));
+ die_errno("could not open or read '%s'",
+ msgfile);
}
}
}
if (ret <= 0) {
if (!ret)
die("early EOF");
- die("read error on input: %s", strerror(errno));
+ die_errno("read error on input");
}
len += ret;
} while (len < min);
#define FLAG_WRITTEN (1u<<21)
static struct obj_info *obj_list;
-unsigned nr_objects;
+static unsigned nr_objects;
/*
* Called only from check_object() after it verified this object
if (fsck_object(obj, 1, fsck_error_function))
die("Error in object");
- if (!fsck_walk(obj, check_object, 0))
+ if (!fsck_walk(obj, check_object, NULL))
die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
write_cached_object(obj);
return 1;
{
unsigned i;
for (i = 0; i < nr_objects; i++)
- check_object(obj_list[i].obj, OBJ_ANY, 0);
+ check_object(obj_list[i].obj, OBJ_ANY, NULL);
}
static void added_object(unsigned nr, enum object_type type,
static void unpack_one(unsigned nr)
{
unsigned shift;
- unsigned char *pack, c;
- unsigned long size;
+ unsigned char *pack;
+ unsigned long size, c;
enum object_type type;
obj_list[nr].offset = consumed_bytes;
#include "cache.h"
#include "pkt-line.h"
#include "exec_cmd.h"
+#include "run-command.h"
+#include "strbuf.h"
#include <syslog.h>
return service->fn();
}
+static void copy_to_log(int fd)
+{
+ struct strbuf line = STRBUF_INIT;
+ FILE *fp;
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ logerror("fdopen of error channel failed");
+ close(fd);
+ return;
+ }
+
+ while (strbuf_getline(&line, fp, '\n') != EOF) {
+ logerror("%s", line.buf);
+ strbuf_setlen(&line, 0);
+ }
+
+ strbuf_release(&line);
+ fclose(fp);
+}
+
+static int run_service_command(const char **argv)
+{
+ struct child_process cld;
+
+ memset(&cld, 0, sizeof(cld));
+ cld.argv = argv;
+ cld.git_cmd = 1;
+ cld.err = -1;
+ if (start_command(&cld))
+ return -1;
+
+ close(0);
+ close(1);
+
+ copy_to_log(cld.err);
+
+ return finish_command(&cld);
+}
+
static int upload_pack(void)
{
/* Timeout as string */
char timeout_buf[64];
+ const char *argv[] = { "upload-pack", "--strict", timeout_buf, ".", NULL };
snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
-
- /* git-upload-pack only ever reads stuff, so this is safe */
- execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL);
- return -1;
+ return run_service_command(argv);
}
static int upload_archive(void)
{
- execl_git_cmd("upload-archive", ".", NULL);
- return -1;
+ static const char *argv[] = { "upload-archive", ".", NULL };
+ return run_service_command(argv);
}
static int receive_pack(void)
{
- execl_git_cmd("receive-pack", ".", NULL);
- return -1;
+ static const char *argv[] = { "receive-pack", ".", NULL };
+ return run_service_command(argv);
}
static struct daemon_service daemon_service[] = {
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
- gai = getaddrinfo(hostname, 0, &hints, &ai);
+ gai = getaddrinfo(hostname, NULL, &hints, &ai);
if (!gai) {
struct sockaddr_in *sin_addr = (void *)ai->ai_addr;
case ECONNABORTED:
continue;
default:
- die("accept returned %s", strerror(errno));
+ die_errno("accept returned");
}
}
handle(incoming, (struct sockaddr *)&ss, sslen);
while (fd != -1 && fd < 2)
fd = dup(fd);
if (fd == -1)
- die("open /dev/null or dup failed: %s", strerror(errno));
+ die_errno("open /dev/null or dup failed");
if (fd > 2)
close(fd);
}
case 0:
break;
case -1:
- die("fork failed: %s", strerror(errno));
+ die_errno("fork failed");
default:
exit(0);
}
if (setsid() == -1)
- die("setsid failed: %s", strerror(errno));
+ die_errno("setsid failed");
close(0);
close(1);
close(2);
{
FILE *f = fopen(path, "w");
if (!f)
- die("cannot open pid file %s: %s", path, strerror(errno));
+ die_errno("cannot open pid file '%s'", path);
if (fprintf(f, "%"PRIuMAX"\n", (uintmax_t) getpid()) < 0 || fclose(f) != 0)
- die("failed to write pid file %s: %s", path, strerror(errno));
+ die_errno("failed to write pid file '%s'", path);
}
static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
socklen_t slen = sizeof(ss);
if (!freopen("/dev/null", "w", stderr))
- die("failed to redirect stderr to /dev/null: %s",
- strerror(errno));
+ die_errno("failed to redirect stderr to /dev/null");
if (getpeername(0, peer, &slen))
peer = NULL;
fd = git_mkstemps(temp->tmp_path, PATH_MAX, template.buf,
strlen(base) + 1);
if (fd < 0)
- die("unable to create temp-file: %s", strerror(errno));
+ die_errno("unable to create temp-file");
if (convert_to_working_tree(path,
(const char *)blob, (size_t)size, &buf)) {
blob = buf.buf;
size = buf.len;
}
if (write_in_full(fd, blob, size) != size)
- die("unable to write temp-file");
+ die_errno("unable to write temp-file");
close(fd);
temp->name = temp->tmp_path;
strcpy(temp->hex, sha1_to_hex(sha1));
if (lstat(name, &st) < 0) {
if (errno == ENOENT)
goto not_a_valid_file;
- die("stat(%s): %s", name, strerror(errno));
+ die_errno("stat(%s)", name);
}
if (S_ISLNK(st.st_mode)) {
struct strbuf sb = STRBUF_INIT;
if (strbuf_readlink(&sb, name, st.st_size) < 0)
- die("readlink(%s)", name);
+ die_errno("readlink(%s)", name);
prep_temp_blob(name, temp, sb.buf, sb.len,
(one->sha1_valid ?
one->sha1 : null_sha1),
return;
}
if (lstat(one->path, &st) < 0)
- die("stat %s", one->path);
+ die_errno("stat '%s'", one->path);
if (index_path(one->sha1, one->path, &st, 0))
die("cannot hash %s", one->path);
}
if (start_command(&child) != 0 ||
strbuf_read(&buf, child.out, 0) < 0 ||
finish_command(&child) != 0) {
+ strbuf_release(&buf);
remove_tempfile();
error("error running textconv command '%s'", pgm);
return NULL;
/*
* See if our compiler is known to support flexible array members.
*/
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && (!defined(__SUNPRO_C) || (__SUNPRO_C > 0x580))
# define FLEX_ARRAY /* empty */
#elif defined(__GNUC__)
# if (__GNUC__ >= 3)
/* Approximation of the length of the decimal representation of this type. */
#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
-#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX)
+#if defined(__sun__)
+ /*
+ * On Solaris, when _XOPEN_EXTENDED is set, its header file
+ * forces the programs to be XPG4v2, defeating any _XOPEN_SOURCE
+ * setting to say we are XPG5 or XPG6. Also on Solaris,
+ * XPG6 programs must be compiled with a c99 compiler, while
+ * non XPG6 programs must be compiled with a pre-c99 compiler.
+ */
+# if __STDC_VERSION__ - 0 >= 199901L
+# define _XOPEN_SOURCE 600
+# else
+# define _XOPEN_SOURCE 500
+# endif
+#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX)
#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
#ifndef __sun__
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
/* General helper functions */
extern void usage(const char *err) NORETURN;
extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
+ extern void die_errno(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
alias_command);
new_argv = xrealloc(new_argv, sizeof(char *) *
- (count + *argcp + 1));
+ (count + *argcp));
/* insert after command name */
memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
- new_argv[count+*argcp] = NULL;
*argv = new_argv;
*argcp += count - 1;
}
if (subdir && chdir(subdir))
- die("Cannot change to %s: %s", subdir, strerror(errno));
+ die_errno("Cannot change to '%s'", subdir);
errno = saved_errno;
/* Check for ENOSPC and EIO errors.. */
if (fflush(stdout))
- die("write failure on standard output: %s", strerror(errno));
+ die_errno("write failure on standard output");
if (ferror(stdout))
die("unknown write failure on standard output");
if (fclose(stdout))
- die("close failed on standard output: %s", strerror(errno));
+ die_errno("close failed on standard output");
return 0;
}
if (ret <= 0) {
if (!ret)
die("early EOF");
- die("read error on input: %s", strerror(errno));
+ die_errno("read error on input");
}
input_len += ret;
if (from_stdin)
} else
output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
if (output_fd < 0)
- die("unable to create %s: %s", pack_name, strerror(errno));
+ die_errno("unable to create '%s'", pack_name);
pack_fd = output_fd;
} else {
input_fd = open(pack_name, O_RDONLY);
if (input_fd < 0)
- die("cannot open packfile '%s': %s",
- pack_name, strerror(errno));
+ die_errno("cannot open packfile '%s'", pack_name);
output_fd = -1;
pack_fd = input_fd;
}
static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_base)
{
- unsigned char *p, c;
- unsigned long size;
+ unsigned char *p;
+ unsigned long size, c;
off_t base_offset;
unsigned shift;
void *data;
p = fill(1);
c = *p;
use(1);
- size += (c & 0x7fUL) << shift;
+ size += (c & 0x7f) << shift;
shift += 7;
}
obj->size = size;
do {
ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
if (n < 0)
- die("cannot pread pack file: %s", strerror(errno));
+ die_errno("cannot pread pack file");
if (!n)
die("premature end of pack file, %lu bytes missing",
len - rdy);
die("invalid %s", typename(type));
if (fsck_object(obj, 1, fsck_error_function))
die("Error in object");
- if (fsck_walk(obj, mark_link, 0))
+ if (fsck_walk(obj, mark_link, NULL))
die("Not all child objects of %s are reachable", sha1_to_hex(obj->sha1));
if (obj->type == OBJ_TREE) {
/* If input_fd is a file, we should have reached its end now. */
if (fstat(input_fd, &st))
- die("cannot fstat packfile: %s", strerror(errno));
+ die_errno("cannot fstat packfile");
if (S_ISREG(st.st_mode) &&
lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
die("pack has junk at the end");
fsync_or_die(output_fd, curr_pack_name);
err = close(output_fd);
if (err)
- die("error while closing pack file: %s", strerror(errno));
+ die_errno("error while closing pack file");
}
if (keep_msg) {
if (keep_fd < 0) {
if (errno != EEXIST)
- die("cannot write keep file '%s' (%s)",
- keep_name, strerror(errno));
+ die_errno("cannot write keep file '%s'",
+ keep_name);
} else {
if (keep_msg_len > 0) {
write_or_die(keep_fd, keep_msg, keep_msg_len);
write_or_die(keep_fd, "\n", 1);
}
if (close(keep_fd) != 0)
- die("cannot close written keep file '%s' (%s)",
- keep_name, strerror(errno));
+ die_errno("cannot close written keep file '%s'",
+ keep_name);
report = "keep";
}
}
static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
mmbuffer_t *result,
- const char *path_unused,
+ const char *path,
mmfile_t *orig,
mmfile_t *src1, const char *name1,
mmfile_t *src2, const char *name2,
if (buffer_is_binary(orig->ptr, orig->size) ||
buffer_is_binary(src1->ptr, src1->size) ||
buffer_is_binary(src2->ptr, src2->size)) {
- warning("Cannot merge binary files: %s vs. %s\n",
- name1, name2);
+ warning("Cannot merge binary files: %s (%s vs. %s)\n",
+ path, name1, name2);
return ll_binary_merge(drv_unused, result,
- path_unused,
+ path,
orig, src1, name1,
src2, name2,
virtual_ancestor);
strcpy(path, ".merge_file_XXXXXX");
fd = xmkstemp(path);
if (write_in_full(fd, src->ptr, src->size) != src->size)
- die("unable to write temp-file");
+ die_errno("unable to write temp-file");
close(fd);
}
{ "B", temp[2] },
{ NULL }
};
- struct child_process child;
- const char *args[20];
+ const char *args[] = { "sh", "-c", NULL, NULL };
int status, fd, i;
struct stat st;
strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict);
- memset(&child, 0, sizeof(child));
- child.argv = args;
- args[0] = "sh";
- args[1] = "-c";
args[2] = cmd.buf;
- args[3] = NULL;
-
- status = run_command(&child);
+ status = run_command_v_opt(args, 0);
if (status < -ERR_RUN_COMMAND_FORK)
; /* failure in run-command */
else
if (!strcmp(var, "merge.default")) {
if (value)
- default_ll_merge = strdup(value);
+ default_ll_merge = xstrdup(value);
return 0;
}
if (!strcmp("name", ep)) {
if (!value)
return error("%s: lacks value", var);
- fn->description = strdup(value);
+ fn->description = xstrdup(value);
return 0;
}
* file named by %A, and signal that it has done with zero exit
* status.
*/
- fn->cmdline = strdup(value);
+ fn->cmdline = xstrdup(value);
return 0;
}
if (!strcmp("recursive", ep)) {
if (!value)
return error("%s: lacks value", var);
- fn->recursive = strdup(value);
+ fn->recursive = xstrdup(value);
return 0;
}
* A virtual commit has (const char *)commit->util set to the name.
*/
-struct commit *make_virtual_commit(struct tree *tree, const char *comment)
+static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
{
struct commit *commit = xcalloc(1, sizeof(struct commit));
commit->tree = tree;
/* Ignore epipe */
if (errno == EPIPE)
break;
- die("merge-recursive: %s", strerror(errno));
+ die_errno("merge-recursive");
} else if (!ret) {
die("merge-recursive: disk full?");
}
mode = 0666;
fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
if (fd < 0)
- die("failed to open %s: %s", path, strerror(errno));
+ die_errno("failed to open '%s'", path);
flush_buffer(fd, buf, size);
close(fd);
} else if (S_ISLNK(mode)) {
safe_create_leading_directories_const(path);
unlink(path);
if (symlink(lnk, path))
- die("failed to symlink %s: %s", path, strerror(errno));
+ die_errno("failed to symlink '%s'", path);
free(lnk);
} else
die("do not know what to do with %06o %s '%s'",
char *name1, *name2;
int merge_status;
- name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
- name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
+ if (strcmp(a->path, b->path)) {
+ name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
+ name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
+ } else {
+ name1 = xstrdup(mkpath("%s", branch1));
+ name2 = xstrdup(mkpath("%s", branch2));
+ }
fill_mm(one->sha1, &orig);
fill_mm(a->sha1, &src1);
unsigned long len, enum object_type *type, unsigned long *sizep)
{
unsigned shift;
- unsigned char c;
- unsigned long size;
+ unsigned long size, c;
unsigned long used = 0;
c = buf[used++];
if (fsync_object_files)
fsync_or_die(fd, "sha1 file");
if (close(fd) != 0)
- die("error when closing sha1 file (%s)", strerror(errno));
+ die_errno("error when closing sha1 file");
}
/* Size of directory component, including the ending '/' */
strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
if (!mkdtemp(temp_dir.buf))
- die ("Could not make temporary directory");
+ die_errno ("Could not make temporary directory");
temp_dir_len = temp_dir.len;
strbuf_addstr(&buf, rsync_url(transport->url));
strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
if (!mkdtemp(temp_dir.buf))
- die ("Could not make temporary directory");
+ die_errno ("Could not make temporary directory");
strbuf_addch(&temp_dir, '/');
if (flags & TRANSPORT_PUSH_ALL) {
char *ref_name;
char *refs_url;
int i = 0;
-
- struct active_request_slot *slot;
- struct slot_results results;
+ int http_ret;
struct ref *refs = NULL;
struct ref *ref = NULL;
refs_url = xmalloc(strlen(transport->url) + 11);
sprintf(refs_url, "%s/info/refs", transport->url);
- slot = get_active_slot();
- slot->results = &results;
- curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
- curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
- curl_easy_setopt(slot->curl, CURLOPT_URL, refs_url);
- curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
-
- if (start_active_slot(slot)) {
- run_active_slot(slot);
- if (results.curl_result != CURLE_OK) {
- strbuf_release(&buffer);
- if (missing_target(&results))
- die("%s not found: did you run git update-server-info on the server?", refs_url);
- else
- die("%s download error - %s", refs_url, curl_errorstr);
- }
- } else {
- strbuf_release(&buffer);
- die("Unable to start HTTP request");
+ http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
+ switch (http_ret) {
+ case HTTP_OK:
+ break;
+ case HTTP_MISSING_TARGET:
+ die("%s not found: did you run git update-server-info on the"
+ " server?", refs_url);
+ default:
+ http_error(refs_url, http_ret);
+ die("HTTP request failed");
}
data = buffer.buf;
free(ref);
}
+ strbuf_release(&buffer);
+ free(refs_url);
return refs;
}
if (transport->push_refs) {
struct ref *remote_refs =
transport->get_refs_list(transport, 1);
- struct ref **remote_tail;
struct ref *local_refs = get_local_heads();
int match_flags = MATCH_REFS_NONE;
int verbose = flags & TRANSPORT_PUSH_VERBOSE;
if (flags & TRANSPORT_PUSH_MIRROR)
match_flags |= MATCH_REFS_MIRROR;
- remote_tail = &remote_refs;
- while (*remote_tail)
- remote_tail = &((*remote_tail)->next);
- if (match_refs(local_refs, remote_refs, &remote_tail,
+ if (match_refs(local_refs, &remote_refs,
refspec_nr, refspec, match_flags)) {
return -1;
}