Whamcloud - gitweb
ext2fs_set_gdt_csum(): Clean up superblock dirty flag handling
[tools/e2fsprogs.git] / lib / ext2fs / rw_bitmaps.c
1 /*
2  * rw_bitmaps.c --- routines to read and write the  inode and block bitmaps.
3  *
4  * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
11
12 #include <stdio.h>
13 #include <string.h>
14 #if HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #include <fcntl.h>
18 #include <time.h>
19 #ifdef HAVE_SYS_STAT_H
20 #include <sys/stat.h>
21 #endif
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25
26 #include "ext2_fs.h"
27 #include "ext2fs.h"
28 #include "e2image.h"
29
30 static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
31 {
32         dgrp_t          i;
33         unsigned int    j;
34         int             block_nbytes, inode_nbytes;
35         unsigned int    nbits;
36         errcode_t       retval;
37         char            *block_buf, *inode_buf;
38         int             lazy_flag = 0;
39         blk_t           blk;
40         blk_t           blk_itr = fs->super->s_first_data_block;
41         ext2_ino_t      ino_itr = 1;
42
43         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
44
45         if (!(fs->flags & EXT2_FLAG_RW))
46                 return EXT2_ET_RO_FILSYS;
47         if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
48                                     EXT2_FEATURE_COMPAT_LAZY_BG))
49                 lazy_flag = 1;
50         inode_nbytes = block_nbytes = 0;
51         if (do_block) {
52                 block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
53                 retval = ext2fs_get_mem(fs->blocksize, &block_buf);
54                 if (retval)
55                         return retval;
56                 memset(block_buf, 0xff, fs->blocksize);
57         }
58         if (do_inode) {
59                 inode_nbytes = (size_t) 
60                         ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
61                 retval = ext2fs_get_mem(fs->blocksize, &inode_buf);
62                 if (retval)
63                         return retval;
64                 memset(inode_buf, 0xff, fs->blocksize);
65         }
66
67         for (i = 0; i < fs->group_desc_count; i++) {
68                 if (!do_block)
69                         goto skip_block_bitmap;
70
71                 if (lazy_flag && fs->group_desc[i].bg_flags &
72                     EXT2_BG_BLOCK_UNINIT) 
73                         goto skip_this_block_bitmap;
74  
75                 retval = ext2fs_get_block_bitmap_range(fs->block_map, 
76                                 blk_itr, block_nbytes << 3, block_buf);
77                 if (retval)
78                         return retval;
79
80                 if (i == fs->group_desc_count - 1) {
81                         /* Force bitmap padding for the last group */
82                         nbits = ((fs->super->s_blocks_count
83                                   - fs->super->s_first_data_block)
84                                  % EXT2_BLOCKS_PER_GROUP(fs->super));
85                         if (nbits)
86                                 for (j = nbits; j < fs->blocksize * 8; j++)
87                                         ext2fs_set_bit(j, block_buf);
88                 }
89                 blk = fs->group_desc[i].bg_block_bitmap;
90                 if (blk) {
91                         retval = io_channel_write_blk(fs->io, blk, 1,
92                                                       block_buf);
93                         if (retval)
94                                 return EXT2_ET_BLOCK_BITMAP_WRITE;
95                 }
96         skip_this_block_bitmap:
97                 blk_itr += block_nbytes << 3;
98         skip_block_bitmap:
99
100                 if (!do_inode)
101                         continue;
102
103                 if (lazy_flag && fs->group_desc[i].bg_flags &
104                     EXT2_BG_INODE_UNINIT) 
105                         goto skip_this_inode_bitmap;
106  
107                 retval = ext2fs_get_inode_bitmap_range(fs->inode_map, 
108                                 ino_itr, inode_nbytes << 3, inode_buf);
109                 if (retval)
110                         return retval;
111
112                 blk = fs->group_desc[i].bg_inode_bitmap;
113                 if (blk) {
114                         retval = io_channel_write_blk(fs->io, blk, 1,
115                                                       inode_buf);
116                         if (retval)
117                                 return EXT2_ET_INODE_BITMAP_WRITE;
118                 }
119         skip_this_inode_bitmap:
120                 ino_itr += inode_nbytes << 3;
121
122         }
123         if (do_block) {
124                 fs->flags &= ~EXT2_FLAG_BB_DIRTY;
125                 ext2fs_free_mem(&block_buf);
126         }
127         if (do_inode) {
128                 fs->flags &= ~EXT2_FLAG_IB_DIRTY;
129                 ext2fs_free_mem(&inode_buf);
130         }
131         return 0;
132 }
133
134 static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
135 {
136         dgrp_t i;
137         char *block_bitmap = 0, *inode_bitmap = 0;
138         char *buf;
139         errcode_t retval;
140         unsigned int block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
141         unsigned inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
142         int lazy_flag = 0;
143         int do_image = fs->flags & EXT2_FLAG_IMAGE_FILE;
144         unsigned int    cnt;
145         blk_t   blk;
146         blk_t   blk_itr = fs->super->s_first_data_block;
147         blk_t   blk_cnt;
148         ext2_ino_t ino_itr = 1;
149         ext2_ino_t ino_cnt;
150
151         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
152
153         fs->write_bitmaps = ext2fs_write_bitmaps;
154
155         if (EXT2_HAS_COMPAT_FEATURE(fs->super,
156                                     EXT2_FEATURE_COMPAT_LAZY_BG) ||
157             EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
158                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
159                 lazy_flag = 1;
160
161         retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
162         if (retval)
163                 return retval;
164         if (do_block) {
165                 if (fs->block_map)
166                         ext2fs_free_block_bitmap(fs->block_map);
167                 sprintf(buf, "block bitmap for %s", fs->device_name);
168                 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
169                 if (retval)
170                         goto cleanup;
171                 retval = ext2fs_get_mem(do_image ? fs->blocksize : 
172                                         block_nbytes, &block_bitmap);
173                 if (retval)
174                         goto cleanup;
175         } else
176                 block_nbytes = 0;
177         if (do_inode) {
178                 if (fs->inode_map)
179                         ext2fs_free_inode_bitmap(fs->inode_map);
180                 sprintf(buf, "inode bitmap for %s", fs->device_name);
181                 retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
182                 if (retval)
183                         goto cleanup;
184                 retval = ext2fs_get_mem(do_image ? fs->blocksize : 
185                                         inode_nbytes, &inode_bitmap);
186                 if (retval)
187                         goto cleanup;
188         } else
189                 inode_nbytes = 0;
190         ext2fs_free_mem(&buf);
191
192         if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
193                 blk = (fs->image_header->offset_inodemap / fs->blocksize);
194                 ino_cnt = fs->super->s_inodes_count;
195                 while (inode_nbytes > 0) {
196                         retval = io_channel_read_blk(fs->image_io, blk++,
197                                                      1, inode_bitmap);
198                         if (retval)
199                                 goto cleanup;
200                         cnt = fs->blocksize << 3;
201                         if (cnt > ino_cnt)
202                                 cnt = ino_cnt;
203                         retval = ext2fs_set_inode_bitmap_range(fs->inode_map, 
204                                                ino_itr, cnt, inode_bitmap);
205                         if (retval)
206                                 goto cleanup;
207                         ino_itr += fs->blocksize << 3;
208                         ino_cnt -= fs->blocksize << 3;
209                         inode_nbytes -= fs->blocksize;
210                 }
211                 blk = (fs->image_header->offset_blockmap /
212                        fs->blocksize);
213                 blk_cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * 
214                         fs->group_desc_count;
215                 while (block_nbytes > 0) {
216                         retval = io_channel_read_blk(fs->image_io, blk++,
217                                                      1, block_bitmap);
218                         if (retval)
219                                 goto cleanup;
220                         cnt = fs->blocksize << 3;
221                         if (cnt > blk_cnt)
222                                 cnt = blk_cnt;
223                         retval = ext2fs_set_block_bitmap_range(fs->block_map, 
224                                        blk_itr, cnt, block_bitmap);
225                         if (retval)
226                                 goto cleanup;
227                         blk_itr += fs->blocksize << 3;
228                         blk_cnt -= fs->blocksize << 3;
229                         block_nbytes -= fs->blocksize;
230                 }
231                 goto success_cleanup;
232         }
233
234         for (i = 0; i < fs->group_desc_count; i++) {
235                 if (block_bitmap) {
236                         blk = fs->group_desc[i].bg_block_bitmap;
237                         if (lazy_flag && fs->group_desc[i].bg_flags &
238                             EXT2_BG_BLOCK_UNINIT &&
239                             ext2fs_group_desc_csum_verify(fs, i))
240                                 blk = 0;
241                         if (blk) {
242                                 retval = io_channel_read_blk(fs->io, blk,
243                                              -block_nbytes, block_bitmap);
244                                 if (retval) {
245                                         retval = EXT2_ET_BLOCK_BITMAP_READ;
246                                         goto cleanup;
247                                 }
248                         } else
249                                 memset(block_bitmap, 0xff, block_nbytes);
250                         cnt = block_nbytes << 3;
251                         retval = ext2fs_set_block_bitmap_range(fs->block_map, 
252                                                blk_itr, cnt, block_bitmap);
253                         if (retval)
254                                 goto cleanup;
255                         blk_itr += block_nbytes << 3;
256                 }
257                 if (inode_bitmap) {
258                         blk = fs->group_desc[i].bg_inode_bitmap;
259                         if (lazy_flag && fs->group_desc[i].bg_flags &
260                             EXT2_BG_INODE_UNINIT &&
261                             ext2fs_group_desc_csum_verify(fs, i))
262                                 blk = 0;
263                         if (blk) {
264                                 retval = io_channel_read_blk(fs->io, blk,
265                                              -inode_nbytes, inode_bitmap);
266                                 if (retval) {
267                                         retval = EXT2_ET_INODE_BITMAP_READ;
268                                         goto cleanup;
269                                 }
270                         } else
271                                 memset(inode_bitmap, 0xff, inode_nbytes);
272                         cnt = inode_nbytes << 3;
273                         retval = ext2fs_set_inode_bitmap_range(fs->inode_map, 
274                                                ino_itr, cnt, inode_bitmap);
275                         if (retval)
276                                 goto cleanup;
277                         ino_itr += inode_nbytes << 3;
278                 }
279         }
280 success_cleanup:
281         if (inode_bitmap)
282                 ext2fs_free_mem(&inode_bitmap);
283         if (block_bitmap)
284                 ext2fs_free_mem(&block_bitmap);
285         return 0;
286         
287 cleanup:
288         if (do_block) {
289                 ext2fs_free_mem(&fs->block_map);
290                 fs->block_map = 0;
291         }
292         if (do_inode) {
293                 ext2fs_free_mem(&fs->inode_map);
294                 fs->inode_map = 0;
295         }
296         if (inode_bitmap)
297                 ext2fs_free_mem(&inode_bitmap);
298         if (block_bitmap)
299                 ext2fs_free_mem(&block_bitmap);
300         if (buf)
301                 ext2fs_free_mem(&buf);
302         return retval;
303 }
304
305 errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs)
306 {
307         return read_bitmaps(fs, 1, 0);
308 }
309
310 errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
311 {
312         return read_bitmaps(fs, 0, 1);
313 }
314
315 errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
316 {
317         return write_bitmaps(fs, 1, 0);
318 }
319
320 errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
321 {
322         return write_bitmaps(fs, 0, 1);
323 }
324
325 errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
326 {
327         if (fs->inode_map && fs->block_map)
328                 return 0;
329
330         return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
331 }
332
333 errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
334 {
335         int do_inode = fs->inode_map && ext2fs_test_ib_dirty(fs);
336         int do_block = fs->block_map && ext2fs_test_bb_dirty(fs);
337
338         if (!do_inode && !do_block)
339                 return 0;
340
341         return write_bitmaps(fs, do_inode, do_block);
342 }