Skip to content

Commit

Permalink
blame,cat-file --textconv: Don't assume mode is ``S_IFREF | 0664''
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kirill Smelkov authored and Junio C Hamano committed Sep 29, 2010
1 parent ab3b7b9 commit 9006471
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 21 deletions.
2 changes: 1 addition & 1 deletion builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);

extern int check_pager_config(const char *cmd);

extern int textconv_object(const char *path, const unsigned char *sha1, char **buf, unsigned long *buf_size);
extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size);

extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
Expand Down
33 changes: 22 additions & 11 deletions builtin/blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct origin {
struct commit *commit;
mmfile_t file;
unsigned char blob_sha1[20];
unsigned mode;
char path[FLEX_ARRAY];
};

Expand All @@ -92,6 +93,7 @@ struct origin {
* Return 1 if the conversion succeeds, 0 otherwise.
*/
int textconv_object(const char *path,
unsigned mode,
const unsigned char *sha1,
char **buf,
unsigned long *buf_size)
Expand All @@ -100,7 +102,7 @@ int textconv_object(const char *path,
struct userdiff_driver *textconv;

df = alloc_filespec(path);
fill_filespec(df, sha1, S_IFREG | 0664);
fill_filespec(df, sha1, mode);
textconv = get_textconv(df);
if (!textconv) {
free_filespec(df);
Expand All @@ -125,7 +127,7 @@ static void fill_origin_blob(struct diff_options *opt,

num_read_blob++;
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
textconv_object(o->path, o->blob_sha1, &file->ptr, &file_size))
textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size))
;
else
file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
Expand Down Expand Up @@ -313,21 +315,23 @@ static struct origin *get_origin(struct scoreboard *sb,
* for an origin is also used to pass the blame for the entire file to
* the parent to detect the case where a child's blob is identical to
* that of its parent's.
*
* This also fills origin->mode for corresponding tree path.
*/
static int fill_blob_sha1(struct origin *origin)
static int fill_blob_sha1_and_mode(struct origin *origin)
{
unsigned mode;
if (!is_null_sha1(origin->blob_sha1))
return 0;
if (get_tree_entry(origin->commit->object.sha1,
origin->path,
origin->blob_sha1, &mode))
origin->blob_sha1, &origin->mode))
goto error_out;
if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
goto error_out;
return 0;
error_out:
hashclr(origin->blob_sha1);
origin->mode = S_IFINVALID;
return -1;
}

