Whamcloud - gitweb
Add support for passing options to the io layer using the URL syntax. For
authorTheodore Ts'o <tytso@mit.edu>
Tue, 30 Nov 2004 19:07:11 +0000 (14:07 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 30 Nov 2004 19:07:11 +0000 (14:07 -0500)
example, /tmp/test.img?offset=1024.  Multiple options can separated using
the & character, although at the moment the only option implemented is
the offset option in the unix_io layer.

16 files changed:
e2fsck/ChangeLog
e2fsck/e2fsck.h
e2fsck/unix.c
lib/ext2fs/ChangeLog
lib/ext2fs/Makefile.in
lib/ext2fs/ext2_io.h
lib/ext2fs/ext2fs.h
lib/ext2fs/freefs.c
lib/ext2fs/io_manager.c [new file with mode: 0644]
lib/ext2fs/openfs.c
lib/ext2fs/test_io.c
lib/ext2fs/unix_io.c
misc/ChangeLog
misc/tune2fs.c
resize/ChangeLog
resize/main.c

index 9d74ecd..cf99a87 100644 (file)
@@ -1,5 +1,11 @@
 2004-11-30  Theodore Ts'o  <tytso@mit.edu>
 
+       * e2fsck.h: Add io_options to e2fsck_struct
+
+       * unix.c: If there is a question mark in the device name, separate
+               out the options to the IO layer, and pass it on to
+               ext2fs_open2().
+
        * Makefile.in: Use Linux-kernel-style makefile output to make it
                easier to see errors/warnings.
 
index ad27745..99ee20a 100644 (file)
@@ -189,6 +189,7 @@ struct e2fsck_struct {
        const char *program_name;
        char *filesystem_name;
        char *device_name;
+       char *io_options;
        int     flags;          /* E2fsck internal flags */
        int     options;
        blk_t   use_superblock; /* sb requested by user */
index 43ef4c9..7e55f87 100644 (file)
@@ -708,6 +708,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
        if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
            !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
                ctx->options |= E2F_OPT_READONLY;
+       ctx->io_options = strchr(argv[optind], '?');
+       if (ctx->io_options) 
+               *ctx->io_options++ = 0;
        ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
        if (!ctx->filesystem_name) {
                com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), 
@@ -869,23 +872,29 @@ restart:
        if ((ctx->options & E2F_OPT_READONLY) == 0)
                flags |= EXT2_FLAG_RW;
 
+       if (ctx->io_options) {
+               int len = strlen(ctx->filesystem_name) + 
+                       strlen(ctx->io_options) + 2;
+       }
+
        if (ctx->superblock && ctx->blocksize) {
-               retval = ext2fs_open(ctx->filesystem_name, flags,
-                                    ctx->superblock, ctx->blocksize,
-                                    io_ptr, &fs);
+               retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, 
+                                     flags, ctx->superblock, ctx->blocksize,
+                                     io_ptr, &fs);
        } else if (ctx->superblock) {
                int blocksize;
                for (blocksize = EXT2_MIN_BLOCK_SIZE;
                     blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
-                       retval = ext2fs_open(ctx->filesystem_name, flags,
-                                            ctx->superblock, blocksize,
-                                            io_ptr, &fs);
+                       retval = ext2fs_open2(ctx->filesystem_name, 
+                                             ctx->io_options, flags,
+                                             ctx->superblock, blocksize,
+                                             io_ptr, &fs);
                        if (!retval)
                                break;
                }
        } else 
-               retval = ext2fs_open(ctx->filesystem_name, flags, 
-                                    0, 0, io_ptr, &fs);
+               retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, 
+                                     flags, 0, 0, io_ptr, &fs);
        if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
            !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
            ((retval == EXT2_ET_BAD_MAGIC) ||
index 5a201d4..bcb699a 100644 (file)
@@ -1,5 +1,24 @@
 2004-11-30  Theodore Ts'o  <tytso@mit.edu>
 
+       * unix_io.c (unix_set_option): Add support for the offset option.
+
+       * test_io.c (test_set_option): Add support for the set_option method.
+
+       * ext2_io.h: Add new io_channel method, set_option(), and change
+               io_channel_write_byte() from a macro to a library function.
+
+       * ext2fs.h, openfs.c(ext2fs_open2): New version of ext2fs_open
+               which adds a new parameter, io_options.
+               (ext2fs_open): If there is a question mark in the
+               filename, and no io_options are specified, assumed that
+               the text following the question mark are io_options.
+       
+       * io_manager.c, Makefile.in: New source file which contains
+               high-level functions for the io_channel layer.
+
+       * freefs.c (ext2fs_free): Make sure we don't free the io_channel
+               if image_io is NULL.
+
        * Makefile.in: Use Linux-kernel-style makefile output to make it
                easier to see errors/warnings.
 
index 5ebcd6c..2c7edf6 100644 (file)
@@ -46,6 +46,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
        initialize.o \
        inline.o \
        inode.o \
+       io_manager.o \
        ismounted.o \
        link.o \
        llseek.o \
@@ -96,11 +97,12 @@ SRCS= ext2_err.c \
        $(srcdir)/getsize.c \
        $(srcdir)/getsectsize.c \
        $(srcdir)/icount.c \
-       $(srcdir)/imager.c \
        $(srcdir)/initialize.c \
        $(srcdir)/inline.c \
        $(srcdir)/inode.c \
        $(srcdir)/inode_io.c \
+       $(srcdir)/imager.c \
+       $(srcdir)/io_manager.c \
        $(srcdir)/ismounted.c \
        $(srcdir)/link.c \
        $(srcdir)/llseek.c \
index b9ba0b6..e17886c 100644 (file)
@@ -68,7 +68,9 @@ struct struct_io_manager {
        errcode_t (*flush)(io_channel channel);
        errcode_t (*write_byte)(io_channel channel, unsigned long offset,
                                int count, const void *data);
-       int             reserved[15];
+       errcode_t (*set_option)(io_channel channel, const char *option, 
+                               const char *arg);
+       int             reserved[14];
 };
 
 #define IO_FLAG_RW     1
@@ -81,9 +83,15 @@ struct struct_io_manager {
 #define io_channel_read_blk(c,b,n,d)   ((c)->manager->read_blk((c),b,n,d))
 #define io_channel_write_blk(c,b,n,d)  ((c)->manager->write_blk((c),b,n,d))
 #define io_channel_flush(c)            ((c)->manager->flush((c)))
-#define io_channel_write_byte(c,b,n,d) ((c)->manager->write_byte((c),b,n,d))
 #define io_channel_bumpcount(c)                ((c)->refcount++)
        
+/* io_manager.c */
+extern errcode_t io_channel_set_options(io_channel channel, 
+                                       const char *options);
+extern errcode_t io_channel_write_byte(io_channel channel, 
+                                      unsigned long offset,
+                                      int count, const void *data);
+
 /* unix_io.c */
 extern io_manager unix_io_manager;
 
index 19be9c5..6a02127 100644 (file)
@@ -851,6 +851,10 @@ extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size,
 extern errcode_t ext2fs_open(const char *name, int flags, int superblock,
                             unsigned int block_size, io_manager manager,
                             ext2_filsys *ret_fs);
+extern errcode_t ext2fs_open2(const char *name, const char *io_options, 
+                             int flags, int superblock, 
+                             unsigned int block_size, io_manager manager,
+                             ext2_filsys *ret_fs);
 extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, 
                                         dgrp_t i);
 errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io);
