1#include"cache.h" 2#include"object-store.h" 3#include"run-command.h" 4#include"sigchain.h" 5#include"connected.h" 6#include"transport.h" 7#include"packfile.h" 8 9/* 10 * If we feed all the commits we want to verify to this command 11 * 12 * $ git rev-list --objects --stdin --not --all 13 * 14 * and if it does not error out, that means everything reachable from 15 * these commits locally exists and is connected to our existing refs. 16 * Note that this does _not_ validate the individual objects. 17 * 18 * Returns 0 if everything is connected, non-zero otherwise. 19 */ 20intcheck_connected(oid_iterate_fn fn,void*cb_data, 21struct check_connected_options *opt) 22{ 23struct child_process rev_list = CHILD_PROCESS_INIT; 24struct check_connected_options defaults = CHECK_CONNECTED_INIT; 25char commit[GIT_MAX_HEXSZ +1]; 26struct object_id oid; 27int err =0; 28struct packed_git *new_pack = NULL; 29struct transport *transport; 30size_t base_len; 31 32if(!opt) 33 opt = &defaults; 34 transport = opt->transport; 35 36if(fn(cb_data, &oid)) { 37if(opt->err_fd) 38close(opt->err_fd); 39return err; 40} 41 42if(transport && transport->smart_options && 43 transport->smart_options->self_contained_and_connected && 44 transport->pack_lockfile && 45strip_suffix(transport->pack_lockfile,".keep", &base_len)) { 46struct strbuf idx_file = STRBUF_INIT; 47strbuf_add(&idx_file, transport->pack_lockfile, base_len); 48strbuf_addstr(&idx_file,".idx"); 49 new_pack =add_packed_git(idx_file.buf, idx_file.len,1); 50strbuf_release(&idx_file); 51} 52 53if(opt->check_refs_only) { 54/* 55 * For partial clones, we don't want to have to do a regular 56 * connectivity check because we have to enumerate and exclude 57 * all promisor objects (slow), and then the connectivity check 58 * itself becomes a no-op because in a partial clone every 59 * object is a promisor object. Instead, just make sure we 60 * received the objects pointed to by each wanted ref. 61 */ 62do{ 63if(!repo_has_object_file(the_repository, &oid)) 64return1; 65}while(!fn(cb_data, &oid)); 66return0; 67} 68 69if(opt->shallow_file) { 70argv_array_push(&rev_list.args,"--shallow-file"); 71argv_array_push(&rev_list.args, opt->shallow_file); 72} 73argv_array_push(&rev_list.args,"rev-list"); 74argv_array_push(&rev_list.args,"--objects"); 75argv_array_push(&rev_list.args,"--stdin"); 76if(repository_format_partial_clone) 77argv_array_push(&rev_list.args,"--exclude-promisor-objects"); 78if(!opt->is_deepening_fetch) { 79argv_array_push(&rev_list.args,"--not"); 80argv_array_push(&rev_list.args,"--all"); 81} 82argv_array_push(&rev_list.args,"--quiet"); 83argv_array_push(&rev_list.args,"--alternate-refs"); 84if(opt->progress) 85argv_array_pushf(&rev_list.args,"--progress=%s", 86_("Checking connectivity")); 87 88 rev_list.git_cmd =1; 89 rev_list.env = opt->env; 90 rev_list.in = -1; 91 rev_list.no_stdout =1; 92if(opt->err_fd) 93 rev_list.err = opt->err_fd; 94else 95 rev_list.no_stderr = opt->quiet; 96 97if(start_command(&rev_list)) 98returnerror(_("Could not run 'git rev-list'")); 99 100sigchain_push(SIGPIPE, SIG_IGN); 101 102 commit[GIT_SHA1_HEXSZ] ='\n'; 103do{ 104/* 105 * If index-pack already checked that: 106 * - there are no dangling pointers in the new pack 107 * - the pack is self contained 108 * Then if the updated ref is in the new pack, then we 109 * are sure the ref is good and not sending it to 110 * rev-list for verification. 111 */ 112if(new_pack &&find_pack_entry_one(oid.hash, new_pack)) 113continue; 114 115memcpy(commit,oid_to_hex(&oid), GIT_SHA1_HEXSZ); 116if(write_in_full(rev_list.in, commit, GIT_SHA1_HEXSZ +1) <0) { 117if(errno != EPIPE && errno != EINVAL) 118error_errno(_("failed write to rev-list")); 119 err = -1; 120break; 121} 122}while(!fn(cb_data, &oid)); 123 124if(close(rev_list.in)) 125 err =error_errno(_("failed to close rev-list's stdin")); 126 127sigchain_pop(SIGPIPE); 128returnfinish_command(&rev_list) || err; 129}