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