/* Distilled from issue found with tar and symlinks.
 * Make sure that the whole stat struct between runs
 * is agreeable.
 */

#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>

static void show_stat(struct stat *st)
{
	printf(
		"------------------\n"
		"st_dev     = %li\n"
		"st_ino     = %li\n"
		"st_mode    = %li\n"
		"st_nlink   = %li\n"
		"st_uid     = %li\n"
		"st_gid     = %li\n"
		"st_rdev    = %li\n"
		"st_size    = %li\n"
		"st_blksize = %li\n"
		"st_blocks  = %li\n"
		"st_atime   = %li\n"
		"st_ansec   = %li\n"
		"st_mtime   = %li\n"
		"st_mnsec   = %li\n"
		"st_ctime   = %li\n"
		"st_cnsec   = %li\n",
		(long int)st->st_dev,
		(long int)st->st_ino,
		(long int)st->st_mode,
		(long int)st->st_nlink,
		(long int)st->st_uid,
		(long int)st->st_gid,
		(long int)st->st_rdev,
		(long int)st->st_size,
		(long int)st->st_blksize,
		(long int)st->st_blocks,
#if !defined(__UCLIBC__) || defined(__USE_MISC)
		(long int)st->st_atime,
		(long int)st->st_atim.tv_nsec,
		(long int)st->st_mtime,
		(long int)st->st_mtim.tv_nsec,
		(long int)st->st_ctime,
		(long int)st->st_ctim.tv_nsec
#else
		(long int)st->st_atime,
		(long int)st->st_atimensec,
		(long int)st->st_mtime,
		(long int)st->st_mtimensec,
		(long int)st->st_ctime,
		(long int)st->st_ctimensec
#endif
	);
}

int main(void)
{
	int ret;
	int fd;
	struct stat fst, st;

	memset(&fst, 0xAA, sizeof(fst));
	memset(&st, 0x55, sizeof(st));

	unlink(".testfile");
	fd = open(".testfile", O_WRONLY | O_CREAT | O_EXCL, 0);
	if (fd < 0) {
		perror("open(.testfile) failed");
		return 1;
	}
	ret = fstat(fd, &fst);
	if (ret != 0) {
		perror("fstat(.testfile) failed");
		return 1;
	}
	close(fd);

	ret = stat(".testfile", &st);
	if (ret != 0) {
		perror("stat(.testfile) failed");
		return 1;
	}

	ret = memcmp(&fst, &st, sizeof(fst));
	if (ret != 0) {
		printf("FAILED: memcmp() = %i\n", ret);
		show_stat(&fst);
		show_stat(&st);
	}

	unlink(".testfile");

	return ret;
}