summaryrefslogtreecommitdiff
path: root/src/attr_replace_test.c
blob: 1218e7264c8f91132364d21762867a19abc2089b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// setattr.c by kanda.motohiro@gmail.com
// xfs extended attribute corruption bug reproducer
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <linux/limits.h>

#define die() do { perror(""); \
fprintf(stderr, "error at line %d\n", __LINE__); \
exit(1); } while (0)

#define fail(...) do { \
fprintf(stderr, __VA_ARGS__); exit (1); \
} while (0)

void usage(char *progname)
{
	fail("usage: %s [-m max_attr_size] <file>\n", progname);
}

int main(int argc, char *argv[])
{
	int ret;
	int fd;
	int c;
	char *path;
	char *name = "user.world";
	char *value;
	struct stat sbuf;
	size_t size = sizeof(value);
	size_t maxsize = XATTR_SIZE_MAX;

	while ((c = getopt(argc, argv, "m:")) != -1) {
		char *endp;

		switch (c) {
		case 'm':
			maxsize = strtoul(optarg, &endp, 0);
			if (*endp || (maxsize > XATTR_SIZE_MAX))
				fail("Invalid 'max_attr_size' value\n");
			break;
		default:
			usage(argv[0]);
		}
	}

	if (optind == argc - 1)
		path = argv[optind];
	else
		usage(argv[0]);

	fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
	if (fd < 0) die();

	/*
	 * The value should be 3/4 the size of a fs block to ensure that we
	 * get to extents format.
	 */
	ret = fstat(fd, &sbuf);
	if (ret < 0) die();
	size = sbuf.st_blksize * 3 / 4;
	if (!size)
		fail("Invalid st_blksize(%ld)\n", sbuf.st_blksize);
	size = MIN(size, maxsize);
	value = malloc(size);
	if (!value)
		fail("Failed to allocate memory\n");

	/* First, create a small xattr. */
	memset(value, '0', 1);
	ret = fsetxattr(fd, name, value, 1, XATTR_CREATE);
	if (ret < 0) die();
	close(fd);

	fd = open(path, O_RDWR);
	if (fd < 0) die();

	/* Then, replace it with bigger one, forcing short form to leaf conversion. */
	memset(value, '1', size);
	ret = fsetxattr(fd, name, value, size, XATTR_REPLACE);
	if (ret < 0) die();
	close(fd);

	return 0;
}