From: Junio C Hamano Date: Mon, 17 Apr 2017 06:29:30 +0000 (-0700) Subject: Merge branch 'jk/loose-object-info-report-error' X-Git-Tag: v2.13.0-rc0~25 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/dfe46c5ce6e68d682f80f9874f0eb107e9fee797?hp=-c Merge branch 'jk/loose-object-info-report-error' Update error handling for codepath that deals with corrupt loose objects. * jk/loose-object-info-report-error: index-pack: detect local corruption in collision check sha1_loose_object_info: return error for corrupted objects --- dfe46c5ce6e68d682f80f9874f0eb107e9fee797 diff --combined builtin/index-pack.c index 197c51912d,9f17adb37b..4ff567db47 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@@ -307,15 -307,14 +307,15 @@@ static const char *open_pack_file(cons if (from_stdin) { input_fd = 0; if (!pack_name) { - static char tmp_file[PATH_MAX]; - output_fd = odb_mkstemp(tmp_file, sizeof(tmp_file), + struct strbuf tmp_file = STRBUF_INIT; + output_fd = odb_mkstemp(&tmp_file, "pack/tmp_pack_XXXXXX"); - pack_name = xstrdup(tmp_file); - } else + pack_name = strbuf_detach(&tmp_file, NULL); + } else { output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600); - if (output_fd < 0) - die_errno(_("unable to create '%s'"), pack_name); + if (output_fd < 0) + die_errno(_("unable to create '%s'"), pack_name); + } nothread_data.pack_fd = output_fd; } else { input_fd = open(pack_name, O_RDONLY); @@@ -810,6 -809,8 +810,8 @@@ static void sha1_object(const void *dat unsigned long has_size; read_lock(); has_type = sha1_object_info(sha1, &has_size); + if (has_type < 0) + die(_("cannot read existing object info %s"), sha1_to_hex(sha1)); if (has_type != type || has_size != size) die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1)); has_data = read_sha1_file(sha1, &has_type, &has_size); @@@ -1443,11 -1444,10 +1445,11 @@@ static void final(const char *final_pac if (!from_stdin) { printf("%s\n", sha1_to_hex(sha1)); } else { - char buf[48]; - int len = snprintf(buf, sizeof(buf), "%s\t%s\n", - report, sha1_to_hex(sha1)); - write_or_die(1, buf, len); + struct strbuf buf = STRBUF_INIT; + + strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(sha1)); + write_or_die(1, buf.buf, buf.len); + strbuf_release(&buf); /* * Let's just mimic git-unpack-objects here and write diff --combined sha1_file.c index 43990dec73,b8fbcc54c5..7369f7495a --- a/sha1_file.c +++ b/sha1_file.c @@@ -129,10 -129,8 +129,10 @@@ enum scld_error safe_create_leading_dir *slash = '\0'; if (!stat(path, &st)) { /* path exists */ - if (!S_ISDIR(st.st_mode)) + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; ret = SCLD_EXISTS; + } } else if (mkdir(path, 0777)) { if (errno == EEXIST && !stat(path, &st) && S_ISDIR(st.st_mode)) @@@ -160,85 -158,13 +160,85 @@@ enum scld_error safe_create_leading_directories_const(const char *path) { + int save_errno; /* path points to cache entries, so xstrdup before messing with it */ char *buf = xstrdup(path); enum scld_error result = safe_create_leading_directories(buf); + + save_errno = errno; free(buf); + errno = save_errno; return result; } +int raceproof_create_file(const char *path, create_file_fn fn, void *cb) +{ + /* + * The number of times we will try to remove empty directories + * in the way of path. This is only 1 because if another + * process is racily creating directories that conflict with + * us, we don't want to fight against them. + */ + int remove_directories_remaining = 1; + + /* + * The number of times that we will try to create the + * directories containing path. We are willing to attempt this + * more than once, because another process could be trying to + * clean up empty directories at the same time as we are + * trying to create them. + */ + int create_directories_remaining = 3; + + /* A scratch copy of path, filled lazily if we need it: */ + struct strbuf path_copy = STRBUF_INIT; + + int ret, save_errno; + + /* Sanity check: */ + assert(*path); + +retry_fn: + ret = fn(path, cb); + save_errno = errno; + if (!ret) + goto out; + + if (errno == EISDIR && remove_directories_remaining-- > 0) { + /* + * A directory is in the way. Maybe it is empty; try + * to remove it: + */ + if (!path_copy.len) + strbuf_addstr(&path_copy, path); + + if (!remove_dir_recursively(&path_copy, REMOVE_DIR_EMPTY_ONLY)) + goto retry_fn; + } else if (errno == ENOENT && create_directories_remaining-- > 0) { + /* + * Maybe the containing directory didn't exist, or + * maybe it was just deleted by a process that is + * racing with us to clean up empty directories. Try + * to create it: + */ + enum scld_error scld_result; + + if (!path_copy.len) + strbuf_addstr(&path_copy, path); + + do { + scld_result = safe_create_leading_directories(path_copy.buf); + if (scld_result == SCLD_OK) + goto retry_fn; + } while (scld_result == SCLD_VANISHED && create_directories_remaining-- > 0); + } + +out: + strbuf_release(&path_copy); + errno = save_errno; + return ret; +} + static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1) { int i; @@@ -662,7 -588,7 +662,7 @@@ static int freshen_file(const char *fn * either does not exist on disk, or has a stale mtime and may be subject to * pruning). */ -static int check_and_freshen_file(const char *fn, int freshen) +int check_and_freshen_file(const char *fn, int freshen) { if (access(fn, F_OK)) return 0; @@@ -2701,17 -2627,6 +2701,17 @@@ const unsigned char *nth_packed_object_ } } +const struct object_id *nth_packed_object_oid(struct object_id *oid, + struct packed_git *p, + uint32_t n) +{ + const unsigned char *hash = nth_packed_object_sha1(p, n); + if (!hash) + return NULL; + hashcpy(oid->hash, hash); + return oid; +} + void check_pack_index_ptr(const struct packed_git *p, const void *vptr) { const unsigned char *ptr = vptr; @@@ -2952,7 -2867,7 +2952,7 @@@ static int sha1_loose_object_info(cons if (status && oi->typep) *oi->typep = status; strbuf_release(&hdrbuf); - return 0; + return (status < 0) ? status : 0; } int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags) @@@ -3758,15 -3673,15 +3758,15 @@@ static int for_each_file_in_obj_subdir( strbuf_setlen(path, baselen); strbuf_addf(path, "/%s", de->d_name); - if (strlen(de->d_name) == 38) { - char hex[41]; - unsigned char sha1[20]; + if (strlen(de->d_name) == GIT_SHA1_HEXSZ - 2) { + char hex[GIT_SHA1_HEXSZ+1]; + struct object_id oid; - snprintf(hex, sizeof(hex), "%02x%s", - subdir_nr, de->d_name); - if (!get_sha1_hex(hex, sha1)) { + xsnprintf(hex, sizeof(hex), "%02x%s", + subdir_nr, de->d_name); + if (!get_oid_hex(hex, &oid)) { if (obj_cb) { - r = obj_cb(sha1, path->buf, data); + r = obj_cb(&oid, path->buf, data); if (r) break; } @@@ -3872,13 -3787,13 +3872,13 @@@ static int for_each_object_in_pack(stru int r = 0; for (i = 0; i < p->num_objects; i++) { - const unsigned char *sha1 = nth_packed_object_sha1(p, i); + struct object_id oid; - if (!sha1) + if (!nth_packed_object_oid(&oid, p, i)) return error("unable to get sha1 of object %u in %s", i, p->pack_name); - r = cb(sha1, p, i, data); + r = cb(&oid, p, i, data); if (r) break; }