inode_io.c revision c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4e
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				     &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), &io);
115	if (retval)
116		goto cleanup;
117	memset(io, 0, sizeof(struct struct_io_channel));
118
119	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
120	io->manager = inode_io_manager;
121	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
122	if (retval)
123		goto cleanup;
124
125	strcpy(io->name, name);
126	io->private_data = data;
127	io->block_size = 1024;
128	io->read_error = 0;
129	io->write_error = 0;
130	io->refcount = 1;
131
132	open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
133	retval = ext2fs_file_open(data->fs, data->ino, open_flags,
134				  &data->file);
135	if (retval)
136		goto cleanup;
137
138	*channel = io;
139	return 0;
140
141cleanup:
142	if (data) {
143		ext2fs_free_mem(&data);
144	}
145	if (io)
146		ext2fs_free_mem(&io);
147	return retval;
148}
149
150static errcode_t inode_close(io_channel channel)
151{
152	struct inode_private_data *data;
153	errcode_t	retval = 0;
154
155	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
156	data = (struct inode_private_data *) channel->private_data;
157	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
158
159	if (--channel->refcount > 0)
160		return 0;
161
162	retval = ext2fs_file_close(data->file);
163
164	ext2fs_free_mem(&channel->private_data);
165	if (channel->name)
166		ext2fs_free_mem(&channel->name);
167	ext2fs_free_mem(&channel);
168	return retval;
169}
170
171static errcode_t inode_set_blksize(io_channel channel, int blksize)
172{
173	struct inode_private_data *data;
174
175	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
176	data = (struct inode_private_data *) channel->private_data;
177	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
178
179	channel->block_size = blksize;
180	return 0;
181}
182
183
184static errcode_t inode_read_blk(io_channel channel, unsigned long block,
185			       int count, void *buf)
186{
187	struct inode_private_data *data;
188	errcode_t	retval;
189
190	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
191	data = (struct inode_private_data *) channel->private_data;
192	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
193
194	if ((retval = ext2fs_file_lseek(data->file,
195					block * channel->block_size,
196					EXT2_SEEK_SET, 0)))
197		return retval;
198
199	count = (count < 0) ? -count : (count * channel->block_size);
200
201	return ext2fs_file_read(data->file, buf, count, 0);
202}
203
204static errcode_t inode_write_blk(io_channel channel, unsigned long block,
205				int count, const void *buf)
206{
207	struct inode_private_data *data;
208	errcode_t	retval;
209
210	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
211	data = (struct inode_private_data *) channel->private_data;
212	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
213
214	if ((retval = ext2fs_file_lseek(data->file,
215					block * channel->block_size,
216					EXT2_SEEK_SET, 0)))
217		return retval;
218
219	count = (count < 0) ? -count : (count * channel->block_size);
220
221	return ext2fs_file_write(data->file, buf, count, 0);
222}
223
224static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
225				 int size, const void *buf)
226{
227	struct inode_private_data *data;
228	errcode_t	retval = 0;
229
230	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
231	data = (struct inode_private_data *) channel->private_data;
232	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
233
234	if ((retval = ext2fs_file_lseek(data->file, offset,
235					EXT2_SEEK_SET, 0)))
236		return retval;
237
238	return ext2fs_file_write(data->file, buf, size, 0);
239}
240
241/*
242 * Flush data buffers to disk.
243 */
244static errcode_t inode_flush(io_channel channel)
245{
246	struct inode_private_data *data;
247
248	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
249	data = (struct inode_private_data *) channel->private_data;
250	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
251
252	return ext2fs_file_flush(data->file);
253}
254
255