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