Home | History | Annotate | Download | only in ext2fs
      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_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 
    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_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 
    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 
    291