• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ext2fs_inode_io_intern2(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode,char ** name)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 
ext2fs_inode_io_intern(ext2_filsys fs,ext2_ino_t ino,char ** name)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 
inode_open(const char * name,int flags,io_channel * channel)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 
inode_close(io_channel channel)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 
inode_set_blksize(io_channel channel,int blksize)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 
inode_read_blk64(io_channel channel,unsigned long long block,int count,void * buf)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_llseek(data->file,
219 				(ext2_off64_t)(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 
inode_read_blk(io_channel channel,unsigned long block,int count,void * buf)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 
inode_write_blk64(io_channel channel,unsigned long long block,int count,const void * buf)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_llseek(data->file,
245 				(ext2_off64_t) (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 
inode_write_blk(io_channel channel,unsigned long block,int count,const void * buf)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 
inode_write_byte(io_channel channel,unsigned long offset,int size,const void * buf)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  */
inode_flush(io_channel channel)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