busybox/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * inode_io.c --- This is allows an inode in an ext2 filesystem image
   4 *      to be accessed via the I/O manager interface.
   5 *
   6 * Copyright (C) 2002 Theodore Ts'o.
   7 *
   8 * %Begin-Header%
   9 * This file may be redistributed under the terms of the GNU Public
  10 * License.
  11 * %End-Header%
  12 */
  13
  14#include <stdio.h>
  15#include <string.h>
  16#if HAVE_UNISTD_H
  17#include <unistd.h>
  18#endif
  19#if HAVE_ERRNO_H
  20#include <errno.h>
  21#endif
  22#include <time.h>
  23
  24#include "ext2_fs.h"
  25#include "ext2fs.h"
  26
  27/*
  28 * For checking structure magic numbers...
  29 */
  30
  31#define EXT2_CHECK_MAGIC(struct, code) \
  32          if ((struct)->magic != (code)) return (code)
  33
  34struct inode_private_data {
  35        int                             magic;
  36        char                            name[32];
  37        ext2_file_t                     file;
  38        ext2_filsys                     fs;
  39        ext2_ino_t                      ino;
  40        struct ext2_inode               inode;
  41        int                             flags;
  42        struct inode_private_data       *next;
  43};
  44
  45#define CHANNEL_HAS_INODE       0x8000
  46
  47static struct inode_private_data *top_intern;
  48static int ino_unique = 0;
  49
  50static errcode_t inode_open(const char *name, int flags, io_channel *channel);
  51static errcode_t inode_close(io_channel channel);
  52static errcode_t inode_set_blksize(io_channel channel, int blksize);
  53static errcode_t inode_read_blk(io_channel channel, unsigned long block,
  54                               int count, void *data);
  55static errcode_t inode_write_blk(io_channel channel, unsigned long block,
  56                                int count, const void *data);
  57static errcode_t inode_flush(io_channel channel);
  58static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
  59                                int size, const void *data);
  60
  61static struct struct_io_manager struct_inode_manager = {
  62        EXT2_ET_MAGIC_IO_MANAGER,
  63        "Inode I/O Manager",
  64        inode_open,
  65        inode_close,
  66        inode_set_blksize,
  67        inode_read_blk,
  68        inode_write_blk,
  69        inode_flush,
  70        inode_write_byte
  71};
  72
  73io_manager inode_io_manager = &struct_inode_manager;
  74
  75errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
  76                                  struct ext2_inode *inode,
  77                                  char **name)
  78{
  79        struct inode_private_data       *data;
  80        errcode_t                       retval;
  81
  82        if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
  83                                     &data)))
  84                return retval;
  85        data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
  86        sprintf(data->name, "%u:%d", ino, ino_unique++);
  87        data->file = 0;
  88        data->fs = fs;
  89        data->ino = ino;
  90        data->flags = 0;
  91        if (inode) {
  92                memcpy(&data->inode, inode, sizeof(struct ext2_inode));
  93                data->flags |= CHANNEL_HAS_INODE;
  94        }
  95        data->next = top_intern;
  96        top_intern = data;
  97        *name = data->name;
  98        return 0;
  99}
 100
 101errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
 102                                 char **name)
 103{
 104        return ext2fs_inode_io_intern2(fs, ino, NULL, name);
 105}
 106
 107
 108static errcode_t inode_open(const char *name, int flags, io_channel *channel)
 109{
 110        io_channel      io = NULL;
 111        struct inode_private_data *prev, *data = NULL;
 112        errcode_t       retval;
 113        int             open_flags;
 114
 115        if (name == 0)
 116                return EXT2_ET_BAD_DEVICE_NAME;
 117
 118        for (data = top_intern, prev = NULL; data;
 119             prev = data, data = data->next)
 120                if (strcmp(name, data->name) == 0)
 121                        break;
 122        if (!data)
 123                return ENOENT;
 124        if (prev)
 125                prev->next = data->next;
 126        else
 127                top_intern = data->next;
 128
 129        retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
 130        if (retval)
 131                goto cleanup;
 132        memset(io, 0, sizeof(struct struct_io_channel));
 133
 134        io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
 135        io->manager = inode_io_manager;
 136        retval = ext2fs_get_mem(strlen(name)+1, &io->name);
 137        if (retval)
 138                goto cleanup;
 139
 140        strcpy(io->name, name);
 141        io->private_data = data;
 142        io->block_size = 1024;
 143        io->read_error = 0;
 144        io->write_error = 0;
 145        io->refcount = 1;
 146
 147        open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
 148        retval = ext2fs_file_open2(data->fs, data->ino,
 149                                   (data->flags & CHANNEL_HAS_INODE) ?
 150                                   &data->inode : 0, open_flags,
 151                                   &data->file);
 152        if (retval)
 153                goto cleanup;
 154
 155        *channel = io;
 156        return 0;
 157
 158cleanup:
 159        if (data) {
 160                ext2fs_free_mem(&data);
 161        }
 162        if (io)
 163                ext2fs_free_mem(&io);
 164        return retval;
 165}
 166
 167static errcode_t inode_close(io_channel channel)
 168{
 169        struct inode_private_data *data;
 170        errcode_t       retval = 0;
 171
 172        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 173        data = (struct inode_private_data *) channel->private_data;
 174        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
 175
 176        if (--channel->refcount > 0)
 177                return 0;
 178
 179        retval = ext2fs_file_close(data->file);
 180
 181        ext2fs_free_mem(&channel->private_data);
 182        if (channel->name)
 183                ext2fs_free_mem(&channel->name);
 184        ext2fs_free_mem(&channel);
 185        return retval;
 186}
 187
 188static errcode_t inode_set_blksize(io_channel channel, int blksize)
 189{
 190        struct inode_private_data *data;
 191
 192        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 193        data = (struct inode_private_data *) channel->private_data;
 194        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
 195
 196        channel->block_size = blksize;
 197        return 0;
 198}
 199
 200
 201static errcode_t inode_read_blk(io_channel channel, unsigned long block,
 202                               int count, void *buf)
 203{
 204        struct inode_private_data *data;
 205        errcode_t       retval;
 206
 207        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 208        data = (struct inode_private_data *) channel->private_data;
 209        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
 210
 211        if ((retval = ext2fs_file_lseek(data->file,
 212                                        block * channel->block_size,
 213                                        EXT2_SEEK_SET, 0)))
 214                return retval;
 215
 216        count = (count < 0) ? -count : (count * channel->block_size);
 217
 218        return ext2fs_file_read(data->file, buf, count, 0);
 219}
 220
 221static errcode_t inode_write_blk(io_channel channel, unsigned long block,
 222                                int count, const void *buf)
 223{
 224        struct inode_private_data *data;
 225        errcode_t       retval;
 226
 227        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 228        data = (struct inode_private_data *) channel->private_data;
 229        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
 230
 231        if ((retval = ext2fs_file_lseek(data->file,
 232                                        block * channel->block_size,
 233                                        EXT2_SEEK_SET, 0)))
 234                return retval;
 235
 236        count = (count < 0) ? -count : (count * channel->block_size);
 237
 238        return ext2fs_file_write(data->file, buf, count, 0);
 239}
 240
 241static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
 242                                 int size, const void *buf)
 243{
 244        struct inode_private_data *data;
 245        errcode_t       retval = 0;
 246
 247        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 248        data = (struct inode_private_data *) channel->private_data;
 249        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
 250
 251        if ((retval = ext2fs_file_lseek(data->file, offset,
 252                                        EXT2_SEEK_SET, 0)))
 253                return retval;
 254
 255        return ext2fs_file_write(data->file, buf, size, 0);
 256}
 257
 258/*
 259 * Flush data buffers to disk.
 260 */
 261static errcode_t inode_flush(io_channel channel)
 262{
 263        struct inode_private_data *data;
 264
 265        EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
 266        data = (struct inode_private_data *) channel->private_data;
 267        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
 268
 269        return ext2fs_file_flush(data->file);
 270}
 271
 272