2 * Author: Colin King <colin.king@canonical.com>
4 * Copyright (C) 2012 Canonical, Ltd.
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.
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.
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
24 #include <sys/types.h>
31 #define TEST_PASSED (0)
32 #define TEST_FAILED (1)
33 #define TEST_ERROR (2)
35 #define SEED (0xdeadbeef)
36 #define BUFF_SZ (65536)
38 #define DEFAULT_SIZE (64*1024)
40 int write_buff(int fd, unsigned char *data, ssize_t size)
42 unsigned char *ptr = data;
47 n = write(fd, ptr, sz);
56 int read_buff(int fd, unsigned char *data, ssize_t size)
58 unsigned char *ptr = data;
63 n = read(fd, ptr, sz);
72 int test_write_random(char *filename, int fd, unsigned char *buff, ssize_t size)
76 srandom((unsigned int)SEED);
80 ssize_t n = (buflen > BUFF_SZ) ? BUFF_SZ : buflen;
82 for (j = 0; j < n; j++)
83 buff[j] = random() & 0xff;
85 if (write_buff(fd, buff, n) < 0) {
95 int test_read_random(char *filename, int fd, unsigned char *buff, ssize_t size)
99 if (lseek(fd, 0, SEEK_SET) < 0) {
100 fprintf(stderr, "seek failed: %s: %s\n", filename, strerror(errno));
104 srandom((unsigned int)SEED);
108 ssize_t n = (buflen > BUFF_SZ) ? BUFF_SZ : buflen;
110 if (read_buff(fd, buff, n) < n) {
111 fprintf(stderr, "read failed: %s %s\n", filename, strerror(errno));
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",
128 int test_read_rest(char *filename, int fd, unsigned char *buff, ssize_t trunc_size, size_t size)
132 if (lseek(fd, trunc_size, SEEK_SET) < 0) {
133 fprintf(stderr, "seek failed: %s: %s\n", filename, strerror(errno));
137 buflen = size - trunc_size;
140 ssize_t n = (buflen > BUFF_SZ) ? BUFF_SZ : buflen;
142 if (read_buff(fd, buff, n) < n) {
143 fprintf(stderr, "read failed: %s %s\n", filename, strerror(errno));
147 for (j = 0; j < n; j++) {
149 fprintf(stderr, "Byte %d different from expected value: %d vs %d\n",
159 int test_exercise(char *filename, ssize_t size)
162 int ret = TEST_FAILED;
163 ssize_t trunc_size = size / 2;
166 unsigned char buff[BUFF_SZ];
169 if ((fd = open(filename, O_RDWR | O_CREAT, 0600)) < 0) {
170 fprintf(stderr, "Failed to open %s: %s\n", filename, strerror(errno));
174 /* Fill with random data */
175 if (test_write_random(filename, fd, buff, size) < 0)
178 /* Read it back sanity check */
179 if (test_read_random(filename, fd, buff, size) < 0)
182 /* Iteratively truncate file down */
183 while (trunc_size > 0) {
185 if (ftruncate(fd, (off_t)trunc_size) < 0) {
186 fprintf(stderr, "ftruncate failed: %s %s\n", filename, strerror(errno));
190 /* Read check the truncated data again */
191 if (test_read_random(filename, fd, buff, trunc_size) < 0)
195 if (fstat(fd, &statbuf) < 0) {
196 fprintf(stderr, "fstat failed: %s %s\n", filename, strerror(errno));
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);
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));
212 if (fstat(fd, &statbuf) < 0) {
213 fprintf(stderr, "fstat failed: %s %s\n", filename, strerror(errno));
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);
222 /* Check the first chunk */
223 if (test_read_random(filename, fd, buff, trunc_size) < 0)
225 /* Check the end is all zero */
226 if (test_read_rest(filename, fd, buff, trunc_size, size) < 0)
236 fprintf(stderr, "close failed: %s: %s\n", filename, strerror(errno));
240 if (unlink(filename) < 0) {
241 fprintf(stderr, "unlink failed: %s: %s\n", filename, strerror(errno));
248 void sighandler(int dummy)
253 int main(int argc, char **argv)
255 ssize_t len = DEFAULT_SIZE;
256 const ssize_t max_len = SSIZE_MAX / 1024;
259 fprintf(stderr, "Syntax: %s filename [size_in_K]\n", argv[0]);
264 len = atoll(argv[2]);
266 fprintf(stderr, "size should be > 0\n");
272 fprintf(stderr, "size should be < %zd\n", max_len);
275 signal(SIGINT, sighandler);
277 exit(test_exercise(argv[1], len * 1024));