inode_io.c revision 51b263e3690ba3136fe63e5c722e0593772620e2
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * inode_io.c --- This is allows an inode in an ext2 filesystem image 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * to be accessed via the I/O manager interface. 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2002 Theodore Ts'o. 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * %Begin-Header% 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This file may be redistributed under the terms of the GNU Public 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License. 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * %End-Header% 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <stdio.h> 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <string.h> 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_UNISTD_H 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <unistd.h> 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_ERRNO_H 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <errno.h> 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <time.h> 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "ext2_fs.h" 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "ext2fs.h" 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * For checking structure magic numbers... 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define EXT2_CHECK_MAGIC(struct, code) \ 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if ((struct)->magic != (code)) return (code) 325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct inode_private_data { 3406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) int magic; 355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) char name[32]; 36c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) ext2_file_t file; 375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ext2_filsys fs; 385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ext2_ino_t ino; 395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) struct ext2_inode inode; 405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int flags; 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) struct inode_private_data *next; 42bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)}; 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define CHANNEL_HAS_INODE 0x8000 457242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccistatic struct inode_private_data *top_intern; 4709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static int ino_unique = 0; 4809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static errcode_t inode_open(const char *name, int flags, io_channel *channel); 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static errcode_t inode_close(io_channel channel); 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static errcode_t inode_set_blksize(io_channel channel, int blksize); 52c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)static errcode_t inode_read_blk(io_channel channel, unsigned long block, 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int count, void *data); 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static errcode_t inode_write_blk(io_channel channel, unsigned long block, 55 int count, const void *data); 56static errcode_t inode_flush(io_channel channel); 57static errcode_t inode_write_byte(io_channel channel, unsigned long offset, 58 int size, const void *data); 59static errcode_t inode_read_blk64(io_channel channel, 60 unsigned long long block, int count, void *data); 61static errcode_t inode_write_blk64(io_channel channel, 62 unsigned long long block, int count, const void *data); 63 64static 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 80io_manager inode_io_manager = &struct_inode_manager; 81 82errcode_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 108errcode_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 115static 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 165cleanup: 166 if (data) { 167 ext2fs_free_mem(&data); 168 } 169 if (io) 170 ext2fs_free_mem(&io); 171 return retval; 172} 173 174static 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 195static 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 208static 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_lseek(data->file, 219 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 228static 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 234static 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_lseek(data->file, 245 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 254static 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 260static 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 */ 280static 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 291