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 
ext2fs_inode_io_intern2(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode,char ** name)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 
ext2fs_inode_io_intern(ext2_filsys fs,ext2_ino_t ino,char ** name)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 
inode_open(const char * name,int flags,io_channel * channel)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 
inode_close(io_channel channel)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 
inode_set_blksize(io_channel channel,int blksize)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 
inode_read_blk64(io_channel channel,unsigned long long block,int count,void * buf)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 
inode_read_blk(io_channel channel,unsigned long block,int count,void * buf)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 
inode_write_blk64(io_channel channel,unsigned long long block,int count,const void * buf)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 
inode_write_blk(io_channel channel,unsigned long block,int count,const void * buf)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 
inode_write_byte(io_channel channel,unsigned long offset,int size,const void * buf)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  */
inode_flush(io_channel channel)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