Merge branch 'jk/signal-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Sun, 1 Feb 2009 01:43:56 +0000 (17:43 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 1 Feb 2009 01:43:56 +0000 (17:43 -0800)
* jk/signal-cleanup:
t0005: use SIGTERM for sigchain test
pager: do wait_for_pager on signal death
refactor signal handling for cleanup functions
chain kill signals for cleanup functions
diff: refactor tempfile cleanup handling
Windows: Fix signal numbers

1  2 
.gitignore
Makefile
builtin-clone.c
diff.c
http-push.c
diff --combined .gitignore
index e8f91ce8cd991800457f2f8387cdb22014cee169,f28a54d262e77f9bd457cd26f83dd78632fc3633..1c57d4c958bc5e8ff539c5f5ddb1c784d923271b
@@@ -144,7 -144,6 +144,7 @@@ git-core-*/?
  gitk-wish
  gitweb/gitweb.cgi
  test-chmtime
 +test-ctype
  test-date
  test-delta
  test-dump-cache-tree
@@@ -153,6 -152,7 +153,7 @@@ test-match-tree
  test-parse-options
  test-path-utils
  test-sha1
+ test-sigchain
  common-cmds.h
  *.tar.gz
  *.dsc
diff --combined Makefile
index a7310f24015480ef31a52f05abee09d69aa1b8e6,fd02decc01a053ad31fdaac66fde86033c0f2bfb..d10895f3c8d9f99ee4e960ebfdab1369099d7f22
+++ b/Makefile
@@@ -23,9 -23,6 +23,9 @@@ all:
  # Define NO_EXPAT if you do not have expat installed.  git-http-push is
  # not built, and you cannot push using http:// and https:// transports.
  #
 +# Define EXPATDIR=/foo/bar if your expat header and library files are in
 +# /foo/bar/include and /foo/bar/lib directories.
 +#
  # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
  #
  # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
@@@ -391,6 -388,7 +391,7 @@@ LIB_H += revision.
  LIB_H += run-command.h
  LIB_H += sha1-lookup.h
  LIB_H += sideband.h
+ LIB_H += sigchain.h
  LIB_H += strbuf.h
  LIB_H += tag.h
  LIB_H += transport.h
@@@ -484,6 -482,7 +485,7 @@@ LIB_OBJS += sha1-lookup.
  LIB_OBJS += sha1_name.o
  LIB_OBJS += shallow.o
  LIB_OBJS += sideband.o
+ LIB_OBJS += sigchain.o
  LIB_OBJS += strbuf.o
  LIB_OBJS += symlinks.o
  LIB_OBJS += tag.o
