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 <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