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