From ea388696e9992dbc8cd0876a06a81f4ce67238cd Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sun, 23 Aug 2026 17:50:41 -1000 Subject: Give up a scan or slot whose lock file was renamed --- source/cgit.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'source/cgit.c') diff --git a/source/cgit.c b/source/cgit.c index 6644213..42325a0 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -350,6 +350,7 @@ static int generate_cached_repolist(const char *path, const char *cached_rc) .l_start = 0, .l_len = 0, }; + struct stat held, named; int err = 0; int fd; int first; @@ -370,6 +371,18 @@ static int generate_cached_repolist(const char *path, const char *cached_rc) close(fd); goto out; } + // The lock landed on whatever inode the path named at open. A holder + // finishing in between renames that inode into place as the live + // list, so truncating it on the strength of the stale descriptor + // would tear down the list other requests are reading. Once the path + // is confirmed to still name this file the rename can no longer + // happen, because doing so takes the lock now held here. + if (fstat(fd, &held) || stat(locked_rc.buf, &named) || + held.st_ino != named.st_ino || held.st_dev != named.st_dev) { + err = EAGAIN; + close(fd); + goto out; + } // A run that died before its rename leaves the lock file behind, so // start from empty now that nobody else can be writing it. if (ftruncate(fd, 0) < 0 || !(f = fdopen(fd, "w"))) { -- cgit v2.8.0