Skip to content

Commit 6d185a5

Browse files
Maxime de Roucypoettering
authored andcommitted
rename_noreplace: use renameat if linkat isn't supported
like on some fuse FS
1 parent 095cb73 commit 6d185a5

File tree

1 file changed

+16
-4
lines changed

1 file changed

+16
-4
lines changed

src/util.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,14 +1268,26 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
12681268
return -errno;
12691269

12701270
/* Let's try linkat(). This will of course failure for non-files, but that's fine. */
1271-
if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) < 0)
1272-
return -errno;
1271+
if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
1272+
if (unlinkat(olddirfd, oldpath, 0) >= 0)
1273+
return 0;
12731274

1274-
if (unlinkat(olddirfd, oldpath, 0) < 0) {
12751275
r = -errno;
12761276
(void) unlinkat(newdirfd, newpath, 0);
12771277
return r;
1278-
}
1278+
} else if (!ERRNO_IS_UNSUPPORTED(errno))
1279+
return -errno;
1280+
1281+
/* if renameat2 and linkat aren't supported, fallback to faccessat+renameat,
1282+
* it isn't atomic but that's the best we can do */
1283+
if (faccessat(newdirfd, newpath, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
1284+
return -EEXIST;
1285+
1286+
if (errno != ENOENT)
1287+
return -errno;
1288+
1289+
if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
1290+
return -errno;
12791291

12801292
return 0;
12811293
}

0 commit comments

Comments
 (0)