diff options
Diffstat (limited to 'refs')
-rw-r--r-- | refs/files-backend.c | 26 | ||||
-rw-r--r-- | refs/packed-backend.c | 23 | ||||
-rw-r--r-- | refs/refs-internal.h | 2 |
3 files changed, 35 insertions, 16 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c index 63e55e6773..561c33ac8a 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -465,8 +465,7 @@ stat_ref: close(fd); strbuf_rtrim(&sb_contents); buf = sb_contents.buf; - if (starts_with(buf, "ref:")) { - buf += 4; + if (skip_prefix(buf, "ref:", &buf)) { while (isspace(*buf)) buf++; @@ -1327,7 +1326,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store, { struct files_ref_store *refs = files_downcast(ref_store, REF_STORE_WRITE, "rename_ref"); - struct object_id oid, orig_oid; + struct object_id orig_oid; int flag = 0, logmoved = 0; struct ref_lock *lock; struct stat loginfo; @@ -1395,7 +1394,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store, */ if (!copy && !refs_read_ref_full(&refs->base, newrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, - &oid, NULL) && + NULL, NULL) && refs_delete_ref(&refs->base, NULL, newrefname, NULL, REF_NO_DEREF)) { if (errno == EISDIR) { @@ -2143,13 +2142,24 @@ static struct ref_iterator_vtable files_reflog_iterator_vtable = { static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store, const char *gitdir) { - struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter)); - struct ref_iterator *ref_iterator = &iter->base; + struct dir_iterator *diter; + struct files_reflog_iterator *iter; + struct ref_iterator *ref_iterator; struct strbuf sb = STRBUF_INIT; - base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable, 0); strbuf_addf(&sb, "%s/logs", gitdir); - iter->dir_iterator = dir_iterator_begin(sb.buf); + + diter = dir_iterator_begin(sb.buf, 0); + if (!diter) { + strbuf_release(&sb); + return empty_ref_iterator_begin(); + } + + iter = xcalloc(1, sizeof(*iter)); + ref_iterator = &iter->base; + + base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable, 0); + iter->dir_iterator = diter; iter->ref_store = ref_store; strbuf_release(&sb); diff --git a/refs/packed-backend.c b/refs/packed-backend.c index c01c7f5901..4458a0f69c 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -1012,14 +1012,23 @@ int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err) } /* - * Now that we hold the `packed-refs` lock, make sure that our - * snapshot matches the current version of the file. Normally - * `get_snapshot()` does that for us, but that function - * assumes that when the file is locked, any existing snapshot - * is still valid. We've just locked the file, but it might - * have changed the moment *before* we locked it. + * There is a stat-validity problem might cause `update-ref -d` + * lost the newly commit of a ref, because a new `packed-refs` + * file might has the same on-disk file attributes such as + * timestamp, file size and inode value, but has a changed + * ref value. + * + * This could happen with a very small chance when + * `update-ref -d` is called and at the same time another + * `pack-refs --all` process is running. + * + * Now that we hold the `packed-refs` lock, it is important + * to make sure we could read the latest version of + * `packed-refs` file no matter we have just mmap it or not. + * So what need to do is clear the snapshot if we hold it + * already. */ - validate_snapshot(refs); + clear_snapshot(refs); /* * Now make sure that the packed-refs file as it exists in the diff --git a/refs/refs-internal.h b/refs/refs-internal.h index f2d8c0123a..ff2436c0fb 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -262,7 +262,7 @@ int refs_rename_ref_available(struct ref_store *refs, * after calling ref_iterator_advance() again or calling * ref_iterator_abort(), you must make a copy. When the iteration has * been exhausted, ref_iterator_advance() releases any resources - * assocated with the iteration, frees the ref_iterator object, and + * associated with the iteration, frees the ref_iterator object, and * returns ITER_DONE. If you want to abort the iteration early, call * ref_iterator_abort(), which also frees the ref_iterator object and * any associated resources. If there was an internal error advancing |