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