Code

detect close failure on just-written file handles
[git.git] / diff.c
diff --git a/diff.c b/diff.c
index 7bbe7590b2e6b8c1f153902e0375df193c5268f2..9938969fa50e8af2a4eabe96ae122111ae42fe75 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -16,8 +16,6 @@
 #define FAST_WORKING_DIRECTORY 1
 #endif
 
-static int use_size_cache;
-
 static int diff_detect_rename_default;
 static int diff_rename_limit_default = -1;
 static int diff_use_color_default;
@@ -188,13 +186,11 @@ static const char *external_diff(void)
        return external_diff_cmd;
 }
 
-#define TEMPFILE_PATH_LEN              50
-
 static struct diff_tempfile {
        const char *name; /* filename external diff should read from */
        char hex[41];
        char mode[10];
-       char tmp_path[TEMPFILE_PATH_LEN];
+       char tmp_path[PATH_MAX];
 } diff_temp[2];
 
 static int count_lines(const char *data, int size)
@@ -1111,10 +1107,8 @@ static void setup_diff_attr_check(struct git_attr_check *check)
        check->attr = attr_diff;
 }
 
-#define FIRST_FEW_BYTES 8000
 static int file_is_binary(struct diff_filespec *one)
 {
-       unsigned long sz;
        struct git_attr_check attr_diff_check;
 
        setup_diff_attr_check(&attr_diff_check);
@@ -1131,10 +1125,7 @@ static int file_is_binary(struct diff_filespec *one)
                        return 0;
                diff_populate_filespec(one, 0);
        }
-       sz = one->size;
-       if (FIRST_FEW_BYTES < sz)
-               sz = FIRST_FEW_BYTES;
-       return !!memchr(one->data, 0, sz);
+       return buffer_is_binary(one->data, one->size);
 }
 
 static void builtin_diff(const char *name_a,
@@ -1236,6 +1227,8 @@ static void builtin_diff(const char *name_a,
        }
 
  free_ab_and_return:
+       diff_free_filespec_data(one);
+       diff_free_filespec_data(two);
        free(a_one);
        free(b_two);
        return;
@@ -1262,7 +1255,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                diff_populate_filespec(two, 0);
                data->deleted = count_lines(one->data, one->size);
                data->added = count_lines(two->data, two->size);
-               return;
+               goto free_and_return;
        }
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
@@ -1284,6 +1277,10 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                ecb.priv = diffstat;
                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
        }
+
+ free_and_return:
+       diff_free_filespec_data(one);
+       diff_free_filespec_data(two);
 }
 
 static void builtin_checkdiff(const char *name_a, const char *name_b,
@@ -1306,7 +1303,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
                die("unable to read files to diff");
 
        if (file_is_binary(two))
-               return;
+               goto free_and_return;
        else {
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
@@ -1320,6 +1317,9 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
                ecb.priv = &data;
                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
        }
+ free_and_return:
+       diff_free_filespec_data(one);
+       diff_free_filespec_data(two);
 }
 
 struct diff_filespec *alloc_filespec(const char *path)
@@ -1344,7 +1344,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
 }
 
 /*
- * Given a name and sha1 pair, if the dircache tells us the file in
+ * Given a name and sha1 pair, if the index tells us the file in
  * the work tree has that object contents, return true, so that
  * prepare_temp_file() does not have to inflate and extract.
  */
@@ -1399,61 +1399,12 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
        return 1;
 }
 
