Initial release for Tizen
[platform/upstream/ecryptfs-utils.git] / tests / kernel / trunc-file / test.c
1 /*
2  * Author: Colin King <colin.king@canonical.com>
3  *
4  * Copyright (C) 2012 Canonical, Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <signal.h>
29 #include <limits.h>
30
31 #define TEST_PASSED     (0)
32 #define TEST_FAILED     (1)
33 #define TEST_ERROR      (2)
34
35 #define SEED            (0xdeadbeef)
36 #define BUFF_SZ         (65536)
37
38 #define DEFAULT_SIZE    (64*1024)
39
40 int write_buff(int fd, unsigned char *data, ssize_t size)
41 {
42         unsigned char *ptr = data;
43         ssize_t n;
44         ssize_t sz = size;
45
46         while (sz > 0) {
47                 n = write(fd, ptr, sz);
48                 if (n < 0)
49                         return -1;
50                 sz -= n;
51                 ptr += n;
52         }
53         return size;
54 }
55
56 int read_buff(int fd, unsigned char *data, ssize_t size)
57 {
58         unsigned char *ptr = data;
59         ssize_t n;
60         ssize_t sz = size;
61
62         while (sz > 0) {
63                 n = read(fd, ptr, sz);
64                 if (n <= 0)
65                         return -1;
66                 sz -= n;
67                 ptr += n;
68         }
69         return size;
70 }
71
72 int test_write_random(char *filename, int fd, unsigned char *buff, ssize_t size)
73 {
74         ssize_t buflen;
75
76         srandom((unsigned int)SEED);
77         buflen = size;
78         while (buflen > 0) {
79                 int j;
80                 ssize_t n = (buflen > BUFF_SZ) ? BUFF_SZ : buflen;
81
82                 for (j = 0; j < n; j++)
83                         buff[j] = random() & 0xff;
84
85                 if (write_buff(fd, buff, n) < 0) {
86                         close(fd);
87                         return -1;
88                 }
89                 buflen -= n;
90         }
91
92         return 0;
93 }
94
95 int test_read_random(char *filename, int fd, unsigned char *buff, ssize_t size)
96 {
97         ssize_t buflen;
98
99         if (lseek(fd, 0, SEEK_SET) < 0) {
100                 fprintf(stderr, "seek failed: %s: %s\n", filename, strerror(errno));
101                 return -1;
102         }
103
104         srandom((unsigned int)SEED);
105         buflen = size;
106         while (buflen > 0) {
107                 int j;
108                 ssize_t n = (buflen > BUFF_SZ) ? BUFF_SZ : buflen;
109
110                 if (read_buff(fd, buff, n) < n) {
111                         fprintf(stderr, "read failed: %s %s\n", filename, strerror(errno));
112                         return -1;
113                 }
114
115                 for (j = 0; j < n; j++) {
116                         unsigned char val = random() & 0xff;
117                         if (buff[j] != val) {
118                                 fprintf(stderr, "Byte %d different from expected value: %d vs %d\n",
119                                         j, val, buff[j]);
120                                 return -1;
121                         }
122                 }
123                 buflen -= n;
124         }
125         return 0;
126 }
127
128 int test_read_rest(char *filename, int fd, unsigned char *buff, ssize_t trunc_size, size_t size)
129 {
130         ssize_t buflen;
131
132         if (lseek(fd, trunc_size, SEEK_SET) < 0) {
133                 fprintf(stderr, "seek failed: %s: %s\n", filename, strerror(errno));
134                 return -1;
135         }
136
137         buflen = size - trunc_size;
138         while (buflen > 0) {
139                 int j;
140                 ssize_t n = (buflen > BUFF_SZ) ? BUFF_SZ : buflen;
141
142                 if (read_buff(fd, buff, n) < n) {
143                         fprintf(stderr, "read failed: %s %s\n", filename, strerror(errno));
144                         return -1;
145                 }
146
147                 for (j = 0; j < n; j++) {
148                         if (buff[j] != 0) {
149                                 fprintf(stderr, "Byte %d different from expected value: %d vs %d\n",
150                                         j, 0, buff[j]);
151                                 return -1;
152                         }
153                 }
154                 buflen -= n;
155         }
156         return 0;
157 }
158
159 int test_exercise(char *filename, ssize_t size)
160 {
161         int fd;
162         int ret = TEST_FAILED;
163         ssize_t trunc_size = size / 2;
164         struct stat statbuf;
165
166         unsigned char buff[BUFF_SZ];
167
168         unlink(filename);
169         if ((fd = open(filename, O_RDWR | O_CREAT, 0600)) < 0) {
170                 fprintf(stderr, "Failed to open %s: %s\n", filename, strerror(errno));
171                 return TEST_FAILED;
172         }
173
174         /* Fill with random data */
175         if (test_write_random(filename, fd, buff, size) < 0)
176                 goto done;
177
178         /* Read it back sanity check */
179         if (test_read_random(filename, fd, buff, size) < 0)
180                 goto done;
181
182         /* Iteratively truncate file down */
183         while (trunc_size > 0) {
184                 /* Truncate */
185                 if (ftruncate(fd, (off_t)trunc_size) < 0) {
186                         fprintf(stderr, "ftruncate failed: %s %s\n", filename, strerror(errno));
187                         goto done;
188                 }
189
190                 /* Read check the truncated data again */
191                 if (test_read_random(filename, fd, buff, trunc_size) < 0)
192                         goto done;
193
194                 /* Check the size */
195                 if (fstat(fd, &statbuf) < 0) {
196                         fprintf(stderr, "fstat failed: %s %s\n", filename, strerror(errno));
197                         goto done;
198                 }
199                 if (statbuf.st_size != (off_t)trunc_size) {
200                         fprintf(stderr, "truncated file size incorrect, got %lu, expected %lu\n",
201                                 (unsigned long)statbuf.st_size, (unsigned long)trunc_size);
202                         goto done;
203                 }
204
205                 /* Extend to full size using truncate, end is now zero */
206                 if (ftruncate(fd, (off_t)size) < 0) {
207                         fprintf(stderr, "ftruncate failed: %s %s\n", filename, strerror(errno));
208                         goto done;
209                 }
210
211                 /* Check the size */
212                 if (fstat(fd, &statbuf) < 0) {
213                         fprintf(stderr, "fstat failed: %s %s\n", filename, strerror(errno));
214                         goto done;
215                 }
216                 if (statbuf.st_size != (off_t)size) {
217                         fprintf(stderr, "truncated file size incorrect, got %lu, expected %lu\n",
218                                 (unsigned long)statbuf.st_size, (unsigned long)size);
219                         goto done;
220                 }
221
222                 /* Check the first chunk */
223                 if (test_read_random(filename, fd, buff, trunc_size) < 0)
224                         goto done;
225                 /* Check the end is all zero */
226                 if (test_read_rest(filename, fd, buff, trunc_size, size) < 0)
227                         goto done;
228
229                 trunc_size >>= 1;
230         }
231
232         ret = TEST_PASSED;
233
234 done:
235         if (close(fd) < 0) {
236                 fprintf(stderr, "close failed: %s: %s\n", filename, strerror(errno));
237                 return TEST_FAILED;
238         }
239
240         if (unlink(filename) < 0) {
241                 fprintf(stderr, "unlink failed: %s: %s\n", filename, strerror(errno));
242                 return TEST_FAILED;
243         }
244
245         return ret;
246 }
247
248 void sighandler(int dummy)
249 {
250         exit(TEST_ERROR);
251 }
252
253 int main(int argc, char **argv)
254 {
255         ssize_t len = DEFAULT_SIZE;
256         const ssize_t max_len = SSIZE_MAX / 1024;
257
258         if (argc < 2) {
259                 fprintf(stderr, "Syntax: %s filename [size_in_K]\n", argv[0]);
260                 exit(TEST_ERROR);
261         }
262
263         if (argc == 3) {
264                 len = atoll(argv[2]);
265                 if (len < 1) {
266                         fprintf(stderr, "size should be > 0\n");
267                         exit(TEST_ERROR);
268                 }
269         }
270
271         if (len > max_len) {
272                 fprintf(stderr, "size should be < %zd\n", max_len);
273                 exit(TEST_ERROR);
274         }
275         signal(SIGINT, sighandler);
276
277         exit(test_exercise(argv[1], len * 1024));
278 }