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