git_signature *git_signature_new(const char *name, const char *email, git_time_t time, int offset) { git_signature *p = NULL; if ((p = git__malloc(sizeof(git_signature))) == NULL) goto cleanup; p->name = git__strdup(name); p->email = git__strdup(email); p->when.time = time; p->when.offset = offset; if (p->name == NULL || p->email == NULL) goto cleanup; return p; cleanup: git_signature_free(p); return NULL; }
int git__compress(git_buf *buf, const void *buff, size_t len) { z_stream zs; char *zb; size_t have; memset(&zs, 0, sizeof(zs)); if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) return -1; zb = git__malloc(BUFFER_SIZE); GITERR_CHECK_ALLOC(zb); zs.next_in = (void *)buff; zs.avail_in = (uInt)len; do { zs.next_out = (unsigned char *)zb; zs.avail_out = BUFFER_SIZE; if (deflate(&zs, Z_FINISH) == Z_STREAM_ERROR) { git__free(zb); return -1; } have = BUFFER_SIZE - (size_t)zs.avail_out; if (git_buf_put(buf, zb, have) < 0) { git__free(zb); return -1; } } while (zs.avail_out == 0); assert(zs.avail_in == 0); deflateEnd(&zs); git__free(zb); return 0; }
int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, const char *filename, const git_oid *id, unsigned int attributes) { git_tree_entry *entry; int pos; assert(bld && id && filename); if (!valid_attributes(attributes)) return GIT_ERROR; if ((pos = git_vector_bsearch2(&bld->entries, entry_search_cmp, filename)) != GIT_ENOTFOUND) { entry = git_vector_get(&bld->entries, pos); if (entry->removed) { entry->removed = 0; bld->entry_count++; } } else { if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL) return GIT_ENOMEM; memset(entry, 0x0, sizeof(git_tree_entry)); entry->filename = git__strdup(filename); entry->filename_len = strlen(entry->filename); bld->entry_count++; } git_oid_cpy(&entry->oid, id); entry->attr = attributes; if (pos == GIT_ENOTFOUND) { if (git_vector_insert(&bld->entries, entry) < 0) return GIT_ENOMEM; } if (entry_out != NULL) *entry_out = entry; return GIT_SUCCESS; }
static git_packlist *scan_packs(pack_backend *backend) { char pb[GIT_PATH_MAX]; struct scanned_pack *state = NULL, *c; size_t cnt; git_packlist *new_list; if (git__fmt(pb, sizeof(pb), "%s/pack", backend->objects_dir) < 0) return NULL; gitfo_dirent(pb, sizeof(pb), scan_one_pack, &state); /* TODO - merge old entries into the new array */ for (cnt = 0, c = state; c; c = c->next) cnt++; new_list = git__malloc(sizeof(*new_list) + (sizeof(new_list->packs[0]) * cnt)); if (!new_list) goto fail; for (cnt = 0, c = state; c; ) { struct scanned_pack *n = c->next; c->pack->backend = backend; new_list->packs[cnt++] = c->pack; free(c); c = n; } new_list->n_packs = cnt; new_list->refcnt = 2; backend->packlist = new_list; return new_list; fail: while (state) { struct scanned_pack *n = state->next; pack_dec(state->pack); free(state); state = n; } return NULL; }
static git_revwalk_commit *commit_to_walkcommit(git_revwalk *walk, git_commit *commit_object) { git_revwalk_commit *commit; commit = (git_revwalk_commit *)git_hashtable_lookup(walk->commits, commit_object); if (commit != NULL) return commit; commit = git__malloc(sizeof(git_revwalk_commit)); if (commit == NULL) return NULL; memset(commit, 0x0, sizeof(git_revwalk_commit)); commit->commit_object = commit_object; GIT_OBJECT_INCREF(commit_object); git_hashtable_insert(walk->commits, commit_object, commit); return commit; }
int git_transport_git(git_transport **out) { transport_git *t; #ifdef GIT_WIN32 int ret; #endif t = git__malloc(sizeof(transport_git)); GITERR_CHECK_ALLOC(t); memset(t, 0x0, sizeof(transport_git)); if (git_vector_init(&t->parent.common, 8, NULL)) goto on_error; if (git_vector_init(&t->parent.refs, 16, NULL) < 0) goto on_error; t->parent.connect = git_connect; t->parent.negotiation_step = git_negotiation_step; t->parent.close = git_close; t->parent.free = git_free; *out = (git_transport *) t; #ifdef GIT_WIN32 ret = WSAStartup(MAKEWORD(2,2), &t->wsd); if (ret != 0) { git_free(*out); giterr_set(GITERR_NET, "Winsock init failed"); return -1; } #endif return 0; on_error: git__free(t); return -1; }
int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset) { int error; git_signature *p = NULL; assert(name && email); *sig_out = NULL; if ((p = git__malloc(sizeof(git_signature))) == NULL) { error = GIT_ENOMEM; goto cleanup; } memset(p, 0x0, sizeof(git_signature)); error = process_trimming(name, &p->name, name + strlen(name), 1); if (error < GIT_SUCCESS) { git__rethrow(GIT_EINVALIDARGS, "Failed to create signature. 'name' argument is invalid"); goto cleanup; } error = process_trimming(email, &p->email, email + strlen(email), 1); if (error < GIT_SUCCESS) { git__rethrow(GIT_EINVALIDARGS, "Failed to create signature. 'email' argument is invalid"); goto cleanup; } p->when.time = time; p->when.offset = offset; *sig_out = p; return error; cleanup: git_signature_free(p); return error; }
static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_err *pkt; size_t alloc_len; line++; len--; GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(git_pkt_err), len); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1); pkt = git__malloc(alloc_len); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_ERR; pkt->len = (int)len; memcpy(pkt->error, line, len); pkt->error[len] = '\0'; *out = (git_pkt *)pkt; return 0; }
int remove_loose_object(const char *repository_folder, git_object *object) { static const char *objects_folder = "objects/"; char *ptr, *full_path, *top_folder; int path_length, objects_length; assert(repository_folder && object); objects_length = strlen(objects_folder); path_length = strlen(repository_folder); ptr = full_path = git__malloc(path_length + objects_length + GIT_OID_HEXSZ + 3); strcpy(ptr, repository_folder); strcpy(ptr + path_length, objects_folder); ptr = top_folder = ptr + path_length + objects_length; *ptr++ = '/'; git_oid_pathfmt(ptr, git_object_id(object)); ptr += GIT_OID_HEXSZ + 1; *ptr = 0; if (gitfo_unlink(full_path) < 0) { fprintf(stderr, "can't delete object file \"%s\"\n", full_path); return -1; } *top_folder = 0; if ((gitfo_rmdir(full_path) < 0) && (errno != ENOTEMPTY)) { fprintf(stderr, "can't remove object directory \"%s\"\n", full_path); return -1; } free(full_path); return GIT_SUCCESS; }
static void assert_mergebase_many(const char *expected_sha, int count, ...) { va_list ap; int i; git_oid *oids; git_oid oid, expected; char *partial_oid; git_object *object; oids = git__malloc(count * sizeof(git_oid)); cl_assert(oids != NULL); memset(oids, 0x0, count * sizeof(git_oid)); va_start(ap, count); for (i = 0; i < count; ++i) { partial_oid = va_arg(ap, char *); cl_git_pass(git_oid_fromstrn(&oid, partial_oid, strlen(partial_oid))); cl_git_pass(git_object_lookup_prefix(&object, _repo, &oid, strlen(partial_oid), GIT_OBJ_COMMIT)); git_oid_cpy(&oids[i], git_object_id(object)); git_object_free(object); } va_end(ap); if (expected_sha == NULL) cl_assert_equal_i(GIT_ENOTFOUND, git_merge_base_many(&oid, _repo, count, oids)); else { cl_git_pass(git_merge_base_many(&oid, _repo, count, oids)); cl_git_pass(git_oid_fromstr(&expected, expected_sha)); cl_assert(git_oid_cmp(&expected, &oid) == 0); } git__free(oids); }
int git_commit_list_push_front(git_commit_list *list, git_commit *commit) { git_commit_node *node = NULL; node = git__malloc(sizeof(git_commit_list)); if (node == NULL) return GIT_ENOMEM; node->commit = commit; node->next = list->head; node->prev = NULL; if (list->head == NULL) { list->head = list->tail = node; } else { list->head->prev = node; list->head = node; } list->size++; return 0; }
static int err_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_err *pkt; size_t alloclen; /* Remove "ERR " from the line */ line += 4; len -= 4; GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); pkt = git__malloc(alloclen); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_ERR; pkt->len = (int)len; memcpy(pkt->error, line, len); pkt->error[len] = '\0'; *out = (git_pkt *) pkt; return 0; }
static int note_new( git_note **out, git_oid *note_oid, git_commit *commit, git_blob *blob) { git_note *note = NULL; note = (git_note *)git__malloc(sizeof(git_note)); GITERR_CHECK_ALLOC(note); git_oid_cpy(¬e->id, note_oid); if (git_signature_dup(¬e->author, git_commit_author(commit)) < 0 || git_signature_dup(¬e->committer, git_commit_committer(commit)) < 0) return -1; note->message = git__strndup(git_blob_rawcontent(blob), git_blob_rawsize(blob)); GITERR_CHECK_ALLOC(note->message); *out = note; return 0; }
int gitfo_read_file(gitfo_buf *obj, const char *path) { git_file fd; size_t len; git_off_t size; unsigned char *buff; assert(obj && path && *path); if ((fd = gitfo_open(path, O_RDONLY)) < 0) return GIT_ERROR; if (((size = gitfo_size(fd)) < 0) || !git__is_sizet(size+1)) { gitfo_close(fd); return GIT_ERROR; } len = (size_t) size; if ((buff = git__malloc(len + 1)) == NULL) { gitfo_close(fd); return GIT_ERROR; } if (gitfo_read(fd, buff, len) < 0) { gitfo_close(fd); free(buff); return GIT_ERROR; } buff[len] = '\0'; gitfo_close(fd); obj->data = buff; obj->len = len; return GIT_SUCCESS; }
int git_cred_ssh_custom_new( git_cred **cred, const char *username, const char *publickey, size_t publickey_len, git_cred_sign_callback sign_callback, void *sign_data) { git_cred_ssh_custom *c; assert(cred); c = git__calloc(1, sizeof(git_cred_ssh_custom)); GITERR_CHECK_ALLOC(c); c->parent.credtype = GIT_CREDTYPE_SSH_CUSTOM; c->parent.free = ssh_custom_free; if (username) { c->username = git__strdup(username); GITERR_CHECK_ALLOC(c->username); } if (publickey_len > 0) { c->publickey = git__malloc(publickey_len); GITERR_CHECK_ALLOC(c->publickey); memcpy(c->publickey, publickey, publickey_len); } c->publickey_len = publickey_len; c->sign_callback = sign_callback; c->sign_data = sign_data; *cred = &c->parent; return 0; }
/** * Converts a wide string to UTF-8. * Memory is allocated to hold the converted string. * The caller is responsible for freeing the string with git__free. * * @param dest Receives a pointer to the UTF-8 string. * @param src The wide string to convert. * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure */ int git__utf16_to_8_alloc(char **dest, const wchar_t *src) { int utf8_size; DWORD dwFlags = get_wc_flags(); *dest = NULL; /* Length of -1 indicates NULL termination of the input string */ utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, src, -1, NULL, 0, NULL, NULL); if (!utf8_size) { git__set_errno(); return -1; } *dest = git__malloc(utf8_size); if (!*dest) { errno = ENOMEM; return -1; } utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, src, -1, *dest, utf8_size, NULL, NULL); if (!utf8_size) { git__set_errno(); git__free(*dest); *dest = NULL; } /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL * terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue, * so underflow is not possible */ return utf8_size - 1; }
wchar_t* gitwin_to_utf16(const char* str) { wchar_t* ret; int cb; if (!str) return NULL; cb = MultiByteToWideChar(_active_codepage, 0, str, -1, NULL, 0); if (cb == 0) return (wchar_t *)git__calloc(1, sizeof(wchar_t)); ret = (wchar_t *)git__malloc(cb * sizeof(wchar_t)); if (!ret) return NULL; if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, (int)cb) == 0) { giterr_set(GITERR_OS, "Could not convert string to UTF-16"); git__free(ret); ret = NULL; } return ret; }
int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) { git_revwalk *walk; walk = git__malloc(sizeof(git_revwalk)); if (walk == NULL) return GIT_ENOMEM; memset(walk, 0x0, sizeof(git_revwalk)); walk->commits = git_hashtable_alloc(64, git_revwalk__commit_hash, git_revwalk__commit_keycmp); if (walk->commits == NULL) { free(walk); return GIT_ENOMEM; } walk->repo = repo; *revwalk_out = walk; return GIT_SUCCESS; }
char *cl_getenv(const char *name) { wchar_t name_utf16[GIT_WIN_PATH]; DWORD alloc_len; wchar_t *value_utf16; char *value_utf8; git__utf8_to_16(name_utf16, GIT_WIN_PATH, name); alloc_len = GetEnvironmentVariableW(name_utf16, NULL, 0); if (alloc_len <= 0) return NULL; alloc_len = GIT_WIN_PATH; cl_assert(value_utf16 = git__calloc(alloc_len, sizeof(wchar_t))); GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len); cl_assert(value_utf8 = git__malloc(alloc_len)); git__utf16_to_8(value_utf8, value_utf16); git__free(value_utf16); return value_utf8; }
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; }
static git_index_tree *read_tree_internal( const char **buffer_in, const char *buffer_end, git_index_tree *parent) { git_index_tree *tree; const char *name_start, *buffer; if ((tree = git__malloc(sizeof(git_index_tree))) == NULL) return NULL; memset(tree, 0x0, sizeof(git_index_tree)); tree->parent = parent; buffer = name_start = *buffer_in; if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL) goto error_cleanup; /* NUL-terminated tree name */ tree->name = git__strdup(name_start); if (++buffer >= buffer_end) goto error_cleanup; /* Blank-terminated ASCII decimal number of entries in this tree */ tree->entries = strtol(buffer, (char **)&buffer, 10); if (*buffer != ' ' || ++buffer >= buffer_end) goto error_cleanup; /* Number of children of the tree, newline-terminated */ tree->children_count = strtol(buffer, (char **)&buffer, 10); if (*buffer != '\n' || ++buffer >= buffer_end) goto error_cleanup; /* 160-bit SHA-1 for this tree and it's children */ if (buffer + GIT_OID_RAWSZ > buffer_end) goto error_cleanup; git_oid_mkraw(&tree->oid, (const unsigned char *)buffer); buffer += GIT_OID_RAWSZ; /* Parse children: */ if (tree->children_count > 0) { unsigned int i; tree->children = git__malloc(tree->children_count * sizeof(git_index_tree *)); if (tree->children == NULL) goto error_cleanup; for (i = 0; i < tree->children_count; ++i) { tree->children[i] = read_tree_internal(&buffer, buffer_end, tree); if (tree->children[i] == NULL) goto error_cleanup; } } *buffer_in = buffer; return tree; error_cleanup: git_index_tree__free(tree); return NULL; }
int git_index_insert(git_index *index, const git_index_entry *source_entry) { git_index_entry *offset; size_t path_length; int position; assert(index && source_entry); if (source_entry->path == NULL) return GIT_EMISSINGOBJDATA; position = git_index_find(index, source_entry->path); if (position == GIT_ENOTFOUND) { /* Resize the entries array */ if (index->entry_count + 1 > index->entries_size) { git_index_entry *new_entries; size_t new_size; new_size = (unsigned int)(index->entries_size * 1.5f); if (new_size < 8) new_size = 8; if ((new_entries = git__malloc(new_size * sizeof(git_index_entry))) == NULL) return GIT_ENOMEM; memcpy(new_entries, index->entries, index->entry_count * sizeof(git_index_entry)); free(index->entries); index->entries_size = new_size; index->entries = new_entries; } offset = &index->entries[index->entry_count]; index->entry_count++; index->sorted = 0; } else { offset = &index->entries[position]; free(offset->path); } memcpy(offset, source_entry, sizeof(git_index_entry)); /* duplicate the path string so we own it */ offset->path = git__strdup(offset->path); if (offset->path == NULL) return GIT_ENOMEM; /* make sure that the path length flag is correct */ path_length = strlen(offset->path); offset->flags &= ~GIT_IDXENTRY_NAMEMASK; if (path_length < GIT_IDXENTRY_NAMEMASK) offset->flags |= path_length & GIT_IDXENTRY_NAMEMASK; else offset->flags |= GIT_IDXENTRY_NAMEMASK;; /* TODO: force the extended index entry flag? */ assert(offset->path); return GIT_SUCCESS; }
int p_readlink(const char *link, char *target, size_t target_len) { typedef DWORD (WINAPI *fpath_func)(HANDLE, LPWSTR, DWORD, DWORD); static fpath_func pGetFinalPath = NULL; HANDLE hFile; DWORD dwRet; wchar_t link_w[GIT_WIN_PATH]; wchar_t* target_w; int error = 0; assert(link && target && target_len > 0); /* * Try to load the pointer to pGetFinalPath dynamically, because * it is not available in platforms older than Vista */ if (pGetFinalPath == NULL) { HMODULE module = GetModuleHandle("kernel32"); if (module != NULL) pGetFinalPath = (fpath_func)GetProcAddress(module, "GetFinalPathNameByHandleW"); if (pGetFinalPath == NULL) { giterr_set(GITERR_OS, "'GetFinalPathNameByHandleW' is not available in this platform"); return -1; } } git__utf8_to_16(link_w, GIT_WIN_PATH, link); hFile = CreateFileW(link_w, // file to open GENERIC_READ, // open for reading FILE_SHARE_READ, // share for reading NULL, // default security OPEN_EXISTING, // existing file only FILE_FLAG_BACKUP_SEMANTICS, // normal file NULL); // no attr. template if (hFile == INVALID_HANDLE_VALUE) { giterr_set(GITERR_OS, "Cannot open '%s' for reading", link); return -1; } target_w = (wchar_t*)git__malloc(target_len * sizeof(wchar_t)); GITERR_CHECK_ALLOC(target_w); dwRet = pGetFinalPath(hFile, target_w, (DWORD)target_len, 0x0); if (dwRet == 0 || dwRet >= target_len || !WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target, (int)(target_len * sizeof(char)), NULL, NULL)) error = -1; git__free(target_w); CloseHandle(hFile); if (error) return error; /* Skip first 4 characters if they are "\\?\" */ if (dwRet > 4 && target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') { unsigned int offset = 4; dwRet -= 4; /* \??\UNC\ */ if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') { offset += 2; dwRet -= 2; target[offset] = '\\'; } memmove(target, target + offset, dwRet); } target[dwRet] = '\0'; return dwRet; }
int git_commit__parse_raw(void *_commit, const char *data, size_t size) { git_commit *commit = _commit; const char *buffer_start = data, *buffer; const char *buffer_end = buffer_start + size; git_oid parent_id; size_t header_len; git_signature dummy_sig; buffer = buffer_start; /* Allocate for one, which will allow not to realloc 90% of the time */ git_array_init_to_size(commit->parent_ids, 1); GITERR_CHECK_ARRAY(commit->parent_ids); /* The tree is always the first field */ if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0) goto bad_buffer; /* * TODO: commit grafts! */ while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { git_oid *new_id = git_array_alloc(commit->parent_ids); GITERR_CHECK_ALLOC(new_id); git_oid_cpy(new_id, &parent_id); } commit->author = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->author); if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0) return -1; /* Some tools create multiple author fields, ignore the extra ones */ while (!git__prefixncmp(buffer, buffer_end - buffer, "author ")) { if (git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n') < 0) return -1; git__free(dummy_sig.name); git__free(dummy_sig.email); } /* Always parse the committer; we need the commit time */ commit->committer = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->committer); if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0) return -1; /* Parse add'l header entries */ while (buffer < buffer_end) { const char *eoln = buffer; if (buffer[-1] == '\n' && buffer[0] == '\n') break; while (eoln < buffer_end && *eoln != '\n') ++eoln; if (git__prefixncmp(buffer, buffer_end - buffer, "encoding ") == 0) { buffer += strlen("encoding "); commit->message_encoding = git__strndup(buffer, eoln - buffer); GITERR_CHECK_ALLOC(commit->message_encoding); } if (eoln < buffer_end && *eoln == '\n') ++eoln; buffer = eoln; } header_len = buffer - buffer_start; commit->raw_header = git__strndup(buffer_start, header_len); GITERR_CHECK_ALLOC(commit->raw_header); /* point "buffer" to data after header, +1 for the final LF */ buffer = buffer_start + header_len + 1; /* extract commit message */ if (buffer <= buffer_end) commit->raw_message = git__strndup(buffer, buffer_end - buffer); else commit->raw_message = git__strdup(""); GITERR_CHECK_ALLOC(commit->raw_message); return 0; bad_buffer: giterr_set(GITERR_OBJECT, "failed to parse bad commit object"); return -1; }
static int http_stream_write_chunked( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { http_stream *s = (http_stream *)stream; http_subtransport *t = OWNING_SUBTRANSPORT(s); assert(t->connected); /* Send the request, if necessary */ if (!s->sent_request) { git_buf request = GIT_BUF_INIT; clear_parser_state(t); if (gen_request(&request, s, 0) < 0) { giterr_set(GITERR_NET, "Failed to generate request"); return -1; } if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) { git_buf_free(&request); return -1; } git_buf_free(&request); s->sent_request = 1; } if (len > CHUNK_SIZE) { /* Flush, if necessary */ if (s->chunk_buffer_len > 0) { if (write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; } /* Write chunk directly */ if (write_chunk(&t->socket, buffer, len) < 0) return -1; } else { /* Append as much to the buffer as we can */ int count = min(CHUNK_SIZE - s->chunk_buffer_len, len); if (!s->chunk_buffer) s->chunk_buffer = git__malloc(CHUNK_SIZE); memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count); s->chunk_buffer_len += count; buffer += count; len -= count; /* Is the buffer full? If so, then flush */ if (CHUNK_SIZE == s->chunk_buffer_len) { if (write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; if (len > 0) { memcpy(s->chunk_buffer, buffer, len); s->chunk_buffer_len = len; } } } return 0; }
int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header) { const size_t header_len = strlen(header); int name_length, email_length; const char *buffer = *buffer_out; const char *line_end, *name_end, *email_end; long offset = 0, time; memset(sig, 0x0, sizeof(git_signature)); line_end = memchr(buffer, '\n', buffer_end - buffer); if (!line_end) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. No newline found");; if (buffer + (header_len + 1) > line_end) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Signature too short"); if (memcmp(buffer, header, header_len) != 0) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Expected prefix '%s' doesn't match actual", header); buffer += header_len; /* Parse name */ if ((name_end = strstr(buffer, " <")) == NULL) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail start"); name_length = name_end - buffer; if (name_length <= 0) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Missing tagger name"); sig->name = git__malloc(name_length + 1); if (sig->name == NULL) return GIT_ENOMEM; memcpy(sig->name, buffer, name_length); sig->name[name_length] = 0; buffer = name_end + 2; if (buffer >= line_end) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly"); /* Parse email */ if ((email_end = strstr(buffer, "> ")) == NULL) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail end"); email_length = email_end - buffer; sig->email = git__malloc(email_length + 1); if (sig->name == NULL) return GIT_ENOMEM; memcpy(sig->email, buffer, email_length); sig->email[email_length] = 0; buffer = email_end + 2; if (buffer >= line_end) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly"); /* verify email */ if (strpbrk(sig->email, "><\n ") != NULL) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Malformed e-mail"); if (git__strtol32(&time, buffer, &buffer, 10) < GIT_SUCCESS) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Timestamp isn't a number"); sig->when.time = (time_t)time; if (parse_timezone_offset(buffer, &offset) < GIT_SUCCESS) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Could not parse timezone offset"); sig->when.offset = offset; *buffer_out = (line_end + 1); return GIT_SUCCESS; }
static int winhttp_stream_read( git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read) { winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); DWORD dw_bytes_read; char replay_count = 0; int error; replay: /* Enforce a reasonable cap on the number of replays */ if (++replay_count >= 7) { giterr_set(GITERR_NET, "Too many redirects or authentication replays"); return -1; } /* Connect if necessary */ if (!s->request && winhttp_stream_connect(s) < 0) return -1; if (!s->received_response) { DWORD status_code, status_code_length, content_type_length, bytes_written; char expected_content_type_8[MAX_CONTENT_TYPE_LEN]; wchar_t expected_content_type[MAX_CONTENT_TYPE_LEN], content_type[MAX_CONTENT_TYPE_LEN]; if (!s->sent_request) { if ((error = send_request(s, s->post_body_len, 0)) < 0) return error; s->sent_request = 1; } if (s->chunked) { assert(s->verb == post_verb); /* Flush, if necessary */ if (s->chunk_buffer_len > 0 && write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; /* Write the final chunk. */ if (!WinHttpWriteData(s->request, "0\r\n\r\n", 5, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write final chunk"); return -1; } } else if (s->post_body) { char *buffer; DWORD len = s->post_body_len, bytes_read; if (INVALID_SET_FILE_POINTER == SetFilePointer(s->post_body, 0, 0, FILE_BEGIN) && NO_ERROR != GetLastError()) { giterr_set(GITERR_OS, "Failed to reset file pointer"); return -1; } buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE); while (len > 0) { DWORD bytes_written; if (!ReadFile(s->post_body, buffer, min(CACHED_POST_BODY_BUF_SIZE, len), &bytes_read, NULL) || !bytes_read) { git__free(buffer); giterr_set(GITERR_OS, "Failed to read from temp file"); return -1; } if (!WinHttpWriteData(s->request, buffer, bytes_read, &bytes_written)) { git__free(buffer); giterr_set(GITERR_OS, "Failed to write data"); return -1; } len -= bytes_read; assert(bytes_read == bytes_written); } git__free(buffer); /* Eagerly close the temp file */ CloseHandle(s->post_body); s->post_body = NULL; } if (!WinHttpReceiveResponse(s->request, 0)) { giterr_set(GITERR_OS, "Failed to receive response"); return -1; } /* Verify that we got a 200 back */ status_code_length = sizeof(status_code); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &status_code_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to retrieve status code"); return -1; } /* The implementation of WinHTTP prior to Windows 7 will not * redirect to an identical URI. Some Git hosters use self-redirects * as part of their DoS mitigation strategy. Check first to see if we * have a redirect status code, and that we haven't already streamed * a post body. (We can't replay a streamed POST.) */ if (!s->chunked && (HTTP_STATUS_MOVED == status_code || HTTP_STATUS_REDIRECT == status_code || (HTTP_STATUS_REDIRECT_METHOD == status_code && get_verb == s->verb) || HTTP_STATUS_REDIRECT_KEEP_VERB == status_code)) { /* Check for Windows 7. This workaround is only necessary on * Windows Vista and earlier. Windows 7 is version 6.1. */ wchar_t *location; DWORD location_length; char *location8; /* OK, fetch the Location header from the redirect. */ if (WinHttpQueryHeaders(s->request, WINHTTP_QUERY_LOCATION, WINHTTP_HEADER_NAME_BY_INDEX, WINHTTP_NO_OUTPUT_BUFFER, &location_length, WINHTTP_NO_HEADER_INDEX) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { giterr_set(GITERR_OS, "Failed to read Location header"); return -1; } location = git__malloc(location_length); GITERR_CHECK_ALLOC(location); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_LOCATION, WINHTTP_HEADER_NAME_BY_INDEX, location, &location_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to read Location header"); git__free(location); return -1; } /* Convert the Location header to UTF-8 */ if (git__utf16_to_8_alloc(&location8, location) < 0) { giterr_set(GITERR_OS, "Failed to convert Location header to UTF-8"); git__free(location); return -1; } git__free(location); /* Replay the request */ winhttp_stream_close(s); if (!git__prefixcmp_icase(location8, prefix_https)) { /* Upgrade to secure connection; disconnect and start over */ if (gitno_connection_data_from_url(&t->connection_data, location8, s->service_url) < 0) { git__free(location8); return -1; } winhttp_close_connection(t); if (winhttp_connect(t) < 0) return -1; } git__free(location8); goto replay; } /* Handle authentication failures */ if (HTTP_STATUS_DENIED == status_code && get_verb == s->verb) { int allowed_types; if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0) return -1; if (allowed_types && (!t->cred || 0 == (t->cred->credtype & allowed_types))) { int cred_error = 1; /* Start with the user-supplied credential callback, if present */ if (t->owner->cred_acquire_cb) { cred_error = t->owner->cred_acquire_cb(&t->cred, t->owner->url, t->connection_data.user, allowed_types, t->owner->cred_acquire_payload); if (cred_error < 0) return cred_error; } /* Invoke the fallback credentials acquisition callback if necessary */ if (cred_error > 0) { cred_error = fallback_cred_acquire_cb(&t->cred, t->owner->url, t->connection_data.user, allowed_types, NULL); if (cred_error < 0) return cred_error; } if (!cred_error) { assert(t->cred); winhttp_stream_close(s); /* Successfully acquired a credential */ goto replay; } } } if (HTTP_STATUS_OK != status_code) { giterr_set(GITERR_NET, "Request failed with status code: %d", status_code); return -1; } /* Verify that we got the correct content-type back */ if (post_verb == s->verb) p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-result", s->service); else p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service); if (git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) { giterr_set(GITERR_OS, "Failed to convert expected content-type to wide characters"); return -1; } content_type_length = sizeof(content_type); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_CONTENT_TYPE, WINHTTP_HEADER_NAME_BY_INDEX, &content_type, &content_type_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to retrieve response content-type"); return -1; } if (wcscmp(expected_content_type, content_type)) { giterr_set(GITERR_NET, "Received unexpected content-type"); return -1; } s->received_response = 1; } if (!WinHttpReadData(s->request, (LPVOID)buffer, (DWORD)buf_size, &dw_bytes_read)) { giterr_set(GITERR_OS, "Failed to read data"); return -1; } *bytes_read = dw_bytes_read; return 0; }
static int winhttp_stream_write_chunked( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { winhttp_stream *s = (winhttp_stream *)stream; int error; if (!s->request && winhttp_stream_connect(s) < 0) return -1; if (!s->sent_request) { /* Send Transfer-Encoding: chunked header */ if (!WinHttpAddRequestHeaders(s->request, transfer_encoding, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { giterr_set(GITERR_OS, "Failed to add a header to the request"); return -1; } if ((error = send_request(s, 0, 1)) < 0) return error; s->sent_request = 1; } if (len > CACHED_POST_BODY_BUF_SIZE) { /* Flush, if necessary */ if (s->chunk_buffer_len > 0) { if (write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; } /* Write chunk directly */ if (write_chunk(s->request, buffer, len) < 0) return -1; } else { /* Append as much to the buffer as we can */ int count = (int)min(CACHED_POST_BODY_BUF_SIZE - s->chunk_buffer_len, len); if (!s->chunk_buffer) s->chunk_buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE); memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count); s->chunk_buffer_len += count; buffer += count; len -= count; /* Is the buffer full? If so, then flush */ if (CACHED_POST_BODY_BUF_SIZE == s->chunk_buffer_len) { if (write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; /* Is there any remaining data from the source? */ if (len > 0) { memcpy(s->chunk_buffer, buffer, len); s->chunk_buffer_len = (unsigned int)len; } } } return 0; }
int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) { char *buffer = (char *)data; const char *buffer_end = (char *)data + len; git_oid oid; int error; /* first parse; the vector hasn't been initialized yet */ if (commit->parents.contents == NULL) { git_vector_init(&commit->parents, 4, NULL, NULL); } clear_parents(commit); if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) return error; if ((error = git_repository_lookup((git_object **)&commit->tree, commit->object.repo, &oid, GIT_OBJ_TREE)) < GIT_SUCCESS) return error; /* * TODO: commit grafts! */ while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { git_commit *parent; if ((error = git_repository_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS) return error; if (git_vector_insert(&commit->parents, parent) < GIT_SUCCESS) return GIT_ENOMEM; } if (parse_flags & COMMIT_FULL_PARSE) { if (commit->author) git_signature_free(commit->author); commit->author = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS) return error; } else { if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) return GIT_EOBJCORRUPTED; buffer++; } /* Always parse the committer; we need the commit time */ if (commit->committer) git_signature_free(commit->committer); commit->committer = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS) return error; /* parse commit message */ while (buffer <= buffer_end && *buffer == '\n') buffer++; if (parse_flags & COMMIT_FULL_PARSE && buffer < buffer_end) { const char *line_end; size_t message_len = buffer_end - buffer; /* Long message */ message_len = buffer_end - buffer; commit->message = git__malloc(message_len + 1); memcpy(commit->message, buffer, message_len); commit->message[message_len] = 0; /* Short message */ if((line_end = memchr(buffer, '\n', buffer_end - buffer)) == NULL) line_end = buffer_end; message_len = line_end - buffer; commit->message_short = git__malloc(message_len + 1); memcpy(commit->message_short, buffer, message_len); commit->message_short[message_len] = 0; } return GIT_SUCCESS; }
static int crlf_check( git_filter *self, void **payload, /* points to NULL ptr on entry, may be set */ const git_filter_source *src, const char **attr_values) { int error; struct crlf_attrs ca; GIT_UNUSED(self); if (!attr_values) { ca.crlf_action = GIT_CRLF_GUESS; ca.eol = GIT_EOL_UNSET; } else { ca.crlf_action = check_crlf(attr_values[2]); /* text */ if (ca.crlf_action == GIT_CRLF_GUESS) ca.crlf_action = check_crlf(attr_values[0]); /* clrf */ ca.eol = check_eol(attr_values[1]); /* eol */ } ca.auto_crlf = GIT_AUTO_CRLF_DEFAULT; /* * Use the core Git logic to see if we should perform CRLF for this file * based on its attributes & the value of `core.autocrlf` */ ca.crlf_action = crlf_input_action(&ca); if (ca.crlf_action == GIT_CRLF_BINARY) return GIT_PASSTHROUGH; if (ca.crlf_action == GIT_CRLF_GUESS || (ca.crlf_action == GIT_CRLF_AUTO && git_filter_source_mode(src) == GIT_FILTER_SMUDGE)) { error = git_repository__cvar( &ca.auto_crlf, git_filter_source_repo(src), GIT_CVAR_AUTO_CRLF); if (error < 0) return error; if (ca.auto_crlf == GIT_AUTO_CRLF_FALSE) return GIT_PASSTHROUGH; if (ca.auto_crlf == GIT_AUTO_CRLF_INPUT && git_filter_source_mode(src) == GIT_FILTER_SMUDGE) return GIT_PASSTHROUGH; } if (git_filter_source_mode(src) == GIT_FILTER_CLEAN) { error = git_repository__cvar( &ca.safe_crlf, git_filter_source_repo(src), GIT_CVAR_SAFE_CRLF); if (error < 0) return error; /* downgrade FAIL to WARN if ALLOW_UNSAFE option is used */ if ((git_filter_source_options(src) & GIT_FILTER_OPT_ALLOW_UNSAFE) && ca.safe_crlf == GIT_SAFE_CRLF_FAIL) ca.safe_crlf = GIT_SAFE_CRLF_WARN; } *payload = git__malloc(sizeof(ca)); GITERR_CHECK_ALLOC(*payload); memcpy(*payload, &ca, sizeof(ca)); return 0; }