@matheusbsbs / matheus-bagliano / commits / 900647104e
Fork 0

blame,cat-file --textconv: Don't assume mode is ``S_IFREF | 0664''

We need to get the correct mode when blame reads the source from the working tree, the index, or trees. This allows us to omit running textconv filters on symbolic links. Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru> Reviewed-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Kirill Smelkov committed Sep 29, 2010 at 15:35 UTC 900647104e02e545064789f3c6b90a5807fba07b
6 files changed +30 -21
builtin.h
+1 -1
@@ -37,7 +37,7 @@ void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);
37
38 extern int check_pager_config(const char *cmd);
39
40 -extern int textconv_object(const char *path, const unsigned char *sha1, char **buf, unsigned long *buf_size);
40 +extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size);
41
42 extern int cmd_add(int argc, const char **argv, const char *prefix);
43 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
builtin/blame.c
+22 -11
@@ -83,6 +83,7 @@ struct origin {
83 struct commit *commit;
84 mmfile_t file;
85 unsigned char blob_sha1[20];
86 + unsigned mode;
87 char path[FLEX_ARRAY];
88 };
89
@@ -92,6 +93,7 @@ struct origin {
93 * Return 1 if the conversion succeeds, 0 otherwise.
94 */
95 int textconv_object(const char *path,
96 + unsigned mode,
97 const unsigned char *sha1,
98 char **buf,
99 unsigned long *buf_size)
@@ -100,7 +102,7 @@ int textconv_object(const char *path,
102 struct userdiff_driver *textconv;
103
104 df = alloc_filespec(path);
103 - fill_filespec(df, sha1, S_IFREG | 0664);
105 + fill_filespec(df, sha1, mode);
106 textconv = get_textconv(df);
107 if (!textconv) {
108 free_filespec(df);
@@ -125,7 +127,7 @@ static void fill_origin_blob(struct diff_options *opt,
127
128 num_read_blob++;
129 if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
128 - textconv_object(o->path, o->blob_sha1, &file->ptr, &file_size))
130 + textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size))
131 ;
132 else
133 file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
@@ -313,21 +315,23 @@ static struct origin *get_origin(struct scoreboard *sb,
315 * for an origin is also used to pass the blame for the entire file to
316 * the parent to detect the case where a child's blob is identical to
317 * that of its parent's.
318 + *
319 + * This also fills origin->mode for corresponding tree path.
320 */
317 -static int fill_blob_sha1(struct origin *origin)
321 +static int fill_blob_sha1_and_mode(struct origin *origin)
322 {
319 - unsigned mode;
323 if (!is_null_sha1(origin->blob_sha1))
324 return 0;
325 if (get_tree_entry(origin->commit->object.sha1,
326 origin->path,
324 - origin->blob_sha1, &mode))
327 + origin->blob_sha1, &origin->mode))
328 goto error_out;
329 if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
330 goto error_out;
331 return 0;
332 error_out:
333 hashclr(origin->blob_sha1);
334 + origin->mode = S_IFINVALID;
335 return -1;
336 }
337
@@ -360,12 +364,14 @@ static struct origin *find_origin(struct scoreboard *sb,
364 /*
365 * If the origin was newly created (i.e. get_origin
366 * would call make_origin if none is found in the
363 - * scoreboard), it does not know the blob_sha1,
367 + * scoreboard), it does not know the blob_sha1/mode,
368 * so copy it. Otherwise porigin was in the
365 - * scoreboard and already knows blob_sha1.
369 + * scoreboard and already knows blob_sha1/mode.
370 */
367 - if (porigin->refcnt == 1)
371 + if (porigin->refcnt == 1) {
372 hashcpy(porigin->blob_sha1, cached->blob_sha1);
373 + porigin->mode = cached->mode;
374 + }
375 return porigin;
376 }
377 /* otherwise it was not very useful; free it */
@@ -400,6 +406,7 @@ static struct origin *find_origin(struct scoreboard *sb,
406 /* The path is the same as parent */
407 porigin = get_origin(sb, parent, origin->path);
408 hashcpy(porigin->blob_sha1, origin->blob_sha1);
409 + porigin->mode = origin->mode;
410 } else {
411 /*
412 * Since origin->path is a pathspec, if the parent
@@ -425,6 +432,7 @@ static struct origin *find_origin(struct scoreboard *sb,
432 case 'M':
433 porigin = get_origin(sb, parent, origin->path);
434 hashcpy(porigin->blob_sha1, p->one->sha1);
435 + porigin->mode = p->one->mode;
436 break;
437 case 'A':
438 case 'T':
@@ -444,6 +452,7 @@ static struct origin *find_origin(struct scoreboard *sb,
452
453 cached = make_origin(porigin->commit, porigin->path);
454 hashcpy(cached->blob_sha1, porigin->blob_sha1);
455 + cached->mode = porigin->mode;
456 parent->util = cached;
457 }
458 return porigin;
@@ -486,6 +495,7 @@ static struct origin *find_rename(struct scoreboard *sb,
495 !strcmp(p->two->path, origin->path)) {
496 porigin = get_origin(sb, parent, p->one->path);
497 hashcpy(porigin->blob_sha1, p->one->sha1);
498 + porigin->mode = p->one->mode;
499 break;
500 }
501 }
@@ -1099,6 +1109,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
1109
1110 norigin = get_origin(sb, parent, p->one->path);
1111 hashcpy(norigin->blob_sha1, p->one->sha1);
1112 + norigin->mode = p->one->mode;
1113 fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
1114 if (!file_p.ptr)
1115 continue;
@@ -2083,7 +2094,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
2094 switch (st.st_mode & S_IFMT) {
2095 case S_IFREG:
2096 if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
2086 - textconv_object(read_from, null_sha1, &buf.buf, &buf_len))
2097 + textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len))
2098 buf.len = buf_len;
2099 else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
2100 die_errno("cannot open or read '%s'", read_from);
@@ -2463,11 +2474,11 @@ parse_done:
2474 }
2475 else {
2476 o = get_origin(&sb, sb.final, path);
2466 - if (fill_blob_sha1(o))
2477 + if (fill_blob_sha1_and_mode(o))
2478 die("no such path %s in %s", path, final_commit_name);
2479
2480 if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
2470 - textconv_object(path, o->blob_sha1, (char **) &sb.final_buf,
2481 + textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf,
2482 &sb.final_buf_size))
2483 ;
2484 else
builtin/cat-file.c
+1 -1
@@ -143,7 +143,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
143 die("git cat-file --textconv %s: <object> must be <sha1:path>",
144 obj_name);
145
146 - if (!textconv_object(obj_context.path, sha1, &buf, &size))
146 + if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
147 die("git cat-file --textconv: unable to run textconv on %s",
148 obj_name);
149 break;
sha1_name.c
+2
@@ -1068,6 +1068,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
1068 struct cache_entry *ce;
1069 int pos;
1070 if (namelen > 2 && name[1] == '/')
1071 + /* don't need mode for commit */
1072 return get_sha1_oneline(name + 2, sha1);
1073 if (namelen < 3 ||
1074 name[2] != ':' ||
@@ -1095,6 +1096,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
1096 break;
1097 if (ce_stage(ce) == stage) {
1098 hashcpy(sha1, ce->sha1);
1099 + oc->mode = ce->ce_mode;
1100 return 0;
1101 }
1102 pos++;
t/t8006-blame-textconv.sh
+2 -4
@@ -94,8 +94,7 @@ test_expect_success SYMLINKS 'blame with --no-textconv (on symlink)' '
94 test_cmp expected result
95 '
96
97 -# fails with '...symlink.bin is not "binary" file'
98 -test_expect_failure SYMLINKS 'blame --textconv (on symlink)' '
97 +test_expect_success SYMLINKS 'blame --textconv (on symlink)' '
98 git blame --textconv symlink.bin >blame &&
99 find_blame <blame >result &&
100 test_cmp expected result
@@ -114,8 +113,7 @@ EOF
113 GIT_AUTHOR_NAME=Number4 git commit -a -m Fourth --date="2010-01-01 23:00:00"
114 '
115
117 -# fails with '...symlink.bin is not "binary" file'
118 -test_expect_failure SYMLINKS 'blame on last commit (-C -C, symlink)' '
116 +test_expect_success SYMLINKS 'blame on last commit (-C -C, symlink)' '
117 git blame -C -C three.bin >blame &&
118 find_blame <blame >result &&
119 cat >expected <<\EOF &&
t/t8007-cat-file-textconv.sh
+2 -4
@@ -79,8 +79,7 @@ test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' '
79 '
80
81
82 -# fails because cat-file tries to run converter on symlink.bin
83 -test_expect_failure SYMLINKS 'cat-file --textconv on index (symlink)' '
82 +test_expect_success SYMLINKS 'cat-file --textconv on index (symlink)' '
83 ! git cat-file --textconv :symlink.bin 2>result &&
84 cat >expected <<\EOF &&
85 fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
@@ -88,8 +87,7 @@ EOF
87 test_cmp expected result
88 '
89
91 -# fails because cat-file tries to run converter on symlink.bin
92 -test_expect_failure SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
90 +test_expect_success SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
91 ! git cat-file --textconv HEAD:symlink.bin 2>result &&
92 cat >expected <<EOF &&
93 fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin