static int verify_one_pack(char *arg, int verbose) { int len = strlen(arg); struct packed_git *g; while (1) { /* Should name foo.idx, but foo.pack may be named; * convert it to foo.idx */ if (!strcmp(arg + len - 5, ".pack")) { strcpy(arg + len - 5, ".idx"); len--; } /* Should name foo.idx now */ if ((g = add_packed_git(arg, len, 1))) break; /* No? did you name just foo? */ strcpy(arg + len, ".idx"); len += 4; if ((g = add_packed_git(arg, len, 1))) break; return error("packfile %s not found.", arg); } return verify_pack(g, verbose); }
static int verify_one_pack(const char *path, unsigned int flags) { char arg[PATH_MAX]; int len; int verbose = flags & VERIFY_PACK_VERBOSE; int stat_only = flags & VERIFY_PACK_STAT_ONLY; struct packed_git *pack; int err; len = strlcpy(arg, path, PATH_MAX); if (len >= PATH_MAX) return error("name too long: %s", path); /* * In addition to "foo.idx" we accept "foo.pack" and "foo"; * normalize these forms to "foo.idx" for add_packed_git(). */ if (has_extension(arg, ".pack")) { strcpy(arg + len - 5, ".idx"); len--; } else if (!has_extension(arg, ".idx")) { if (len + 4 >= PATH_MAX) return error("name too long: %s.idx", arg); strcpy(arg + len, ".idx"); len += 4; } /* * add_packed_git() uses our buffer (containing "foo.idx") to * build the pack filename ("foo.pack"). Make sure it fits. */ if (len + 1 >= PATH_MAX) { arg[len - 4] = '\0'; return error("name too long: %s.pack", arg); } pack = add_packed_git(arg, len, 1); if (!pack) return error("packfile %s not found.", arg); install_packed_git(pack); if (!stat_only) err = verify_pack(pack); else err = open_pack_index(pack); if (verbose || stat_only) { if (err) printf("%s: bad\n", pack->pack_name); else { show_pack_info(pack, flags); if (!stat_only) printf("%s: ok\n", pack->pack_name); } } return err; }
/* * If we feed all the commits we want to verify to this command * * $ git rev-list --objects --stdin --not --all * * and if it does not error out, that means everything reachable from * these commits locally exists and is connected to our existing refs. * Note that this does _not_ validate the individual objects. * * Returns 0 if everything is connected, non-zero otherwise. */ int check_connected(sha1_iterate_fn fn, void *cb_data, struct check_connected_options *opt) { struct child_process rev_list = CHILD_PROCESS_INIT; struct check_connected_options defaults = CHECK_CONNECTED_INIT; char commit[41]; unsigned char sha1[20]; int err = 0; struct packed_git *new_pack = NULL; struct transport *transport; size_t base_len; if (!opt) opt = &defaults; transport = opt->transport; if (fn(cb_data, sha1)) { if (opt->err_fd) close(opt->err_fd); return err; } if (transport && transport->smart_options && transport->smart_options->self_contained_and_connected && transport->pack_lockfile && strip_suffix(transport->pack_lockfile, ".keep", &base_len)) { struct strbuf idx_file = STRBUF_INIT; strbuf_add(&idx_file, transport->pack_lockfile, base_len); strbuf_addstr(&idx_file, ".idx"); new_pack = add_packed_git(idx_file.buf, idx_file.len, 1); strbuf_release(&idx_file); } if (opt->shallow_file) { argv_array_push(&rev_list.args, "--shallow-file"); argv_array_push(&rev_list.args, opt->shallow_file); } argv_array_push(&rev_list.args,"rev-list"); argv_array_push(&rev_list.args, "--objects"); argv_array_push(&rev_list.args, "--stdin"); argv_array_push(&rev_list.args, "--not"); argv_array_push(&rev_list.args, "--all"); argv_array_push(&rev_list.args, "--quiet"); if (opt->progress) argv_array_pushf(&rev_list.args, "--progress=%s", _("Checking connectivity")); rev_list.git_cmd = 1; rev_list.env = opt->env; rev_list.in = -1; rev_list.no_stdout = 1; if (opt->err_fd) rev_list.err = opt->err_fd; else rev_list.no_stderr = opt->quiet; if (start_command(&rev_list)) return error(_("Could not run 'git rev-list'")); sigchain_push(SIGPIPE, SIG_IGN); commit[40] = '\n'; do { /* * If index-pack already checked that: * - there are no dangling pointers in the new pack * - the pack is self contained * Then if the updated ref is in the new pack, then we * are sure the ref is good and not sending it to * rev-list for verification. */ if (new_pack && find_pack_entry_one(sha1, new_pack)) continue; memcpy(commit, sha1_to_hex(sha1), 40); if (write_in_full(rev_list.in, commit, 41) < 0) { if (errno != EPIPE && errno != EINVAL) error_errno(_("failed write to rev-list")); err = -1; break; } } while (!fn(cb_data, sha1)); if (close(rev_list.in)) err = error_errno(_("failed to close rev-list's stdin")); sigchain_pop(SIGPIPE); return finish_command(&rev_list) || err; }