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