@@@ -820,7 -819,6 +822,7 @@@ ifeq ($(uname_S),Darwin
                        BASIC_LDFLAGS += -L/opt/local/lib
                endif
        endif
 +      PTHREAD_LIBS =
  endif
  
  ifndef CC_LD_DYNPATH
@@@ -853,12 -851,7 +855,12 @@@ els
                endif
        endif
        ifndef NO_EXPAT
 -              EXPAT_LIBEXPAT = -lexpat
 +              ifdef EXPATDIR
 +                      BASIC_CFLAGS += -I$(EXPATDIR)/include
 +                      EXPAT_LIBEXPAT = -L$(EXPATDIR)/$(lib) $(CC_LD_DYNPATH)$(EXPATDIR)/$(lib) -lexpat
 +              else
 +                      EXPAT_LIBEXPAT = -lexpat
 +              endif
        endif
  endif
  
@@@ -1296,7 -1289,7 +1298,7 @@@ $(LIB_FILE): $(LIB_OBJS
        $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
  
  XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
 -      xdiff/xmerge.o
 +      xdiff/xmerge.o xdiff/xpatience.o
  $(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
        xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
  
@@@ -1366,7 -1359,6 +1368,7 @@@ endi
  ### Testing rules
  
  TEST_PROGRAMS += test-chmtime$X
 +TEST_PROGRAMS += test-ctype$X
  TEST_PROGRAMS += test-date$X
  TEST_PROGRAMS += test-delta$X
  TEST_PROGRAMS += test-genrandom$X
@@@ -1374,6 -1366,7 +1376,7 @@@ TEST_PROGRAMS += test-match-trees$
  TEST_PROGRAMS += test-parse-options$X
  TEST_PROGRAMS += test-path-utils$X
  TEST_PROGRAMS += test-sha1$X
+ TEST_PROGRAMS += test-sigchain$X
  
  all:: $(TEST_PROGRAMS)
  
@@@ -1386,8 -1379,6 +1389,8 @@@ export NO_SVN_TEST
  test: all
        $(MAKE) -C t/ all
  
 +test-ctype$X: ctype.o
 +
  test-date$X: date.o ctype.o
  
  test-delta$X: diff-delta.o patch-delta.o
@@@ -1453,12 -1444,10 +1456,12 @@@ endi
        { $(RM) "$$execdir/git-add$X" && \
                ln git-add$X "$$execdir/git-add$X" 2>/dev/null || \
                cp git-add$X "$$execdir/git-add$X"; } && \
 -      { $(foreach p,$(filter-out git-add$X,$(BUILT_INS)), $(RM) "$$execdir/$p" && \
 -              ln "$$execdir/git-add$X" "$$execdir/$p" 2>/dev/null || \
 -              ln -s "git-add$X" "$$execdir/$p" 2>/dev/null || \
 -              cp "$$execdir/git-add$X" "$$execdir/$p" || exit;) } && \
 +      { for p in $(filter-out git-add$X,$(BUILT_INS)); do \
 +              $(RM) "$$execdir/$$p" && \
 +              ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \
 +              ln -s "git-add$X" "$$execdir/$$p" 2>/dev/null || \
 +              cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \
 +        done } && \
        ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
  
  install-doc:
diff --combined builtin-clone.c
index 1e9c9aa8446370070d56126ad851701c4c418de0,44c80734b70b13780cbb48b0566bf99e2233f2a8..f73029e2ba285bfb20bce1760cef711f7a55fd02
@@@ -19,6 -19,7 +19,7 @@@
  #include "strbuf.h"
  #include "dir.h"
  #include "pack-refs.h"
+ #include "sigchain.h"
  
  /*
   * Overall FIXMEs:
@@@ -288,7 -289,7 +289,7 @@@ static void remove_junk(void
  static void remove_junk_on_signal(int signo)
  {
        remove_junk();
-       signal(SIGINT, SIG_DFL);
+       sigchain_pop(signo);
        raise(signo);
  }
  
@@@ -357,7 -358,6 +358,7 @@@ int cmd_clone(int argc, const char **ar
        struct stat buf;
        const char *repo_name, *repo, *work_tree, *git_dir;
        char *path, *dir;
 +      int dest_exists;
        const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
        struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
        struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
                dir = guess_dir_name(repo_name, is_bundle, option_bare);
        strip_trailing_slashes(dir);
  
 -      if (!stat(dir, &buf))
 -              die("destination directory '%s' already exists.", dir);
 +      dest_exists = !stat(dir, &buf);
 +      if (dest_exists && !is_empty_dir(dir))
 +              die("destination path '%s' already exists and is not "
 +                      "an empty directory.", dir);
  
        strbuf_addf(&reflog_msg, "clone: from %s", repo);
  
                if (safe_create_leading_directories_const(work_tree) < 0)
                        die("could not create leading directories of '%s': %s",
                                        work_tree, strerror(errno));
 -              if (mkdir(work_tree, 0755))
 +              if (!dest_exists && mkdir(work_tree, 0755))
                        die("could not create work tree dir '%s': %s.",
                                        work_tree, strerror(errno));
                set_git_work_tree(work_tree);
        }
        junk_git_dir = git_dir;
        atexit(remove_junk);
-       signal(SIGINT, remove_junk_on_signal);
+       sigchain_push_common(remove_junk_on_signal);
  
        setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);
  
                                             option_upload_pack);
  
                refs = transport_get_remote_refs(transport);
 -              transport_fetch_refs(transport, refs);
 +              if(refs)
 +                      transport_fetch_refs(transport, refs);
        }
  
 -      clear_extra_refs();
 +      if (refs) {
 +              clear_extra_refs();
  
 -      mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
 +              mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
  
 -      head_points_at = locate_head(refs, mapped_refs, &remote_head);
 +              head_points_at = locate_head(refs, mapped_refs, &remote_head);
 +      }
 +      else {
 +              warning("You appear to have cloned an empty repository.");
 +              head_points_at = NULL;
 +              remote_head = NULL;
 +              option_no_checkout = 1;
 +      }
  
        if (head_points_at) {
                /* Local default branch link */
diff --combined diff.c
index 972b3daa6578776ca2f262d8e4d3290bae64e234,8ce898a6b09f7ad013c285ba46bdf6922fbe9bc5..d8b1c22d56233e91dc9548a80116996a351c480f
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -12,6 -12,7 +12,7 @@@
  #include "run-command.h"
  #include "utf8.h"
  #include "userdiff.h"
+ #include "sigchain.h"
  
  #ifdef NO_FAST_WORKING_DIRECTORY
  #define FAST_WORKING_DIRECTORY 0
@@@ -23,7 -24,6 +24,7 @@@ static int diff_detect_rename_default
  static int diff_rename_limit_default = 200;
  static int diff_suppress_blank_empty;
  int diff_use_color_default = -1;
 +static const char *diff_word_regex_cfg;
  static const char *external_diff_cmd_cfg;
  int diff_auto_refresh_index = 1;
  static int diff_mnemonic_prefix;
@@@ -93,8 -93,6 +94,8 @@@ int git_diff_ui_config(const char *var
        }
        if (!strcmp(var, "diff.external"))
                return git_config_string(&external_diff_cmd_cfg, var, value);
 +      if (!strcmp(var, "diff.wordregex"))
 +              return git_config_string(&diff_word_regex_cfg, var, value);
  
        return git_diff_basic_config(var, value, cb);
  }
@@@ -121,9 -119,7 +122,9 @@@ int git_diff_basic_config(const char *v
        }
  
        /* like GNU diff's --suppress-blank-empty option  */
 -      if (!strcmp(var, "diff.suppress-blank-empty")) {
 +      if (!strcmp(var, "diff.suppressblankempty") ||
 +                      /* for backwards compatibility */
 +                      !strcmp(var, "diff.suppress-blank-empty")) {
                diff_suppress_blank_empty = git_config_bool(var, value);
                return 0;
        }
@@@ -170,6 -166,33 +171,33 @@@ static struct diff_tempfile 
        char tmp_path[PATH_MAX];
  } diff_temp[2];
  
+ static struct diff_tempfile *claim_diff_tempfile(void) {
+       int i;
+       for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
+               if (!diff_temp[i].name)
+                       return diff_temp + i;
+       die("BUG: diff is failing to clean up its tempfiles");
+ }
+ static int remove_tempfile_installed;
+ static void remove_tempfile(void)
+ {
+       int i;
+       for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
+               if (diff_temp[i].name == diff_temp[i].tmp_path) {
+                       unlink(diff_temp[i].name);
+                       diff_temp[i].name = NULL;
+               }
+ }
+ static void remove_tempfile_on_signal(int signo)
+ {
+       remove_tempfile();
+       sigchain_pop(signo);
+       raise(signo);
+ }
  static int count_lines(const char *data, int size)
  {
        int count, ch, completely_empty = 1, nl_just_seen = 0;
@@@ -324,138 -347,82 +352,138 @@@ static int fill_mmfile(mmfile_t *mf, st
  struct diff_words_buffer {
        mmfile_t text;
        long alloc;
 -      long current; /* output pointer */
 -      int suppressed_newline;
 +      struct diff_words_orig {
 +              const char *begin, *end;
 +      } *orig;
 +      int orig_nr, orig_alloc;
  };
  
  static void diff_words_append(char *line, unsigned long len,
                struct diff_words_buffer *buffer)
  {
 -      if (buffer->text.size + len > buffer->alloc) {
 -              buffer->alloc = (buffer->text.size + len) * 3 / 2;
 -              buffer->text.ptr = xrealloc(buffer->text.ptr, buffer->alloc);
 -      }
 +      ALLOC_GROW(buffer->text.ptr, buffer->text.size + len, buffer->alloc);
        line++;
        len--;
        memcpy(buffer->text.ptr + buffer->text.size, line, len);
        buffer->text.size += len;
 +      buffer->text.ptr[buffer->text.size] = '\0';
  }
  
  struct diff_words_data {
        struct diff_words_buffer minus, plus;
 +      const char *current_plus;
        FILE *file;
 +      regex_t *word_regex;
  };
  
 -static void print_word(FILE *file, struct diff_words_buffer *buffer, int len, int color,
 -              int suppress_newline)
 +static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
  {
 -      const char *ptr;
 -      int eol = 0;
 +      struct diff_words_data *diff_words = priv;
 +      int minus_first, minus_len, plus_first, plus_len;
 +      const char *minus_begin, *minus_end, *plus_begin, *plus_end;
  
 -      if (len == 0)
 +      if (line[0] != '@' || parse_hunk_header(line, len,
 +                      &minus_first, &minus_len, &plus_first, &plus_len))
                return;
  
 -      ptr  = buffer->text.ptr + buffer->current;
 -      buffer->current += len;
 -
 -      if (ptr[len - 1] == '\n') {
 -              eol = 1;
 -              len--;
 +      /* POSIX requires that first be decremented by one if len == 0... */
 +      if (minus_len) {
 +              minus_begin = diff_words->minus.orig[minus_first].begin;
 +              minus_end =
 +                      diff_words->minus.orig[minus_first + minus_len - 1].end;
 +      } else
 +              minus_begin = minus_end =
 +                      diff_words->minus.orig[minus_first].end;
 +
 +      if (plus_len) {
 +              plus_begin = diff_words->plus.orig[plus_first].begin;
 +              plus_end = diff_words->plus.orig[plus_first + plus_len - 1].end;
 +      } else
 +              plus_begin = plus_end = diff_words->plus.orig[plus_first].end;
 +
 +      if (diff_words->current_plus != plus_begin)
 +              fwrite(diff_words->current_plus,
 +                              plus_begin - diff_words->current_plus, 1,
 +                              diff_words->file);
 +      if (minus_begin != minus_end)
 +              color_fwrite_lines(diff_words->file,
 +                              diff_get_color(1, DIFF_FILE_OLD),
 +                              minus_end - minus_begin, minus_begin);
 +      if (plus_begin != plus_end)
 +              color_fwrite_lines(diff_words->file,
 +                              diff_get_color(1, DIFF_FILE_NEW),
 +                              plus_end - plus_begin, plus_begin);
 +
 +      diff_words->current_plus = plus_end;
 +}
 +
 +/* This function starts looking at *begin, and returns 0 iff a word was found. */
 +static int find_word_boundaries(mmfile_t *buffer, regex_t *word_regex,
 +              int *begin, int *end)
 +{
 +      if (word_regex && *begin < buffer->size) {
 +              regmatch_t match[1];
 +              if (!regexec(word_regex, buffer->ptr + *begin, 1, match, 0)) {
 +                      char *p = memchr(buffer->ptr + *begin + match[0].rm_so,
 +                                      '\n', match[0].rm_eo - match[0].rm_so);
 +                      *end = p ? p - buffer->ptr : match[0].rm_eo + *begin;
 +                      *begin += match[0].rm_so;
 +                      return *begin >= *end;
 +              }
 +              return -1;
        }
  
 -      fputs(diff_get_color(1, color), file);
 -      fwrite(ptr, len, 1, file);
 -      fputs(diff_get_color(1, DIFF_RESET), file);
 +      /* find the next word */
 +      while (*begin < buffer->size && isspace(buffer->ptr[*begin]))
 +              (*begin)++;
 +      if (*begin >= buffer->size)
 +              return -1;
  
 -      if (eol) {
 -              if (suppress_newline)
 -                      buffer->suppressed_newline = 1;
 -              else
 -                      putc('\n', file);
 -      }
 +      /* find the end of the word */
 +      *end = *begin + 1;
 +      while (*end < buffer->size && !isspace(buffer->ptr[*end]))
 +              (*end)++;
 +
 +      return 0;
  }
  
 -static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
 +/*
 + * This function splits the words in buffer->text, stores the list with
 + * newline separator into out, and saves the offsets of the original words
 + * in buffer->orig.
 + */
 +static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out,
 +              regex_t *word_regex)
  {
 -      struct diff_words_data *diff_words = priv;
 +      int i, j;
 +      long alloc = 0;
  
 -      if (diff_words->minus.suppressed_newline) {
 -              if (line[0] != '+')
 -                      putc('\n', diff_words->file);
 -              diff_words->minus.suppressed_newline = 0;
 -      }
 +      out->size = 0;
 +      out->ptr = NULL;
  
 -      len--;
 -      switch (line[0]) {
 -              case '-':
 -                      print_word(diff_words->file,
 -                                 &diff_words->minus, len, DIFF_FILE_OLD, 1);
 -                      break;
 -              case '+':
 -                      print_word(diff_words->file,
 -                                 &diff_words->plus, len, DIFF_FILE_NEW, 0);
 -                      break;
 -              case ' ':
 -                      print_word(diff_words->file,
 -                                 &diff_words->plus, len, DIFF_PLAIN, 0);
 -                      diff_words->minus.current += len;
 -                      break;
 +      /* fake an empty "0th" word */
 +      ALLOC_GROW(buffer->orig, 1, buffer->orig_alloc);
 +      buffer->orig[0].begin = buffer->orig[0].end = buffer->text.ptr;
 +      buffer->orig_nr = 1;
 +
 +      for (i = 0; i < buffer->text.size; i++) {
 +              if (find_word_boundaries(&buffer->text, word_regex, &i, &j))
 +                      return;
 +
 +              /* store original boundaries */
 +              ALLOC_GROW(buffer->orig, buffer->orig_nr + 1,
 +                              buffer->orig_alloc);
 +              buffer->orig[buffer->orig_nr].begin = buffer->text.ptr + i;
 +              buffer->orig[buffer->orig_nr].end = buffer->text.ptr + j;
 +              buffer->orig_nr++;
 +
 +              /* store one word */
 +              ALLOC_GROW(out->ptr, out->size + j - i + 1, alloc);
 +              memcpy(out->ptr + out->size, buffer->text.ptr + i, j - i);
 +              out->ptr[out->size + j - i] = '\n';
 +              out->size += j - i + 1;
 +
 +              i = j - 1;
        }
  }
  
@@@ -466,36 -433,38 +494,36 @@@ static void diff_words_show(struct diff
        xdemitconf_t xecfg;
        xdemitcb_t ecb;
        mmfile_t minus, plus;
 -      int i;
 +
 +      /* special case: only removal */
 +      if (!diff_words->plus.text.size) {
 +              color_fwrite_lines(diff_words->file,
 +                      diff_get_color(1, DIFF_FILE_OLD),
 +                      diff_words->minus.text.size, diff_words->minus.text.ptr);
 +              diff_words->minus.text.size = 0;
 +              return;
 +      }
 +
 +      diff_words->current_plus = diff_words->plus.text.ptr;
  
        memset(&xpp, 0, sizeof(xpp));
        memset(&xecfg, 0, sizeof(xecfg));
 -      minus.size = diff_words->minus.text.size;
 -      minus.ptr = xmalloc(minus.size);
 -      memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size);
 -      for (i = 0; i < minus.size; i++)
 -              if (isspace(minus.ptr[i]))
 -                      minus.ptr[i] = '\n';
 -      diff_words->minus.current = 0;
 -
 -      plus.size = diff_words->plus.text.size;
 -      plus.ptr = xmalloc(plus.size);
 -      memcpy(plus.ptr, diff_words->plus.text.ptr, plus.size);
 -      for (i = 0; i < plus.size; i++)
 -              if (isspace(plus.ptr[i]))
 -                      plus.ptr[i] = '\n';
 -      diff_words->plus.current = 0;
 -
 +      diff_words_fill(&diff_words->minus, &minus, diff_words->word_regex);
 +      diff_words_fill(&diff_words->plus, &plus, diff_words->word_regex);
        xpp.flags = XDF_NEED_MINIMAL;
 -      xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
 +      /* as only the hunk header will be parsed, we need a 0-context */
 +      xecfg.ctxlen = 0;
        xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
                      &xpp, &xecfg, &ecb);
        free(minus.ptr);
        free(plus.ptr);
 +      if (diff_words->current_plus != diff_words->plus.text.ptr +
 +                      diff_words->plus.text.size)
 +              fwrite(diff_words->current_plus,
 +                      diff_words->plus.text.ptr + diff_words->plus.text.size
 +                      - diff_words->current_plus, 1,
 +                      diff_words->file);
        diff_words->minus.text.size = diff_words->plus.text.size = 0;
 -
 -      if (diff_words->minus.suppressed_newline) {
 -              putc('\n', diff_words->file);
 -              diff_words->minus.suppressed_newline = 0;
 -      }
  }
  
  typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
@@@ -519,10 -488,7 +547,10 @@@ static void free_diff_words_data(struc
                        diff_words_show(ecbdata->diff_words);
  
                free (ecbdata->diff_words->minus.text.ptr);
 +              free (ecbdata->diff_words->minus.orig);
                free (ecbdata->diff_words->plus.text.ptr);
 +              free (ecbdata->diff_words->plus.orig);
 +              free(ecbdata->diff_words->word_regex);
                free(ecbdata->diff_words);
                ecbdata->diff_words = NULL;
        }
@@@ -1385,12 -1351,6 +1413,12 @@@ static const struct userdiff_funcname *
        return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
  }
  
 +static const char *userdiff_word_regex(struct diff_filespec *one)
 +{
 +      diff_filespec_load_driver(one);
 +      return one->driver->word_regex;
 +}
 +
  void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
  {
        if (!options->a_prefix)
@@@ -1551,21 -1511,6 +1579,21 @@@ static void builtin_diff(const char *na
                        ecbdata.diff_words =
                                xcalloc(1, sizeof(struct diff_words_data));
                        ecbdata.diff_words->file = o->file;
 +                      if (!o->word_regex)
 +                              o->word_regex = userdiff_word_regex(one);
 +                      if (!o->word_regex)
 +                              o->word_regex = userdiff_word_regex(two);
 +                      if (!o->word_regex)
 +                              o->word_regex = diff_word_regex_cfg;
 +                      if (o->word_regex) {
 +                              ecbdata.diff_words->word_regex = (regex_t *)
 +                                      xmalloc(sizeof(regex_t));
 +                              if (regcomp(ecbdata.diff_words->word_regex,
 +                                              o->word_regex,
 +                                              REG_EXTENDED | REG_NEWLINE))
 +                                      die ("Invalid regular expression: %s",
 +                                                      o->word_regex);
 +                      }
                }
                xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
                              &xpp, &xecfg, &ecb);
@@@ -1940,10 -1885,11 +1968,11 @@@ static void prep_temp_blob(struct diff_
        sprintf(temp->mode, "%06o", mode);
  }
  
- static void prepare_temp_file(const char *name,
-                             struct diff_tempfile *temp,
-                             struct diff_filespec *one)
+ static struct diff_tempfile *prepare_temp_file(const char *name,
+               struct diff_filespec *one)
  {
+       struct diff_tempfile *temp = claim_diff_tempfile();
        if (!DIFF_FILE_VALID(one)) {
        not_a_valid_file:
                /* A '-' entry produces this for file-2, and
                temp->name = "/dev/null";
                strcpy(temp->hex, ".");
                strcpy(temp->mode, ".");
-               return;
+               return temp;
+       }
+       if (!remove_tempfile_installed) {
+               atexit(remove_tempfile);
+               sigchain_push_common(remove_tempfile_on_signal);
+               remove_tempfile_installed = 1;
        }
  
        if (!one->sha1_valid ||
                         */
                        sprintf(temp->mode, "%06o", one->mode);
                }
-               return;
+               return temp;
        }
        else {
                if (diff_populate_filespec(one, 0))
                prep_temp_blob(temp, one->data, one->size,
                               one->sha1, one->mode);
        }
- }
- static void remove_tempfile(void)
- {
-       int i;
-       for (i = 0; i < 2; i++)
-               if (diff_temp[i].name == diff_temp[i].tmp_path) {
-                       unlink(diff_temp[i].name);
-                       diff_temp[i].name = NULL;
-               }
- }
- static void remove_tempfile_on_signal(int signo)
- {
-       remove_tempfile();
-       signal(SIGINT, SIG_DFL);
-       raise(signo);
+       return temp;
  }
  
  /* An external diff command takes:
@@@ -2035,34 -1970,22 +2053,22 @@@ static void run_external_diff(const cha
                              int complete_rewrite)
  {
        const char *spawn_arg[10];
-       struct diff_tempfile *temp = diff_temp;
        int retval;
-       static int atexit_asked = 0;
-       const char *othername;
        const char **arg = &spawn_arg[0];
  
-       othername = (other? other : name);
-       if (one && two) {
-               prepare_temp_file(name, &temp[0], one);
-               prepare_temp_file(othername, &temp[1], two);
-               if (! atexit_asked &&
-                   (temp[0].name == temp[0].tmp_path ||
-                    temp[1].name == temp[1].tmp_path)) {
-                       atexit_asked = 1;
-                       atexit(remove_tempfile);
-               }
-               signal(SIGINT, remove_tempfile_on_signal);
-       }
        if (one && two) {
+               struct diff_tempfile *temp_one, *temp_two;
+               const char *othername = (other ? other : name);
+               temp_one = prepare_temp_file(name, one);
+               temp_two = prepare_temp_file(othername, two);
                *arg++ = pgm;
                *arg++ = name;
-               *arg++ = temp[0].name;
-               *arg++ = temp[0].hex;
-               *arg++ = temp[0].mode;
-               *arg++ = temp[1].name;
-               *arg++ = temp[1].hex;
-               *arg++ = temp[1].mode;
+               *arg++ = temp_one->name;
+               *arg++ = temp_one->hex;
+               *arg++ = temp_one->mode;
+               *arg++ = temp_two->name;
+               *arg++ = temp_two->hex;
+               *arg++ = temp_two->mode;
                if (other) {
                        *arg++ = other;
                        *arg++ = xfrm_msg;
@@@ -2555,8 -2478,6 +2561,8 @@@ int diff_opt_parse(struct diff_options 
                options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
        else if (!strcmp(arg, "--ignore-space-at-eol"))
                options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL;
 +      else if (!strcmp(arg, "--patience"))
 +              options->xdl_opts |= XDF_PATIENCE_DIFF;
  
        /* flags options */
        else if (!strcmp(arg, "--binary")) {
                DIFF_OPT_CLR(options, COLOR_DIFF);
        else if (!strcmp(arg, "--color-words"))
                options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
 +      else if (!prefixcmp(arg, "--color-words=")) {
 +              options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
 +              options->word_regex = arg + 14;
 +      }
        else if (!strcmp(arg, "--exit-code"))
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        else if (!strcmp(arg, "--quiet"))
@@@ -3537,15 -3454,15 +3543,15 @@@ void diff_unmerge(struct diff_options *
  static char *run_textconv(const char *pgm, struct diff_filespec *spec,
                size_t *outsize)
  {
-       struct diff_tempfile temp;
+       struct diff_tempfile *temp;
        const char *argv[3];
        const char **arg = argv;
        struct child_process child;
        struct strbuf buf = STRBUF_INIT;
  
-       prepare_temp_file(spec->path, &temp, spec);
+       temp = prepare_temp_file(spec->path, spec);
        *arg++ = pgm;
-       *arg++ = temp.name;
+       *arg++ = temp->name;
        *arg = NULL;
  
        memset(&child, 0, sizeof(child));
        if (start_command(&child) != 0 ||
            strbuf_read(&buf, child.out, 0) < 0 ||
            finish_command(&child) != 0) {
-               if (temp.name == temp.tmp_path)
-                       unlink(temp.name);
+               remove_tempfile();
                error("error running textconv command '%s'", pgm);
                return NULL;
        }
-       if (temp.name == temp.tmp_path)
-               unlink(temp.name);
+       remove_tempfile();
  
        return strbuf_detach(&buf, outsize);
  }
diff --combined http-push.c
index 59037df5025f0e71b882d53489fe5274aa9065f0,7d5c23edc4b864958671a26bde64ce21e54924bc..53c14141e0518dddf2a67ffabb04ce79b14fa618
@@@ -10,6 -10,7 +10,7 @@@
  #include "exec_cmd.h"
  #include "remote.h"
  #include "list-objects.h"
+ #include "sigchain.h"
  
  #include <expat.h>
  
@@@ -177,38 -178,6 +178,38 @@@ struct remote_ls_ct
        struct remote_ls_ctx *parent;
  };
  
 +/* get_dav_token_headers options */
 +enum dav_header_flag {
 +      DAV_HEADER_IF = (1u << 0),
 +      DAV_HEADER_LOCK = (1u << 1),
 +      DAV_HEADER_TIMEOUT = (1u << 2)
 +};
 +
 +static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options)
 +{
 +      struct strbuf buf = STRBUF_INIT;
 +      struct curl_slist *dav_headers = NULL;
 +
 +      if (options & DAV_HEADER_IF) {
 +              strbuf_addf(&buf, "If: (<%s>)", lock->token);
 +              dav_headers = curl_slist_append(dav_headers, buf.buf);
 +              strbuf_reset(&buf);
 +      }
 +      if (options & DAV_HEADER_LOCK) {
 +              strbuf_addf(&buf, "Lock-Token: <%s>", lock->token);
 +              dav_headers = curl_slist_append(dav_headers, buf.buf);
 +              strbuf_reset(&buf);
 +      }
 +      if (options & DAV_HEADER_TIMEOUT) {
 +              strbuf_addf(&buf, "Timeout: Second-%ld", lock->timeout);
 +              dav_headers = curl_slist_append(dav_headers, buf.buf);
 +              strbuf_reset(&buf);
 +      }
 +      strbuf_release(&buf);
 +
 +      return dav_headers;
 +}
 +
  static void finish_request(struct transfer_request *request);
  static void release_request(struct transfer_request *request);
  
@@@ -241,7 -210,7 +242,7 @@@ static size_t fwrite_sha1_file(void *pt
        do {
                request->stream.next_out = expn;
                request->stream.avail_out = sizeof(expn);
 -              request->zret = inflate(&request->stream, Z_SYNC_FLUSH);
 +              request->zret = git_inflate(&request->stream, Z_SYNC_FLUSH);
                git_SHA1_Update(&request->c, expn,
                            sizeof(expn) - request->stream.avail_out);
        } while (request->stream.avail_in && request->zret == Z_OK);
@@@ -301,7 -270,7 +302,7 @@@ static void start_fetch_loose(struct tr
  
        memset(&request->stream, 0, sizeof(request->stream));
  
 -      inflateInit(&request->stream);
 +      git_inflate_init(&request->stream);
  
        git_SHA1_Init(&request->c);
  
           file; also rewind to the beginning of the local file. */
        if (prev_read == -1) {
                memset(&request->stream, 0, sizeof(request->stream));
 -              inflateInit(&request->stream);
 +              git_inflate_init(&request->stream);
                git_SHA1_Init(&request->c);
                if (prev_posn>0) {
                        prev_posn = 0;
@@@ -620,12 -589,18 +621,12 @@@ static int refresh_lock(struct remote_l
  {
        struct active_request_slot *slot;
        struct slot_results results;
 -      char *if_header;
 -      char timeout_header[25];
 -      struct curl_slist *dav_headers = NULL;
 +      struct curl_slist *dav_headers;
        int rc = 0;
  
        lock->refreshing = 1;
  
 -      if_header = xmalloc(strlen(lock->token) + 25);
 -      sprintf(if_header, "If: (<%s>)", lock->token);
 -      sprintf(timeout_header, "Timeout: Second-%ld", lock->timeout);
 -      dav_headers = curl_slist_append(dav_headers, if_header);
 -      dav_headers = curl_slist_append(dav_headers, timeout_header);
 +      dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF | DAV_HEADER_TIMEOUT);
  
        slot = get_active_slot();
        slot->results = &results;
  
        lock->refreshing = 0;
        curl_slist_free_all(dav_headers);
 -      free(if_header);
  
        return rc;
  }
@@@ -767,7 -743,7 +768,7 @@@ static void finish_request(struct trans
                        if (request->http_code == 416)
                                fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
  
 -                      inflateEnd(&request->stream);
 +                      git_inflate_end(&request->stream);
                        git_SHA1_Final(request->real_sha1, &request->c);
                        if (request->zret != Z_STREAM_END) {
                                unlink(request->tmpfile);
@@@ -1226,8 -1202,7 +1227,8 @@@ static struct remote_lock *lock_remote(
        /* Make sure leading directories exist for the remote ref */
        ep = strchr(url + strlen(remote->url) + 1, '/');
        while (ep) {
 -              *ep = 0;
 +              char saved_character = ep[1];
 +              ep[1] = '\0';
                slot = get_active_slot();
                slot->results = &results;
                curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
                        free(url);
                        return NULL;
                }
 -              *ep = '/';
 +              ep[1] = saved_character;
                ep = strchr(ep + 1, '/');
        }
  
@@@ -1328,10 -1303,14 +1329,10 @@@ static int unlock_remote(struct remote_
        struct active_request_slot *slot;
        struct slot_results results;
        struct remote_lock *prev = remote->locks;
 -      char *lock_token_header;
 -      struct curl_slist *dav_headers = NULL;
 +      struct curl_slist *dav_headers;
        int rc = 0;
  
 -      lock_token_header = xmalloc(strlen(lock->token) + 31);
 -      sprintf(lock_token_header, "Lock-Token: <%s>",
 -              lock->token);
 -      dav_headers = curl_slist_append(dav_headers, lock_token_header);
 +      dav_headers = get_dav_token_headers(lock, DAV_HEADER_LOCK);
  
        slot = get_active_slot();
        slot->results = &results;
        }
  
        curl_slist_free_all(dav_headers);
 -      free(lock_token_header);
  
        if (remote->locks == lock) {
                remote->locks = lock->next;
@@@ -1384,7 -1364,7 +1385,7 @@@ static void remove_locks(void
  static void remove_locks_on_signal(int signo)
  {
        remove_locks();
-       signal(signo, SIG_DFL);
+       sigchain_pop(signo);
        raise(signo);
  }
  
@@@ -1455,8 -1435,10 +1456,8 @@@ static void handle_remote_ls_ctx(struc
                        }
                        if (path) {
                                path += remote->path_len;
 +                              ls->dentry_name = xstrdup(path);
                        }
 -                      ls->dentry_name = xmalloc(strlen(path) -
 -                                                remote->path_len + 1);
 -                      strcpy(ls->dentry_name, path + remote->path_len);
                } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
                        ls->dentry_flags |= IS_DIR;
                }
        }
  }
  
 +/*
 + * NEEDSWORK: remote_ls() ignores info/refs on the remote side.  But it
 + * should _only_ heed the information from that file, instead of trying to
 + * determine the refs from the remote file system (badly: it does not even
 + * know about packed-refs).
 + */
  static void remote_ls(const char *path, int flags,
                      void (*userFunc)(struct remote_ls_ctx *ls),
                      void *userData)
@@@ -1751,10 -1727,13 +1752,10 @@@ static int update_remote(unsigned char 
  {
        struct active_request_slot *slot;
        struct slot_results results;
 -      char *if_header;
        struct buffer out_buffer = { STRBUF_INIT, 0 };
 -      struct curl_slist *dav_headers = NULL;
 +      struct curl_slist *dav_headers;
  
 -      if_header = xmalloc(strlen(lock->token) + 25);
 -      sprintf(if_header, "If: (<%s>)", lock->token);
 -      dav_headers = curl_slist_append(dav_headers, if_header);
 +      dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
  
        strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
  
        if (start_active_slot(slot)) {
                run_active_slot(slot);
                strbuf_release(&out_buffer.buf);
 -              free(if_header);
                if (results.curl_result != CURLE_OK) {
                        fprintf(stderr,
                                "PUT error: curl result=%d, HTTP code=%ld\n",
                }
        } else {
                strbuf_release(&out_buffer.buf);
 -              free(if_header);
                fprintf(stderr, "Unable to start PUT request\n");
                return 0;
        }
@@@ -1963,12 -1944,15 +1964,12 @@@ static void update_remote_info_refs(str
        struct buffer buffer = { STRBUF_INIT, 0 };
        struct active_request_slot *slot;
        struct slot_results results;
 -      char *if_header;
 -      struct curl_slist *dav_headers = NULL;
 +      struct curl_slist *dav_headers;
  
        remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
                  add_remote_info_ref, &buffer.buf);
        if (!aborted) {
 -              if_header = xmalloc(strlen(lock->token) + 25);
 -              sprintf(if_header, "If: (<%s>)", lock->token);
 -              dav_headers = curl_slist_append(dav_headers, if_header);
 +              dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
  
                slot = get_active_slot();
                slot->results = &results;
                                        results.curl_result, results.http_code);
                        }
                }
 -              free(if_header);
        }
        strbuf_release(&buffer.buf);
  }
@@@ -2277,10 -2262,7 +2278,7 @@@ int main(int argc, char **argv
                goto cleanup;
        }
  
-       signal(SIGINT, remove_locks_on_signal);
-       signal(SIGHUP, remove_locks_on_signal);
-       signal(SIGQUIT, remove_locks_on_signal);
-       signal(SIGTERM, remove_locks_on_signal);
+       sigchain_push_common(remove_locks_on_signal);
  
        /* Check whether the remote has server info files */
        remote->can_update_info_refs = 0;