// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2018 Red Hat, Inc.
 * All Rights Reserved.
 */

#include "command.h"
#include "input.h"
#include "init.h"
#include "io.h"

static cmdinfo_t swapext_cmd;

static void
swapext_help(void)
{
	printf(_(
"\n"
" Swaps extents between the open file descriptor and the supplied filename.\n"
"\n"));
}

static int
xfs_bulkstat_single(
	int			fd,
	xfs_ino_t		*lastip,
	struct xfs_bstat	*ubuffer)
{
	struct xfs_fsop_bulkreq	bulkreq;

	bulkreq.lastip = (__u64 *)lastip;
	bulkreq.icount = 1;
	bulkreq.ubuffer = ubuffer;
	bulkreq.ocount = NULL;
	return ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq);
}

static int
swapext_f(
	int			argc,
	char			**argv)
{
	int			fd;
	int			error;
	struct xfs_swapext	sx;
	struct stat		stat;

	/* open the donor file */
	fd = openfile(argv[1], NULL, 0, 0, NULL);
	if (fd < 0)
		return 0;

	/*
	 * stat the target file to get the inode number and use the latter to
	 * get the bulkstat info for the swapext cmd.
	 */
	error = fstat(file->fd, &stat);
	if (error) {
		perror("fstat");
		goto out;
	}

	error = xfs_bulkstat_single(file->fd, &stat.st_ino, &sx.sx_stat);
	if (error) {
		perror("bulkstat");
		goto out;
	}
	sx.sx_version = XFS_SX_VERSION;
	sx.sx_fdtarget = file->fd;
	sx.sx_fdtmp = fd;
	sx.sx_offset = 0;
	sx.sx_length = stat.st_size;
	error = ioctl(file->fd, XFS_IOC_SWAPEXT, &sx);
	if (error)
		perror("swapext");

out:
	close(fd);
	return 0;
}

void
swapext_init(void)
{
	swapext_cmd.name = "swapext";
	swapext_cmd.cfunc = swapext_f;
	swapext_cmd.argmin = 1;
	swapext_cmd.argmax = 1;
	swapext_cmd.flags = CMD_NOMAP_OK;
	swapext_cmd.args = _("<donorfile>");
	swapext_cmd.oneline = _("Swap extents between files.");
	swapext_cmd.help = swapext_help;

	add_command(&swapext_cmd);
}
