aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2025-05-27 13:59:10 -0700
committerJunio C Hamano <gitster@pobox.com>2025-05-27 13:59:10 -0700
commitd8b48af39141d4552e6e2c091957a59b806808a1 (patch)
treec923958e28b63c2291865f64576523ad3545734f
parent3950f8f1b431860c35e938db7fc0360cadba3bf0 (diff)
parent86ddd588f24acf3960489dccb8aed82dc570796b (diff)
downloadgit-d8b48af39141d4552e6e2c091957a59b806808a1.tar.gz
Merge branch 'sj/use-mmap-to-check-packed-refs'
The code path to access the "packed-refs" file while "fsck" is taught to mmap the file, instead of reading the whole file in the memory. * sj/use-mmap-to-check-packed-refs: packed-backend: mmap large "packed-refs" file during fsck packed-backend: extract snapshot allocation in `load_contents` packed-backend: fsck should warn when "packed-refs" file is empty
-rw-r--r--Documentation/fsck-msgids.adoc6
-rw-r--r--fsck.h1
-rw-r--r--refs/packed-backend.c73
-rwxr-xr-xt/t0602-reffiles-fsck.sh17
4 files changed, 67 insertions, 30 deletions
diff --git a/Documentation/fsck-msgids.adoc b/Documentation/fsck-msgids.adoc
index 9601fff228..0ba4f9a27e 100644
--- a/Documentation/fsck-msgids.adoc
+++ b/Documentation/fsck-msgids.adoc
@@ -59,6 +59,12 @@
`emptyName`::
(WARN) A path contains an empty name.
+`emptyPackedRefsFile`::
+ (INFO) "packed-refs" file is empty. Report to the
+ git@vger.kernel.org mailing list if you see this error. As only
+ very early versions of Git would create such an empty
+ "packed_refs" file, we might tighten this rule in the future.
+
`extraHeaderEntry`::
(IGNORE) Extra headers found after `tagger`.
diff --git a/fsck.h b/fsck.h
index b1deae61ee..0c5869ac34 100644
--- a/fsck.h
+++ b/fsck.h
@@ -84,6 +84,7 @@ enum fsck_msg_type {
FUNC(LARGE_PATHNAME, WARN) \
/* infos (reported as warnings, but ignored by default) */ \
FUNC(BAD_FILEMODE, INFO) \
+ FUNC(EMPTY_PACKED_REFS_FILE, INFO) \
FUNC(GITMODULES_PARSE, INFO) \
FUNC(GITIGNORE_SYMLINK, INFO) \
FUNC(GITATTRIBUTES_SYMLINK, INFO) \
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 3ad1ed0787..7fd73a0e6d 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -517,6 +517,32 @@ static int refname_contains_nul(struct strbuf *refname)
#define SMALL_FILE_SIZE (32*1024)
+static int allocate_snapshot_buffer(struct snapshot *snapshot, int fd, struct stat *st)
+{
+ ssize_t bytes_read;
+ size_t size;
+
+ size = xsize_t(st->st_size);
+ if (!size)
+ return 0;
+
+ if (mmap_strategy == MMAP_NONE || size <= SMALL_FILE_SIZE) {
+ snapshot->buf = xmalloc(size);
+ bytes_read = read_in_full(fd, snapshot->buf, size);
+ if (bytes_read < 0 || bytes_read != size)
+ die_errno("couldn't read %s", snapshot->refs->path);
+ snapshot->mmapped = 0;
+ } else {
+ snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ snapshot->mmapped = 1;
+ }
+
+ snapshot->start = snapshot->buf;
+ snapshot->eof = snapshot->buf + size;
+
+ return 1;
+}
+
/*
* Depending on `mmap_strategy`, either mmap or read the contents of
* the `packed-refs` file into the snapshot. Return 1 if the file
@@ -525,10 +551,9 @@ static int refname_contains_nul(struct strbuf *refname)
*/
static int load_contents(struct snapshot *snapshot)
{
- int fd;
struct stat st;
- size_t size;
- ssize_t bytes_read;
+ int ret;
+ int fd;
fd = open(snapshot->refs->path, O_RDONLY);
if (fd < 0) {
@@ -550,27 +575,11 @@ static int load_contents(struct snapshot *snapshot)
if (fstat(fd, &st) < 0)
die_errno("couldn't stat %s", snapshot->refs->path);
- size = xsize_t(st.st_size);
-
- if (!size) {
- close(fd);
- return 0;
- } else if (mmap_strategy == MMAP_NONE || size <= SMALL_FILE_SIZE) {
- snapshot->buf = xmalloc(size);
- bytes_read = read_in_full(fd, snapshot->buf, size);
- if (bytes_read < 0 || bytes_read != size)
- die_errno("couldn't read %s", snapshot->refs->path);
- snapshot->mmapped = 0;
- } else {
- snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- snapshot->mmapped = 1;
- }
- close(fd);
- snapshot->start = snapshot->buf;
- snapshot->eof = snapshot->buf + size;
+ ret = allocate_snapshot_buffer(snapshot, fd, &st);
- return 1;
+ close(fd);
+ return ret;
}
static const char *find_reference_location_1(struct snapshot *snapshot,
@@ -2059,7 +2068,7 @@ static int packed_fsck(struct ref_store *ref_store,
{
struct packed_ref_store *refs = packed_downcast(ref_store,
REF_STORE_READ, "fsck");
- struct strbuf packed_ref_content = STRBUF_INIT;
+ struct snapshot snapshot = { 0 };
unsigned int sorted = 0;
struct stat st;
int ret = 0;
@@ -2103,21 +2112,25 @@ static int packed_fsck(struct ref_store *ref_store,
goto cleanup;
}
- if (strbuf_read(&packed_ref_content, fd, 0) < 0) {
- ret = error_errno(_("unable to read '%s'"), refs->path);
+ if (!allocate_snapshot_buffer(&snapshot, fd, &st)) {
+ struct fsck_ref_report report = { 0 };
+ report.path = "packed-refs";
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_EMPTY_PACKED_REFS_FILE,
+ "file is empty");
goto cleanup;
}
- ret = packed_fsck_ref_content(o, ref_store, &sorted, packed_ref_content.buf,
- packed_ref_content.buf + packed_ref_content.len);
+ ret = packed_fsck_ref_content(o, ref_store, &sorted, snapshot.start,
+ snapshot.eof);
if (!ret && sorted)
- ret = packed_fsck_ref_sorted(o, ref_store, packed_ref_content.buf,
- packed_ref_content.buf + packed_ref_content.len);
+ ret = packed_fsck_ref_sorted(o, ref_store, snapshot.start,
+ snapshot.eof);
cleanup:
if (fd >= 0)
close(fd);
- strbuf_release(&packed_ref_content);
+ clear_snapshot_buffer(&snapshot);
return ret;
}
diff --git a/t/t0602-reffiles-fsck.sh b/t/t0602-reffiles-fsck.sh
index 9d1dc2144c..f671ac4d3a 100755
--- a/t/t0602-reffiles-fsck.sh
+++ b/t/t0602-reffiles-fsck.sh
@@ -647,6 +647,23 @@ test_expect_success SYMLINKS 'the filetype of packed-refs should be checked' '
)
'
+test_expect_success 'empty packed-refs should be reported' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit default &&
+
+ >.git/packed-refs &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: packed-refs: emptyPackedRefsFile: file is empty
+ EOF
+ rm .git/packed-refs &&
+ test_cmp expect err
+ )
+'
+
test_expect_success 'packed-refs header should be checked' '
test_when_finished "rm -rf repo" &&
git init repo &&