diff --git a/compat-usrmerge.changes b/compat-usrmerge.changes index 6a2d438..eb5757f 100644 --- a/compat-usrmerge.changes +++ b/compat-usrmerge.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Tue Jun 1 23:27:08 UTC 2021 - Niklas Haas + +- add fallback for filesystems without renameat2 + ------------------------------------------------------------------- Thu Mar 25 09:50:48 UTC 2021 - Ludwig Nussel diff --git a/xmv.c b/xmv.c index f7c31a4..d29bae5 100644 --- a/xmv.c +++ b/xmv.c @@ -66,10 +66,34 @@ int main(int argc, char** argv) if (argc-optind < 2) help(argv[0], 1); - r = syscall (SYS_renameat2, AT_FDCWD, argv[optind], AT_FDCWD, argv[optind+1], RENAME_EXCHANGE); + const char *source = argv[optind], *target = argv[optind+1]; + r = syscall (SYS_renameat2, AT_FDCWD, source, AT_FDCWD, target, RENAME_EXCHANGE); if (r < 0) { - perror("renameat2"); - return 1; + if (errno != EINVAL) { + perror("renameat2"); + return 1; + } + + /* Fallback for systems without renameat2 support */ + char *tmp; + r = asprintf(&tmp, "%s.XXXXXX", target); + if (r < 0) { + perror("asprintf"); + return 1; + } + mktemp(tmp); + + r = renameat(AT_FDCWD, target, AT_FDCWD, tmp); + if (!r) + r = renameat(AT_FDCWD, source, AT_FDCWD, target); + if (!r) + r = renameat(AT_FDCWD, tmp, AT_FDCWD, source); + free(tmp); + + if (r < 0) { + perror("renameat"); + return 1; + } } return 0;