pg_verifybackup / pg_combinebackup: missing readdir() error check in directory scan

Started by Daria Lepikhovaabout 1 month ago1 messageshackers
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253885
psql -h localhost -U postgres

Built from patchset v1 (message #1), October 22, 2026 at 07:20 AM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t253885_1 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t253885_1 && git checkout t253885_1

Patchset v1 (message #1) is on t253885_1

Jump to latest
#1Daria Lepikhova
daria.n.lepikhova@gmail.com

Hi,

While reading pg_verifybackup sources I noticed that the directory scan
never

checks errno after the readdir() loop, although similar loops elsewhere in

the tree does. And pg_combinebackup has the same problem:

while (errno = 0, (dirent = readdir(dir)) != NULL)

{

...

}

A failure partway through the scan is then indistinguishable from the end

of the directory. pg_verifybackup reports the entries it never reached as

"present in the manifest but not on disk"; pg_combinebackup writes out the

truncated directory and exits normally.

There are four such loops: verify_plain_backup_directory() and

verify_tar_backup() in pg_verifybackup.c, process_directory_recursively()

and scan_for_existing_tablespaces() in pg_combinebackup.c.

Commit 6f03927fce (Properly check for readdir/closedir() failures) added

the errno check to pg_archivecleanup.c, fd.c, initdb.c and other call

sites. pg_verifybackup and pg_combinebackup came later, which is probably

why the check never made it into their code.

The attached patch makes small changes to pg_verifybackup and

pg_combinebackup, adding the missing checks. pg_fatal() seems sufficient

for pg_combinebackup. For pg_verifybackup I don't think

report_backup_error() alone is enough: it keeps going, so the bogus

"missing file" reports remain and merely gain one more line. The patch

adds the directory to the ignore list as well, which is what the same

function already does when opendir() fails.

I simulated a readdir() failure on a plain backup of 21000 files.

pg_verifybackup reported 16732 of them as missing, though everyone was on

disk. With the patch it reports a single "could not read directory" error.

Unfortunately I couldn't come up with a portable test that would

demonstrate this; if someone can, I'd be grateful. The pattern seems clear

enough even without one.

--

Daria Lepikhova

Attachments:

t253885_1
v1-0001-Check-for-readdir-failures-in-pg_verifybackup-and.patchapplication/octet-stream; name=v1-0001-Check-for-readdir-failures-in-pg_verifybackup-and.patchDownload+19-1