Skip to content

Commit 9006471

Browse files
navytuxgitster
authored andcommitted
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 <[email protected]> Reviewed-by: Matthieu Moy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ab3b7b9 commit 9006471

File tree

6 files changed

+30
-21
lines changed

6 files changed

+30
-21
lines changed

builtin.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);
3737

3838
extern int check_pager_config(const char *cmd);
3939

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);
4141

4242
extern int cmd_add(int argc, const char **argv, const char *prefix);
4343
extern int cmd_annotate(int argc, const char **argv, const char *prefix);

builtin/blame.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct origin {
8383
struct commit *commit;
8484
mmfile_t file;
8585
unsigned char blob_sha1[20];
86+
unsigned mode;
8687
char path[FLEX_ARRAY];
8788
};
8889

@@ -92,6 +93,7 @@ struct origin {
9293
* Return 1 if the conversion succeeds, 0 otherwise.
9394
*/
9495
int textconv_object(const char *path,
96+
unsigned mode,
9597
const unsigned char *sha1,
9698
char **buf,
9799
unsigned long *buf_size)
@@ -100,7 +102,7 @@ int textconv_object(const char *path,
100102
struct userdiff_driver *textconv;
101103

102104
df = alloc_filespec(path);
103-
fill_filespec(df, sha1, S_IFREG | 0664);
105+
fill_filespec(df, sha1, mode);
104106
textconv = get_textconv(df);
105107
if (!textconv) {
106108
free_filespec(df);
@@ -125,7 +127,7 @@ static void fill_origin_blob(struct diff_options *opt,
125127

126128
num_read_blob++;
127129
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))
129131
;
130132
else
131133
file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
@@ -313,21 +315,23 @@ static struct origin *get_origin(struct scoreboard *sb,
313315
* for an origin is also used to pass the blame for the entire file to
314316
* the parent to detect the case where a child's blob is identical to
315317
* that of its parent's.
318+
*
319+
* This also fills origin->mode for corresponding tree path.
316320
*/
317-
static int fill_blob_sha1(struct origin *origin)
321+
static int fill_blob_sha1_and_mode(struct origin *origin)
318322
{
319-
unsigned mode;
320323
if (!is_null_sha1(origin->blob_sha1))
321324
return 0;
322325
if (get_tree_entry(origin->commit->object.sha1,
323326
origin->path,
324-
origin->blob_sha1, &mode))
327+
origin->blob_sha1, &origin->mode))
325328
goto error_out;
326329
if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
327330
goto error_out;
328331
return 0;
329332
error_out:
330333
hashclr(origin->blob_sha1);
334+
origin->mode = S_IFINVALID;
331335
return -1;
332336
}
333337

@@ -360,12 +364,14 @@ static struct origin *find_origin(struct scoreboard *sb,
360364
/*
361365
* If the origin was newly created (i.e. get_origin
362366
* 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,
364368
* so copy it. Otherwise porigin was in the
365-
* scoreboard and already knows blob_sha1.
369+
* scoreboard and already knows blob_sha1/mode.
366370
*/
367-
if (porigin->refcnt == 1)
371+
if (porigin->refcnt == 1) {
368372
hashcpy(porigin->blob_sha1, cached->blob_sha1);
373+
porigin->mode = cached->mode;
374+
}
369375
return porigin;
370376
}
371377
/* otherwise it was not very useful; free it */
@@ -400,6 +406,7 @@ static struct origin *find_origin(struct scoreboard *sb,
400406
/* The path is the same as parent */
401407
porigin = get_origin(sb, parent, origin->path);
402408
hashcpy(porigin->blob_sha1, origin->blob_sha1);
409+
porigin->mode = origin->mode;
403410
} else {
404411
/*
405412
* Since origin->path is a pathspec, if the parent
@@ -425,6 +432,7 @@ static struct origin *find_origin(struct scoreboard *sb,
425432
case 'M':
426433
porigin = get_origin(sb, parent, origin->path);
427434
hashcpy(porigin->blob_sha1, p->one->sha1);
435+
porigin->mode = p->one->mode;
428436
break;
429437
case 'A':
430438
case 'T':
@@ -444,6 +452,7 @@ static struct origin *find_origin(struct scoreboard *sb,
444452

445453
cached = make_origin(porigin->commit, porigin->path);
446454
hashcpy(cached->blob_sha1, porigin->blob_sha1);
455+
cached->mode = porigin->mode;
447456
parent->util = cached;
448457
}
449458
return porigin;
@@ -486,6 +495,7 @@ static struct origin *find_rename(struct scoreboard *sb,
486495
!strcmp(p->two->path, origin->path)) {
487496
porigin = get_origin(sb, parent, p->one->path);
488497
hashcpy(porigin->blob_sha1, p->one->sha1);
498+
porigin->mode = p->one->mode;
489499
break;
490500
}
491501
}
@@ -1099,6 +1109,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
10991109

11001110
norigin = get_origin(sb, parent, p->one->path);
11011111
hashcpy(norigin->blob_sha1, p->one->sha1);
1112+
norigin->mode = p->one->mode;
11021113
fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
11031114
if (!file_p.ptr)
11041115
continue;
@@ -2083,7 +2094,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
20832094
switch (st.st_mode & S_IFMT) {
20842095
case S_IFREG:
20852096
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))
20872098
buf.len = buf_len;
20882099
else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
20892100
die_errno("cannot open or read '%s'", read_from);
@@ -2463,11 +2474,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
24632474
}
24642475
else {
24652476
o = get_origin(&sb, sb.final, path);
2466-
if (fill_blob_sha1(o))
2477+
if (fill_blob_sha1_and_mode(o))
24672478
die("no such path %s in %s", path, final_commit_name);
24682479

24692480
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,
24712482
&sb.final_buf_size))
24722483
;
24732484
else

builtin/cat-file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
143143
die("git cat-file --textconv %s: <object> must be <sha1:path>",
144144
obj_name);
145145

146-
if (!textconv_object(obj_context.path, sha1, &buf, &size))
146+
if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
147147
die("git cat-file --textconv: unable to run textconv on %s",
148148
obj_name);
149149
break;

sha1_name.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
10681068
struct cache_entry *ce;
10691069
int pos;
10701070
if (namelen > 2 && name[1] == '/')
1071+
/* don't need mode for commit */
10711072
return get_sha1_oneline(name + 2, sha1);
10721073
if (namelen < 3 ||
10731074
name[2] != ':' ||
@@ -1095,6 +1096,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
10951096
break;
10961097
if (ce_stage(ce) == stage) {
10971098
hashcpy(sha1, ce->sha1);
1099+
oc->mode = ce->ce_mode;
10981100
return 0;
10991101
}
11001102
pos++;

t/t8006-blame-textconv.sh

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ test_expect_success SYMLINKS 'blame with --no-textconv (on symlink)' '
9494
test_cmp expected result
9595
'
9696

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)' '
9998
git blame --textconv symlink.bin >blame &&
10099
find_blame <blame >result &&
101100
test_cmp expected result
@@ -114,8 +113,7 @@ EOF
114113
GIT_AUTHOR_NAME=Number4 git commit -a -m Fourth --date="2010-01-01 23:00:00"
115114
'
116115

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)' '
119117
git blame -C -C three.bin >blame &&
120118
find_blame <blame >result &&
121119
cat >expected <<\EOF &&

t/t8007-cat-file-textconv.sh

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,15 @@ test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' '
7979
'
8080

8181

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)' '
8483
! git cat-file --textconv :symlink.bin 2>result &&
8584
cat >expected <<\EOF &&
8685
fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
8786
EOF
8887
test_cmp expected result
8988
'
9089

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)' '
9391
! git cat-file --textconv HEAD:symlink.bin 2>result &&
9492
cat >expected <<EOF &&
9593
fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin

0 commit comments

Comments
 (0)