/*
 * 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;
}
