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