index 9dda403..029ffaa 100644 (file)
@@ -24,7 +24,8 @@ void ext2fs_free(ext2_filsys fs)
        if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
                return;
        if (fs->image_io != fs->io) {
-               io_channel_close(fs->image_io);
+               if (fs->image_io)
+                       io_channel_close(fs->image_io);
        }
        if (fs->io) {
                io_channel_close(fs->io);
diff --git a/lib/ext2fs/io_manager.c b/lib/ext2fs/io_manager.c
new file mode 100644 (file)
index 0000000..e50d7e4
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * io_manager.c --- the I/O manager abstraction
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t io_channel_set_options(io_channel channel, const char *opts)
+{
+       errcode_t retval = 0;
+       char *next, *ptr, *options, *arg;
+
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+       if (!opts)
+               return 0;
+
+       if (!channel->manager->set_option)
+               return EXT2_ET_INVALID_ARGUMENT;
+
+       options = malloc(strlen(opts)+1);
+       if (!options)
+               return EXT2_ET_NO_MEMORY;
+       strcpy(options, opts);
+       ptr = options;
+
+       while (ptr && *ptr) {
+               next = strchr(ptr, '&');
+               if (next)
+                       *next++ = 0;
+
+               arg = strchr(ptr, '=');
+               if (arg)
+                       *arg++ = 0;
+
+               retval = (channel->manager->set_option)(channel, ptr, arg);
+               if (retval)
+                       break;
+               ptr = next;
+       }
+       free(options);
+       return retval;
+}
+
+errcode_t io_channel_write_byte(io_channel channel, unsigned long offset,
+                               int count, const void *data)
+{
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+       if (channel->manager->write_byte) 
+               return channel->manager->write_byte(channel, offset, 
+                                                   count, data);
+
+       return EXT2_ET_UNIMPLEMENTED;
+}
index dac8a38..05de84f 100644 (file)
@@ -59,6 +59,14 @@ blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
        return ret_blk;
 }
 
