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