Initial public busybox upstream commit
[busybox4maemo] / e2fsprogs / old_e2fsprogs / ext2fs / inode_io.c
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
34 struct 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
47 static struct inode_private_data *top_intern;
48 static int ino_unique = 0;
49
50 static errcode_t inode_open(const char *name, int flags, io_channel *channel);
51 static errcode_t inode_close(io_channel channel);
52 static errcode_t inode_set_blksize(io_channel channel, int blksize);
53 static errcode_t inode_read_blk(io_channel channel, unsigned long block,
54                                int count, void *data);
55 static errcode_t inode_write_blk(io_channel channel, unsigned long block,
56                                 int count, const void *data);
57 static errcode_t inode_flush(io_channel channel);
58 static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
59                                 int size, const void *data);
60
61 static 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
73 io_manager inode_io_manager = &struct_inode_manager;
74
75 errcode_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
101 errcode_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
108 static 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
158 cleanup:
159         if (data) {
160                 ext2fs_free_mem(&data);
161         }
162         if (io)
163                 ext2fs_free_mem(&io);
164         return retval;
165 }
166
167 static 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
188 static 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
201 static 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
221 static 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
241 static 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  */
261 static 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