#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/clonefile.h>

#define MAX_SIZE (1024 * 1024 * 100)
#define BLOCK_SIZE (4096)
char msg[MAX_SIZE];
char zero[BLOCK_SIZE];

int main(int argc, char ** argv)
{
	// sparse fill test
	// block size i 4 KB
	int src = open("cc1", O_RDONLY);
	int dst = open("B", O_CREAT | O_TRUNC | O_RDWR, 0700);
	printf("src %i  dst %i\n", src, dst);
	//- printf("SET %i  CUR %i  END %i  HOLE %i  DATA %i\n", SEEK_SET, SEEK_CUR, SEEK_END, SEEK_HOLE, SEEK_DATA);

	const char * p = msg;
	const char * n = msg;
	const char * e = msg;
	off_t a = 0;
	off_t b = 0;
	off_t s = 0;
	off_t t = 0;
	ssize_t c = 0;
	ssize_t i = 0;
	ssize_t r = 0;
	ssize_t w = 0;
	int ea = 0;
	int eb = 0;
	int es = 0;
	int et = 0;

	errno = 0;
	s = lseek(src, 0, SEEK_END);
	es = errno;

	if (s == -1)
	{
		printf(
			"lseek(SEEK_END) failed  s %lli %2i %s\n",
			s, es, strerror(es)
		);

		return 1;
	}

	if (s > sizeof(msg))
	{
		printf("msg too small %zu %lli\n", sizeof(msg), s);
		return 2;
	}

	t = ftruncate(dst, s);
	et = errno;

	if (t == -1)
	{
		printf(
			"ftruncate(%lli) failed  %lli %2i %s\n",
			s, t, et, strerror(et)
		);

		return 3;
	}

	a = lseek(src, 0, SEEK_SET);
	ea = errno;

	if (a == -1)
	{
		printf(
			"lseek(SEEK_SET) failed  a %lli %2i %s\n",
			a, ea, strerror(ea)
		);

		return 4;
	}

	// read all data
	r = read(src, msg, s);

	if (r != s)
	{
		printf("expected %zi  read %zi\n", c, r);
		return 5;
	}

	memset(zero, 0, sizeof(zero));


	for (e = msg + s; p < e; p = n)
	{
		errno = 0;
		n = p + BLOCK_SIZE;

		if (n > e)
		{
			n = e;
		}

		c = n - p;

		if (memcmp(zero, p, c))
		{
			// write valid sector
			//- printf("%08zx copy\n", p - msg);
			w = write(dst, p, c);

			if (w != c)
			{
				printf("expected %zi  wrote %zi\n", c, w);
				break;
			}

			i += c;
		}
		else
		{
			// skip empty sector
			printf("%08zx skip\n", p - msg);
			b = lseek(dst, c, SEEK_CUR);
			eb = errno;

			if (b == -1)
			{
				printf(
					"lseek(SEEK_CUR) failed  b %lli %2i %s\n",
					b, eb, strerror(eb)
				);

				break;
			}
		}
	}

	b = lseek(src, 0, SEEK_CUR);

	close(src);
	close(dst);

	printf("total bytes copied %zx / %llx %llx\n", i, b, s);

	return 0;
}
