Whamcloud - gitweb
Many files:
[tools/e2fsprogs.git] / lib / ext2fs / inode.c
1 /*
2  * inode.c --- utility routines to read and write inodes
3  * 
4  * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
5  * under the terms of the GNU Public License.
6  */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14
15 #include <linux/fs.h>
16 #include <linux/ext2_fs.h>
17
18 #include "ext2fs.h"
19
20 errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
21                                  ext2_inode_scan *ret_scan)
22 {
23         ext2_inode_scan scan;
24
25         scan = (ext2_inode_scan) malloc(sizeof(struct ext2_struct_inode_scan));
26         if (!scan)
27                 return ENOMEM;
28         memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
29
30         scan->fs = fs;
31         scan->current_group = -1;
32         scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
33         scan->groups_left = fs->group_desc_count;
34         scan->inode_buffer = malloc(scan->inode_buffer_blocks * fs->blocksize);
35         if (!scan->inode_buffer) {
36                 free(scan);
37                 return ENOMEM;
38         }
39         *ret_scan = scan;
40         return 0;
41 }
42
43 void ext2fs_close_inode_scan(ext2_inode_scan scan)
44 {
45         free(scan->inode_buffer);
46         scan->inode_buffer = NULL;
47         free(scan);
48         return;
49 }
50
51 errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ino_t *ino,
52                                 struct ext2_inode *inode)
53 {
54         errcode_t       retval;
55         int             num_blocks;
56         
57         if (!scan->inode_buffer)
58                 return EINVAL;
59         
60         if (scan->inodes_left <= 0) {
61                 if (scan->blocks_left <= 0) {
62                         if (scan->groups_left <= 0) {
63                                 *ino = 0;
64                                 return 0;
65                         }
66                         scan->current_group++;
67                         scan->groups_left--;
68                         
69                         scan->current_block = scan->fs->group_desc[scan->current_group].bg_inode_table;
70                         scan->blocks_left = (EXT2_INODES_PER_GROUP(scan->fs->super) /
71                                              EXT2_INODES_PER_BLOCK(scan->fs->super));
72                 } else {
73                         scan->current_block += scan->inode_buffer_blocks;
74                 }
75                 scan->blocks_left -= scan->inode_buffer_blocks;
76                 num_blocks = scan->inode_buffer_blocks;
77                 if (scan->blocks_left < 0)
78                         num_blocks += scan->blocks_left;
79                 
80                 scan->inodes_left = EXT2_INODES_PER_BLOCK(scan->fs->super) *
81                         num_blocks;
82
83                 retval = io_channel_read_blk(scan->fs->io, scan->current_block,
84                                              num_blocks, scan->inode_buffer);
85                 if (retval)
86                         return EXT2_ET_NEXT_INODE_READ;
87                 scan->inode_scan_ptr = (struct ext2_inode *) scan->inode_buffer;
88         }
89         *inode = *scan->inode_scan_ptr++;
90         scan->inodes_left--;
91         scan->current_inode++;
92         *ino = scan->current_inode;
93         return 0;
94 }
95
96 /*
97  * Functions to read and write a single inode.
98  */
99 static char *inode_buffer = 0;
100 static blk_t inode_buffer_block;
101 static int inode_buffer_size = 0;
102
103 errcode_t ext2fs_read_inode (ext2_filsys fs, unsigned long ino,
104                              struct ext2_inode * inode)
105 {
106         unsigned long group;
107         unsigned long block;
108         unsigned long block_nr;
109         errcode_t       retval;
110         int i;
111
112         if (ino > fs->super->s_inodes_count)
113                 return EXT2_ET_BAD_INODE_NUM;
114         if (inode_buffer_size != fs->blocksize) {
115                 if (inode_buffer)
116                         free(inode_buffer);
117                 inode_buffer_size = 0;
118                 inode_buffer = malloc(fs->blocksize);
119                 if (!inode_buffer)
120                         return ENOMEM;
121                 inode_buffer_size = fs->blocksize;
122                 inode_buffer_block = 0;
123         }
124                 
125         group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
126         block = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) /
127                 EXT2_INODES_PER_BLOCK(fs->super);
128         i = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) %
129                 EXT2_INODES_PER_BLOCK(fs->super);
130         block_nr = fs->group_desc[group].bg_inode_table + block;
131         if (block_nr != inode_buffer_block) {
132                 retval = io_channel_read_blk(fs->io, block_nr, 1,
133                                              inode_buffer);
134                 if (retval)
135                         return retval;
136                 inode_buffer_block = block_nr;
137         }
138         memcpy (inode, (struct ext2_inode *) inode_buffer + i,
139                 sizeof (struct ext2_inode));
140         return 0;
141 }
142
143 errcode_t ext2fs_write_inode(ext2_filsys fs, unsigned long ino,
144                      struct ext2_inode * inode)
145 {
146         unsigned long group;
147         unsigned long block;
148         unsigned long block_nr;
149         errcode_t       retval;
150         int i;
151
152         if (!(fs->flags & EXT2_FLAG_RW))
153                 return EXT2_ET_RO_FILSYS;
154
155         if (ino > fs->super->s_inodes_count)
156                 return EXT2_ET_BAD_INODE_NUM;
157
158         if (inode_buffer_size != fs->blocksize) {
159                 if (inode_buffer)
160                         free(inode_buffer);
161                 inode_buffer_size = 0;
162                 inode_buffer = malloc(fs->blocksize);
163                 if (!inode_buffer)
164                         return ENOMEM;
165                 inode_buffer_size = fs->blocksize;
166                 inode_buffer_block = 0;
167         }
168                 
169         group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
170         block = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) /
171                 EXT2_INODES_PER_BLOCK(fs->super);
172         i = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) %
173                 EXT2_INODES_PER_BLOCK(fs->super);
174         block_nr = fs->group_desc[group].bg_inode_table + block;
175         if (inode_buffer_block != block_nr) {
176                 retval = io_channel_read_blk(fs->io, block_nr, 1,
177                                              inode_buffer);
178                 if (retval)
179                         return retval;
180                 inode_buffer_block = block_nr;
181         }
182         memcpy ((struct ext2_inode *) inode_buffer + i, inode,
183                 sizeof (struct ext2_inode));
184         retval = io_channel_write_blk(fs->io, block_nr, 1, inode_buffer);
185         if (retval)
186                 return retval;
187         fs->flags |= EXT2_FLAG_CHANGED;
188         return 0;
189 }
190
191 errcode_t ext2fs_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
192 {
193         struct ext2_inode       inode;
194         int                     i;
195         errcode_t               retval;
196         
197         if (ino > fs->super->s_inodes_count)
198                 return EXT2_ET_BAD_INODE_NUM;
199
200         if (fs->get_blocks) {
201                 if (!(*fs->get_blocks)(fs, ino, blocks))
202                         return 0;
203         }
204         retval = ext2fs_read_inode(fs, ino, &inode);
205         if (retval)
206                 return retval;
207         for (i=0; i < EXT2_N_BLOCKS; i++)
208                 blocks[i] = inode.i_block[i];
209         return 0;
210 }
211
212 errcode_t ext2fs_check_directory(ext2_filsys fs, ino_t ino)
213 {
214         struct  ext2_inode      inode;
215         errcode_t               retval;
216         
217         if (ino > fs->super->s_inodes_count)
218                 return EXT2_ET_BAD_INODE_NUM;
219
220         if (fs->check_directory)
221                 return (fs->check_directory)(fs, ino);
222         retval = ext2fs_read_inode(fs, ino, &inode);
223         if (retval)
224                 return retval;
225         if (!S_ISDIR(inode.i_mode))
226                 return ENOTDIR;
227         return 0;
228 }
229
230         
231