Here's a first try at a patch to check for the historically documented "link() returning -1 but succeeding" case for NFS.
-- Kevin J. McCarthy GPG Fingerprint: 8975 A9B3 3AA3 7910 385C 5308 ADEF 7684 8031 6BDA
From f0faf6cf205e0b96c2fb93ea12393458843aa485 Mon Sep 17 00:00:00 2001 From: Kevin McCarthy <ke...@8t8.us> Date: Sun, 26 Aug 2018 18:43:20 -0700 Subject: [PATCH] Add additional error handling to safe_rename(). It is apparently possible for link() to return an error but the link to still be created. Add a double check for that case. If the files match, unlink the src and return success. --- lib.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib.c b/lib.c index 9a5d5325..0f65a641 100644 --- a/lib.c +++ b/lib.c @@ -446,12 +446,31 @@ int safe_symlink(const char *oldpath, const char *newpath) int safe_rename (const char *src, const char *target) { struct stat ssb, tsb; + int link_errno; if (!src || !target) return -1; if (link (src, target) != 0) { + link_errno = errno; + + /* + * It is historically documented that link can return -1 if NFS + * dies after creating the link. In that case, we are supposed + * to use stat to check if the link was created. + */ + if ((lstat (src, &ssb) == 0) && + (lstat (target, &tsb) == 0) && + (compare_stat (&ssb, &tsb) == 0)) + { + dprint (1, (debugfile, + "safe_rename: link (%s, %s) reported failure: %s (%d) but actually succeded\n", + src, target, strerror (errno), errno)); + goto success; + } + + errno = link_errno; /* * Coda does not allow cross-directory links, but tells @@ -533,11 +552,11 @@ int safe_rename (const char *src, const char *target) } #endif +success: /* * Unlink the original link. Should we really ignore the return * value here? XXX */ - if (unlink (src) == -1) { dprint (1, (debugfile, "safe_rename: unlink (%s) failed: %s (%d)\n", -- 2.18.0
signature.asc
Description: PGP signature