+errcode_t ext2fs_open(const char *name, int flags, int superblock,
+                     unsigned int block_size, io_manager manager, 
+                     ext2_filsys *ret_fs)
+{
+       return ext2fs_open2(name, 0, flags, superblock, block_size, 
+                           manager, ret_fs);
+}
+
 /*
  *  Note: if superblock is non-zero, block-size must also be non-zero.
  *     Superblock and block_size can be zero to use the default size.
@@ -70,16 +78,17 @@ blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
  *                             features aren't supported.
  *     EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
  */
-errcode_t ext2fs_open(const char *name, int flags, int superblock,
-                     unsigned int block_size, io_manager manager, 
-                     ext2_filsys *ret_fs)
+errcode_t ext2fs_open2(const char *name, const char *io_options,
+                      int flags, int superblock,
+                      unsigned int block_size, io_manager manager, 
+                      ext2_filsys *ret_fs)
 {
        ext2_filsys     fs;
        errcode_t       retval;
        unsigned long   i;
        int             j, groups_per_block, blocks_per_group;
        blk_t           group_block, blk;
-       char            *dest;
+       char            *dest, *cp;
        struct ext2_group_desc *gdp;
        
        EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
@@ -92,16 +101,26 @@ errcode_t ext2fs_open(const char *name, int flags, int superblock,
        fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
        fs->flags = flags;
        fs->umask = 022;
-       retval = manager->open(name, (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
+       retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
+       if (retval)
+               goto cleanup;
+       strcpy(fs->device_name, name);
+       cp = strchr(fs->device_name, '?');
+       if (!io_options && cp) {
+               *cp++ = 0;
+               io_options = cp;
+       }
+               
+       retval = manager->open(fs->device_name, 
+                              (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
                               &fs->io);
        if (retval)
                goto cleanup;
+       if (io_options && 
+           (retval = io_channel_set_options(fs->io, io_options)))
+               goto cleanup;
        fs->image_io = fs->io;
        fs->io->app_data = fs;
-       retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
-       if (retval)
-               goto cleanup;
-       strcpy(fs->device_name, name);
        retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
        if (retval)
                goto cleanup;
index 02b6e18..6a3b248 100644 (file)
@@ -56,6 +56,8 @@ static errcode_t test_write_blk(io_channel channel, unsigned long block,
 static errcode_t test_flush(io_channel channel);
 static errcode_t test_write_byte(io_channel channel, unsigned long offset,
                                 int count, const void *buf);
+static errcode_t test_set_option(io_channel channel, const char *option, 
+                                const char *arg);
 
 static struct struct_io_manager struct_test_manager = {
        EXT2_ET_MAGIC_IO_MANAGER,
@@ -66,8 +68,8 @@ static struct struct_io_manager struct_test_manager = {
        test_read_blk,
        test_write_blk,
        test_flush,
-       test_write_byte
-       
+       test_write_byte,
+       test_set_option
 };
 
 io_manager test_io_manager = &struct_test_manager;
@@ -94,6 +96,7 @@ void (*test_io_cb_write_byte)
 #define TEST_FLAG_SET_BLKSIZE          0x04
 #define TEST_FLAG_FLUSH                        0x08
 #define TEST_FLAG_DUMP                 0x10
+#define TEST_FLAG_SET_OPTION           0x20
 
 static void test_dump_block(io_channel channel,
                            struct test_private_data *data,
@@ -351,3 +354,29 @@ static errcode_t test_flush(io_channel channel)
        return retval;
 }
 
+static errcode_t test_set_option(io_channel channel, const char *option, 
+                                const char *arg)
+{
+       struct test_private_data *data;
+       errcode_t       retval = 0;
+
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+       data = (struct test_private_data *) channel->private_data;
+       EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+
+       if (data->flags & TEST_FLAG_SET_OPTION)
+               fprintf(data->outfile, "Test_io: set_option(%s, %s) ", 
+                       option, arg);
+       if (data->real && data->real->manager->set_option) {
+               retval = (data->real->manager->set_option)(data->real, 
+                                                          option, arg);
+               if (data->flags & TEST_FLAG_SET_OPTION)
+                       fprintf(data->outfile, "returned %s\n",
+                               retval ? error_message(retval) : "OK");
+       } else {
+               if (data->flags & TEST_FLAG_SET_OPTION)
+                       fprintf(data->outfile, "not implemented\n");
+       }
+       return retval;
+}
index 7df3243..e1df0d6 100644 (file)
@@ -68,6 +68,7 @@ struct unix_private_data {
        int     dev;
        int     flags;
        int     access_time;
+       ext2_loff_t offset;
        struct unix_cache cache[CACHE_SIZE];
 };
 
@@ -81,6 +82,8 @@ static errcode_t unix_write_blk(io_channel channel, unsigned long block,
 static errcode_t unix_flush(io_channel channel);
 static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
                                int size, const void *data);
+static errcode_t unix_set_option(io_channel channel, const char *option, 
+                                const char *arg);
 
 static void reuse_cache(io_channel channel, struct unix_private_data *data,
                 struct unix_cache *cache, unsigned long block);
@@ -103,10 +106,11 @@ static struct struct_io_manager struct_unix_manager = {
        unix_write_blk,
        unix_flush,
 #ifdef NEED_BOUNCE_BUFFER
-       0
+       0,
 #else
-       unix_write_byte
+       unix_write_byte,
 #endif
+       unix_set_option
 };
 
 io_manager unix_io_manager = &struct_unix_manager;
@@ -126,7 +130,7 @@ static errcode_t raw_read_blk(io_channel channel,
        int             actual = 0;
 
        size = (count < 0) ? -count : count * channel->block_size;
-       location = (ext2_loff_t) block * channel->block_size;
+       location = ((ext2_loff_t) block * channel->block_size) + data->offset;
        if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
                retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
                goto error_out;
@@ -164,7 +168,7 @@ static errcode_t raw_read_blk(io_channel channel,
        char            sector[BLOCKALIGN];
 
        size = (count < 0) ? -count : count * channel->block_size;
-       location = (ext2_loff_t) block * channel->block_size;
+       location = ((ext2_loff_t) block * channel->block_size) + data->offset;
 #ifdef DEBUG
        printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
                        count, size, block, channel->block_size, location);
@@ -221,7 +225,7 @@ static errcode_t raw_write_blk(io_channel channel,
                        size = count * channel->block_size;
        }
 
-       location = (ext2_loff_t) block * channel->block_size;
+       location = ((ext2_loff_t) block * channel->block_size) + data->offset;
        if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
                retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
                goto error_out;
@@ -406,12 +410,12 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
 
        if ((retval = alloc_cache(io, data)))
                goto cleanup;
-       
+
        open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
 #ifdef HAVE_OPEN64
-       data->dev = open64(name, open_flags);
+       data->dev = open64(io->name, open_flags);
 #else
-       data->dev = open(name, open_flags);
+       data->dev = open(io->name, open_flags);
 #endif
        if (data->dev < 0) {
                retval = errno;
@@ -652,7 +656,7 @@ static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
                return retval;
 #endif
 
-       if (lseek(data->dev, offset, SEEK_SET) < 0)
+       if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
                return errno;
        
        actual = write(data->dev, buf, size);
@@ -681,3 +685,26 @@ static errcode_t unix_flush(io_channel channel)
        return retval;
 }
 
+static errcode_t unix_set_option(io_channel channel, const char *option, 
+                                const char *arg)
+{
+       struct unix_private_data *data;
+       unsigned long tmp;
+       char *end;
+
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+       data = (struct unix_private_data *) channel->private_data;
+       EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+       if (!strcmp(option, "offset")) {
+               if (!arg)
+                       return EXT2_ET_INVALID_ARGUMENT;
+
+               tmp = strtoul(arg, &end, 0);
+               if (*end)
+                       return EXT2_ET_INVALID_ARGUMENT;
+               data->offset = tmp;
+               return 0;
+       }
+       return EXT2_ET_INVALID_ARGUMENT;
+}
index 06c8c51..796968d 100644 (file)
@@ -1,5 +1,9 @@
 2004-11-30  Theodore Ts'o  <tytso@mit.edu>
 
+       * tune2fs.c: If there is a question mark in the device name,
+               separate out the options to the IO layer, and pass it on
+               to ext2fs_open2().
+
        * Makefile.in: Use Linux-kernel-style makefile output to make it
                easier to see errors/warnings.
 
index e7c3baf..2a8ac02 100644 (file)
@@ -58,6 +58,7 @@ extern int optind;
 const char * program_name = "tune2fs";
 char * device_name;
 char * new_label, *new_last_mounted, *new_UUID;
+char * io_options;
 static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
 static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
 static time_t last_check_time;
@@ -449,6 +450,9 @@ static void parse_e2label_options(int argc, char ** argv)
                fputs(_("Usage: e2label device [newlabel]\n"), stderr);
                exit(1);
        }
+       io_options = strchr(argv[1], '?');
+       if (io_options)
+               *io_options++ = 0;
        device_name = blkid_get_devname(NULL, argv[1], NULL);
        if (!device_name) {
                com_err("e2label", 0, _("Unable to resolve '%s'"), 
@@ -704,6 +708,9 @@ static void parse_tune2fs_options(int argc, char **argv)
                usage();
        if (!open_flag && !l_flag)
                usage();
+       io_options = strchr(argv[optind], '?');
+       if (io_options)
+               *io_options++ = 0;
        device_name = blkid_get_devname(NULL, argv[optind], NULL);
        if (!device_name) {
                com_err("tune2fs", 0, _("Unable to resolve '%s'"), 
@@ -762,7 +769,8 @@ int main (int argc, char ** argv)
 #else
        io_ptr = unix_io_manager;
 #endif
-       retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs);
+       retval = ext2fs_open2(device_name, io_options, open_flag, 
+                             0, 0, io_ptr, &fs);
         if (retval) {
                com_err (program_name, retval, _("while trying to open %s"),
                         device_name);
index 50c7469..d676707 100644 (file)
@@ -1,5 +1,9 @@
 2004-11-30  Theodore Ts'o  <tytso@mit.edu>
 
+       * main.c: If there is a question mark in the device name,
+               separate out the options to the IO layer, and pass it on
+               to ext2fs_open2().
+
        * Makefile.in: Use Linux-kernel-style makefile output to make it
                easier to see errors/warnings.
 
index b32a7ea..3d137ef 100644 (file)
@@ -25,7 +25,7 @@ extern int optind;
 
 #include "../version.h"
 
-char *program_name, *device_name;
+char *program_name, *device_name, *io_options;
 
 static void usage (char *prog)
 {
@@ -195,6 +195,10 @@ int main (int argc, char ** argv)
        if (optind < argc)
                usage(program_name);
        
+       io_options = strchr(device_name, '?');
+       if (io_options)
+               *io_options++ = 0;
+
        check_mount(device_name);
        
        if (flush) {
@@ -222,8 +226,8 @@ int main (int argc, char ** argv)
        } else 
                io_ptr = unix_io_manager;
 
-       retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
-                             io_ptr, &fs);
+       retval = ext2fs_open2(device_name, io_options, EXT2_FLAG_RW, 
+                             0, 0, io_ptr, &fs);
        if (retval) {
                com_err (program_name, retval, _("while trying to open %s"),
                         device_name);