1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2018 Google LLC
4 */
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include <dirent.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <sys/mount.h>
12 #include <errno.h>
13 #include <sys/wait.h>
14 #include <sys/xattr.h>
15 #include <alloca.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <linux/random.h>
21 #include <linux/unistd.h>
22
23 #include "../../kselftest.h"
24
25 #include "lz4.h"
26 #include "utils.h"
27
28 #define __packed __attribute__((__packed__))
29
30 #define TEST_FAILURE 1
31 #define TEST_SUCCESS 0
32 #define INCFS_MAX_MTREE_LEVELS 8
33
34 #define INCFS_ROOT_INODE 0
35
36 struct hash_block {
37 char data[INCFS_DATA_FILE_BLOCK_SIZE];
38 };
39
40 struct test_signature {
41 void *data;
42 size_t size;
43
44 char add_data[100];
45 size_t add_data_size;
46 };
47
48 struct test_file {
49 int index;
50 incfs_uuid_t id;
51 char *name;
52 off_t size;
53 char root_hash[INCFS_MAX_HASH_SIZE];
54 struct hash_block *mtree;
55 int mtree_block_count;
56 struct test_signature sig;
57 };
58
59 struct test_files_set {
60 struct test_file *files;
61 int files_count;
62 };
63
64 struct linux_dirent64 {
65 uint64_t d_ino;
66 int64_t d_off;
67 unsigned short d_reclen;
68 unsigned char d_type;
69 char d_name[0];
70 } __packed;
71
72 /*
73 * The certificate below and the private key were created by calling:
74 * openssl req -x509 -newkey rsa:4096 -keyout private.key -out cert.crt
75 * -days 1000 -sha256 -nodes -outform PEM -subj
76 * "/C=US/ST=WA/L=Kirkland/O=Example/OU=Org/CN=www.example.com"
77 */
78 char x509_cert[] =
79 "-----BEGIN CERTIFICATE-----\n"
80 "MIIFvzCCA6egAwIBAgIUXpwqelEljm6BBllRQGHLrls2MYgwDQYJKoZIhvcNAQEL\n"
81 "BQAwbzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcM\n"
82 "CEtpcmtsYW5kMRAwDgYDVQQKDAdFeGFtcGxlMQwwCgYDVQQLDANPcmcxGDAWBgNV\n"
83 "BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xOTA4MDgyMzA3MDZaFw0yMjA1MDQyMzA3\n"
84 "MDZaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMREwDwYDVQQH\n"
85 "DAhLaXJrbGFuZDEQMA4GA1UECgwHRXhhbXBsZTEMMAoGA1UECwwDT3JnMRgwFgYD\n"
86 "VQQDDA93d3cuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n"
87 "AoICAQC1LuFW/lDV/GflqFMz7RDvFFgWld982ZuDJRaK55JNj+MI4RZNL61PDw43\n"
88 "NeeJtqUoVxSLS9wHURjSjD/CV5GudUOnzGfbwFlLko+jhYRT4HNFS+5ys1FEJLtA\n"
89 "uYcY4P9GHQEXYUX+ue82A2kJ91oY6G3vCQYJFiGteb6TRDICmug31x4pBfB8rOdt\n"
90 "4/NXS/Dn+S0/mJlxw34IKfqrlFjzUziRZtAWWqDcfxFDUizSggkdXIUq4GY38RAD\n"
91 "qGewNNCab3ClJDP7/M32BhSNgsIKhgtSTM2+ocfvBhwup+BjV6UbL21DPAshlolV\n"
92 "gSL1HM2jin5bi4bpFMreY0LXwFih87/6AVSfQHY9TZrombVZnMxvB7NG1NCSwDBT\n"
93 "qjjFb3oiSMugJzY+MhISM754m46fwUyHZ1ylWCLJEU8kQ5A1q9vvqMcaDa4uTGP3\n"
94 "UgC6SyVmZxG2o+AO6m8TRTCtqHN41mPTM9HK4T1UyuzVpykSc2LlYkKE517SyEiV\n"
95 "XDmotNb2myXNYHHTjRYNxkq75Lbii2I4Q4z8XtDngaIrhZqACKSqIt2CocGjx61S\n"
96 "oxKWi+LGa7B4NaCMjz1LnaOIsXn1rJDRnUWL49T42g4kOi/5QaC2JDygfefw1hAb\n"
97 "uxkq9EYUDg+w9broltiBf4rKAnw8JMySARnyPZbj0lhZK3va5wIDAQABo1MwUTAd\n"
98 "BgNVHQ4EFgQUo6JN3gY2yGbzOTNj8Al7hNB3rw0wHwYDVR0jBBgwFoAUo6JN3gY2\n"
99 "yGbzOTNj8Al7hNB3rw0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
100 "AgEAQb3pJqOzM4whfNVdpEOswd1EApcWNM1ps9iTlEEjDoRv9F7F1PW0uXCIpk3B\n"
101 "j5JgCmIxAcPnzj42rduRSx421hHMZhbAIWI/JL4ZSF64qlG0YrmJDXlJgSMoyst5\n"
102 "biUqeWgO7Js5udPt3zhkeA62z3hGM6dE5B3k7gHTaKKtK17+UeR9imZKsOK8GBnM\n"
103 "rxMPI6XghxxAK2OQ/r09DHDiyf/GxgOE46oknfXfMPx3HaSvDKrZUTZ+UvVbM5c2\n"
104 "5eXOgH5UO/e4llLknJK7CoP/R6G7pV44iT4t4t9FMnvCYvavAHwfR+6z5vTF3o8a\n"
105 "wd80fC8z1vfLsIPLROdzBl9rGCvv536fPiEA677CM1AZkjfT0a9DVzrE1NDvuCUF\n"
106 "0KgEdiNwux+hO6dbTyiS38yPT6TbpoWJptJmFhFkC4hGvUgoX/TI0covSyf74VRH\n"
107 "k3BHojOBMYiX1K66xoN7fhlGK8cith3L0XXPB8CgSEUPWURvm8RCaGuX2T3FZomF\n"
108 "BCnNpN+WNnN3Yf4OkjtuvtxxktUU7pfVLsUxrdpo/ph4rWm6U83VT/Zlq92aF4vW\n"
109 "QJ+7uraQFip7e+Gy9g3UJINm3B7b1C4ch/Z/upCZESOI/23sVGzkfTgOrS+23i6/\n"
110 "Vi9YW75zySC2FCa1AWMS1NmS5qfDSycJUgD6YvOUg0C54ZI=\n"
111 "-----END CERTIFICATE-----";
112
113 char private_key[] =
114 "-----BEGIN PRIVATE KEY-----\n"
115 "MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC1LuFW/lDV/Gfl\n"
116 "qFMz7RDvFFgWld982ZuDJRaK55JNj+MI4RZNL61PDw43NeeJtqUoVxSLS9wHURjS\n"
117 "jD/CV5GudUOnzGfbwFlLko+jhYRT4HNFS+5ys1FEJLtAuYcY4P9GHQEXYUX+ue82\n"
118 "A2kJ91oY6G3vCQYJFiGteb6TRDICmug31x4pBfB8rOdt4/NXS/Dn+S0/mJlxw34I\n"
119 "KfqrlFjzUziRZtAWWqDcfxFDUizSggkdXIUq4GY38RADqGewNNCab3ClJDP7/M32\n"
120 "BhSNgsIKhgtSTM2+ocfvBhwup+BjV6UbL21DPAshlolVgSL1HM2jin5bi4bpFMre\n"
121 "Y0LXwFih87/6AVSfQHY9TZrombVZnMxvB7NG1NCSwDBTqjjFb3oiSMugJzY+MhIS\n"
122 "M754m46fwUyHZ1ylWCLJEU8kQ5A1q9vvqMcaDa4uTGP3UgC6SyVmZxG2o+AO6m8T\n"
123 "RTCtqHN41mPTM9HK4T1UyuzVpykSc2LlYkKE517SyEiVXDmotNb2myXNYHHTjRYN\n"
124 "xkq75Lbii2I4Q4z8XtDngaIrhZqACKSqIt2CocGjx61SoxKWi+LGa7B4NaCMjz1L\n"
125 "naOIsXn1rJDRnUWL49T42g4kOi/5QaC2JDygfefw1hAbuxkq9EYUDg+w9broltiB\n"
126 "f4rKAnw8JMySARnyPZbj0lhZK3va5wIDAQABAoICAQCMKul/0J2e/ncub6t2t4dr\n"
127 "PnTrfCT6xKqPqciny4Ee6hr9So1jR2gvink380bd/mQFMmEdZqGhM3cdpAzLf82f\n"
128 "hu7BSNxsYIF0er0PB4MZFMJ4sMaXC+zp5/TJnP5MG/zBND0c5k8tQpEyWy8O28Jj\n"
129 "FKW/0F5P90Q0ncP20EJUS50tXgniOMsU2Prtw/UE6yZDgD0mPxsurMu66ycXSFwM\n"
130 "WqyfqEeBk7lw/AjR6Sft71W31lTbl+DclG0MN2OIKUPcxiwCRmDFKI36MDgERk1x\n"
131 "sMPfdrWRLj2ryDFTUuLAWBTOVEGWS0RdRsWWVaJCuHbKd6FLl0TW2xQbOfWDTjYC\n"
132 "Ps31ejh163qdbk7OGOZIbd83fP3jsyL+4eNzhUpeXMKhfG58mFIv4yhdZIUOpuL6\n"
133 "aqnoU9z9wEsJKj/SrKr3nw6tuTnmbXgNjun9LfTFmqqDRBYd0Okiprw6jHNM1jgA\n"
134 "GG0kC/K7r89jKymVDABwGMFCS33ynR1Tb6zG+cqgNMPw19Fy3uQuW21CjqSzCOyP\n"
135 "aEVCEUZeP+ofql5+7ZKi6Dj+EdTfeKt2ihgheHZZoaYSINb8tsnKbdJhwBfW9PFT\n"
136 "aT/hu3bnO2FPC8H2NGOqxOEeel9ALU4SFu1pOknEhiL3/mNfOQ+KgrSRDtNRlcL0\n"
137 "cto05J90u0cmqwWKlshfaQKCAQEA5dcklxs4ezyzt28NcsiyS02oZ+9TkQp6pCXV\n"
138 "kx7AwhivAmVTlJ+c6BegA5EPd7A1gknM3+EKzGpoBOqmlF45G57phVIAphAp4oCH\n"
139 "UOVtIQgM8p4EU2gtX+uNOopdYlpBQnWimXaHA2sOD9/yTbZ03j/McRH6D15+iCld\n"
140 "3880GHdZaYYbQmHoSDg39LRRO1bdS3WC0oKBD2gPi3K0b9RaZSwKzuVrmlvrLURj\n"
141 "WMZfmkGl4BsITfuoTxbWFVncG3Kb9eYkYUFZy4M2G/s849PS/HjrN7BvgpanjtVp\n"
142 "1/39APQfAYfUuBPbKYnb6F8dE0pb5cVd4uMZklAeTb3bXjOO9QKCAQEAyc4CxWXr\n"
143 "bG6Do5dGpWudQ7ucq00MR0T3MHQIu5XTn6BsPHAJ9ZgrQw9C24PXm2VEjjsrMs5T\n"
144 "rHNF9oeO39s25Za1iyJ+893icqA3h3ivCUOOoVE54BkuJK6REhkXPD5G1ubmxeBz\n"
145 "MKNehlpd/eSbJJArkzKFZ8sBtLt8i9VFhRnXSpDAbiMpCbjW+bem9MWdLmkenSnu\n"
146 "OUbnqYcJhFBCvOT7ZCHFCDNUNPfHcaReSY2EYjw0ZqtqAZD0Q+DL+RkLz7l1+/bF\n"
147 "eEwNjmjFTcwRyawqf38D4miU0H6ca16FkeSlbmM5p3HdwZK2HVYYz3FSwhox6Ebd\n"
148 "n6in42qfL4Ug6wKCAQAh9IDRWhIkErmyNdPUy1WbzmM8x5ye5t9rdLNywq5TfnYM\n"
149 "co/AezwhBax8GmgglIWzM9fykzqXLHklkMz/SlRBgl6ZdZ3m6qhlb/uNtfdDU/8l\n"
150 "sLaO4+sgKpp4tYxKRW8ytFJLPbmAhcZUDg+r73KgiuhXJAK/VoR29TWLJP9bRfaN\n"
151 "omRQkEpSsQuDOUhu7cxPo5KqKuGKNyNkxJNnmgWowLLwEfCtozrBO0M6EER7c4tf\n"
152 "6l51tuIMnSEPknD0FSB5WYCyZYcwi7fotlsuhVK8PdjyJzyyHDOw5FJ4uGsyQt55\n"
153 "yWlhsH1GS7mTQMn42Zlt/pR6OnbCqNdxQMUxy4gpAoIBAFvMbs5E0pb8nr0n72cI\n"
154 "UP2itl3mKpOw95D+94n9WcrfOt0zShSCKAvVQWCB1O5HXqwklj4CRWXI+iZu+7sx\n"
155 "CQPfTq3//ygH4x6paxkg+N6J8LPJMz6Rtb/R+QP2je9FlQvk9U1GEKArcLBFI0R/\n"
156 "XWOAgZHwBWd1nU0NjFY/qeQmIR02Q5LWQ7C8eG4X8MafriSShO6RSGCdtHwVhWq+\n"
157 "59ztfL3L7skQMFn37K3xS0LCMVpOcLfTeeFEgxjthVvG3OydPOJlGubiEbiaSEZf\n"
158 "cif/PUXKDYZMdIVzUsw0ryXykJ5qXKuizHFlv5oQtDCJKFBLgjBbLC2YluaIdekz\n"
159 "8gkCggEBAJWxS7EuB/qL7fOz0o3HRy0plR3qbwZ0pLoCz0Ii7WxraBS1yQwmxif1\n"
160 "Rgv89GyFqg1yQl3CSrMiw7oC9WxxxuiEZDO18c4KO3NTv9K4itN9OPQVBTHmEhod\n"
161 "KWcyP4/W/Sfuae77PyclSqUsAARRrKYn2fpLTS5ibaU0QZgHmdPgYDUrPr+6PHKK\n"
162 "ZfQKU2uBfuo6zoMbMmFi3UYG49j9rv4d6v+44vS1MPHV9JK/LD8YfBhgx8Pg/u6D\n"
163 "nUgipS48pkGjJr2u2Vu7Mx70vqz0Yf2neyyDbdLtkYauC4w7YKPTD0yzDJyGuAeB\n"
164 "GyPbW1yZa5vE302a1Cr0Cd7RC4AFAAw=\n"
165 "-----END PRIVATE KEY-----";
166
get_test_files_set(void)167 struct test_files_set get_test_files_set(void)
168 {
169 static struct test_file files[] = {
170 { .index = 0, .name = "file_one_byte", .size = 1 },
171 { .index = 1,
172 .name = "file_one_block",
173 .size = INCFS_DATA_FILE_BLOCK_SIZE },
174 { .index = 2,
175 .name = "file_one_and_a_half_blocks",
176 .size = INCFS_DATA_FILE_BLOCK_SIZE +
177 INCFS_DATA_FILE_BLOCK_SIZE / 2 },
178 { .index = 3,
179 .name = "file_three",
180 .size = 300 * INCFS_DATA_FILE_BLOCK_SIZE + 3 },
181 { .index = 4,
182 .name = "file_four",
183 .size = 400 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
184 { .index = 5,
185 .name = "file_five",
186 .size = 500 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
187 { .index = 6,
188 .name = "file_six",
189 .size = 600 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
190 { .index = 7,
191 .name = "file_seven",
192 .size = 700 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
193 { .index = 8,
194 .name = "file_eight",
195 .size = 800 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
196 { .index = 9,
197 .name = "file_nine",
198 .size = 900 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
199 { .index = 10, .name = "file_big", .size = 500 * 1024 * 1024 }
200 };
201 return (struct test_files_set){ .files = files,
202 .files_count = ARRAY_SIZE(files) };
203 }
204
get_small_test_files_set(void)205 struct test_files_set get_small_test_files_set(void)
206 {
207 static struct test_file files[] = {
208 { .index = 0, .name = "file_one_byte", .size = 1 },
209 { .index = 1,
210 .name = "file_one_block",
211 .size = INCFS_DATA_FILE_BLOCK_SIZE },
212 { .index = 2,
213 .name = "file_one_and_a_half_blocks",
214 .size = INCFS_DATA_FILE_BLOCK_SIZE +
215 INCFS_DATA_FILE_BLOCK_SIZE / 2 },
216 { .index = 3,
217 .name = "file_three",
218 .size = 300 * INCFS_DATA_FILE_BLOCK_SIZE + 3 },
219 { .index = 4,
220 .name = "file_four",
221 .size = 400 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }
222 };
223 return (struct test_files_set){ .files = files,
224 .files_count = ARRAY_SIZE(files) };
225 }
226
get_file_block_seed(int file,int block)227 static int get_file_block_seed(int file, int block)
228 {
229 return 7919 * file + block;
230 }
231
min(loff_t a,loff_t b)232 static loff_t min(loff_t a, loff_t b)
233 {
234 return a < b ? a : b;
235 }
236
flush_and_fork(void)237 static pid_t flush_and_fork(void)
238 {
239 fflush(stdout);
240 return fork();
241 }
242
print_error(char * msg)243 static void print_error(char *msg)
244 {
245 ksft_print_msg("%s: %s\n", msg, strerror(errno));
246 }
247
wait_for_process(pid_t pid)248 static int wait_for_process(pid_t pid)
249 {
250 int status;
251 int wait_res;
252
253 wait_res = waitpid(pid, &status, 0);
254 if (wait_res <= 0) {
255 print_error("Can't wait for the child");
256 return -EINVAL;
257 }
258 if (!WIFEXITED(status)) {
259 ksft_print_msg("Unexpected child status pid=%d\n", pid);
260 return -EINVAL;
261 }
262 status = WEXITSTATUS(status);
263 if (status != 0)
264 return status;
265 return 0;
266 }
267
rnd_buf(uint8_t * data,size_t len,unsigned int seed)268 static void rnd_buf(uint8_t *data, size_t len, unsigned int seed)
269 {
270 int i;
271
272 for (i = 0; i < len; i++) {
273 seed = 1103515245 * seed + 12345;
274 data[i] = (uint8_t)(seed >> (i % 13));
275 }
276 }
277
bin2hex(char * dst,const void * src,size_t count)278 char *bin2hex(char *dst, const void *src, size_t count)
279 {
280 const unsigned char *_src = src;
281 static const char hex_asc[] = "0123456789abcdef";
282
283 while (count--) {
284 unsigned char x = *_src++;
285
286 *dst++ = hex_asc[(x & 0xf0) >> 4];
287 *dst++ = hex_asc[(x & 0x0f)];
288 }
289 *dst = 0;
290 return dst;
291 }
292
get_index_filename(char * mnt_dir,incfs_uuid_t id)293 static char *get_index_filename(char *mnt_dir, incfs_uuid_t id)
294 {
295 char path[FILENAME_MAX];
296 char str_id[1 + 2 * sizeof(id)];
297
298 bin2hex(str_id, id.bytes, sizeof(id.bytes));
299 snprintf(path, ARRAY_SIZE(path), "%s/.index/%s", mnt_dir, str_id);
300
301 return strdup(path);
302 }
303
open_file_by_id(char * mnt_dir,incfs_uuid_t id)304 int open_file_by_id(char *mnt_dir, incfs_uuid_t id)
305 {
306 char *path = get_index_filename(mnt_dir, id);
307 int fd = open(path, O_RDWR);
308
309 free(path);
310 if (fd < 0) {
311 print_error("Can't open file by id.");
312 return -errno;
313 }
314
315 return fd;
316 }
317
get_file_attr(char * mnt_dir,incfs_uuid_t id,char * value,int size)318 int get_file_attr(char *mnt_dir, incfs_uuid_t id, char *value, int size)
319 {
320 char *path = get_index_filename(mnt_dir, id);
321 int res;
322
323 res = getxattr(path, INCFS_XATTR_METADATA_NAME, value, size);
324 if (res < 0)
325 res = -errno;
326
327 free(path);
328 return res;
329 }
330
same_id(incfs_uuid_t * id1,incfs_uuid_t * id2)331 static bool same_id(incfs_uuid_t *id1, incfs_uuid_t *id2)
332 {
333 return !memcmp(id1->bytes, id2->bytes, sizeof(id1->bytes));
334 }
335
emit_test_blocks(char * mnt_dir,struct test_file * file,int blocks[],int count)336 static int emit_test_blocks(char *mnt_dir, struct test_file *file,
337 int blocks[], int count)
338 {
339 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
340 uint8_t comp_data[2 * INCFS_DATA_FILE_BLOCK_SIZE];
341 int block_count = (count > 32) ? 32 : count;
342 int data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE * block_count;
343 uint8_t *data_buf = malloc(data_buf_size);
344 uint8_t *current_data = data_buf;
345 uint8_t *data_end = data_buf + data_buf_size;
346 struct incfs_new_data_block *block_buf =
347 calloc(block_count, sizeof(*block_buf));
348 ssize_t write_res = 0;
349 int fd;
350 int error = 0;
351 int i = 0;
352 int blocks_written = 0;
353
354 fd = open_file_by_id(mnt_dir, file->id);
355 if (fd <= 0) {
356 error = -errno;
357 goto out;
358 }
359
360 for (i = 0; i < block_count; i++) {
361 int block_index = blocks[i];
362 bool compress = (file->index + block_index) % 2 == 0;
363 int seed = get_file_block_seed(file->index, block_index);
364 off_t block_offset =
365 ((off_t)block_index) * INCFS_DATA_FILE_BLOCK_SIZE;
366 size_t block_size = 0;
367
368 if (block_offset > file->size) {
369 error = -EINVAL;
370 break;
371 }
372 if (file->size - block_offset >
373 INCFS_DATA_FILE_BLOCK_SIZE)
374 block_size = INCFS_DATA_FILE_BLOCK_SIZE;
375 else
376 block_size = file->size - block_offset;
377
378 rnd_buf(data, block_size, seed);
379 if (compress) {
380 size_t comp_size = LZ4_compress_default(
381 (char *)data, (char *)comp_data, block_size,
382 ARRAY_SIZE(comp_data));
383
384 if (comp_size <= 0) {
385 error = -EBADMSG;
386 break;
387 }
388 if (current_data + comp_size > data_end) {
389 error = -ENOMEM;
390 break;
391 }
392 memcpy(current_data, comp_data, comp_size);
393 block_size = comp_size;
394 block_buf[i].compression = COMPRESSION_LZ4;
395 } else {
396 if (current_data + block_size > data_end) {
397 error = -ENOMEM;
398 break;
399 }
400 memcpy(current_data, data, block_size);
401 block_buf[i].compression = COMPRESSION_NONE;
402 }
403
404 block_buf[i].block_index = block_index;
405 block_buf[i].data_len = block_size;
406 block_buf[i].data = ptr_to_u64(current_data);
407 block_buf[i].compression =
408 compress ? COMPRESSION_LZ4 : COMPRESSION_NONE;
409 current_data += block_size;
410 }
411
412 if (!error) {
413 write_res = write(fd, block_buf, sizeof(*block_buf) * i);
414 if (write_res < 0)
415 error = -errno;
416 else
417 blocks_written = write_res / sizeof(*block_buf);
418 }
419 if (error) {
420 ksft_print_msg(
421 "Writing data block error. Write returned: %d. Error:%s\n",
422 write_res, strerror(-error));
423 }
424
425 out:
426 free(block_buf);
427 free(data_buf);
428 close(fd);
429 return (error < 0) ? error : blocks_written;
430 }
431
emit_test_block(char * mnt_dir,struct test_file * file,int block_index)432 static int emit_test_block(char *mnt_dir, struct test_file *file,
433 int block_index)
434 {
435 int res = emit_test_blocks(mnt_dir, file, &block_index, 1);
436
437 if (res == 0)
438 return -EINVAL;
439 if (res == 1)
440 return 0;
441 return res;
442 }
443
shuffle(int array[],int count,unsigned int seed)444 static void shuffle(int array[], int count, unsigned int seed)
445 {
446 int i;
447
448 for (i = 0; i < count - 1; i++) {
449 int items_left = count - i;
450 int shuffle_index;
451 int v;
452
453 seed = 1103515245 * seed + 12345;
454 shuffle_index = i + seed % items_left;
455
456 v = array[shuffle_index];
457 array[shuffle_index] = array[i];
458 array[i] = v;
459 }
460 }
461
emit_test_file_data(char * mount_dir,struct test_file * file)462 static int emit_test_file_data(char *mount_dir, struct test_file *file)
463 {
464 int i;
465 int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
466 int *block_indexes = NULL;
467 int result = 0;
468 int blocks_written = 0;
469
470 if (file->size == 0)
471 return 0;
472
473 block_indexes = calloc(block_cnt, sizeof(*block_indexes));
474 for (i = 0; i < block_cnt; i++)
475 block_indexes[i] = i;
476 shuffle(block_indexes, block_cnt, file->index);
477
478 for (i = 0; i < block_cnt; i += blocks_written) {
479 blocks_written = emit_test_blocks(mount_dir, file,
480 block_indexes + i, block_cnt - i);
481 if (blocks_written < 0) {
482 result = blocks_written;
483 goto out;
484 }
485 if (blocks_written == 0) {
486 result = -EIO;
487 goto out;
488 }
489 }
490 out:
491 free(block_indexes);
492 return result;
493 }
494
read_whole_file(char * filename)495 static loff_t read_whole_file(char *filename)
496 {
497 int fd = -1;
498 loff_t result;
499 loff_t bytes_read = 0;
500 uint8_t buff[16 * 1024];
501
502 fd = open(filename, O_RDONLY);
503 if (fd <= 0)
504 return fd;
505
506 while (1) {
507 int read_result = read(fd, buff, ARRAY_SIZE(buff));
508
509 if (read_result < 0) {
510 print_error("Error during reading from a file.");
511 result = -errno;
512 goto cleanup;
513 } else if (read_result == 0)
514 break;
515
516 bytes_read += read_result;
517 }
518 result = bytes_read;
519
520 cleanup:
521 close(fd);
522 return result;
523 }
524
read_test_file(uint8_t * buf,size_t len,char * filename,int block_idx)525 static int read_test_file(uint8_t *buf, size_t len, char *filename,
526 int block_idx)
527 {
528 int fd = -1;
529 int result;
530 int bytes_read = 0;
531 size_t bytes_to_read = len;
532 off_t offset = ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE;
533
534 fd = open(filename, O_RDONLY);
535 if (fd <= 0)
536 return fd;
537
538 if (lseek(fd, offset, SEEK_SET) != offset) {
539 print_error("Seek error");
540 return -errno;
541 }
542
543 while (bytes_read < bytes_to_read) {
544 int read_result =
545 read(fd, buf + bytes_read, bytes_to_read - bytes_read);
546 if (read_result < 0) {
547 result = -errno;
548 goto cleanup;
549 } else if (read_result == 0)
550 break;
551
552 bytes_read += read_result;
553 }
554 result = bytes_read;
555
556 cleanup:
557 close(fd);
558 return result;
559 }
560
create_backing_dir(char * mount_dir)561 static char *create_backing_dir(char *mount_dir)
562 {
563 struct stat st;
564 char backing_dir_name[255];
565
566 snprintf(backing_dir_name, ARRAY_SIZE(backing_dir_name), "%s-src",
567 mount_dir);
568
569 if (stat(backing_dir_name, &st) == 0) {
570 if (S_ISDIR(st.st_mode)) {
571 int error = delete_dir_tree(backing_dir_name);
572
573 if (error) {
574 ksft_print_msg(
575 "Can't delete existing backing dir. %d\n",
576 error);
577 return NULL;
578 }
579 } else {
580 if (unlink(backing_dir_name)) {
581 print_error("Can't clear backing dir");
582 return NULL;
583 }
584 }
585 }
586
587 if (mkdir(backing_dir_name, 0777)) {
588 if (errno != EEXIST) {
589 print_error("Can't open/create backing dir");
590 return NULL;
591 }
592 }
593
594 return strdup(backing_dir_name);
595 }
596
validate_test_file_content_with_seed(char * mount_dir,struct test_file * file,unsigned int shuffle_seed)597 static int validate_test_file_content_with_seed(char *mount_dir,
598 struct test_file *file,
599 unsigned int shuffle_seed)
600 {
601 int error = -1;
602 char *filename = concat_file_name(mount_dir, file->name);
603 off_t size = file->size;
604 loff_t actual_size = get_file_size(filename);
605 int block_cnt = 1 + (size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
606 int *block_indexes = NULL;
607 int i;
608
609 block_indexes = alloca(sizeof(int) * block_cnt);
610 for (i = 0; i < block_cnt; i++)
611 block_indexes[i] = i;
612
613 if (shuffle_seed != 0)
614 shuffle(block_indexes, block_cnt, shuffle_seed);
615
616 if (actual_size != size) {
617 ksft_print_msg(
618 "File size doesn't match. name: %s expected size:%ld actual size:%ld\n",
619 filename, size, actual_size);
620 error = -1;
621 goto failure;
622 }
623
624 for (i = 0; i < block_cnt; i++) {
625 int block_idx = block_indexes[i];
626 uint8_t expected_block[INCFS_DATA_FILE_BLOCK_SIZE];
627 uint8_t actual_block[INCFS_DATA_FILE_BLOCK_SIZE];
628 int seed = get_file_block_seed(file->index, block_idx);
629 size_t bytes_to_compare = min(
630 (off_t)INCFS_DATA_FILE_BLOCK_SIZE,
631 size - ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE);
632 int read_result =
633 read_test_file(actual_block, INCFS_DATA_FILE_BLOCK_SIZE,
634 filename, block_idx);
635 if (read_result < 0) {
636 ksft_print_msg(
637 "Error reading block %d from file %s. Error: %s\n",
638 block_idx, filename, strerror(-read_result));
639 error = read_result;
640 goto failure;
641 }
642 rnd_buf(expected_block, INCFS_DATA_FILE_BLOCK_SIZE, seed);
643 if (memcmp(expected_block, actual_block, bytes_to_compare)) {
644 ksft_print_msg(
645 "File contents don't match. name: %s block:%d\n",
646 file->name, block_idx);
647 error = -2;
648 goto failure;
649 }
650 }
651 free(filename);
652 return 0;
653
654 failure:
655 free(filename);
656 return error;
657 }
658
validate_test_file_content(char * mount_dir,struct test_file * file)659 static int validate_test_file_content(char *mount_dir, struct test_file *file)
660 {
661 return validate_test_file_content_with_seed(mount_dir, file, 0);
662 }
663
data_producer(char * mount_dir,struct test_files_set * test_set)664 static int data_producer(char *mount_dir, struct test_files_set *test_set)
665 {
666 int ret = 0;
667 int timeout_ms = 1000;
668 struct incfs_pending_read_info prs[100] = {};
669 int prs_size = ARRAY_SIZE(prs);
670 int fd = open_commands_file(mount_dir);
671
672 if (fd < 0)
673 return -errno;
674
675 while ((ret = wait_for_pending_reads(fd, timeout_ms, prs, prs_size)) >
676 0) {
677 int read_count = ret;
678 int i;
679
680 for (i = 0; i < read_count; i++) {
681 int j = 0;
682 struct test_file *file = NULL;
683
684 for (j = 0; j < test_set->files_count; j++) {
685 bool same = same_id(&(test_set->files[j].id),
686 &(prs[i].file_id));
687
688 if (same) {
689 file = &test_set->files[j];
690 break;
691 }
692 }
693 if (!file) {
694 ksft_print_msg(
695 "Unknown file in pending reads.\n");
696 break;
697 }
698
699 ret = emit_test_block(mount_dir, file,
700 prs[i].block_index);
701 if (ret < 0) {
702 ksft_print_msg("Emitting test data error: %s\n",
703 strerror(-ret));
704 break;
705 }
706 }
707 }
708 close(fd);
709 return ret;
710 }
711
build_mtree(struct test_file * file)712 static int build_mtree(struct test_file *file)
713 {
714 char data[INCFS_DATA_FILE_BLOCK_SIZE] = {};
715 const int digest_size = SHA256_DIGEST_SIZE;
716 const int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
717 int block_count = 0;
718 int hash_block_count = 0;
719 int total_tree_block_count = 0;
720 int tree_lvl_index[INCFS_MAX_MTREE_LEVELS] = {};
721 int tree_lvl_count[INCFS_MAX_MTREE_LEVELS] = {};
722 int levels_count = 0;
723 char data_to_sign[256] = {};
724 int sig_data_size;
725 int i, level;
726
727 if (file->size == 0)
728 return 0;
729
730 block_count = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
731 hash_block_count = block_count;
732 for (i = 0; hash_block_count > 1; i++) {
733 hash_block_count = (hash_block_count + hash_per_block - 1)
734 / hash_per_block;
735 tree_lvl_count[i] = hash_block_count;
736 total_tree_block_count += hash_block_count;
737 }
738 levels_count = i;
739
740 for (i = 0; i < levels_count; i++) {
741 int prev_lvl_base = (i == 0) ? total_tree_block_count :
742 tree_lvl_index[i - 1];
743
744 tree_lvl_index[i] = prev_lvl_base - tree_lvl_count[i];
745 }
746
747 file->mtree_block_count = total_tree_block_count;
748 if (block_count == 1) {
749 int seed = get_file_block_seed(file->index, 0);
750
751 rnd_buf((uint8_t *)data, file->size, seed);
752 sha256(data, file->size, file->root_hash);
753 return 0;
754 }
755
756 file->mtree = calloc(total_tree_block_count, sizeof(*file->mtree));
757 /* Build level 0 hashes. */
758 for (i = 0; i < block_count; i++) {
759 off_t offset = i * INCFS_DATA_FILE_BLOCK_SIZE;
760 size_t block_size = INCFS_DATA_FILE_BLOCK_SIZE;
761 int block_index = tree_lvl_index[0] +
762 i / hash_per_block;
763 int block_off = (i % hash_per_block) * digest_size;
764 int seed = get_file_block_seed(file->index, i);
765 char *hash_ptr = file->mtree[block_index].data + block_off;
766
767 if (file->size - offset < block_size)
768 block_size = file->size - offset;
769
770 rnd_buf((uint8_t *)data, block_size, seed);
771 sha256(data, block_size, hash_ptr);
772 }
773
774 /* Build higher levels of hash tree. */
775 for (level = 1; level < levels_count; level++) {
776 int prev_lvl_base = tree_lvl_index[level - 1];
777 int prev_lvl_count = tree_lvl_count[level - 1];
778
779 for (i = 0; i < prev_lvl_count; i++) {
780 int block_index =
781 i / hash_per_block + tree_lvl_index[level];
782 int block_off = (i % hash_per_block) * digest_size;
783 char *hash_ptr =
784 file->mtree[block_index].data + block_off;
785
786 sha256(file->mtree[i + prev_lvl_base].data,
787 INCFS_DATA_FILE_BLOCK_SIZE, hash_ptr);
788 }
789 }
790
791 /* Calculate root hash from the top block */
792 sha256(file->mtree[0].data,
793 INCFS_DATA_FILE_BLOCK_SIZE, file->root_hash);
794
795 /* Calculating digital signature */
796 snprintf(file->sig.add_data, sizeof(file->sig.add_data), "%ld",
797 file->size);
798 memcpy(data_to_sign, file->root_hash, SHA256_DIGEST_SIZE);
799 memcpy(data_to_sign + SHA256_DIGEST_SIZE, file->sig.add_data,
800 strlen(file->sig.add_data));
801 sig_data_size = SHA256_DIGEST_SIZE + strlen(file->sig.add_data);
802 if (!sign_pkcs7(data_to_sign, sig_data_size, private_key, x509_cert,
803 &file->sig.data, &file->sig.size)) {
804 ksft_print_msg("Signing failed.\n");
805 return -EINVAL;
806 }
807
808 return 0;
809 }
810
load_hash_tree(const char * mount_dir,struct test_file * file)811 static int load_hash_tree(const char *mount_dir, struct test_file *file)
812 {
813 int err;
814 int i;
815 int fd;
816
817 size_t blocks_size =
818 file->mtree_block_count * sizeof(struct incfs_new_data_block);
819 struct incfs_new_data_block *blocks = NULL;
820 char *file_path;
821
822 if (blocks_size == 0)
823 return 0;
824
825 blocks = malloc(blocks_size);
826 if (!blocks)
827 return -ENOMEM;
828
829 for (i = 0; i < file->mtree_block_count; i++) {
830 blocks[i] = (struct incfs_new_data_block){
831 .block_index = i,
832 .data_len = INCFS_DATA_FILE_BLOCK_SIZE,
833 .data = ptr_to_u64(file->mtree[i].data),
834 .flags = INCFS_BLOCK_FLAGS_HASH
835 };
836 }
837
838 file_path = concat_file_name(mount_dir, file->name);
839 fd = open(file_path, O_RDWR);
840 free(file_path);
841 if (fd < 0) {
842 err = errno;
843 goto failure;
844 }
845
846 err = write(fd, blocks, blocks_size);
847 close(fd);
848
849 if (err < blocks_size)
850 err = errno;
851 else {
852 err = 0;
853 free(file->mtree);
854 }
855
856 failure:
857 free(blocks);
858 return err;
859 }
860
cant_touch_index_test(char * mount_dir)861 static int cant_touch_index_test(char *mount_dir)
862 {
863 char *file_name = "test_file";
864 int file_size = 123;
865 incfs_uuid_t file_id;
866 char *index_path = concat_file_name(mount_dir, ".index");
867 char *subdir = concat_file_name(index_path, "subdir");
868 char *dst_name = concat_file_name(mount_dir, "something");
869 char *filename_in_index = NULL;
870 char *file_path = concat_file_name(mount_dir, file_name);
871 char *backing_dir;
872 int cmd_fd = -1;
873 int err;
874
875 backing_dir = create_backing_dir(mount_dir);
876 if (!backing_dir)
877 goto failure;
878
879 /* Mount FS and release the backing file. */
880 if (mount_fs(mount_dir, backing_dir, 50) != 0)
881 goto failure;
882 free(backing_dir);
883
884 cmd_fd = open_commands_file(mount_dir);
885 if (cmd_fd < 0)
886 goto failure;
887
888
889 err = mkdir(subdir, 0777);
890 if (err == 0 || errno != EBUSY) {
891 print_error("Shouldn't be able to crate subdir in index\n");
892 goto failure;
893 }
894
895 err = emit_file(cmd_fd, ".index", file_name, &file_id,
896 file_size, NULL);
897 if (err != -EBUSY) {
898 print_error("Shouldn't be able to crate a file in index\n");
899 goto failure;
900 }
901
902 err = emit_file(cmd_fd, NULL, file_name, &file_id,
903 file_size, NULL);
904 if (err < 0)
905 goto failure;
906 filename_in_index = get_index_filename(mount_dir, file_id);
907
908 err = unlink(filename_in_index);
909 if (err == 0 || errno != EBUSY) {
910 print_error("Shouldn't be delete from index\n");
911 goto failure;
912 }
913
914
915 err = rename(filename_in_index, dst_name);
916 if (err == 0 || errno != EBUSY) {
917 print_error("Shouldn't be able to move from index\n");
918 goto failure;
919 }
920
921 free(filename_in_index);
922 filename_in_index = concat_file_name(index_path, "abc");
923 err = link(file_path, filename_in_index);
924 if (err == 0 || errno != EBUSY) {
925 print_error("Shouldn't be able to link inside index\n");
926 goto failure;
927 }
928
929 close(cmd_fd);
930 free(subdir);
931 free(index_path);
932 free(dst_name);
933 free(filename_in_index);
934 if (umount(mount_dir) != 0) {
935 print_error("Can't unmout FS");
936 goto failure;
937 }
938
939 return TEST_SUCCESS;
940
941 failure:
942 free(subdir);
943 free(dst_name);
944 free(index_path);
945 free(filename_in_index);
946 close(cmd_fd);
947 umount(mount_dir);
948 return TEST_FAILURE;
949 }
950
iterate_directory(char * dir_to_iterate,bool root,int file_count)951 static bool iterate_directory(char *dir_to_iterate, bool root, int file_count)
952 {
953 struct expected_name {
954 const char *name;
955 bool root_only;
956 bool found;
957 } names[] = {
958 {INCFS_LOG_FILENAME, true, false},
959 {INCFS_PENDING_READS_FILENAME, true, false},
960 {".index", true, false},
961 {"..", false, false},
962 {".", false, false},
963 };
964
965 bool pass = true, found;
966 int i;
967
968 /* Test directory iteration */
969 int fd = open(dir_to_iterate, O_RDONLY | O_DIRECTORY);
970
971 if (fd < 0) {
972 print_error("Can't open directory\n");
973 return false;
974 }
975
976 for (;;) {
977 /* Enough space for one dirent - no name over 30 */
978 char buf[sizeof(struct linux_dirent64) + NAME_MAX];
979 struct linux_dirent64 *dirent = (struct linux_dirent64 *) buf;
980 int nread;
981 int i;
982
983 for (i = 0; i < NAME_MAX; ++i) {
984 nread = syscall(__NR_getdents64, fd, buf,
985 sizeof(struct linux_dirent64) + i);
986
987 if (nread >= 0)
988 break;
989 if (errno != EINVAL)
990 break;
991 }
992
993 if (nread == 0)
994 break;
995 if (nread < 0) {
996 print_error("Error iterating directory\n");
997 pass = false;
998 goto failure;
999 }
1000
1001 /* Expected size is rounded up to 8 byte boundary. Not sure if
1002 * this is universal truth or just happenstance, but useful test
1003 * for the moment
1004 */
1005 if (nread != (((sizeof(struct linux_dirent64)
1006 + strlen(dirent->d_name) + 1) + 7) & ~7)) {
1007 print_error("Wrong dirent size");
1008 pass = false;
1009 goto failure;
1010 }
1011
1012 found = false;
1013 for (i = 0; i < sizeof(names) / sizeof(*names); ++i)
1014 if (!strcmp(dirent->d_name, names[i].name)) {
1015 if (names[i].root_only && !root) {
1016 print_error("Root file error");
1017 pass = false;
1018 goto failure;
1019 }
1020
1021 if (names[i].found) {
1022 print_error("File appears twice");
1023 pass = false;
1024 goto failure;
1025 }
1026
1027 names[i].found = true;
1028 found = true;
1029 break;
1030 }
1031
1032 if (!found)
1033 --file_count;
1034 }
1035
1036 for (i = 0; i < sizeof(names) / sizeof(*names); ++i) {
1037 if (!names[i].found)
1038 if (root || !names[i].root_only) {
1039 print_error("Expected file not present");
1040 pass = false;
1041 goto failure;
1042 }
1043 }
1044
1045 if (file_count) {
1046 print_error("Wrong number of files\n");
1047 pass = false;
1048 goto failure;
1049 }
1050
1051 failure:
1052 close(fd);
1053 return pass;
1054 }
1055
basic_file_ops_test(char * mount_dir)1056 static int basic_file_ops_test(char *mount_dir)
1057 {
1058 struct test_files_set test = get_test_files_set();
1059 const int file_num = test.files_count;
1060 char *subdir1 = concat_file_name(mount_dir, "subdir1");
1061 char *subdir2 = concat_file_name(mount_dir, "subdir2");
1062 char *backing_dir;
1063 int cmd_fd = -1;
1064 int i, err;
1065
1066 backing_dir = create_backing_dir(mount_dir);
1067 if (!backing_dir)
1068 goto failure;
1069
1070 /* Mount FS and release the backing file. */
1071 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1072 goto failure;
1073 free(backing_dir);
1074
1075 cmd_fd = open_commands_file(mount_dir);
1076 if (cmd_fd < 0)
1077 goto failure;
1078
1079 err = mkdir(subdir1, 0777);
1080 if (err < 0 && errno != EEXIST) {
1081 print_error("Can't create subdir1\n");
1082 goto failure;
1083 }
1084
1085 err = mkdir(subdir2, 0777);
1086 if (err < 0 && errno != EEXIST) {
1087 print_error("Can't create subdir2\n");
1088 goto failure;
1089 }
1090
1091 /* Create all test files in subdir1 directory */
1092 for (i = 0; i < file_num; i++) {
1093 struct test_file *file = &test.files[i];
1094 loff_t size;
1095 char *file_path = concat_file_name(subdir1, file->name);
1096
1097 err = emit_file(cmd_fd, "subdir1", file->name, &file->id,
1098 file->size, NULL);
1099 if (err < 0)
1100 goto failure;
1101
1102 size = get_file_size(file_path);
1103 free(file_path);
1104 if (size != file->size) {
1105 ksft_print_msg("Wrong size %lld of %s.\n",
1106 size, file->name);
1107 goto failure;
1108 }
1109 }
1110
1111 if (!iterate_directory(subdir1, false, file_num))
1112 goto failure;
1113
1114 /* Link the files to subdir2 */
1115 for (i = 0; i < file_num; i++) {
1116 struct test_file *file = &test.files[i];
1117 char *src_name = concat_file_name(subdir1, file->name);
1118 char *dst_name = concat_file_name(subdir2, file->name);
1119 loff_t size;
1120
1121 err = link(src_name, dst_name);
1122 if (err < 0) {
1123 print_error("Can't move file\n");
1124 goto failure;
1125 }
1126
1127 size = get_file_size(dst_name);
1128 if (size != file->size) {
1129 ksft_print_msg("Wrong size %lld of %s.\n",
1130 size, file->name);
1131 goto failure;
1132 }
1133 free(src_name);
1134 free(dst_name);
1135 }
1136
1137 /* Move the files from subdir2 to the mount dir */
1138 for (i = 0; i < file_num; i++) {
1139 struct test_file *file = &test.files[i];
1140 char *src_name = concat_file_name(subdir2, file->name);
1141 char *dst_name = concat_file_name(mount_dir, file->name);
1142 loff_t size;
1143
1144 err = rename(src_name, dst_name);
1145 if (err < 0) {
1146 print_error("Can't move file\n");
1147 goto failure;
1148 }
1149
1150 size = get_file_size(dst_name);
1151 if (size != file->size) {
1152 ksft_print_msg("Wrong size %lld of %s.\n",
1153 size, file->name);
1154 goto failure;
1155 }
1156 free(src_name);
1157 free(dst_name);
1158 }
1159
1160 /* +2 because there are 2 subdirs */
1161 if (!iterate_directory(mount_dir, true, file_num + 2))
1162 goto failure;
1163
1164 /* Open and close all files from the mount dir */
1165 for (i = 0; i < file_num; i++) {
1166 struct test_file *file = &test.files[i];
1167 char *path = concat_file_name(mount_dir, file->name);
1168 int fd;
1169
1170 fd = open(path, O_RDWR);
1171 free(path);
1172 if (fd <= 0) {
1173 print_error("Can't open file");
1174 goto failure;
1175 }
1176 if (close(fd)) {
1177 print_error("Can't close file");
1178 goto failure;
1179 }
1180 }
1181
1182 /* Delete all files from the mount dir */
1183 for (i = 0; i < file_num; i++) {
1184 struct test_file *file = &test.files[i];
1185 char *path = concat_file_name(mount_dir, file->name);
1186
1187 err = unlink(path);
1188 free(path);
1189 if (err < 0) {
1190 print_error("Can't unlink file");
1191 goto failure;
1192 }
1193 }
1194
1195 err = delete_dir_tree(subdir1);
1196 if (err) {
1197 ksft_print_msg("Error deleting subdir1 %d", err);
1198 goto failure;
1199 }
1200
1201 err = rmdir(subdir2);
1202 if (err) {
1203 print_error("Error deleting subdir2");
1204 goto failure;
1205 }
1206
1207 close(cmd_fd);
1208 cmd_fd = -1;
1209 if (umount(mount_dir) != 0) {
1210 print_error("Can't unmout FS");
1211 goto failure;
1212 }
1213
1214 return TEST_SUCCESS;
1215
1216 failure:
1217 close(cmd_fd);
1218 umount(mount_dir);
1219 return TEST_FAILURE;
1220 }
1221
dynamic_files_and_data_test(char * mount_dir)1222 static int dynamic_files_and_data_test(char *mount_dir)
1223 {
1224 struct test_files_set test = get_test_files_set();
1225 const int file_num = test.files_count;
1226 const int missing_file_idx = 5;
1227 int cmd_fd = -1;
1228 char *backing_dir;
1229 int i;
1230
1231 backing_dir = create_backing_dir(mount_dir);
1232 if (!backing_dir)
1233 goto failure;
1234
1235 /* Mount FS and release the backing file. */
1236 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1237 goto failure;
1238 free(backing_dir);
1239
1240 cmd_fd = open_commands_file(mount_dir);
1241 if (cmd_fd < 0)
1242 goto failure;
1243
1244 /* Check that test files don't exist in the filesystem. */
1245 for (i = 0; i < file_num; i++) {
1246 struct test_file *file = &test.files[i];
1247 char *filename = concat_file_name(mount_dir, file->name);
1248
1249 if (access(filename, F_OK) != -1) {
1250 ksft_print_msg(
1251 "File %s somehow already exists in a clean FS.\n",
1252 filename);
1253 goto failure;
1254 }
1255 free(filename);
1256 }
1257
1258 /* Write test data into the command file. */
1259 for (i = 0; i < file_num; i++) {
1260 struct test_file *file = &test.files[i];
1261 int res;
1262
1263 build_mtree(file);
1264 res = emit_file(cmd_fd, NULL, file->name, &file->id,
1265 file->size, NULL);
1266 if (res < 0) {
1267 ksft_print_msg("Error %s emiting file %s.\n",
1268 strerror(-res), file->name);
1269 goto failure;
1270 }
1271
1272 /* Skip writing data to one file so we can check */
1273 /* that it's missing later. */
1274 if (i == missing_file_idx)
1275 continue;
1276
1277 res = load_hash_tree(mount_dir, file);
1278 if (res) {
1279 ksft_print_msg("Can't load hashes for %s. error: %s\n",
1280 file->name, strerror(-res));
1281 goto failure;
1282 }
1283
1284 res = emit_test_file_data(mount_dir, file);
1285 if (res) {
1286 ksft_print_msg("Error %s emiting data for %s.\n",
1287 strerror(-res), file->name);
1288 goto failure;
1289 }
1290 }
1291
1292 /* Validate contents of the FS */
1293 for (i = 0; i < file_num; i++) {
1294 struct test_file *file = &test.files[i];
1295
1296 if (i == missing_file_idx) {
1297 /* No data has been written to this file. */
1298 /* Check for read error; */
1299 uint8_t buf;
1300 char *filename =
1301 concat_file_name(mount_dir, file->name);
1302 int res = read_test_file(&buf, 1, filename, 0);
1303
1304 free(filename);
1305 if (res > 0) {
1306 ksft_print_msg(
1307 "Data present, even though never writtern.\n");
1308 goto failure;
1309 }
1310 if (res != -ETIME) {
1311 ksft_print_msg("Wrong error code: %d.\n", res);
1312 goto failure;
1313 }
1314 } else {
1315 if (validate_test_file_content(mount_dir, file) < 0)
1316 goto failure;
1317 }
1318 }
1319
1320 close(cmd_fd);
1321 cmd_fd = -1;
1322 if (umount(mount_dir) != 0) {
1323 print_error("Can't unmout FS");
1324 goto failure;
1325 }
1326
1327 return TEST_SUCCESS;
1328
1329 failure:
1330 close(cmd_fd);
1331 umount(mount_dir);
1332 return TEST_FAILURE;
1333 }
1334
concurrent_reads_and_writes_test(char * mount_dir)1335 static int concurrent_reads_and_writes_test(char *mount_dir)
1336 {
1337 struct test_files_set test = get_test_files_set();
1338 const int file_num = test.files_count;
1339 /* Validate each file from that many child processes. */
1340 const int child_multiplier = 3;
1341 int cmd_fd = -1;
1342 char *backing_dir;
1343 int status;
1344 int i;
1345 pid_t producer_pid;
1346 pid_t *child_pids = alloca(child_multiplier * file_num * sizeof(pid_t));
1347
1348 backing_dir = create_backing_dir(mount_dir);
1349 if (!backing_dir)
1350 goto failure;
1351
1352 /* Mount FS and release the backing file. */
1353 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1354 goto failure;
1355 free(backing_dir);
1356
1357 cmd_fd = open_commands_file(mount_dir);
1358 if (cmd_fd < 0)
1359 goto failure;
1360
1361 /* Tell FS about the files, without actually providing the data. */
1362 for (i = 0; i < file_num; i++) {
1363 struct test_file *file = &test.files[i];
1364 int res;
1365
1366 res = emit_file(cmd_fd, NULL, file->name, &file->id,
1367 file->size, NULL);
1368 if (res)
1369 goto failure;
1370 }
1371
1372 /* Start child processes acessing data in the files */
1373 for (i = 0; i < file_num * child_multiplier; i++) {
1374 struct test_file *file = &test.files[i / child_multiplier];
1375 pid_t child_pid = flush_and_fork();
1376
1377 if (child_pid == 0) {
1378 /* This is a child process, do the data validation. */
1379 int ret = validate_test_file_content_with_seed(
1380 mount_dir, file, i);
1381 if (ret >= 0) {
1382 /* Zero exit status if data is valid. */
1383 exit(0);
1384 }
1385
1386 /* Positive status if validation error found. */
1387 exit(-ret);
1388 } else if (child_pid > 0) {
1389 child_pids[i] = child_pid;
1390 } else {
1391 print_error("Fork error");
1392 goto failure;
1393 }
1394 }
1395
1396 producer_pid = flush_and_fork();
1397 if (producer_pid == 0) {
1398 int ret;
1399 /*
1400 * This is a child that should provide data to
1401 * pending reads.
1402 */
1403
1404 ret = data_producer(mount_dir, &test);
1405 exit(-ret);
1406 } else {
1407 status = wait_for_process(producer_pid);
1408 if (status != 0) {
1409 ksft_print_msg("Data produces failed. %d(%s) ", status,
1410 strerror(status));
1411 goto failure;
1412 }
1413 }
1414
1415 /* Check that all children has finished with 0 exit status */
1416 for (i = 0; i < file_num * child_multiplier; i++) {
1417 struct test_file *file = &test.files[i / child_multiplier];
1418
1419 status = wait_for_process(child_pids[i]);
1420 if (status != 0) {
1421 ksft_print_msg(
1422 "Validation for the file %s failed with code %d (%s)\n",
1423 file->name, status, strerror(status));
1424 goto failure;
1425 }
1426 }
1427
1428 /* Check that there are no pending reads left */
1429 {
1430 struct incfs_pending_read_info prs[1] = {};
1431 int timeout = 0;
1432 int read_count = wait_for_pending_reads(cmd_fd, timeout, prs,
1433 ARRAY_SIZE(prs));
1434
1435 if (read_count) {
1436 ksft_print_msg(
1437 "Pending reads pending when all data written\n");
1438 goto failure;
1439 }
1440 }
1441
1442 close(cmd_fd);
1443 cmd_fd = -1;
1444 if (umount(mount_dir) != 0) {
1445 print_error("Can't unmout FS");
1446 goto failure;
1447 }
1448
1449 return TEST_SUCCESS;
1450
1451 failure:
1452 close(cmd_fd);
1453 umount(mount_dir);
1454 return TEST_FAILURE;
1455 }
1456
work_after_remount_test(char * mount_dir)1457 static int work_after_remount_test(char *mount_dir)
1458 {
1459 struct test_files_set test = get_test_files_set();
1460 const int file_num = test.files_count;
1461 const int file_num_stage1 = file_num / 2;
1462 const int file_num_stage2 = file_num;
1463 char *backing_dir = NULL;
1464 int i = 0;
1465 int cmd_fd = -1;
1466
1467 backing_dir = create_backing_dir(mount_dir);
1468 if (!backing_dir)
1469 goto failure;
1470
1471 /* Mount FS and release the backing file. */
1472 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1473 goto failure;
1474
1475 cmd_fd = open_commands_file(mount_dir);
1476 if (cmd_fd < 0)
1477 goto failure;
1478
1479 /* Write first half of the data into the command file. (stage 1) */
1480 for (i = 0; i < file_num_stage1; i++) {
1481 struct test_file *file = &test.files[i];
1482 int res;
1483
1484 build_mtree(file);
1485 if (emit_file(cmd_fd, NULL, file->name, &file->id,
1486 file->size, NULL))
1487 goto failure;
1488
1489 if (emit_test_file_data(mount_dir, file))
1490 goto failure;
1491
1492 res = load_hash_tree(mount_dir, file);
1493 if (res) {
1494 ksft_print_msg("Can't load hashes for %s. error: %s\n",
1495 file->name, strerror(-res));
1496 goto failure;
1497 }
1498 }
1499
1500 /* Unmount and mount again, to see that data is persistent. */
1501 close(cmd_fd);
1502 cmd_fd = -1;
1503 if (umount(mount_dir) != 0) {
1504 print_error("Can't unmout FS");
1505 goto failure;
1506 }
1507
1508 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1509 goto failure;
1510
1511 cmd_fd = open_commands_file(mount_dir);
1512 if (cmd_fd < 0)
1513 goto failure;
1514
1515 /* Write the second half of the data into the command file. (stage 2) */
1516 for (; i < file_num_stage2; i++) {
1517 struct test_file *file = &test.files[i];
1518 int res = emit_file(cmd_fd, NULL, file->name, &file->id,
1519 file->size, NULL);
1520
1521 if (res)
1522 goto failure;
1523
1524 if (emit_test_file_data(mount_dir, file))
1525 goto failure;
1526 }
1527
1528 /* Validate contents of the FS */
1529 for (i = 0; i < file_num_stage2; i++) {
1530 struct test_file *file = &test.files[i];
1531
1532 if (validate_test_file_content(mount_dir, file) < 0)
1533 goto failure;
1534 }
1535
1536 /* Delete all files */
1537 for (i = 0; i < file_num; i++) {
1538 struct test_file *file = &test.files[i];
1539 char *filename = concat_file_name(mount_dir, file->name);
1540 char *filename_in_index = get_index_filename(mount_dir,
1541 file->id);
1542
1543 if (access(filename, F_OK) != 0) {
1544 ksft_print_msg("File %s is not visible.\n", filename);
1545 goto failure;
1546 }
1547
1548 if (access(filename_in_index, F_OK) != 0) {
1549 ksft_print_msg("File %s is not visible.\n",
1550 filename_in_index);
1551 goto failure;
1552 }
1553
1554 unlink(filename);
1555
1556 if (access(filename, F_OK) != -1) {
1557 ksft_print_msg("File %s is still present.\n", filename);
1558 goto failure;
1559 }
1560
1561 if (access(filename_in_index, F_OK) != 0) {
1562 ksft_print_msg("File %s is still present.\n",
1563 filename_in_index);
1564 goto failure;
1565 }
1566 free(filename);
1567 free(filename_in_index);
1568 }
1569
1570 /* Unmount and mount again, to see that deleted files stay deleted. */
1571 close(cmd_fd);
1572 cmd_fd = -1;
1573 if (umount(mount_dir) != 0) {
1574 print_error("Can't unmout FS");
1575 goto failure;
1576 }
1577
1578 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1579 goto failure;
1580
1581 cmd_fd = open_commands_file(mount_dir);
1582 if (cmd_fd < 0)
1583 goto failure;
1584
1585 /* Validate all deleted files are still deleted. */
1586 for (i = 0; i < file_num; i++) {
1587 struct test_file *file = &test.files[i];
1588 char *filename = concat_file_name(mount_dir, file->name);
1589
1590 if (access(filename, F_OK) != -1) {
1591 ksft_print_msg("File %s is still visible.\n", filename);
1592 goto failure;
1593 }
1594 free(filename);
1595 }
1596
1597 /* Final unmount */
1598 close(cmd_fd);
1599 free(backing_dir);
1600 cmd_fd = -1;
1601 if (umount(mount_dir) != 0) {
1602 print_error("Can't unmout FS");
1603 goto failure;
1604 }
1605
1606 return TEST_SUCCESS;
1607
1608 failure:
1609 close(cmd_fd);
1610 free(backing_dir);
1611 umount(mount_dir);
1612 return TEST_FAILURE;
1613 }
1614
attribute_test(char * mount_dir)1615 static int attribute_test(char *mount_dir)
1616 {
1617 char file_attr[] = "metadata123123";
1618 char attr_buf[INCFS_MAX_FILE_ATTR_SIZE] = {};
1619 int cmd_fd = -1;
1620 incfs_uuid_t file_id;
1621 int attr_res = 0;
1622 char *backing_dir;
1623
1624
1625 backing_dir = create_backing_dir(mount_dir);
1626 if (!backing_dir)
1627 goto failure;
1628
1629 /* Mount FS and release the backing file. */
1630 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1631 goto failure;
1632
1633
1634 cmd_fd = open_commands_file(mount_dir);
1635 if (cmd_fd < 0)
1636 goto failure;
1637
1638 if (emit_file(cmd_fd, NULL, "file", &file_id, 12, file_attr))
1639 goto failure;
1640
1641 /* Test attribute values */
1642 attr_res = get_file_attr(mount_dir, file_id, attr_buf,
1643 ARRAY_SIZE(attr_buf));
1644 if (attr_res != strlen(file_attr)) {
1645 ksft_print_msg("Get file attr error: %d\n", attr_res);
1646 goto failure;
1647 }
1648 if (strcmp(attr_buf, file_attr) != 0) {
1649 ksft_print_msg("Incorrect file attr value: '%s'", attr_buf);
1650 goto failure;
1651 }
1652
1653 /* Unmount and mount again, to see that attributes are persistent. */
1654 close(cmd_fd);
1655 cmd_fd = -1;
1656 if (umount(mount_dir) != 0) {
1657 print_error("Can't unmout FS");
1658 goto failure;
1659 }
1660
1661 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1662 goto failure;
1663
1664 cmd_fd = open_commands_file(mount_dir);
1665 if (cmd_fd < 0)
1666 goto failure;
1667
1668 /* Test attribute values again after remount*/
1669 attr_res = get_file_attr(mount_dir, file_id, attr_buf,
1670 ARRAY_SIZE(attr_buf));
1671 if (attr_res != strlen(file_attr)) {
1672 ksft_print_msg("Get dir attr error: %d\n", attr_res);
1673 goto failure;
1674 }
1675 if (strcmp(attr_buf, file_attr) != 0) {
1676 ksft_print_msg("Incorrect file attr value: '%s'", attr_buf);
1677 goto failure;
1678 }
1679
1680 /* Final unmount */
1681 close(cmd_fd);
1682 free(backing_dir);
1683 cmd_fd = -1;
1684 if (umount(mount_dir) != 0) {
1685 print_error("Can't unmout FS");
1686 goto failure;
1687 }
1688
1689 return TEST_SUCCESS;
1690
1691 failure:
1692 close(cmd_fd);
1693 free(backing_dir);
1694 umount(mount_dir);
1695 return TEST_FAILURE;
1696 }
1697
child_procs_waiting_for_data_test(char * mount_dir)1698 static int child_procs_waiting_for_data_test(char *mount_dir)
1699 {
1700 struct test_files_set test = get_test_files_set();
1701 const int file_num = test.files_count;
1702 int cmd_fd = -1;
1703 int i;
1704 pid_t *child_pids = alloca(file_num * sizeof(pid_t));
1705 char *backing_dir;
1706
1707 backing_dir = create_backing_dir(mount_dir);
1708 if (!backing_dir)
1709 goto failure;
1710
1711 /* Mount FS and release the backing file. (10s wait time) */
1712 if (mount_fs(mount_dir, backing_dir, 10000) != 0)
1713 goto failure;
1714
1715
1716 cmd_fd = open_commands_file(mount_dir);
1717 if (cmd_fd < 0)
1718 goto failure;
1719
1720 /* Tell FS about the files, without actually providing the data. */
1721 for (i = 0; i < file_num; i++) {
1722 struct test_file *file = &test.files[i];
1723
1724 emit_file(cmd_fd, NULL, file->name, &file->id,
1725 file->size, NULL);
1726 }
1727
1728 /* Start child processes acessing data in the files */
1729 for (i = 0; i < file_num; i++) {
1730 struct test_file *file = &test.files[i];
1731 pid_t child_pid = flush_and_fork();
1732
1733 if (child_pid == 0) {
1734 /* This is a child process, do the data validation. */
1735 int ret = validate_test_file_content(mount_dir, file);
1736
1737 if (ret >= 0) {
1738 /* Zero exit status if data is valid. */
1739 exit(0);
1740 }
1741
1742 /* Positive status if validation error found. */
1743 exit(-ret);
1744 } else if (child_pid > 0) {
1745 child_pids[i] = child_pid;
1746 } else {
1747 print_error("Fork error");
1748 goto failure;
1749 }
1750 }
1751
1752 /* Write test data into the command file. */
1753 for (i = 0; i < file_num; i++) {
1754 struct test_file *file = &test.files[i];
1755
1756 if (emit_test_file_data(mount_dir, file))
1757 goto failure;
1758 }
1759
1760 /* Check that all children has finished with 0 exit status */
1761 for (i = 0; i < file_num; i++) {
1762 struct test_file *file = &test.files[i];
1763 int status = wait_for_process(child_pids[i]);
1764
1765 if (status != 0) {
1766 ksft_print_msg(
1767 "Validation for the file %s failed with code %d (%s)\n",
1768 file->name, status, strerror(status));
1769 goto failure;
1770 }
1771 }
1772
1773 close(cmd_fd);
1774 free(backing_dir);
1775 cmd_fd = -1;
1776 if (umount(mount_dir) != 0) {
1777 print_error("Can't unmout FS");
1778 goto failure;
1779 }
1780
1781 return TEST_SUCCESS;
1782
1783 failure:
1784 close(cmd_fd);
1785 free(backing_dir);
1786 umount(mount_dir);
1787 return TEST_FAILURE;
1788 }
1789
multiple_providers_test(char * mount_dir)1790 static int multiple_providers_test(char *mount_dir)
1791 {
1792 struct test_files_set test = get_test_files_set();
1793 const int file_num = test.files_count;
1794 const int producer_count = 5;
1795 int cmd_fd = -1;
1796 int status;
1797 int i;
1798 pid_t *producer_pids = alloca(producer_count * sizeof(pid_t));
1799 char *backing_dir;
1800
1801 backing_dir = create_backing_dir(mount_dir);
1802 if (!backing_dir)
1803 goto failure;
1804
1805 /* Mount FS and release the backing file. (10s wait time) */
1806 if (mount_fs(mount_dir, backing_dir, 10000) != 0)
1807 goto failure;
1808
1809 cmd_fd = open_commands_file(mount_dir);
1810 if (cmd_fd < 0)
1811 goto failure;
1812
1813 /* Tell FS about the files, without actually providing the data. */
1814 for (i = 0; i < file_num; i++) {
1815 struct test_file *file = &test.files[i];
1816
1817 if (emit_file(cmd_fd, NULL, file->name, &file->id,
1818 file->size, NULL) < 0)
1819 goto failure;
1820 }
1821
1822 /* Start producer processes */
1823 for (i = 0; i < producer_count; i++) {
1824 pid_t producer_pid = flush_and_fork();
1825
1826 if (producer_pid == 0) {
1827 int ret;
1828 /*
1829 * This is a child that should provide data to
1830 * pending reads.
1831 */
1832
1833 ret = data_producer(mount_dir, &test);
1834 exit(-ret);
1835 } else if (producer_pid > 0) {
1836 producer_pids[i] = producer_pid;
1837 } else {
1838 print_error("Fork error");
1839 goto failure;
1840 }
1841 }
1842
1843 /* Validate FS content */
1844 for (i = 0; i < file_num; i++) {
1845 struct test_file *file = &test.files[i];
1846 char *filename = concat_file_name(mount_dir, file->name);
1847 loff_t read_result = read_whole_file(filename);
1848
1849 free(filename);
1850 if (read_result != file->size) {
1851 ksft_print_msg(
1852 "Error validating file %s. Result: %ld\n",
1853 file->name, read_result);
1854 goto failure;
1855 }
1856 }
1857
1858 /* Check that all producers has finished with 0 exit status */
1859 for (i = 0; i < producer_count; i++) {
1860 status = wait_for_process(producer_pids[i]);
1861 if (status != 0) {
1862 ksft_print_msg("Producer %d failed with code (%s)\n", i,
1863 strerror(status));
1864 goto failure;
1865 }
1866 }
1867
1868 close(cmd_fd);
1869 free(backing_dir);
1870 cmd_fd = -1;
1871 if (umount(mount_dir) != 0) {
1872 print_error("Can't unmout FS");
1873 goto failure;
1874 }
1875
1876 return TEST_SUCCESS;
1877
1878 failure:
1879 close(cmd_fd);
1880 free(backing_dir);
1881 umount(mount_dir);
1882 return TEST_FAILURE;
1883 }
1884
signature_test(char * mount_dir)1885 static int signature_test(char *mount_dir)
1886 {
1887 struct test_files_set test = get_test_files_set();
1888 const int file_num = test.files_count;
1889 int i = 0;
1890 unsigned char sig_buf[INCFS_MAX_SIGNATURE_SIZE];
1891 char *backing_dir;
1892 int cmd_fd = -1;
1893
1894 backing_dir = create_backing_dir(mount_dir);
1895 if (!backing_dir)
1896 goto failure;
1897
1898 /* Mount FS and release the backing file. (10s wait time) */
1899 if (mount_fs(mount_dir, backing_dir, 10000) != 0)
1900 goto failure;
1901
1902 cmd_fd = open_commands_file(mount_dir);
1903 if (cmd_fd < 0)
1904 goto failure;
1905
1906 /* Write hashes and data. */
1907 for (i = 0; i < file_num; i++) {
1908 struct test_file *file = &test.files[i];
1909 int res;
1910
1911 build_mtree(file);
1912
1913 res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id,
1914 file->size, file->root_hash,
1915 file->sig.data, file->sig.size, file->sig.add_data);
1916
1917 if (res) {
1918 ksft_print_msg("Emit failed for %s. error: %s\n",
1919 file->name, strerror(-res));
1920 goto failure;
1921 }
1922
1923 if (emit_test_file_data(mount_dir, file))
1924 goto failure;
1925
1926 res = load_hash_tree(mount_dir, file);
1927 if (res) {
1928 ksft_print_msg("Can't load hashes for %s. error: %s\n",
1929 file->name, strerror(-res));
1930 goto failure;
1931 }
1932 }
1933
1934 /* Validate data */
1935 for (i = 0; i < file_num; i++) {
1936 struct test_file *file = &test.files[i];
1937 int sig_len;
1938 char *path;
1939 int fd;
1940
1941 if (validate_test_file_content(mount_dir, file) < 0)
1942 goto failure;
1943
1944 path = concat_file_name(mount_dir, file->name);
1945 fd = open(path, O_RDWR);
1946 free(path);
1947 if (fd < 0) {
1948 print_error("Can't open file");
1949 goto failure;
1950 }
1951
1952 sig_len = get_file_signature(fd, sig_buf, ARRAY_SIZE(sig_buf));
1953
1954 if (close(fd)) {
1955 print_error("Can't close file");
1956 goto failure;
1957 }
1958
1959 if (sig_len < 0) {
1960 ksft_print_msg("Can't load signature %s. error: %s\n",
1961 file->name, strerror(-sig_len));
1962 goto failure;
1963 }
1964
1965 if (sig_len != file->sig.size ||
1966 memcmp(sig_buf, file->sig.data, sig_len)) {
1967 ksft_print_msg("Signature mismatch %s.\n",
1968 file->name);
1969 goto failure;
1970 }
1971 }
1972
1973 /* Unmount and mount again, to make sure the signature is persistent. */
1974 close(cmd_fd);
1975 cmd_fd = -1;
1976 if (umount(mount_dir) != 0) {
1977 print_error("Can't unmout FS");
1978 goto failure;
1979 }
1980 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1981 goto failure;
1982
1983 cmd_fd = open_commands_file(mount_dir);
1984 if (cmd_fd < 0)
1985 goto failure;
1986
1987 /* Validate data again */
1988 for (i = 0; i < file_num; i++) {
1989 struct test_file *file = &test.files[i];
1990 int sig_len;
1991 char *path;
1992 int fd;
1993
1994 if (validate_test_file_content(mount_dir, file) < 0)
1995 goto failure;
1996
1997 path = concat_file_name(mount_dir, file->name);
1998 fd = open(path, O_RDWR);
1999 free(path);
2000 if (fd < 0) {
2001 print_error("Can't open file");
2002 goto failure;
2003 }
2004
2005 sig_len = get_file_signature(fd, sig_buf, ARRAY_SIZE(sig_buf));
2006
2007 if (close(fd)) {
2008 print_error("Can't close file");
2009 goto failure;
2010 }
2011
2012 if (sig_len < 0) {
2013 ksft_print_msg("Can't load signature %s. error: %s\n",
2014 file->name, strerror(-sig_len));
2015 goto failure;
2016 }
2017 if (sig_len != file->sig.size ||
2018 memcmp(sig_buf, file->sig.data, sig_len)) {
2019 ksft_print_msg("Signature mismatch %s.\n",
2020 file->name);
2021 goto failure;
2022 }
2023 }
2024
2025 /* Final unmount */
2026 close(cmd_fd);
2027 cmd_fd = -1;
2028 if (umount(mount_dir) != 0) {
2029 print_error("Can't unmout FS");
2030 goto failure;
2031 }
2032 return TEST_SUCCESS;
2033
2034 failure:
2035 close(cmd_fd);
2036 free(backing_dir);
2037 umount(mount_dir);
2038 return TEST_FAILURE;
2039 }
2040
hash_tree_test(char * mount_dir)2041 static int hash_tree_test(char *mount_dir)
2042 {
2043 char *backing_dir;
2044 struct test_files_set test = get_test_files_set();
2045 const int file_num = test.files_count;
2046 const int corrupted_file_idx = 5;
2047 int i = 0;
2048 int cmd_fd = -1;
2049
2050 backing_dir = create_backing_dir(mount_dir);
2051 if (!backing_dir)
2052 goto failure;
2053
2054 /* Mount FS and release the backing file. */
2055 if (mount_fs(mount_dir, backing_dir, 50) != 0)
2056 goto failure;
2057
2058 cmd_fd = open_commands_file(mount_dir);
2059 if (cmd_fd < 0)
2060 goto failure;
2061
2062 /* Write hashes and data. */
2063 for (i = 0; i < file_num; i++) {
2064 struct test_file *file = &test.files[i];
2065 int res;
2066
2067 build_mtree(file);
2068 res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id,
2069 file->size, file->root_hash,
2070 file->sig.data, file->sig.size, file->sig.add_data);
2071
2072 if (i == corrupted_file_idx) {
2073 /* Corrupt third blocks hash */
2074 file->mtree[0].data[2 * SHA256_DIGEST_SIZE] ^= 0xff;
2075 }
2076 if (emit_test_file_data(mount_dir, file))
2077 goto failure;
2078
2079 res = load_hash_tree(mount_dir, file);
2080 if (res) {
2081 ksft_print_msg("Can't load hashes for %s. error: %s\n",
2082 file->name, strerror(-res));
2083 goto failure;
2084 }
2085 }
2086
2087 /* Validate data */
2088 for (i = 0; i < file_num; i++) {
2089 struct test_file *file = &test.files[i];
2090
2091 if (i == corrupted_file_idx) {
2092 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2093 char *filename =
2094 concat_file_name(mount_dir, file->name);
2095 int res;
2096
2097 res = read_test_file(data, INCFS_DATA_FILE_BLOCK_SIZE,
2098 filename, 2);
2099 free(filename);
2100 if (res != -EBADMSG) {
2101 ksft_print_msg("Hash violation missed1. %d\n",
2102 res);
2103 goto failure;
2104 }
2105 } else if (validate_test_file_content(mount_dir, file) < 0)
2106 goto failure;
2107 }
2108
2109 /* Unmount and mount again, to that hashes are persistent. */
2110 close(cmd_fd);
2111 cmd_fd = -1;
2112 if (umount(mount_dir) != 0) {
2113 print_error("Can't unmout FS");
2114 goto failure;
2115 }
2116 if (mount_fs(mount_dir, backing_dir, 50) != 0)
2117 goto failure;
2118
2119 cmd_fd = open_commands_file(mount_dir);
2120 if (cmd_fd < 0)
2121 goto failure;
2122
2123 /* Validate data again */
2124 for (i = 0; i < file_num; i++) {
2125 struct test_file *file = &test.files[i];
2126
2127 if (i == corrupted_file_idx) {
2128 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2129 char *filename =
2130 concat_file_name(mount_dir, file->name);
2131 int res;
2132
2133 res = read_test_file(data, INCFS_DATA_FILE_BLOCK_SIZE,
2134 filename, 2);
2135 free(filename);
2136 if (res != -EBADMSG) {
2137 ksft_print_msg("Hash violation missed2. %d\n",
2138 res);
2139 goto failure;
2140 }
2141 } else if (validate_test_file_content(mount_dir, file) < 0)
2142 goto failure;
2143 }
2144
2145 /* Final unmount */
2146 close(cmd_fd);
2147 cmd_fd = -1;
2148 if (umount(mount_dir) != 0) {
2149 print_error("Can't unmout FS");
2150 goto failure;
2151 }
2152 return TEST_SUCCESS;
2153
2154 failure:
2155 close(cmd_fd);
2156 free(backing_dir);
2157 umount(mount_dir);
2158 return TEST_FAILURE;
2159 }
2160
validate_logs(char * mount_dir,int log_fd,struct test_file * file)2161 static int validate_logs(char *mount_dir, int log_fd, struct test_file *file)
2162 {
2163 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2164 struct incfs_pending_read_info prs[100] = {};
2165 int prs_size = ARRAY_SIZE(prs);
2166 int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
2167 int res;
2168 int read_count;
2169 int i;
2170 char *filename = concat_file_name(mount_dir, file->name);
2171 int fd;
2172
2173 fd = open(filename, O_RDONLY);
2174 free(filename);
2175 if (fd <= 0)
2176 return TEST_FAILURE;
2177
2178 if (block_cnt > prs_size)
2179 block_cnt = prs_size;
2180
2181 for (i = 0; i < block_cnt; i++) {
2182 res = pread(fd, data, sizeof(data),
2183 INCFS_DATA_FILE_BLOCK_SIZE * i);
2184 if (res <= 0)
2185 goto failure;
2186 }
2187
2188 read_count = wait_for_pending_reads(log_fd, 0, prs, prs_size);
2189 if (read_count < 0) {
2190 ksft_print_msg("Error reading logged reads %s.\n",
2191 strerror(-read_count));
2192 goto failure;
2193 }
2194
2195 if (read_count != block_cnt) {
2196 ksft_print_msg("Bad log read count %s %d %d.\n", file->name,
2197 read_count, block_cnt);
2198 goto failure;
2199 }
2200
2201 for (i = 0; i < read_count; i++) {
2202 struct incfs_pending_read_info *read = &prs[i];
2203
2204 if (!same_id(&read->file_id, &file->id)) {
2205 ksft_print_msg("Bad log read ino %s\n", file->name);
2206 goto failure;
2207 }
2208
2209 if (read->block_index != i) {
2210 ksft_print_msg("Bad log read ino %s %d %d.\n",
2211 file->name, read->block_index, i);
2212 goto failure;
2213 }
2214
2215 if (i != 0) {
2216 unsigned long psn = prs[i - 1].serial_number;
2217
2218 if (read->serial_number != psn + 1) {
2219 ksft_print_msg("Bad log read sn %s %d %d.\n",
2220 file->name, read->serial_number,
2221 psn);
2222 goto failure;
2223 }
2224 }
2225
2226 if (read->timestamp_us == 0) {
2227 ksft_print_msg("Bad log read timestamp %s.\n",
2228 file->name);
2229 goto failure;
2230 }
2231 }
2232 close(fd);
2233 return TEST_SUCCESS;
2234
2235 failure:
2236 close(fd);
2237 return TEST_FAILURE;
2238 }
2239
read_log_test(char * mount_dir)2240 static int read_log_test(char *mount_dir)
2241 {
2242 struct test_files_set test = get_test_files_set();
2243 const int file_num = test.files_count;
2244 int i = 0;
2245 int cmd_fd = -1, log_fd = -1;
2246 char *backing_dir;
2247
2248 backing_dir = create_backing_dir(mount_dir);
2249 if (!backing_dir)
2250 goto failure;
2251
2252 if (mount_fs_opt(mount_dir, backing_dir, "readahead=0") != 0)
2253 goto failure;
2254
2255 cmd_fd = open_commands_file(mount_dir);
2256 if (cmd_fd < 0)
2257 goto failure;
2258
2259 log_fd = open_log_file(mount_dir);
2260 if (cmd_fd < 0)
2261 ksft_print_msg("Can't open log file.\n");
2262
2263 /* Write data. */
2264 for (i = 0; i < file_num; i++) {
2265 struct test_file *file = &test.files[i];
2266
2267 if (emit_file(cmd_fd, NULL, file->name, &file->id,
2268 file->size, NULL))
2269 goto failure;
2270
2271 if (emit_test_file_data(mount_dir, file))
2272 goto failure;
2273 }
2274
2275 /* Validate data */
2276 for (i = 0; i < file_num; i++) {
2277 struct test_file *file = &test.files[i];
2278
2279 if (validate_logs(mount_dir, log_fd, file))
2280 goto failure;
2281 }
2282
2283 /* Unmount and mount again, to see that logs work after remount. */
2284 close(cmd_fd);
2285 close(log_fd);
2286 cmd_fd = -1;
2287 if (umount(mount_dir) != 0) {
2288 print_error("Can't unmout FS");
2289 goto failure;
2290 }
2291
2292 if (mount_fs_opt(mount_dir, backing_dir, "readahead=0") != 0)
2293 goto failure;
2294
2295 cmd_fd = open_commands_file(mount_dir);
2296 if (cmd_fd < 0)
2297 goto failure;
2298
2299 log_fd = open_log_file(mount_dir);
2300 if (cmd_fd < 0)
2301 ksft_print_msg("Can't open log file.\n");
2302
2303 /* Validate data again */
2304 for (i = 0; i < file_num; i++) {
2305 struct test_file *file = &test.files[i];
2306
2307 if (validate_logs(mount_dir, log_fd, file))
2308 goto failure;
2309 }
2310
2311 /* Final unmount */
2312 close(cmd_fd);
2313 close(log_fd);
2314 free(backing_dir);
2315 if (umount(mount_dir) != 0) {
2316 print_error("Can't unmout FS");
2317 goto failure;
2318 }
2319
2320 return TEST_SUCCESS;
2321
2322 failure:
2323 close(cmd_fd);
2324 close(log_fd);
2325 free(backing_dir);
2326 umount(mount_dir);
2327 return TEST_FAILURE;
2328 }
2329
setup_mount_dir()2330 static char *setup_mount_dir()
2331 {
2332 struct stat st;
2333 char *current_dir = getcwd(NULL, 0);
2334 char *mount_dir = concat_file_name(current_dir, "incfs-mount-dir");
2335
2336 free(current_dir);
2337 if (stat(mount_dir, &st) == 0) {
2338 if (S_ISDIR(st.st_mode))
2339 return mount_dir;
2340
2341 ksft_print_msg("%s is a file, not a dir.\n", mount_dir);
2342 return NULL;
2343 }
2344
2345 if (mkdir(mount_dir, 0777)) {
2346 print_error("Can't create mount dir.");
2347 return NULL;
2348 }
2349
2350 return mount_dir;
2351 }
2352
main(int argc,char * argv[])2353 int main(int argc, char *argv[])
2354 {
2355 char *mount_dir = NULL;
2356 int fails = 0;
2357 int i;
2358 int fd, count;
2359
2360 // Seed randomness pool for testing on QEMU
2361 // NOTE - this abuses the concept of randomness - do *not* ever do this
2362 // on a machine for production use - the device will think it has good
2363 // randomness when it does not.
2364 fd = open("/dev/urandom", O_WRONLY);
2365 count = 4096;
2366 for (int i = 0; i < 128; ++i)
2367 ioctl(fd, RNDADDTOENTCNT, &count);
2368 close(fd);
2369
2370 ksft_print_header();
2371
2372 if (geteuid() != 0)
2373 ksft_print_msg("Not a root, might fail to mount.\n");
2374
2375 mount_dir = setup_mount_dir();
2376 if (mount_dir == NULL)
2377 ksft_exit_fail_msg("Can't create a mount dir\n");
2378
2379 #define MAKE_TEST(test) \
2380 { \
2381 test, #test \
2382 }
2383 struct {
2384 int (*pfunc)(char *dir);
2385 const char *name;
2386 } cases[] = {
2387 MAKE_TEST(basic_file_ops_test),
2388 MAKE_TEST(cant_touch_index_test),
2389 MAKE_TEST(dynamic_files_and_data_test),
2390 MAKE_TEST(concurrent_reads_and_writes_test),
2391 MAKE_TEST(attribute_test),
2392 MAKE_TEST(work_after_remount_test),
2393 MAKE_TEST(child_procs_waiting_for_data_test),
2394 MAKE_TEST(multiple_providers_test),
2395 MAKE_TEST(signature_test),
2396 MAKE_TEST(hash_tree_test),
2397 MAKE_TEST(read_log_test),
2398 };
2399 #undef MAKE_TEST
2400
2401 ksft_set_plan(ARRAY_SIZE(cases));
2402
2403 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
2404 ksft_print_msg("Running %s\n", cases[i].name);
2405 if (cases[i].pfunc(mount_dir) == TEST_SUCCESS)
2406 ksft_test_result_pass("%s\n", cases[i].name);
2407 else {
2408 ksft_test_result_fail("%s\n", cases[i].name);
2409 fails++;
2410 }
2411 }
2412
2413 umount2(mount_dir, MNT_FORCE);
2414 rmdir(mount_dir);
2415
2416 if (fails > 0)
2417 ksft_exit_pass();
2418 else
2419 ksft_exit_pass();
2420 return 0;
2421 }
2422