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