blob: 8f712a40e1af88ebe09a4be9f6b2c6fc31fa09f8 [file] [log] [blame]
/*
* Copyright (c) 2014, Miklos Szeredi <mszeredi@suse.cz>
* This file is published under GPL2+.
*
* This is a trivial wrapper around the renameat2 syscall.
*/
#include "global.h"
#ifndef HAVE_RENAMEAT2
#include <sys/syscall.h>
#if !defined(SYS_renameat2) && defined(__x86_64__)
#define SYS_renameat2 316
#endif
#if !defined(SYS_renameat2) && defined(__i386__)
#define SYS_renameat2 353
#endif
static int renameat2(int dfd1, const char *path1,
int dfd2, const char *path2,
unsigned int flags)
{
#ifdef SYS_renameat2
return syscall(SYS_renameat2, dfd1, path1, dfd2, path2, flags);
#else
errno = ENOSYS;
return -1;
#endif
}
#endif
#ifndef RENAME_NOREPLACE
#define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */
#endif
#ifndef RENAME_EXCHANGE
#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
#endif
#ifndef RENAME_WHITEOUT
#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */
#endif
int main(int argc, char *argv[])
{
int ret;
int c;
const char *path1 = NULL;
const char *path2 = NULL;
unsigned int flags = 0;
int test = 0;
for (c = 1; c < argc; c++) {
if (argv[c][0] == '-') {
switch (argv[c][1]) {
case 't':
test = 1;
break;
case 'n':
flags |= RENAME_NOREPLACE;
break;
case 'x':
flags |= RENAME_EXCHANGE;
break;
case 'w':
flags |= RENAME_WHITEOUT;
break;
default:
goto usage;
}
} else if (!path1) {
path1 = argv[c];
} else if (!path2) {
path2 = argv[c];
} else {
goto usage;
}
}
if (!test && (!path1 || !path2))
goto usage;
ret = renameat2(AT_FDCWD, path1, AT_FDCWD, path2, flags);
if (ret == -1) {
if (test) {
if (errno == ENOSYS || errno == EINVAL)
return 1;
else
return 0;
}
/*
* Turn EEXIST into ENOTEMPTY. E.g. XFS uses EEXIST, and that
* is also accepted by the standards.
*
* This applies only to plain rename and RENAME_WHITEOUT
*/
if (errno == EEXIST && (!flags || (flags & RENAME_WHITEOUT)))
errno = ENOTEMPTY;
perror("");
return 1;
}
return 0;
usage:
fprintf(stderr,
"usage: %s [-t] [-n|-x|-w] path1 path2\n"
" -t test\n"
" -n noreplace\n"
" -x exchange\n"
" -w whiteout\n", argv[0]);
return 1;
}