• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/busybox/e2fsprogs/old_e2fsprogs/ext2fs/
1/* vi: set sw=4 ts=4: */
2/*
3 * inode_io.c --- This is allows an inode in an ext2 filesystem image
4 *	to be accessed via the I/O manager interface.
5 *
6 * Copyright (C) 2002 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
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
34struct 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
47static struct inode_private_data *top_intern;
48static int ino_unique = 0;
49
50static errcode_t inode_open(const char *name, int flags, io_channel *channel);
51static errcode_t inode_close(io_channel channel);
52static errcode_t inode_set_blksize(io_channel channel, int blksize);
53static errcode_t inode_read_blk(io_channel channel, unsigned long block,
54			       int count, void *data);
55static errcode_t inode_write_blk(io_channel channel, unsigned long block,
56				int count, const void *data);
57static errcode_t inode_flush(io_channel channel);
58static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
59				int size, const void *data);
60
61static struct struct_io_manager struct_inode_manager = {
62	EXT2_ET_MAGIC_IO_MANAGER,
63	"Inode I/O Manager",
64	inode_open,
65	inode_close,
66	inode_set_blksize,
67	inode_read_blk,
68	inode_write_blk,
69	inode_flush,
70	inode_write_byte
71};
72
73io_manager inode_io_manager = &struct_inode_manager;
74
75errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
76				  struct ext2_inode *inode,
77				  char **name)
78{
79	struct inode_private_data	*data;
80	errcode_t			retval;
81
82	if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
83				     &data)))
84		return retval;
85	data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
86	sprintf(data->name, "%u:%d", ino, ino_unique++);
87	data->file = 0;
88	data->fs = fs;
89	data->ino = ino;
90	data->flags = 0;
91	if (inode) {
92		memcpy(&data->inode, inode, sizeof(struct ext2_inode));
93		data->flags |= CHANNEL_HAS_INODE;
94	}
95	data->next = top_intern;
96	top_intern = data;
97	*name = data->name;
98	return 0;
99}
100
101errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
102				 char **name)
103{
104	return ext2fs_inode_io_intern2(fs, ino, NULL, name);
105}
106
107
108static errcode_t inode_open(const char *name, int flags, io_channel *channel)
109{
110	io_channel	io = NULL;
111	struct inode_private_data *prev, *data = NULL;
112	errcode_t	retval;
113	int		open_flags;
114
115	if (name == 0)
116		return EXT2_ET_BAD_DEVICE_NAME;
117
118	for (data = top_intern, prev = NULL; data;
119	     prev = data, data = data->next)
120		if (strcmp(name, data->name) == 0)
121			break;
122	if (!data)
123		return ENOENT;
124	if (prev)
125		prev->next = data->next;
126	else
127		top_intern = data->next;
128
129	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
130	if (retval)
131		goto cleanup;
132	memset(io, 0, sizeof(struct struct_io_channel));
133
134	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
135	io->manager = inode_io_manager;
136	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
137	if (retval)
138		goto cleanup;
139
140	strcpy(io->name, name);
141	io->private_data = data;
142	io->block_size = 1024;
143	io->read_error = 0;
144	io->write_error = 0;
145	io->refcount = 1;
146
147	open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
148	retval = ext2fs_file_open2(data->fs, data->ino,
149				   (data->flags & CHANNEL_HAS_INODE) ?
150				   &data->inode : 0, open_flags,
151				   &data->file);
152	if (retval)
153		goto cleanup;
154
155	*channel = io;
156	return 0;
157
158cleanup:
159	if (data) {
160		ext2fs_free_mem(&data);
161	}
162	if (io)
163		ext2fs_free_mem(&io);
164	return retval;
165}
166
167static errcode_t inode_close(io_channel channel)
168{
169	struct inode_private_data *data;
170	errcode_t	retval = 0;
171
172	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
173	data = (struct inode_private_data *) channel->private_data;
174	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
175
176	if (--channel->refcount > 0)
177		return 0;
178
179	retval = ext2fs_file_close(data->file);
180
181	ext2fs_free_mem(&channel->private_data);
182	if (channel->name)
183		ext2fs_free_mem(&channel->name);
184	ext2fs_free_mem(&channel);
185	return retval;
186}
187
188static errcode_t inode_set_blksize(io_channel channel, int blksize)
189{
190	struct inode_private_data *data;
191
192	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
193	data = (struct inode_private_data *) channel->private_data;
194	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
195
196	channel->block_size = blksize;
197	return 0;
198}
199
200
201static errcode_t inode_read_blk(io_channel channel, unsigned long block,
202			       int count, void *buf)
203{
204	struct inode_private_data *data;
205	errcode_t	retval;
206
207	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
208	data = (struct inode_private_data *) channel->private_data;
209	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
210
211	if ((retval = ext2fs_file_lseek(data->file,
212					block * channel->block_size,
213					EXT2_SEEK_SET, 0)))
214		return retval;
215
216	count = (count < 0) ? -count : (count * channel->block_size);
217
218	return ext2fs_file_read(data->file, buf, count, 0);
219}
220
221static errcode_t inode_write_blk(io_channel channel, unsigned long block,
222				int count, const void *buf)
223{
224	struct inode_private_data *data;
225	errcode_t	retval;
226
227	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
228	data = (struct inode_private_data *) channel->private_data;
229	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
230
231	if ((retval = ext2fs_file_lseek(data->file,
232					block * channel->block_size,
233					EXT2_SEEK_SET, 0)))
234		return retval;
235
236	count = (count < 0) ? -count : (count * channel->block_size);
237
238	return ext2fs_file_write(data->file, buf, count, 0);
239}
240
241static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
242				 int size, const void *buf)
243{
244	struct inode_private_data *data;
245	errcode_t	retval = 0;
246
247	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
248	data = (struct inode_private_data *) channel->private_data;
249	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
250
251	if ((retval = ext2fs_file_lseek(data->file, offset,
252					EXT2_SEEK_SET, 0)))
253		return retval;
254
255	return ext2fs_file_write(data->file, buf, size, 0);
256}
257
258/*
259 * Flush data buffers to disk.
260 */
261static errcode_t inode_flush(io_channel channel)
262{
263	struct inode_private_data *data;
264
265	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
266	data = (struct inode_private_data *) channel->private_data;
267	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
268
269	return ext2fs_file_flush(data->file);
270}
271
272