test_io.c revision 1d2ff46ae7533ffd038534b189f272d2a4122e4e
1/*
2 * test_io.c --- This is the Test I/O interface.
3 *
4 * Copyright (C) 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <stdlib.h>
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#if HAVE_ERRNO_H
27#include <errno.h>
28#endif
29
30#include "et/com_err.h"
31#include "ext2fs/ext2_err.h"
32#include "io.h"
33
34/*
35 * For checking structure magic numbers...
36 */
37
38#define EXT2_CHECK_MAGIC(struct, code) \
39	  if ((struct)->magic != (code)) return (code)
40
41struct test_private_data {
42	int	magic;
43	io_channel real;
44	void (*read_blk)(unsigned long block, int count, errcode_t err);
45	void (*write_blk)(unsigned long block, int count, errcode_t err);
46	void (*set_blksize)(int blksize, errcode_t err);
47};
48
49static errcode_t test_open(const char *name, int flags, io_channel *channel);
50static errcode_t test_close(io_channel channel);
51static errcode_t test_set_blksize(io_channel channel, int blksize);
52static errcode_t test_read_blk(io_channel channel, unsigned long block,
53			       int count, void *data);
54static errcode_t test_write_blk(io_channel channel, unsigned long block,
55				int count, const void *data);
56static errcode_t test_flush(io_channel channel);
57
58static struct struct_io_manager struct_test_manager = {
59	EXT2_ET_MAGIC_IO_MANAGER,
60	"Test I/O Manager",
61	test_open,
62	test_close,
63	test_set_blksize,
64	test_read_blk,
65	test_write_blk,
66	test_flush
67};
68
69io_manager test_io_manager = &struct_test_manager;
70
71/*
72 * These global variable can be set by the test program as
73 * necessary *before* calling test_open
74 */
75io_manager test_io_backing_manager = 0;
76void (*test_io_cb_read_blk)
77	(unsigned long block, int count, errcode_t err) = 0;
78void (*test_io_cb_write_blk)
79	(unsigned long block, int count, errcode_t err) = 0;
80void (*test_io_cb_set_blksize)
81	(int blksize, errcode_t err) = 0;
82
83static errcode_t test_open(const char *name, int flags, io_channel *channel)
84{
85	io_channel	io = NULL;
86	struct test_private_data *data = NULL;
87	errcode_t	retval;
88
89	if (name == 0)
90		return EXT2_ET_BAD_DEVICE_NAME;
91	io = (io_channel) malloc(sizeof(struct struct_io_channel));
92	if (!io)
93		return ENOMEM;
94	memset(io, 0, sizeof(struct struct_io_channel));
95	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
96	data = (struct test_private_data *)
97		malloc(sizeof(struct test_private_data));
98	if (!data) {
99		retval = ENOMEM;
100		goto cleanup;
101	}
102	io->manager = test_io_manager;
103	io->name = malloc(strlen(name)+1);
104	if (!io->name) {
105		retval = ENOMEM;
106		goto cleanup;
107	}
108	strcpy(io->name, name);
109	io->private_data = data;
110	io->block_size = 1024;
111	io->read_error = 0;
112	io->write_error = 0;
113	io->refcount = 1;
114
115	memset(data, 0, sizeof(struct test_private_data));
116	data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL;
117	if (test_io_backing_manager) {
118		retval = test_io_backing_manager->open(name, flags,
119						       &data->real);
120		if (retval)
121			goto cleanup;
122	} else
123		data->real = 0;
124	data->read_blk = 	test_io_cb_read_blk;
125	data->write_blk = 	test_io_cb_write_blk;
126	data->set_blksize = 	test_io_cb_set_blksize;
127
128	*channel = io;
129	return 0;
130
131cleanup:
132	if (io)
133		free(io);
134	if (data)
135		free(data);
136	return retval;
137}
138
139static errcode_t test_close(io_channel channel)
140{
141	struct test_private_data *data;
142	errcode_t	retval = 0;
143
144	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
145	data = (struct test_private_data *) channel->private_data;
146	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
147
148	if (--channel->refcount > 0)
149		return 0;
150
151	if (data->real)
152		retval = io_channel_close(data->real);
153
154	if (channel->private_data)
155		free(channel->private_data);
156	if (channel->name)
157		free(channel->name);
158	free(channel);
159	return retval;
160}
161
162static errcode_t test_set_blksize(io_channel channel, int blksize)
163{
164	struct test_private_data *data;
165	errcode_t	retval = 0;
166
167	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
168	data = (struct test_private_data *) channel->private_data;
169	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
170
171	if (data->real)
172		retval = io_channel_set_blksize(data->real, blksize);
173	if (data->set_blksize)
174		data->set_blksize(blksize, retval);
175	else
176		printf("Test_io: set_blksize(%d) returned %s\n",
177		       blksize, retval ? error_message(retval) : "OK");
178	return retval;
179}
180
181
182static errcode_t test_read_blk(io_channel channel, unsigned long block,
183			       int count, void *buf)
184{
185	struct test_private_data *data;
186	errcode_t	retval = 0;
187
188	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
189	data = (struct test_private_data *) channel->private_data;
190	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
191
192	if (data->real)
193		retval = io_channel_read_blk(data->real, block, count, buf);
194	if (data->read_blk)
195		data->read_blk(block, count, retval);
196	else
197		printf("Test_io: read_blk(%lu, %d) returned %s\n",
198		       block, count, retval ? error_message(retval) : "OK");
199	return retval;
200}
201
202static errcode_t test_write_blk(io_channel channel, unsigned long block,
203			       int count, const void *buf)
204{
205	struct test_private_data *data;
206	errcode_t	retval = 0;
207
208	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
209	data = (struct test_private_data *) channel->private_data;
210	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
211
212	if (data->real)
213		retval = io_channel_write_blk(data->real, block, count, buf);
214	if (data->write_blk)
215		data->write_blk(block, count, retval);
216	else
217		printf("Test_io: write_blk(%lu, %d) returned %s\n",
218		       block, count, retval ? error_message(retval) : "OK");
219	return retval;
220}
221
222/*
223 * Flush data buffers to disk.
224 */
225static errcode_t test_flush(io_channel channel)
226{
227	struct test_private_data *data;
228
229	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
230	data = (struct test_private_data *) channel->private_data;
231	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
232
233	if (data->real)
234		return io_channel_flush(data->real);
235	return 0;
236}
237
238