busybox/e2fsprogs/old_e2fsprogs/ext2fs/test_io.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * test_io.c --- This is the Test I/O interface.
   4 *
   5 * Copyright (C) 1996 Theodore Ts'o.
   6 *
   7 * %Begin-Header%
   8 * This file may be redistributed under the terms of the GNU Public
   9 * License.
  10 * %End-Header%
  11 */
  12
  13#include <stdio.h>
  14#include <string.h>
  15#if HAVE_UNISTD_H
  16#include <unistd.h>
  17#endif
  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
  27#include "ext2_fs.h"
  28#include "ext2fs.h"
  29
  30/*
  31 * For checking structure magic numbers...
  32 */
  33
  34#define EXT2_CHECK_MAGIC(struct, code) \
  35          if ((struct)->magic != (code)) return (code)
  36
  37struct test_private_data {
  38        int     magic;
  39        io_channel real;
  40        int flags;
  41        FILE *outfile;
  42        unsigned long block;
  43        int read_abort_count, write_abort_count;
  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        void (*write_byte)(unsigned long block, int count, errcode_t err);
  48};
  49
  50static errcode_t test_open(const char *name, int flags, io_channel *channel);
  51static errcode_t test_close(io_channel channel);
  52static errcode_t test_set_blksize(io_channel channel, int blksize);
  53static errcode_t test_read_blk(io_channel channel, unsigned long block,
  54                               int count, void *data);
  55static errcode_t test_write_blk(io_channel channel, unsigned long block,
  56                                int count, const void *data);
  57static errcode_t test_flush(io_channel channel);
  58static errcode_t test_write_byte(io_channel channel, unsigned long offset,
  59                                 int count, const void *buf);
  60static errcode_t test_set_option(io_channel channel, const char *option,
  61                                 const char *arg);
  62
  63static struct struct_io_manager struct_test_manager = {
  64        EXT2_ET_MAGIC_IO_MANAGER,
  65        "Test I/O Manager",
  66        test_open,
  67        test_close,
  68        test_set_blksize,
  69        test_read_blk,
  70        test_write_blk,
  71        test_flush,
  72        test_write_byte,
  73        test_set_option
  74};
  75
  76io_manager test_io_manager = &struct_test_manager;
  77
  78/*
  79 * These global variable can be set by the test program as
  80 * necessary *before* calling test_open
  81 */
  82io_manager test_io_backing_manager = 0;
  83void (*test_io_cb_read_blk)
  84        (unsigned long block, int count, errcode_t err) = 0;
  85void (*test_io_cb_write_blk)
  86        (unsigned long block, int count, errcode_t err) = 0;
  87void (*test_io_cb_set_blksize)
  88        (int blksize, errcode_t err) = 0;
  89void (*test_io_cb_write_byte)
  90        (unsigned long block, int count, errcode_t err) = 0;
  91
  92/*
  93 * Test flags
  94 */
  95#define TEST_FLAG_READ                  0x01
  96#define TEST_FLAG_WRITE                 0x02
  97#define TEST_FLAG_SET_BLKSIZE           0x04
  98#define TEST_FLAG_FLUSH                 0x08
  99#define TEST_FLAG_DUMP                  0x10
 100#define TEST_FLAG_SET_OPTION            0x20
 101
 102static void test_dump_block(io_channel channel,
 103                            struct test_private_data *data,
 104                            unsigned long block, const void *buf)
 105{
 106        const unsigned char *cp;
 107        FILE *f = data->outfile;
 108        int     i;
 109        unsigned long   cksum = 0;
 110
 111        for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
 112                cksum += *cp;
 113        }
 114        fprintf(f, "Contents of block %lu, checksum %08lu:\n", block, cksum);
 115        for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
 116                if ((i % 16) == 0)
 117                        fprintf(f, "%04x: ", i);
 118                fprintf(f, "%02x%c", *cp, ((i % 16) == 15) ? '\n' : ' ');
 119        }
 120}
 121
 122static void test_abort(io_channel channel, unsigned long block)
 123{
 124        struct test_private_data *data;
 125        FILE *f;
 126
 127        data = (struct test_private_data *) channel->private_data;
 128        f = data->outfile;
 129        test_flush(channel);
 130
 131        fprintf(f, "Aborting due to I/O to block %lu\n", block);
 132        fflush(f);
 133        abort();
 134}
 135
 136static errcode_t test_open(const char *name, int flags, io_channel *channel)
 137{
 138        io_channel      io = NULL;
 139        struct test_private_data *data = NULL;
 140        errcode_t       retval;
 141        char            *value;
 142
 143        if (name == 0)
 144                return EXT2_ET_BAD_DEVICE_NAME;
 145        retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
 146        if (retval)
 147                return retval;
 148        memset(io, 0, sizeof(struct struct_io_channel));
 149        io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
 150        retval = ext2fs_get_mem(sizeof(struct test_private_data), &data);
 151        if (retval) {
 152                retval = EXT2_ET_NO_MEMORY;
 153                goto cleanup;
 154        }
 155        io->manager = test_io_manager;
 156        retval = ext2fs_get_mem(strlen(name)+1, &io->name);
 157        if (retval)
 158                goto cleanup;
 159
 160        strcpy(io->name, name);
 161        io->private_data = data;
 162        io->block_size = 1024;
 163        io->read_error = 0;
 164        io->write_error = 0;
 165        io->refcount = 1;
 166
 167        memset(data, 0, sizeof(struct test_private_data));
 168        data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL;
 169        if (test_io_backing_manager) {
 170                retval = test_io_backing_manager->open(name, flags,
 171                                                       &data->real);
 172                if (retval)
 173                        goto cleanup;
 174        } else
 175                data->real = 0;
 176        data->read_blk =        test_io_cb_read_blk;
 177        data->write_blk =       test_io_cb_write_blk;
 178        data->set_blksize =     test_io_cb_set_blksize;
 179        data->write_byte =      test_io_cb_write_byte;
 180
 181        data->outfile = NULL;
 182        if ((value = getenv("TEST_IO_LOGFILE")) != NULL)
 183                data->outfile = fopen_for_write(value);
 184        if (!data->outfile)
 185                data->outfile = stderr;
 186
 187        data->flags = 0;
 188        if ((value = getenv("TEST_IO_FLAGS")) != NULL)
 189                data->flags = strtoul(value, NULL, 0);
 190
 191        data->block = 0;
 192        if ((value = getenv("TEST_IO_BLOCK")) != NULL)
 193                data->block = strtoul(value, NULL, 0);
 194
 195        data->read_abort_count = 0;
 196        if ((value = getenv("TEST_IO_READ_ABORT")) != NULL)
 197                data->read_abort_count = strtoul(value, NULL, 0);
 198
 199        data->write_abort_count = 0;
 200        if ((value = getenv("TEST_IO_WRITE_ABORT")) != NULL)
 201                data->write_abort_count = strtoul(value, NULL, 0);
 202
 203        *channel = io;
 204        return 0;
 205
 206cleanup:
 207        ext2fs_free_mem(&io);
 208        ext2fs_free_mem(&data);
 209        return retval;
 210}
 211
 212static errcode_t test_close(io_channel channel)
 213{
 214        struct test_private_data *data;
 215        errcode_t       retval = 0;
 216
 217        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 218        data = (struct test_private_data *) channel->private_data;
 219        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
 220
 221        if (--channel->refcount > 0)
 222                return 0;
 223
 224        if (data->real)
 225                retval = io_channel_close(data->real);
 226
 227        if (data->outfile && data->outfile != stderr)
 228                fclose(data->outfile);
 229
 230        ext2fs_free_mem(&channel->private_data);
 231        ext2fs_free_mem(&channel->name);
 232        ext2fs_free_mem(&channel);
 233        return retval;
 234}
 235
 236static errcode_t test_set_blksize(io_channel channel, int blksize)
 237{
 238        struct test_private_data *data;
 239        errcode_t       retval = 0;
 240
 241        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 242        data = (struct test_private_data *) channel->private_data;
 243        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
 244
 245        if (data->real)
 246                retval = io_channel_set_blksize(data->real, blksize);
 247        if (data->set_blksize)
 248                data->set_blksize(blksize, retval);
 249        if (data->flags & TEST_FLAG_SET_BLKSIZE)
 250                fprintf(data->outfile,
 251                        "Test_io: set_blksize(%d) returned %s\n",
 252                        blksize, retval ? error_message(retval) : "OK");
 253        channel->block_size = blksize;
 254        return retval;
 255}
 256
 257
 258static errcode_t test_read_blk(io_channel channel, unsigned long block,
 259                               int count, void *buf)
 260{
 261        struct test_private_data *data;
 262        errcode_t       retval = 0;
 263
 264        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 265        data = (struct test_private_data *) channel->private_data;
 266        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
 267
 268        if (data->real)
 269                retval = io_channel_read_blk(data->real, block, count, buf);
 270        if (data->read_blk)
 271                data->read_blk(block, count, retval);
 272        if (data->flags & TEST_FLAG_READ)
 273                fprintf(data->outfile,
 274                        "Test_io: read_blk(%lu, %d) returned %s\n",
 275                        block, count, retval ? error_message(retval) : "OK");
 276        if (data->block && data->block == block) {
 277                if (data->flags & TEST_FLAG_DUMP)
 278                        test_dump_block(channel, data, block, buf);
 279                if (--data->read_abort_count == 0)
 280                        test_abort(channel, block);
 281        }
 282        return retval;
 283}
 284
 285static errcode_t test_write_blk(io_channel channel, unsigned long block,
 286                               int count, const void *buf)
 287{
 288        struct test_private_data *data;
 289        errcode_t       retval = 0;
 290
 291        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 292        data = (struct test_private_data *) channel->private_data;
 293        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
 294
 295        if (data->real)
 296                retval = io_channel_write_blk(data->real, block, count, buf);
 297        if (data->write_blk)
 298                data->write_blk(block, count, retval);
 299        if (data->flags & TEST_FLAG_WRITE)
 300                fprintf(data->outfile,
 301                        "Test_io: write_blk(%lu, %d) returned %s\n",
 302                        block, count, retval ? error_message(retval) : "OK");
 303        if (data->block && data->block == block) {
 304                if (data->flags & TEST_FLAG_DUMP)
 305                        test_dump_block(channel, data, block, buf);
 306                if (--data->write_abort_count == 0)
 307                        test_abort(channel, block);
 308        }
 309        return retval;
 310}
 311
 312static errcode_t test_write_byte(io_channel channel, unsigned long offset,
 313                               int count, const void *buf)
 314{
 315        struct test_private_data *data;
 316        errcode_t       retval = 0;
 317
 318        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 319        data = (struct test_private_data *) channel->private_data;
 320        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
 321
 322        if (data->real && data->real->manager->write_byte)
 323                retval = io_channel_write_byte(data->real, offset, count, buf);
 324        if (data->write_byte)
 325                data->write_byte(offset, count, retval);
 326        if (data->flags & TEST_FLAG_WRITE)
 327                fprintf(data->outfile,
 328                        "Test_io: write_byte(%lu, %d) returned %s\n",
 329                        offset, count, retval ? error_message(retval) : "OK");
 330        return retval;
 331}
 332
 333/*
 334 * Flush data buffers to disk.
 335 */
 336static errcode_t test_flush(io_channel channel)
 337{
 338        struct test_private_data *data;
 339        errcode_t       retval = 0;
 340
 341        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 342        data = (struct test_private_data *) channel->private_data;
 343        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
 344
 345        if (data->real)
 346                retval = io_channel_flush(data->real);
 347
 348        if (data->flags & TEST_FLAG_FLUSH)
 349                fprintf(data->outfile, "Test_io: flush() returned %s\n",
 350                        retval ? error_message(retval) : "OK");
 351
 352        return retval;
 353}
 354
 355static errcode_t test_set_option(io_channel channel, const char *option,
 356                                 const char *arg)
 357{
 358        struct test_private_data *data;
 359        errcode_t       retval = 0;
 360
 361        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 362        data = (struct test_private_data *) channel->private_data;
 363        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
 364
 365
 366        if (data->flags & TEST_FLAG_SET_OPTION)
 367                fprintf(data->outfile, "Test_io: set_option(%s, %s) ",
 368                        option, arg);
 369        if (data->real && data->real->manager->set_option) {
 370                retval = (data->real->manager->set_option)(data->real,
 371                                                           option, arg);
 372                if (data->flags & TEST_FLAG_SET_OPTION)
 373                        fprintf(data->outfile, "returned %s\n",
 374                                retval ? error_message(retval) : "OK");
 375        } else {
 376                if (data->flags & TEST_FLAG_SET_OPTION)
 377                        fprintf(data->outfile, "not implemented\n");
 378        }
 379        return retval;
 380}
 381