blob: 4bfa93aef4400df31027b5b83e6245700f3df293 [file] [log] [blame]
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001/* 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