Expand Down Expand Up @@ -360,12 +364,14 @@ static struct origin *find_origin(struct scoreboard *sb,
/*
* If the origin was newly created (i.e. get_origin
* would call make_origin if none is found in the
* scoreboard), it does not know the blob_sha1,
* scoreboard), it does not know the blob_sha1/mode,
* so copy it. Otherwise porigin was in the
* scoreboard and already knows blob_sha1.
* scoreboard and already knows blob_sha1/mode.
*/
if (porigin->refcnt == 1)
if (porigin->refcnt == 1) {
hashcpy(porigin->blob_sha1, cached->blob_sha1);
porigin->mode = cached->mode;
}
return porigin;
}
/* otherwise it was not very useful; free it */
Expand Down Expand Up @@ -400,6 +406,7 @@ static struct origin *find_origin(struct scoreboard *sb,
/* The path is the same as parent */
porigin = get_origin(sb, parent, origin->path);
hashcpy(porigin->blob_sha1, origin->blob_sha1);
porigin->mode = origin->mode;
} else {
/*
* Since origin->path is a pathspec, if the parent
Expand All @@ -425,6 +432,7 @@ static struct origin *find_origin(struct scoreboard *sb,
case 'M':
porigin = get_origin(sb, parent, origin->path);
hashcpy(porigin->blob_sha1, p->one->sha1);
porigin->mode = p->one->mode;
break;
case 'A':
case 'T':
Expand All @@ -444,6 +452,7 @@ static struct origin *find_origin(struct scoreboard *sb,

cached = make_origin(porigin->commit, porigin->path);
hashcpy(cached->blob_sha1, porigin->blob_sha1);
cached->mode = porigin->mode;
parent->util = cached;
}
return porigin;
Expand Down Expand Up @@ -486,6 +495,7 @@ static struct origin *find_rename(struct scoreboard *sb,
!strcmp(p->two->path, origin->path)) {
porigin = get_origin(sb, parent, p->one->path);
hashcpy(porigin->blob_sha1, p->one->sha1);
porigin->mode = p->one->mode;
break;
}
}
Expand Down Expand Up @@ -1099,6 +1109,7 @@ static int find_copy_in_parent(struct scoreboard *sb,

norigin = get_origin(sb, parent, p->one->path);
hashcpy(norigin->blob_sha1, p->one->sha1);
norigin->mode = p->one->mode;
fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
if (!file_p.ptr)
continue;
Expand Down Expand Up @@ -2083,7 +2094,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
switch (st.st_mode & S_IFMT) {
case S_IFREG:
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
textconv_object(read_from, null_sha1, &buf.buf, &buf_len))
textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len))
buf.len = buf_len;
else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
die_errno("cannot open or read '%s'", read_from);
Expand Down Expand Up @@ -2463,11 +2474,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
}
else {
o = get_origin(&sb, sb.final, path);
if (fill_blob_sha1(o))
if (fill_blob_sha1_and_mode(o))
die("no such path %s in %s", path, final_commit_name);

if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
textconv_object(path, o->blob_sha1, (char **) &sb.final_buf,
textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf,
&sb.final_buf_size))
;
else
Expand Down
2 changes: 1 addition & 1 deletion builtin/cat-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
die("git cat-file --textconv %s: <object> must be <sha1:path>",
obj_name);

if (!textconv_object(obj_context.path, sha1, &buf, &size))
if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
die("git cat-file --textconv: unable to run textconv on %s",
obj_name);
break;
Expand Down
2 changes: 2 additions & 0 deletions sha1_name.c
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
struct cache_entry *ce;
int pos;
if (namelen > 2 && name[1] == '/')
/* don't need mode for commit */
return get_sha1_oneline(name + 2, sha1);
if (namelen < 3 ||
name[2] != ':' ||
Expand Down Expand Up @@ -1095,6 +1096,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
break;
if (ce_stage(ce) == stage) {
hashcpy(sha1, ce->sha1);
oc->mode = ce->ce_mode;
return 0;
}
pos++;
Expand Down
6 changes: 2 additions & 4 deletions t/t8006-blame-textconv.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ test_expect_success SYMLINKS 'blame with --no-textconv (on symlink)' '
test_cmp expected result
'

# fails with '...symlink.bin is not "binary" file'
test_expect_failure SYMLINKS 'blame --textconv (on symlink)' '
test_expect_success SYMLINKS 'blame --textconv (on symlink)' '
git blame --textconv symlink.bin >blame &&
find_blame <blame >result &&
test_cmp expected result
Expand All @@ -114,8 +113,7 @@ EOF
GIT_AUTHOR_NAME=Number4 git commit -a -m Fourth --date="2010-01-01 23:00:00"
'

# fails with '...symlink.bin is not "binary" file'
test_expect_failure SYMLINKS 'blame on last commit (-C -C, symlink)' '
test_expect_success SYMLINKS 'blame on last commit (-C -C, symlink)' '
git blame -C -C three.bin >blame &&
find_blame <blame >result &&
cat >expected <<\EOF &&
Expand Down
6 changes: 2 additions & 4 deletions t/t8007-cat-file-textconv.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,15 @@ test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' '
'


# fails because cat-file tries to run converter on symlink.bin
test_expect_failure SYMLINKS 'cat-file --textconv on index (symlink)' '
test_expect_success SYMLINKS 'cat-file --textconv on index (symlink)' '
! git cat-file --textconv :symlink.bin 2>result &&
cat >expected <<\EOF &&
fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
EOF
test_cmp expected result
'

# fails because cat-file tries to run converter on symlink.bin
test_expect_failure SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
test_expect_success SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
! git cat-file --textconv HEAD:symlink.bin 2>result &&
cat >expected <<EOF &&
fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin
Expand Down

0 comments on commit 9006471

Please sign in to comment.