/*
 * DF-2633 verifier - after remount, walk fill.bin and classify each 64KB
 * block against the deterministic generator (fillbuf(0xC0FFEE123456789 +
 * blockno)): OK / HOLE(all zero) / MISMATCH / EOF.  Reports totals and the
 * list of first 40 lost blocks.  Quantifies exactly which write()-
 * successful data vanished.
 */
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define BLSZ 65536
#define MAXBLOCKS 8192

static uint64_t
xs64(uint64_t *s)
{
	uint64_t x = *s;
	x ^= x << 13; x ^= x >> 7; x ^= x << 17;
	*s = x;
	return x;
}

static void
fillbuf(uint64_t seed, uint8_t *buf, size_t n)
{
	size_t i;
	for (i = 0; i < n; i += 8) {
		uint64_t r = xs64(&seed);
		memcpy(buf + i, &r, (n - i >= 8) ? 8 : n - i);
	}
}

int
main(int argc, char **argv)
{
	const char *file;
	uint8_t *exp, *got;
	int fd, rc, i;
	long ok = 0, hole = 0, mism = 0, eof = 0, listed = 0;
	off_t off = 0;
	struct stat sb;

	if (argc != 2) {
		fprintf(stderr, "usage: %s <fill.bin>\n", argv[0]);
		return 2;
	}
	file = argv[1];
	setvbuf(stdout, NULL, _IONBF, 0);
	fd = open(file, O_RDONLY);
	if (fd < 0) { perror(file); return 2; }
	if (fstat(fd, &sb) == 0)
		printf("VERIFY_SIZE %jd\n", (intmax_t)sb.st_size);
	exp = malloc(BLSZ);
	got = malloc(BLSZ);
	for (i = 0; i < MAXBLOCKS; ++i, off += BLSZ) {
		fillbuf(0xC0FFEE123456789ULL + i, exp, BLSZ);
		rc = read(fd, got, BLSZ);
		if (rc == 0) { eof = 1; break; }
		if (rc < 0) { printf("VERIFY_READ_ERR %d\n", errno); break; }
		if (rc < BLSZ) {
			/* short (tail) block: zero-pad compare */
			memset(got + rc, 0, BLSZ - rc);
			memset(exp + rc, 0, BLSZ - rc);
		}
		{
			int z = 1, m = 0, k;
			for (k = 0; k < BLSZ; k += 8) {
				if (memcmp(got + k, exp + k, 8) != 0) { m = 1; }
				if (memcmp(got + k, "\0\0\0\0\0\0\0\0", 8) != 0) { z = 0; }
			}
			if (m == 0) ++ok;
			else if (z) ++hole;
			else ++mism;
			if (m && listed < 40) {
				printf("LOST_BLOCK idx=%d off=%jd class=%s\n",
				    i, (intmax_t)off, z ? "hole" : "mismatch");
				++listed;
			}
		}
	}
	printf("VERIFY_DONE ok=%ld hole=%ld mismatch=%ld%s\n",
	    ok, hole, mism, eof ? " eof" : "");
	return 0;
}
