summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2017-05-10 14:27:12 +0200
committerPatrick Steinhardt <ps@pks.im>2017-06-06 09:38:43 +0200
commitfebe8c14a0cb3530f49a3990c1ff031d45d12ce6 (patch)
tree66654736b6d47a0501d1b266c08b70be4c70c4e0
parent8a5e7aaecf7ce48dfab805debfc92458ab1112c5 (diff)
downloadlibgit2-febe8c14a0cb3530f49a3990c1ff031d45d12ce6.tar.gz
index: fix confusion with shared prefix in compressed path names
The index version 4 introduced compressed path names for the entries. From the git.git index-format documentation: At the beginning of an entry, an integer N in the variable width encoding [...] is stored, followed by a NUL-terminated string S. Removing N bytes from the end of the path name for the previous entry, and replacing it with the string S yields the path name for this entry. But instead of stripping N bytes from the previous path's string and using the remaining prefix, we were instead simply concatenating the previous path with the current entry path, which is obviously wrong. Fix the issue by correctly copying the first N bytes of the previous entry only and concatenating the result with our current entry's path.
-rw-r--r--src/index.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/src/index.c b/src/index.c
index 932a5306a..f5115a62d 100644
--- a/src/index.c
+++ b/src/index.c
@@ -2355,21 +2355,24 @@ static size_t read_entry(
entry.path = (char *)path_ptr;
} else {
size_t varint_len;
- size_t shared = git_decode_varint((const unsigned char *)path_ptr,
- &varint_len);
- size_t len = strlen(path_ptr + varint_len);
+ size_t strip_len = git_decode_varint((const unsigned char *)path_ptr,
+ &varint_len);
size_t last_len = strlen(*last);
- size_t tmp_path_len;
+ size_t prefix_len = last_len - strip_len;
+ size_t suffix_len = strlen(path_ptr + varint_len);
+ size_t path_len;
if (varint_len == 0)
return index_error_invalid("incorrect prefix length");
- GITERR_CHECK_ALLOC_ADD(&tmp_path_len, shared, len + 1);
- tmp_path = git__malloc(tmp_path_len);
+ GITERR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len);
+ GITERR_CHECK_ALLOC_ADD(&path_len, path_len, 1);
+ tmp_path = git__malloc(path_len);
GITERR_CHECK_ALLOC(tmp_path);
- memcpy(tmp_path, last, last_len);
- memcpy(tmp_path + last_len, path_ptr + varint_len, len);
- entry_size = long_entry_size(shared + len);
+
+ memcpy(tmp_path, last, prefix_len);
+ memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1);
+ entry_size = long_entry_size(prefix_len + suffix_len);
entry.path = tmp_path;
}