The Pedigree Project 0.1
ext2.c
1#define _GNU_SOURCE
2#include <fcntl.h>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
6
7#include "contract.h"
8#include <sys/stat.h>
9#include <sys/xattr.h>
10
11static int sectors(void) {
12 int failed = 0;
13 struct xa_file file = {.fd = -1};
14 struct stat initial, with_ea, after;
15 CHECK(!xa_create(&file, XA_EXT2, 0));
16 CHECK(!fstat(file.fd, &initial) && !initial.st_size);
17 CHECK(!fsetxattr(file.fd, "user.first", "a", 1, XATTR_CREATE));
18 CHECK(!fstat(file.fd, &with_ea));
19 CHECK(with_ea.st_size == 0 &&
20 with_ea.st_blocks == initial.st_blocks + (blkcnt_t)(xa_block / 512));
21 CHECK(!fsetxattr(file.fd, "user.empty", NULL, 0, XATTR_CREATE));
22 CHECK(!fstat(file.fd, &after) && after.st_blocks == with_ea.st_blocks);
23 CHECK(!fremovexattr(file.fd, "user.first"));
24 CHECK(!xa_value(&file, XA_FD, "user.empty", NULL, 0));
25 CHECK(!fstat(file.fd, &after) && after.st_blocks == with_ea.st_blocks);
26 CHECK(!fremovexattr(file.fd, "user.empty"));
27 CHECK(!fstat(file.fd, &after) && !after.st_size && after.st_blocks == initial.st_blocks);
28 CHECK(!xa_names(&file, XA_FD, NULL, 0));
29 CHECK(!fsetxattr(file.fd, "user.reused", "b", 1, XATTR_CREATE));
30 CHECK(!fstat(file.fd, &after) && after.st_blocks == with_ea.st_blocks);
31out:
32 xa_close(&file);
33 return failed;
34}
35
36static int capacity_and_resize(void) {
37 int failed = 0, alias = -1;
38 struct xa_file file = {.fd = -1};
39 const size_t original_size = xa_block + 137, grown_size = xa_block + 211;
40 unsigned char *data = NULL, *actual = NULL, *large = NULL;
41 struct stat before, after;
42 static const unsigned char value[] = {0, 0xff, 7, 0, 3};
43 const char* names[] = {"user.keep"};
44 data = malloc(original_size);
45 actual = malloc(grown_size);
46 large = malloc(xa_block + 1);
47 CHECK(data && actual && large);
48 for (size_t n = 0; n < original_size; ++n)
49 data[n] = (unsigned char)(n * 37 + 11);
50 memset(large, 0xa3, xa_block + 1);
51 CHECK(!xa_create(&file, XA_EXT2, 0));
52 CHECK(!xa_write_all(file.fd, data, original_size));
53 CHECK(!fsetxattr(file.fd, "user.keep", value, sizeof(value), XATTR_CREATE));
54 CHECK(!fstat(file.fd, &before));
55 errno = 0;
56 CHECK(fsetxattr(file.fd, "user.keep", large, xa_block + 1, XATTR_REPLACE) == -1 &&
57 errno == (xa_block == 65536 ? E2BIG : ERANGE));
58 errno = 0;
59 CHECK(fsetxattr(file.fd, "user.keep", large, xa_block, XATTR_REPLACE) == -1 && errno == ENOSPC);
60 errno = 0;
61 CHECK(fsetxattr(file.fd, "user.no-space", large, xa_block, XATTR_CREATE) == -1 &&
62 errno == ENOSPC);
63 CHECK(!fstat(file.fd, &after));
64 CHECK(after.st_size == before.st_size && after.st_blocks == before.st_blocks &&
65 after.st_ctim.tv_sec == before.st_ctim.tv_sec &&
66 after.st_ctim.tv_nsec == before.st_ctim.tv_nsec);
67 CHECK(!xa_value(&file, XA_FD, "user.keep", value, sizeof(value)));
68 CHECK(!xa_names(&file, XA_FD, names, 1));
69 CHECK(pread(file.fd, actual, original_size, 0) == (ssize_t)original_size &&
70 !memcmp(actual, data, original_size));
71 alias = xa_open_alias(&file);
72 CHECK(alias >= 0);
73 CHECK(!ftruncate(alias, 137));
74 CHECK(!xa_value(&file, XA_FD, "user.keep", value, sizeof(value)));
75 CHECK(!ftruncate(alias, grown_size));
76 CHECK(!fstat(file.fd, &after) && after.st_size == (off_t)grown_size);
77 memset(actual, 0xa5, grown_size);
78 CHECK(pread(file.fd, actual, grown_size, 0) == (ssize_t)grown_size);
79 CHECK(!memcmp(actual, data, 137));
80 for (size_t n = 137; n < grown_size; ++n)
81 CHECK(actual[n] == 0);
82 CHECK(!xa_value(&file, XA_PATH, "user.keep", value, sizeof(value)));
83 CHECK(!xa_names(&file, XA_PATH, names, 1));
84 CHECK(!ftruncate(file.fd, 0));
85 CHECK(!fstat(alias, &after) && !after.st_size && after.st_blocks == (blkcnt_t)(xa_block / 512));
86 CHECK(!fremovexattr(alias, "user.keep"));
87 CHECK(!fstat(file.fd, &after) && !after.st_size && !after.st_blocks);
88out:
89 if (alias >= 0)
90 close(alias);
91 xa_close(&file);
92 free(large);
93 free(actual);
94 free(data);
95 return failed;
96}
97
98int xa_ext2(void) {
99 return sectors() || capacity_and_resize();
100}