inode_io.c revision 546a1ff18cc912003883ff67ba3e87c69f700fc4
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 Public
9 * License.
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
33struct 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	int				flags;
40	struct inode_private_data	*next;
41};
42
43static struct inode_private_data *top_intern;
44static int ino_unique = 0;
45
46static errcode_t inode_open(const char *name, int flags, io_channel *channel);
47static errcode_t inode_close(io_channel channel);
48static errcode_t inode_set_blksize(io_channel channel, int blksize);
49static errcode_t inode_read_blk(io_channel channel, unsigned long block,
50			       int count, void *data);
51static errcode_t inode_write_blk(io_channel channel, unsigned long block,
52				int count, const void *data);
53static errcode_t inode_flush(io_channel channel);
54static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
55				int size, const void *data);
56
57static struct struct_io_manager struct_inode_manager = {
58	EXT2_ET_MAGIC_IO_MANAGER,
59	"Inode I/O Manager",
60	inode_open,
61	inode_close,
62	inode_set_blksize,
63	inode_read_blk,
64	inode_write_blk,
65	inode_flush,
66	inode_write_byte
67};
68
69io_manager inode_io_manager = &struct_inode_manager;
70
71errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
72				 char **name)
73{
74	struct inode_private_data 	*data;
75	errcode_t			retval;
76
77	if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
78				     (void **) &data)))
79		return retval;
80	data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
81	sprintf(data->name, "%u:%d", ino, ino_unique++);
82	data->file = 0;
83	data->fs = fs;
84	data->ino = ino;
85	data->flags = 0;
86	data->next = top_intern;
87	top_intern = data;
88	*name = data->name;
89	return 0;
90}
91
92
93static errcode_t inode_open(const char *name, int flags, io_channel *channel)
94{
95	io_channel	io = NULL;
96	struct inode_private_data *prev, *data = NULL;
97	errcode_t	retval;
98	int		open_flags;
99
100	if (name == 0)
101		return EXT2_ET_BAD_DEVICE_NAME;
102
103	for (data = top_intern, prev = NULL; data;
104	     prev = data, data = data->next)
105		if (strcmp(name, data->name) == 0)
106			break;
107	if (!data)
108		return ENOENT;
109	if (prev)
110		prev->next = data->next;
111	else
112		top_intern = data->next;
113
114	retval = ext2fs_get_mem(sizeof(struct struct_io_channel),
115				(void **) &io);
116	if (retval)
117		goto cleanup;
118	memset(io, 0, sizeof(struct struct_io_channel));
119
120	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
121	io->manager = inode_io_manager;
122	retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name);
123	if (retval)
124		goto cleanup;
125
126	strcpy(io->name, name);
127	io->private_data = data;
128	io->block_size = 1024;
129	io->read_error = 0;
130	io->write_error = 0;
131	io->refcount = 1;
132
133	open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
134	retval = ext2fs_file_open(data->fs, data->ino, open_flags,
135				  &data->file);
136	if (retval)
137		goto cleanup;
138
139	*channel = io;
140	return 0;
141
142cleanup:
143	if (data) {
144		ext2fs_free_mem((void **) &data);
145	}
146	if (io)
147		ext2fs_free_mem((void **) &io);
148	return retval;
149}
150
151static errcode_t inode_close(io_channel channel)
152{
153	struct inode_private_data *data;
154	errcode_t	retval = 0;
155
156	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
157	data = (struct inode_private_data *) channel->private_data;
158	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
159
160	if (--channel->refcount > 0)
161		return 0;
162
163	retval = ext2fs_file_close(data->file);
164
165	ext2fs_free_mem((void **) &channel->private_data);
166	if (channel->name)
167		ext2fs_free_mem((void **) &channel->name);
168	ext2fs_free_mem((void **) &channel);
169	return retval;
170}
171
172static errcode_t inode_set_blksize(io_channel channel, int blksize)
173{
174	struct inode_private_data *data;
175
176	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
177	data = (struct inode_private_data *) channel->private_data;
178	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
179
180	channel->block_size = blksize;
181	return 0;
182}
183
184
185static errcode_t inode_read_blk(io_channel channel, unsigned long block,
186			       int count, void *buf)
187{
188	struct inode_private_data *data;
189	errcode_t	retval;
190
191	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
192	data = (struct inode_private_data *) channel->private_data;
193	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
194
195	if ((retval = ext2fs_file_lseek(data->file,
196					block * channel->block_size,
197					EXT2_SEEK_SET, 0)))
198		return retval;
199
200	count = (count < 0) ? -count : (count * channel->block_size);
201
202	return ext2fs_file_read(data->file, buf, count, 0);
203}
204
205static errcode_t inode_write_blk(io_channel channel, unsigned long block,
206				int count, const void *buf)
207{
208	struct inode_private_data *data;
209	errcode_t	retval;
210
211	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
212	data = (struct inode_private_data *) channel->private_data;
213	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
214
215	if ((retval = ext2fs_file_lseek(data->file,
216					block * channel->block_size,
217					EXT2_SEEK_SET, 0)))
218		return retval;
219
220	count = (count < 0) ? -count : (count * channel->block_size);
221
222	return ext2fs_file_write(data->file, buf, count, 0);
223}
224
225static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
226				 int size, const void *buf)
227{
228	struct inode_private_data *data;
229	errcode_t	retval = 0;
230
231	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
232	data = (struct inode_private_data *) channel->private_data;
233	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
234
235	if ((retval = ext2fs_file_lseek(data->file, offset,
236					EXT2_SEEK_SET, 0)))
237		return retval;
238
239	return ext2fs_file_write(data->file, buf, size, 0);
240}
241
242/*
243 * Flush data buffers to disk.
244 */
245static errcode_t inode_flush(io_channel channel)
246{
247	struct inode_private_data *data;
248
249	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
250	data = (struct inode_private_data *) channel->private_data;
251	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
252
253	return ext2fs_file_flush(data->file);
254}
255
256