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 33 struct 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 struct ext2_inode inode; 40 int flags; 41 struct inode_private_data *next; 42 }; 43 44 #define CHANNEL_HAS_INODE 0x8000 45 46 static struct inode_private_data *top_intern; 47 static int ino_unique = 0; 48 49 static errcode_t inode_open(const char *name, int flags, io_channel *channel); 50 static errcode_t inode_close(io_channel channel); 51 static errcode_t inode_set_blksize(io_channel channel, int blksize); 52 static errcode_t inode_read_blk(io_channel channel, unsigned long block, 53 int count, void *data); 54 static errcode_t inode_write_blk(io_channel channel, unsigned long block, 55 int count, const void *data); 56 static errcode_t inode_flush(io_channel channel); 57 static errcode_t inode_write_byte(io_channel channel, unsigned long offset, 58 int size, const void *data); 59 60 static struct struct_io_manager struct_inode_manager = { 61 EXT2_ET_MAGIC_IO_MANAGER, 62 "Inode I/O Manager", 63 inode_open, 64 inode_close, 65 inode_set_blksize, 66 inode_read_blk, 67 inode_write_blk, 68 inode_flush, 69 inode_write_byte 70 }; 71 72 io_manager inode_io_manager = &struct_inode_manager; 73 74 errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino, 75 struct ext2_inode *inode, 76 char **name) 77 { 78 struct inode_private_data *data; 79 errcode_t retval; 80 81 if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data), 82 &data))) 83 return retval; 84 data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL; 85 sprintf(data->name, "%u:%d", ino, ino_unique++); 86 data->file = 0; 87 data->fs = fs; 88 data->ino = ino; 89 data->flags = 0; 90 if (inode) { 91 memcpy(&data->inode, inode, sizeof(struct ext2_inode)); 92 data->flags |= CHANNEL_HAS_INODE; 93 } 94 data->next = top_intern; 95 top_intern = data; 96 *name = data->name; 97 return 0; 98 } 99 100 errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, 101 char **name) 102 { 103 return ext2fs_inode_io_intern2(fs, ino, NULL, name); 104 } 105 106 107 static errcode_t inode_open(const char *name, int flags, io_channel *channel) 108 { 109 io_channel io = NULL; 110 struct inode_private_data *prev, *data = NULL; 111 errcode_t retval; 112 int open_flags; 113 114 if (name == 0) 115 return EXT2_ET_BAD_DEVICE_NAME; 116 117 for (data = top_intern, prev = NULL; data; 118 prev = data, data = data->next) 119 if (strcmp(name, data->name) == 0) 120 break; 121 if (!data) 122 return ENOENT; 123 if (prev) 124 prev->next = data->next; 125 else 126 top_intern = data->next; 127 128 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); 129 if (retval) 130 goto cleanup; 131 memset(io, 0, sizeof(struct struct_io_channel)); 132 133 io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 134 io->manager = inode_io_manager; 135 retval = ext2fs_get_mem(strlen(name)+1, &io->name); 136 if (retval) 137 goto cleanup; 138 139 strcpy(io->name, name); 140 io->private_data = data; 141 io->block_size = 1024; 142 io->read_error = 0; 143 io->write_error = 0; 144 io->refcount = 1; 145 146 open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0; 147 retval = ext2fs_file_open2(data->fs, data->ino, 148 (data->flags & CHANNEL_HAS_INODE) ? 149 &data->inode : 0, open_flags, 150 &data->file); 151 if (retval) 152 goto cleanup; 153 154 *channel = io; 155 return 0; 156 157 cleanup: 158 if (data) { 159 ext2fs_free_mem(&data); 160 } 161 if (io) 162 ext2fs_free_mem(&io); 163 return retval; 164 } 165 166 static errcode_t inode_close(io_channel channel) 167 { 168 struct inode_private_data *data; 169 errcode_t retval = 0; 170 171 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 172 data = (struct inode_private_data *) channel->private_data; 173 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); 174 175 if (--channel->refcount > 0) 176 return 0; 177 178 retval = ext2fs_file_close(data->file); 179 180 ext2fs_free_mem(&channel->private_data); 181 if (channel->name) 182 ext2fs_free_mem(&channel->name); 183 ext2fs_free_mem(&channel); 184 return retval; 185 } 186 187 static errcode_t inode_set_blksize(io_channel channel, int blksize) 188 { 189 struct inode_private_data *data; 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 channel->block_size = blksize; 196 return 0; 197 } 198 199 200 static errcode_t inode_read_blk(io_channel channel, unsigned long block, 201 int count, void *buf) 202 { 203 struct inode_private_data *data; 204 errcode_t retval; 205 206 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 207 data = (struct inode_private_data *) channel->private_data; 208 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); 209 210 if ((retval = ext2fs_file_lseek(data->file, 211 block * channel->block_size, 212 EXT2_SEEK_SET, 0))) 213 return retval; 214 215 count = (count < 0) ? -count : (count * channel->block_size); 216 217 return ext2fs_file_read(data->file, buf, count, 0); 218 } 219 220 static errcode_t inode_write_blk(io_channel channel, unsigned long block, 221 int count, const void *buf) 222 { 223 struct inode_private_data *data; 224 errcode_t retval; 225 226 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 227 data = (struct inode_private_data *) channel->private_data; 228 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); 229 230 if ((retval = ext2fs_file_lseek(data->file, 231 block * channel->block_size, 232 EXT2_SEEK_SET, 0))) 233 return retval; 234 235 count = (count < 0) ? -count : (count * channel->block_size); 236 237 return ext2fs_file_write(data->file, buf, count, 0); 238 } 239 240 static errcode_t inode_write_byte(io_channel channel, unsigned long offset, 241 int size, const void *buf) 242 { 243 struct inode_private_data *data; 244 errcode_t retval = 0; 245 246 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 247 data = (struct inode_private_data *) channel->private_data; 248 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); 249 250 if ((retval = ext2fs_file_lseek(data->file, offset, 251 EXT2_SEEK_SET, 0))) 252 return retval; 253 254 return ext2fs_file_write(data->file, buf, size, 0); 255 } 256 257 /* 258 * Flush data buffers to disk. 259 */ 260 static errcode_t inode_flush(io_channel channel) 261 { 262 struct inode_private_data *data; 263 264 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 265 data = (struct inode_private_data *) channel->private_data; 266 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); 267 268 return ext2fs_file_flush(data->file); 269 } 270 271