static int on_body_download_pack(http_parser *parser, const char *str, size_t len) { download_pack_cbdata *data = (download_pack_cbdata *) parser->data; transport_http *t = data->transport; git_indexer_stream *idx = data->idx; git_indexer_stats *stats = data->stats; return t->error = git_indexer_stream_add(idx, str, len, stats); }
int index_pack(git_repository *repo, int argc, char **argv) { git_indexer_stream *idx; git_indexer_stats stats = {0, 0}; int error, fd; char hash[GIT_OID_HEXSZ + 1] = {0}; ssize_t read_bytes; char buf[512]; if (argc < 2) { fprintf(stderr, "I need a packfile\n"); return EXIT_FAILURE; } if (git_indexer_stream_new(&idx, ".git") < 0) { puts("bad idx"); return -1; } if ((fd = open(argv[1], 0)) < 0) { perror("open"); return -1; } do { read_bytes = read(fd, buf, sizeof(buf)); if (read_bytes < 0) break; if ((error = git_indexer_stream_add(idx, buf, read_bytes, &stats)) < 0) goto cleanup; printf("\rIndexing %d of %d", stats.processed, stats.total); } while (read_bytes > 0); if (read_bytes < 0) { error = -1; perror("failed reading"); goto cleanup; } if ((error = git_indexer_stream_finalize(idx, &stats)) < 0) goto cleanup; printf("\rIndexing %d of %d\n", stats.processed, stats.total); git_oid_fmt(hash, git_indexer_stream_hash(idx)); puts(hash); cleanup: close(fd); git_indexer_stream_free(idx); return error; }
/* * As the server is probably using Transfer-Encoding: chunked, we have * to use the HTTP parser to download the pack instead of giving it to * the simple downloader. Furthermore, we're using keep-alive * connections, so the simple downloader would just hang. */ static int http_download_pack(git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats) { transport_http *t = (transport_http *) transport; git_buf *oldbuf = &t->buf; int recvd; http_parser_settings settings; char buffer[1024]; gitno_buffer buf; git_buf path = GIT_BUF_INIT; git_indexer_stream *idx = NULL; download_pack_cbdata data; gitno_buffer_setup(transport, &buf, buffer, sizeof(buffer)); if (memcmp(oldbuf->ptr, "PACK", strlen("PACK"))) { giterr_set(GITERR_NET, "The pack doesn't start with a pack signature"); return -1; } if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0) return -1; if (git_indexer_stream_new(&idx, git_buf_cstr(&path)) < 0) return -1; /* * This is part of the previous response, so we don't want to * re-init the parser, just set these two callbacks. */ memset(stats, 0, sizeof(git_indexer_stats)); data.stats = stats; data.idx = idx; data.transport = t; t->parser.data = &data; t->transfer_finished = 0; memset(&settings, 0x0, sizeof(settings)); settings.on_message_complete = on_message_complete_download_pack; settings.on_body = on_body_download_pack; *bytes = git_buf_len(oldbuf); if (git_indexer_stream_add(idx, git_buf_cstr(oldbuf), git_buf_len(oldbuf), stats) < 0) goto on_error; gitno_buffer_setup(transport, &buf, buffer, sizeof(buffer)); do { size_t parsed; if ((recvd = gitno_recv(&buf)) < 0) goto on_error; parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset); if (parsed != buf.offset || t->error < 0) goto on_error; *bytes += recvd; gitno_consume_n(&buf, parsed); } while (recvd > 0 && !t->transfer_finished); if (git_indexer_stream_finalize(idx, stats) < 0) goto on_error; git_indexer_stream_free(idx); return 0; on_error: git_indexer_stream_free(idx); git_buf_free(&path); return -1; }