-static struct sha1_size_cache {
-       unsigned char sha1[20];
-       unsigned long size;
-} **sha1_size_cache;
-static int sha1_size_cache_nr, sha1_size_cache_alloc;
-
-static struct sha1_size_cache *locate_size_cache(unsigned char *sha1,
-                                                int find_only,
-                                                unsigned long size)
-{
-       int first, last;
-       struct sha1_size_cache *e;
-
-       first = 0;
-       last = sha1_size_cache_nr;
-       while (last > first) {
-               int cmp, next = (last + first) >> 1;
-               e = sha1_size_cache[next];
-               cmp = hashcmp(e->sha1, sha1);
-               if (!cmp)
-                       return e;
-               if (cmp < 0) {
-                       last = next;
-                       continue;
-               }
-               first = next+1;
-       }
-       /* not found */
-       if (find_only)
-               return NULL;
-       /* insert to make it at "first" */
-       if (sha1_size_cache_alloc <= sha1_size_cache_nr) {
-               sha1_size_cache_alloc = alloc_nr(sha1_size_cache_alloc);
-               sha1_size_cache = xrealloc(sha1_size_cache,
-                                          sha1_size_cache_alloc *
-                                          sizeof(*sha1_size_cache));
-       }
-       sha1_size_cache_nr++;
-       if (first < sha1_size_cache_nr)
-               memmove(sha1_size_cache + first + 1, sha1_size_cache + first,
-                       (sha1_size_cache_nr - first - 1) *
-                       sizeof(*sha1_size_cache));
-       e = xmalloc(sizeof(struct sha1_size_cache));
-       sha1_size_cache[first] = e;
-       hashcpy(e->sha1, sha1);
-       e->size = size;
-       return e;
-}
-
 static int populate_from_stdin(struct diff_filespec *s)
 {
 #define INCREMENT 1024
        char *buf;
        unsigned long size;
-       int got;
+       ssize_t got;
 
        size = 0;
        buf = NULL;
@@ -1503,13 +1454,13 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
        if (S_ISDIR(s->mode))
                return -1;
 
-       if (!use_size_cache)
-               size_only = 0;
-
        if (s->data)
-               return err;
+               return 0;
+
+       if (size_only && 0 < s->size)
+               return 0;
 
-       if (S_ISDIRLNK(s->mode))
+       if (S_ISGITLINK(s->mode))
                return diff_populate_gitlink(s, size_only);
 
        if (!s->sha1_valid ||
@@ -1570,19 +1521,8 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
        }
        else {
                enum object_type type;
-               struct sha1_size_cache *e;
-
-               if (size_only && use_size_cache &&
-                   (e = locate_size_cache(s->sha1, 1, 0)) != NULL) {
-                       s->size = e->size;
-                       return 0;
-               }
-
-               if (size_only) {
+               if (size_only)
                        type = sha1_object_info(s->sha1, &s->size);
-                       if (use_size_cache && 0 < type)
-                               locate_size_cache(s->sha1, 0, s->size);
-               }
                else {
                        s->data = read_sha1_file(s->sha1, &type, &s->size);
                        s->should_free = 1;
@@ -1597,8 +1537,11 @@ void diff_free_filespec_data(struct diff_filespec *s)
                free(s->data);
        else if (s->should_munmap)
                munmap(s->data, s->size);
-       s->should_free = s->should_munmap = 0;
-       s->data = NULL;
+
+       if (s->should_free || s->should_munmap) {
+               s->should_free = s->should_munmap = 0;
+               s->data = NULL;
+       }
        free(s->cnt_data);
        s->cnt_data = NULL;
 }
@@ -1611,7 +1554,7 @@ static void prep_temp_blob(struct diff_tempfile *temp,
 {
        int fd;
 
-       fd = git_mkstemp(temp->tmp_path, TEMPFILE_PATH_LEN, ".diff_XXXXXX");
+       fd = git_mkstemp(temp->tmp_path, PATH_MAX, ".diff_XXXXXX");
        if (fd < 0)
                die("unable to create temp-file");
        if (write_in_full(fd, blob, size) != size)
@@ -2090,8 +2033,6 @@ int diff_setup_done(struct diff_options *options)
                         */
                        read_cache();
        }
-       if (options->setup & DIFF_SETUP_USE_SIZE_CACHE)
-               use_size_cache = 1;
        if (options->abbrev <= 0 || 40 < options->abbrev)
                options->abbrev = 40; /* full */
 
@@ -2162,6 +2103,8 @@ static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *va
        return 1;
 }
 
+static int diff_scoreopt_parse(const char *opt);
+
 int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 {
        const char *arg = av[0];
@@ -2258,6 +2201,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->detect_rename = DIFF_DETECT_RENAME;
        }
        else if (!prefixcmp(arg, "-C")) {
+               if (options->detect_rename == DIFF_DETECT_COPY)
+                       options->find_copies_harder = 1;
                if ((options->rename_score =
                     diff_scoreopt_parse(arg)) == -1)
                        return -1;
@@ -2265,6 +2210,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        }
        else if (!strcmp(arg, "--find-copies-harder"))
                options->find_copies_harder = 1;
+       else if (!strcmp(arg, "--follow"))
+               options->follow_renames = 1;
        else if (!strcmp(arg, "--abbrev"))
                options->abbrev = DEFAULT_ABBREV;
        else if (!prefixcmp(arg, "--abbrev=")) {
@@ -2333,7 +2280,7 @@ static int parse_num(const char **cp_p)
        return (int)((num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale));
 }
 
-int diff_scoreopt_parse(const char *opt)
+static int diff_scoreopt_parse(const char *opt)
 {
        int opt1, opt2, cmd;
 
@@ -3090,7 +3037,7 @@ void diff_addremove(struct diff_options *options,
         * entries to the diff-core.  They will be prefixed
         * with something like '=' or '*' (I haven't decided
         * which but should not make any difference).
-        * Feeding the same new and old to diff_change() 
+        * Feeding the same new and old to diff_change()
         * also has the same effect.
         * Before the final output happens, they are pruned after
         * merged into rename/copy pairs as appropriate.
@@ -3117,7 +3064,7 @@ void diff_change(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
-                const char *base, const char *path) 
+                const char *base, const char *path)
 {
        char concatpath[PATH_MAX];
        struct diff_filespec *one, *two;