void test_object_raw_hash__hash_buffer_in_single_call(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, hello_id)); git_hash_buf(&id2, hello_text, strlen(hello_text)); cl_assert(git_oid_cmp(&id1, &id2) == 0); }
int git_index__parse(git_index *index, const char *buffer, size_t buffer_size) { unsigned int i; struct index_header header; git_oid checksum_calculated, checksum_expected; #define seek_forward(_increase) { \ if (_increase >= buffer_size) \ return GIT_EOBJCORRUPTED; \ buffer += _increase; \ buffer_size -= _increase;\ } if (buffer_size < INDEX_HEADER_SIZE + INDEX_FOOTER_SIZE) return GIT_EOBJCORRUPTED; /* Precalculate the SHA1 of the files's contents -- we'll match it to * the provided SHA1 in the footer */ git_hash_buf(&checksum_calculated, (const void *)buffer, buffer_size - INDEX_FOOTER_SIZE); /* Parse header */ if (read_header(&header, buffer) < 0) return GIT_EOBJCORRUPTED; seek_forward(INDEX_HEADER_SIZE); index->entry_count = header.entry_count; /* If there is already a entires array, reuse it if it can hold all the * entries. If not, free and reallocate */ if (index->entry_count > index->entries_size) { free(index->entries); index->entries_size = (uint32_t)(index->entry_count * 1.3f); index->entries = git__malloc(index->entries_size * sizeof(git_index_entry)); } /* Parse all the entries */ for (i = 0; i < index->entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) { size_t entry_size; entry_size = read_entry(&index->entries[i], buffer, buffer_size); /* 0 bytes read means an object corruption */ if (entry_size == 0) return GIT_EOBJCORRUPTED; seek_forward(entry_size); } if (i != index->entry_count) return GIT_EOBJCORRUPTED; /* There's still space for some extensions! */ while (buffer_size > INDEX_FOOTER_SIZE) { size_t extension_size; extension_size = read_extension(index, buffer, buffer_size); /* see if we have read any bytes from the extension */ if (extension_size == 0) return GIT_EOBJCORRUPTED; seek_forward(extension_size); } if (buffer_size != INDEX_FOOTER_SIZE) return GIT_EOBJCORRUPTED; /* 160-bit SHA-1 over the content of the index file before this checksum. */ git_oid_mkraw(&checksum_expected, (const unsigned char *)buffer); if (git_oid_cmp(&checksum_calculated, &checksum_expected) != 0) return GIT_EOBJCORRUPTED; #undef seek_forward return 0; }
int git_futils_readbuffer_updated( git_buf *out, const char *path, git_oid *checksum, int *updated) { int error; git_file fd; struct stat st; git_buf buf = GIT_BUF_INIT; git_oid checksum_new; assert(out && path && *path); if (updated != NULL) *updated = 0; if (p_stat(path, &st) < 0) return git_path_set_error(errno, path, "stat"); if (S_ISDIR(st.st_mode)) { giterr_set(GITERR_INVALID, "requested file is a directory"); return GIT_ENOTFOUND; } if (!git__is_sizet(st.st_size+1)) { giterr_set(GITERR_OS, "invalid regular file stat for '%s'", path); return -1; } if ((fd = git_futils_open_ro(path)) < 0) return fd; if (git_futils_readbuffer_fd(&buf, fd, (size_t)st.st_size) < 0) { p_close(fd); return -1; } p_close(fd); if (checksum) { if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) { git_buf_free(&buf); return error; } /* * If we were given a checksum, we only want to use it if it's different */ if (!git_oid__cmp(checksum, &checksum_new)) { git_buf_free(&buf); if (updated) *updated = 0; return 0; } git_oid_cpy(checksum, &checksum_new); } /* * If we're here, the file did change, or the user didn't have an old version */ if (updated != NULL) *updated = 1; git_buf_swap(out, &buf); git_buf_free(&buf); return 0; }
void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void) { #define MAX_OIDS 1000 git_oid_shorten *os; char *oids[MAX_OIDS]; char number_buffer[16]; git_oid oid; size_t i, j; int min_len = 0, found_collision; os = git_oid_shorten_new(0); cl_assert(os != NULL); /* * Insert in the shortener 1000 unique SHA1 ids */ for (i = 0; i < MAX_OIDS; ++i) { char *oid_text; sprintf(number_buffer, "%u", (unsigned int)i); git_hash_buf(&oid, number_buffer, strlen(number_buffer)); oid_text = git__malloc(GIT_OID_HEXSZ + 1); git_oid_fmt(oid_text, &oid); oid_text[GIT_OID_HEXSZ] = 0; min_len = git_oid_shorten_add(os, oid_text); cl_assert(min_len >= 0); oids[i] = oid_text; } /* * Compare the first `min_char - 1` characters of each * SHA1 OID. If the minimizer worked, we should find at * least one collision */ found_collision = 0; for (i = 0; i < MAX_OIDS; ++i) { for (j = 0; j < MAX_OIDS; ++j) { if (i != j && memcmp(oids[i], oids[j], min_len - 1) == 0) found_collision = 1; } } cl_assert(found_collision == 1); /* * Compare the first `min_char` characters of each * SHA1 OID. If the minimizer worked, every single preffix * should be unique. */ found_collision = 0; for (i = 0; i < MAX_OIDS; ++i) { for (j = 0; j < MAX_OIDS; ++j) { if (i != j && memcmp(oids[i], oids[j], min_len) == 0) found_collision = 1; } } cl_assert(found_collision == 0); /* cleanup */ for (i = 0; i < MAX_OIDS; ++i) git__free(oids[i]); git_oid_shorten_free(os); #undef MAX_OIDS }
static int parse_index(git_index *index, const char *buffer, size_t buffer_size) { unsigned int i; struct index_header header; git_oid checksum_calculated, checksum_expected; #define seek_forward(_increase) { \ if (_increase >= buffer_size) \ return git__throw(GIT_EOBJCORRUPTED, "Failed to seek forward. Buffer size exceeded"); \ buffer += _increase; \ buffer_size -= _increase;\ } if (buffer_size < INDEX_HEADER_SIZE + INDEX_FOOTER_SIZE) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse index. Buffer too small"); /* Precalculate the SHA1 of the files's contents -- we'll match it to * the provided SHA1 in the footer */ git_hash_buf(&checksum_calculated, buffer, buffer_size - INDEX_FOOTER_SIZE); /* Parse header */ if (read_header(&header, buffer) < GIT_SUCCESS) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse index. Header is corrupted"); seek_forward(INDEX_HEADER_SIZE); git_vector_clear(&index->entries); /* Parse all the entries */ for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) { size_t entry_size; git_index_entry *entry; entry = git__malloc(sizeof(git_index_entry)); if (entry == NULL) return GIT_ENOMEM; entry_size = read_entry(entry, buffer, buffer_size); /* 0 bytes read means an object corruption */ if (entry_size == 0) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse index. Entry size is zero"); if (git_vector_insert(&index->entries, entry) < GIT_SUCCESS) return GIT_ENOMEM; seek_forward(entry_size); } if (i != header.entry_count) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse index. Header entries changed while parsing"); /* There's still space for some extensions! */ while (buffer_size > INDEX_FOOTER_SIZE) { size_t extension_size; extension_size = read_extension(index, buffer, buffer_size); /* see if we have read any bytes from the extension */ if (extension_size == 0) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse index. Extension size is zero"); seek_forward(extension_size); } if (buffer_size != INDEX_FOOTER_SIZE) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse index. Buffer size does not match index footer size"); /* 160-bit SHA-1 over the content of the index file before this checksum. */ git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer); if (git_oid_cmp(&checksum_calculated, &checksum_expected) != 0) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse index. Calculated checksum does not match expected checksum"); #undef seek_forward /* force sorting in the vector: the entries are * assured to be sorted on the index */ index->entries.sorted = 1; return GIT_SUCCESS; }