Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
28239be3
Unverified
Commit
28239be3
authored
Nov 13, 2018
by
Patrick Steinhardt
Committed by
GitHub
Nov 13, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4818 from pks-t/pks/index-collision
Index collision fixes
parents
11fbead8
8b6e2895
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
89 additions
and
47 deletions
+89
-47
src/index.c
+40
-45
tests/index/collision.c
+49
-2
No files found.
src/index.c
View file @
28239be3
...
@@ -1096,7 +1096,6 @@ static int index_entry_dup_nocache(
...
@@ -1096,7 +1096,6 @@ static int index_entry_dup_nocache(
static
int
has_file_name
(
git_index
*
index
,
static
int
has_file_name
(
git_index
*
index
,
const
git_index_entry
*
entry
,
size_t
pos
,
int
ok_to_replace
)
const
git_index_entry
*
entry
,
size_t
pos
,
int
ok_to_replace
)
{
{
int
retval
=
0
;
size_t
len
=
strlen
(
entry
->
path
);
size_t
len
=
strlen
(
entry
->
path
);
int
stage
=
GIT_IDXENTRY_STAGE
(
entry
);
int
stage
=
GIT_IDXENTRY_STAGE
(
entry
);
const
char
*
name
=
entry
->
path
;
const
char
*
name
=
entry
->
path
;
...
@@ -1112,14 +1111,13 @@ static int has_file_name(git_index *index,
...
@@ -1112,14 +1111,13 @@ static int has_file_name(git_index *index,
continue
;
continue
;
if
(
p
->
path
[
len
]
!=
'/'
)
if
(
p
->
path
[
len
]
!=
'/'
)
continue
;
continue
;
retval
=
-
1
;
if
(
!
ok_to_replace
)
if
(
!
ok_to_replace
)
break
;
return
-
1
;
if
(
index_remove_entry
(
index
,
--
pos
)
<
0
)
if
(
index_remove_entry
(
index
,
--
pos
)
<
0
)
break
;
break
;
}
}
return
retval
;
return
0
;
}
}
/*
/*
...
@@ -1129,7 +1127,6 @@ static int has_file_name(git_index *index,
...
@@ -1129,7 +1127,6 @@ static int has_file_name(git_index *index,
static
int
has_dir_name
(
git_index
*
index
,
static
int
has_dir_name
(
git_index
*
index
,
const
git_index_entry
*
entry
,
int
ok_to_replace
)
const
git_index_entry
*
entry
,
int
ok_to_replace
)
{
{
int
retval
=
0
;
int
stage
=
GIT_IDXENTRY_STAGE
(
entry
);
int
stage
=
GIT_IDXENTRY_STAGE
(
entry
);
const
char
*
name
=
entry
->
path
;
const
char
*
name
=
entry
->
path
;
const
char
*
slash
=
name
+
strlen
(
name
);
const
char
*
slash
=
name
+
strlen
(
name
);
...
@@ -1141,14 +1138,13 @@ static int has_dir_name(git_index *index,
...
@@ -1141,14 +1138,13 @@ static int has_dir_name(git_index *index,
if
(
*--
slash
==
'/'
)
if
(
*--
slash
==
'/'
)
break
;
break
;
if
(
slash
<=
entry
->
path
)
if
(
slash
<=
entry
->
path
)
return
retval
;
return
0
;
}
}
len
=
slash
-
name
;
len
=
slash
-
name
;
if
(
!
index_find
(
&
pos
,
index
,
name
,
len
,
stage
))
{
if
(
!
index_find
(
&
pos
,
index
,
name
,
len
,
stage
))
{
retval
=
-
1
;
if
(
!
ok_to_replace
)
if
(
!
ok_to_replace
)
break
;
return
-
1
;
if
(
index_remove_entry
(
index
,
pos
)
<
0
)
if
(
index_remove_entry
(
index
,
pos
)
<
0
)
break
;
break
;
...
@@ -1169,20 +1165,18 @@ static int has_dir_name(git_index *index,
...
@@ -1169,20 +1165,18 @@ static int has_dir_name(git_index *index,
break
;
/* not our subdirectory */
break
;
/* not our subdirectory */
if
(
GIT_IDXENTRY_STAGE
(
&
p
->
entry
)
==
stage
)
if
(
GIT_IDXENTRY_STAGE
(
&
p
->
entry
)
==
stage
)
return
retval
;
return
0
;
}
}
}
}
return
retval
;
return
0
;
}
}
static
int
check_file_directory_collision
(
git_index
*
index
,
static
int
check_file_directory_collision
(
git_index
*
index
,
git_index_entry
*
entry
,
size_t
pos
,
int
ok_to_replace
)
git_index_entry
*
entry
,
size_t
pos
,
int
ok_to_replace
)
{
{
int
retval
=
has_file_name
(
index
,
entry
,
pos
,
ok_to_replace
);
if
(
has_file_name
(
index
,
entry
,
pos
,
ok_to_replace
)
<
0
||
retval
=
retval
+
has_dir_name
(
index
,
entry
,
ok_to_replace
);
has_dir_name
(
index
,
entry
,
ok_to_replace
)
<
0
)
{
if
(
retval
)
{
giterr_set
(
GITERR_INDEX
,
giterr_set
(
GITERR_INDEX
,
"'%s' appears as both a file and a directory"
,
entry
->
path
);
"'%s' appears as both a file and a directory"
,
entry
->
path
);
return
-
1
;
return
-
1
;
...
@@ -1337,57 +1331,58 @@ static int index_insert(
...
@@ -1337,57 +1331,58 @@ static int index_insert(
bool
trust_mode
,
bool
trust_mode
,
bool
trust_id
)
bool
trust_id
)
{
{
int
error
=
0
;
size_t
path_length
,
position
;
git_index_entry
*
existing
,
*
best
,
*
entry
;
git_index_entry
*
existing
,
*
best
,
*
entry
;
size_t
path_length
,
position
;
int
error
;
assert
(
index
&&
entry_ptr
);
assert
(
index
&&
entry_ptr
);
entry
=
*
entry_ptr
;
entry
=
*
entry_ptr
;
/*
m
ake sure that the path length flag is correct */
/*
M
ake sure that the path length flag is correct */
path_length
=
((
struct
entry_internal
*
)
entry
)
->
pathlen
;
path_length
=
((
struct
entry_internal
*
)
entry
)
->
pathlen
;
index_entry_adjust_namemask
(
entry
,
path_length
);
index_entry_adjust_namemask
(
entry
,
path_length
);
/*
t
his entry is now up-to-date and should not be checked for raciness */
/*
T
his entry is now up-to-date and should not be checked for raciness */
entry
->
flags_extended
|=
GIT_IDXENTRY_UPTODATE
;
entry
->
flags_extended
|=
GIT_IDXENTRY_UPTODATE
;
git_vector_sort
(
&
index
->
entries
);
git_vector_sort
(
&
index
->
entries
);
/* look if an entry with this path already exists, either staged, or (if
/*
* Look if an entry with this path already exists, either staged, or (if
* this entry is a regular staged item) as the "ours" side of a conflict.
* this entry is a regular staged item) as the "ours" side of a conflict.
*/
*/
index_existing_and_best
(
&
existing
,
&
position
,
&
best
,
index
,
entry
);
index_existing_and_best
(
&
existing
,
&
position
,
&
best
,
index
,
entry
);
/*
u
pdate the file mode */
/*
U
pdate the file mode */
entry
->
mode
=
trust_mode
?
entry
->
mode
=
trust_mode
?
git_index__create_mode
(
entry
->
mode
)
:
git_index__create_mode
(
entry
->
mode
)
:
index_merge_mode
(
index
,
best
,
entry
->
mode
);
index_merge_mode
(
index
,
best
,
entry
->
mode
);
/*
c
anonicalize the directory name */
/*
C
anonicalize the directory name */
if
(
!
trust_path
)
if
(
!
trust_path
&&
(
error
=
canonicalize_directory_path
(
index
,
entry
,
best
))
<
0
)
error
=
canonicalize_directory_path
(
index
,
entry
,
best
)
;
goto
out
;
/*
e
nsure that the given id exists (unless it's a submodule) */
/*
E
nsure that the given id exists (unless it's a submodule) */
if
(
!
error
&&
!
trust_id
&&
INDEX_OWNER
(
index
)
&&
if
(
!
trust_id
&&
INDEX_OWNER
(
index
)
&&
(
entry
->
mode
&
GIT_FILEMODE_COMMIT
)
!=
GIT_FILEMODE_COMMIT
)
{
(
entry
->
mode
&
GIT_FILEMODE_COMMIT
)
!=
GIT_FILEMODE_COMMIT
)
{
if
(
!
git_object__is_valid
(
INDEX_OWNER
(
index
),
&
entry
->
id
,
if
(
!
git_object__is_valid
(
INDEX_OWNER
(
index
),
&
entry
->
id
,
git_object__type_from_filemode
(
entry
->
mode
)))
git_object__type_from_filemode
(
entry
->
mode
)))
{
error
=
-
1
;
error
=
-
1
;
goto
out
;
}
}
}
/* look for tree / blob name collisions, removing conflicts if requested */
/* Look for tree / blob name collisions, removing conflicts if requested */
if
(
!
error
)
if
((
error
=
check_file_directory_collision
(
index
,
entry
,
position
,
replace
))
<
0
)
error
=
check_file_directory_collision
(
index
,
entry
,
position
,
replace
);
goto
out
;
if
(
error
<
0
)
/* skip changes */
;
/* if we are replacing an existing item, overwrite the existing entry
/*
* If we are replacing an existing item, overwrite the existing entry
* and return it in place of the passed in one.
* and return it in place of the passed in one.
*/
*/
else
if
(
existing
)
{
if
(
existing
)
{
if
(
replace
)
{
if
(
replace
)
{
index_entry_cpy
(
existing
,
entry
);
index_entry_cpy
(
existing
,
entry
);
...
@@ -1396,25 +1391,25 @@ static int index_insert(
...
@@ -1396,25 +1391,25 @@ static int index_insert(
}
}
index_entry_free
(
entry
);
index_entry_free
(
entry
);
*
entry_ptr
=
e
ntry
=
e
xisting
;
*
entry_ptr
=
existing
;
}
}
else
{
else
{
/*
/* i
f replace is not requested or no existing entry exists, insert
* I
f replace is not requested or no existing entry exists, insert
* at the sorted position. (Since we re-sort after each insert to
* at the sorted position. (Since we re-sort after each insert to
* check for dups, this is actually cheaper in the long run.)
* check for dups, this is actually cheaper in the long run.)
*/
*/
error
=
git_vector_insert_sorted
(
&
index
->
entries
,
entry
,
index_no_dups
);
if
((
error
=
git_vector_insert_sorted
(
&
index
->
entries
,
entry
,
index_no_dups
))
<
0
)
goto
out
;
if
(
error
==
0
)
{
INSERT_IN_MAP
(
index
,
entry
,
&
error
);
INSERT_IN_MAP
(
index
,
entry
,
&
error
);
}
}
}
index
->
dirty
=
1
;
out
:
if
(
error
<
0
)
{
if
(
error
<
0
)
{
index_entry_free
(
*
entry_ptr
);
index_entry_free
(
*
entry_ptr
);
*
entry_ptr
=
NULL
;
*
entry_ptr
=
NULL
;
}
else
{
index
->
dirty
=
1
;
}
}
return
error
;
return
error
;
...
...
tests/index/collision.c
View file @
28239be3
...
@@ -23,9 +23,10 @@ void test_index_collision__cleanup(void)
...
@@ -23,9 +23,10 @@ void test_index_collision__cleanup(void)
cl_git_sandbox_cleanup
();
cl_git_sandbox_cleanup
();
}
}
void
test_index_collision__add
(
void
)
void
test_index_collision__add
_blob_with_conflicting_file
(
void
)
{
{
git_index_entry
entry
;
git_index_entry
entry
;
git_tree_entry
*
tentry
;
git_oid
tree_id
;
git_oid
tree_id
;
git_tree
*
tree
;
git_tree
*
tree
;
...
@@ -39,13 +40,59 @@ void test_index_collision__add(void)
...
@@ -39,13 +40,59 @@ void test_index_collision__add(void)
entry
.
path
=
"a/b"
;
entry
.
path
=
"a/b"
;
cl_git_pass
(
git_index_add
(
g_index
,
&
entry
));
cl_git_pass
(
git_index_add
(
g_index
,
&
entry
));
/* Check a/b exists here */
cl_git_pass
(
git_index_write_tree
(
&
tree_id
,
g_index
));
cl_git_pass
(
git_tree_lookup
(
&
tree
,
g_repo
,
&
tree_id
));
cl_git_pass
(
git_tree_entry_bypath
(
&
tentry
,
tree
,
"a/b"
));
git_tree_entry_free
(
tentry
);
git_tree_free
(
tree
);
/* create a tree/blob collision */
/* create a tree/blob collision */
entry
.
path
=
"a/b/c"
;
entry
.
path
=
"a/b/c"
;
cl_git_
fail
(
git_index_add
(
g_index
,
&
entry
));
cl_git_
pass
(
git_index_add
(
g_index
,
&
entry
));
/* a/b should now be a tree and a/b/c a blob */
cl_git_pass
(
git_index_write_tree
(
&
tree_id
,
g_index
));
cl_git_pass
(
git_index_write_tree
(
&
tree_id
,
g_index
));
cl_git_pass
(
git_tree_lookup
(
&
tree
,
g_repo
,
&
tree_id
));
cl_git_pass
(
git_tree_lookup
(
&
tree
,
g_repo
,
&
tree_id
));
cl_git_pass
(
git_tree_entry_bypath
(
&
tentry
,
tree
,
"a/b/c"
));
git_tree_entry_free
(
tentry
);
git_tree_free
(
tree
);
}
void
test_index_collision__add_blob_with_conflicting_dir
(
void
)
{
git_index_entry
entry
;
git_tree_entry
*
tentry
;
git_oid
tree_id
;
git_tree
*
tree
;
memset
(
&
entry
,
0
,
sizeof
(
entry
));
entry
.
ctime
.
seconds
=
12346789
;
entry
.
mtime
.
seconds
=
12346789
;
entry
.
mode
=
0100644
;
entry
.
file_size
=
0
;
git_oid_cpy
(
&
entry
.
id
,
&
g_empty_id
);
entry
.
path
=
"a/b/c"
;
cl_git_pass
(
git_index_add
(
g_index
,
&
entry
));
/* Check a/b/c exists here */
cl_git_pass
(
git_index_write_tree
(
&
tree_id
,
g_index
));
cl_git_pass
(
git_tree_lookup
(
&
tree
,
g_repo
,
&
tree_id
));
cl_git_pass
(
git_tree_entry_bypath
(
&
tentry
,
tree
,
"a/b/c"
));
git_tree_entry_free
(
tentry
);
git_tree_free
(
tree
);
/* create a blob/tree collision */
entry
.
path
=
"a/b"
;
cl_git_pass
(
git_index_add
(
g_index
,
&
entry
));
/* a/b should now be a tree and a/b/c a blob */
cl_git_pass
(
git_index_write_tree
(
&
tree_id
,
g_index
));
cl_git_pass
(
git_tree_lookup
(
&
tree
,
g_repo
,
&
tree_id
));
cl_git_pass
(
git_tree_entry_bypath
(
&
tentry
,
tree
,
"a/b"
));
cl_git_fail
(
git_tree_entry_bypath
(
&
tentry
,
tree
,
"a/b/c"
));
git_tree_entry_free
(
tentry
);
git_tree_free
(
tree
);
git_tree_free
(
tree
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment