Whamcloud - gitweb
libext2fs: don't hang in ext2fs_new_block2() on a full bigalloc file system
[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 Library
8  * General Public License, version 2.
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             csum_flag = 0;
39         blk64_t         blk;
40         blk64_t         blk_itr = EXT2FS_B2C(fs, 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
48         if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
49                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
50                 csum_flag = 1;
51
52         inode_nbytes = block_nbytes = 0;
53         if (do_block) {
54                 block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
55                 retval = ext2fs_get_memalign(fs->blocksize, fs->blocksize,
56                                              &block_buf);
57                 if (retval)
58                         return retval;
59                 memset(block_buf, 0xff, fs->blocksize);
60         }
61         if (do_inode) {
62                 inode_nbytes = (size_t)
63                         ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
64                 retval = ext2fs_get_memalign(fs->blocksize, fs->blocksize,
65                                              &inode_buf);
66                 if (retval)
67                         return retval;
68                 memset(inode_buf, 0xff, fs->blocksize);
69         }
70
71         for (i = 0; i < fs->group_desc_count; i++) {
72                 if (!do_block)
73                         goto skip_block_bitmap;
74
75                 if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT)
76                     )
77                         goto skip_this_block_bitmap;
78
79                 retval = ext2fs_get_block_bitmap_range2(fs->block_map,
80                                 blk_itr, block_nbytes << 3, block_buf);
81                 if (retval)
82                         return retval;
83
84                 if (i == fs->group_desc_count - 1) {
85                         /* Force bitmap padding for the last group */
86                         nbits = EXT2FS_NUM_B2C(fs,
87                                 ((ext2fs_blocks_count(fs->super)
88                                   - (__u64) fs->super->s_first_data_block)
89                                  % (__u64) EXT2_BLOCKS_PER_GROUP(fs->super)));
90                         if (nbits)
91                                 for (j = nbits; j < fs->blocksize * 8; j++)
92                                         ext2fs_set_bit(j, block_buf);
93                 }
94                 blk = ext2fs_block_bitmap_loc(fs, i);
95                 if (blk) {
96                         retval = io_channel_write_blk64(fs->io, blk, 1,
97                                                         block_buf);
98                         if (retval)
99                                 return EXT2_ET_BLOCK_BITMAP_WRITE;
100                 }
101         skip_this_block_bitmap:
102                 blk_itr += block_nbytes << 3;
103         skip_block_bitmap:
104
105                 if (!do_inode)
106                         continue;
107
108                 if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT)
109                     )
110                         goto skip_this_inode_bitmap;
111
112                 retval = ext2fs_get_inode_bitmap_range2(fs->inode_map,
113                                 ino_itr, inode_nbytes << 3, inode_buf);
114                 if (retval)
115                         return retval;
116
117                 blk = ext2fs_inode_bitmap_loc(fs, i);
118                 if (blk) {
119                         retval = io_channel_write_blk64(fs->io, blk, 1,
120                                                       inode_buf);
121                         if (retval)
122                                 return EXT2_ET_INODE_BITMAP_WRITE;
123                 }
124         skip_this_inode_bitmap:
125                 ino_itr += inode_nbytes << 3;
126
127         }
128         if (do_block) {
129                 fs->flags &= ~EXT2_FLAG_BB_DIRTY;
130                 ext2fs_free_mem(&block_buf);
131         }
132         if (do_inode) {
133                 fs->flags &= ~EXT2_FLAG_IB_DIRTY;
134                 ext2fs_free_mem(&inode_buf);
135         }
136         return 0;
137 }
138
139 static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
140 {
141         dgrp_t i;
142         char *block_bitmap = 0, *inode_bitmap = 0;
143         char *buf;
144         errcode_t retval;
145         int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
146         int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
147         int csum_flag = 0;
148         int do_image = fs->flags & EXT2_FLAG_IMAGE_FILE;
149         unsigned int    cnt;
150         blk64_t blk;
151         blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
152         blk64_t   blk_cnt;
153         ext2_ino_t ino_itr = 1;
154         ext2_ino_t ino_cnt;
155
156         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
157
158         fs->write_bitmaps = ext2fs_write_bitmaps;
159
160         if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
161                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
162                 csum_flag = 1;
163
164         retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
165         if (retval)
166                 return retval;
167         if (do_block) {
168                 if (fs->block_map)
169                         ext2fs_free_block_bitmap(fs->block_map);
170                 strcpy(buf, "block bitmap for ");
171                 strcat(buf, fs->device_name);
172                 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
173                 if (retval)
174                         goto cleanup;
175                 if (do_image)
176                         retval = ext2fs_get_mem(fs->blocksize, &block_bitmap);
177                 else
178                         retval = ext2fs_get_memalign((unsigned) block_nbytes,
179                                                      fs->blocksize,
180                                                      &block_bitmap);
181                         
182                 if (retval)
183                         goto cleanup;
184         } else
185                 block_nbytes = 0;
186         if (do_inode) {
187                 if (fs->inode_map)
188                         ext2fs_free_inode_bitmap(fs->inode_map);
189                 strcpy(buf, "inode bitmap for ");
190                 strcat(buf, fs->device_name);
191                 retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
192                 if (retval)
193                         goto cleanup;
194                 retval = ext2fs_get_mem(do_image ? fs->blocksize :
195                                         (unsigned) inode_nbytes, &inode_bitmap);
196                 if (retval)
197                         goto cleanup;
198         } else
199                 inode_nbytes = 0;
200         ext2fs_free_mem(&buf);
201
202         if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
203                 blk = (fs->image_header->offset_inodemap / fs->blocksize);
204                 ino_cnt = fs->super->s_inodes_count;
205                 while (inode_nbytes > 0) {
206                         retval = io_channel_read_blk64(fs->image_io, blk++,
207                                                      1, inode_bitmap);
208                         if (retval)
209                                 goto cleanup;
210                         cnt = fs->blocksize << 3;
211                         if (cnt > ino_cnt)
212                                 cnt = ino_cnt;
213                         retval = ext2fs_set_inode_bitmap_range2(fs->inode_map,
214                                                ino_itr, cnt, inode_bitmap);
215                         if (retval)
216                                 goto cleanup;
217                         ino_itr += fs->blocksize << 3;
218                         ino_cnt -= fs->blocksize << 3;
219                         inode_nbytes -= fs->blocksize;
220                 }
221                 blk = (fs->image_header->offset_blockmap /
222                        fs->blocksize);
223                 blk_cnt = (blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) *
224                         fs->group_desc_count;
225                 while (block_nbytes > 0) {
226                         retval = io_channel_read_blk64(fs->image_io, blk++,
227                                                      1, block_bitmap);
228                         if (retval)
229                                 goto cleanup;
230                         cnt = fs->blocksize << 3;
231                         if (cnt > blk_cnt)
232                                 cnt = blk_cnt;
233                         retval = ext2fs_set_block_bitmap_range2(fs->block_map,
234                                        blk_itr, cnt, block_bitmap);
235                         if (retval)
236                                 goto cleanup;
237                         blk_itr += fs->blocksize << 3;
238                         blk_cnt -= fs->blocksize << 3;
239                         block_nbytes -= fs->blocksize;
240                 }
241                 goto success_cleanup;
242         }
243
244         for (i = 0; i < fs->group_desc_count; i++) {
245                 if (block_bitmap) {
246                         blk = ext2fs_block_bitmap_loc(fs, i);
247                         if (csum_flag &&
248                             ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) &&
249                             ext2fs_group_desc_csum_verify(fs, i))
250                                 blk = 0;
251                         if (blk) {
252                                 retval = io_channel_read_blk64(fs->io, blk,
253                                              -block_nbytes, block_bitmap);
254                                 if (retval) {
255                                         retval = EXT2_ET_BLOCK_BITMAP_READ;
256                                         goto cleanup;
257                                 }
258                         } else
259                                 memset(block_bitmap, 0, block_nbytes);
260                         cnt = block_nbytes << 3;
261                         retval = ext2fs_set_block_bitmap_range2(fs->block_map,
262                                                blk_itr, cnt, block_bitmap);
263                         if (retval)
264                                 goto cleanup;
265                         blk_itr += block_nbytes << 3;
266                 }
267                 if (inode_bitmap) {
268                         blk = ext2fs_inode_bitmap_loc(fs, i);
269                         if (csum_flag &&
270                             ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) &&
271                             ext2fs_group_desc_csum_verify(fs, i))
272                                 blk = 0;
273                         if (blk) {
274                                 retval = io_channel_read_blk64(fs->io, blk,
275                                              -inode_nbytes, inode_bitmap);
276                                 if (retval) {
277                                         retval = EXT2_ET_INODE_BITMAP_READ;
278                                         goto cleanup;
279                                 }
280                         } else
281                                 memset(inode_bitmap, 0, inode_nbytes);
282                         cnt = inode_nbytes << 3;
283                         retval = ext2fs_set_inode_bitmap_range2(fs->inode_map,
284                                                ino_itr, cnt, inode_bitmap);
285                         if (retval)
286                                 goto cleanup;
287                         ino_itr += inode_nbytes << 3;
288                 }
289         }
290 success_cleanup:
291         if (inode_bitmap)
292                 ext2fs_free_mem(&inode_bitmap);
293         if (block_bitmap)
294                 ext2fs_free_mem(&block_bitmap);
295         return 0;
296
297 cleanup:
298         if (do_block) {
299                 ext2fs_free_mem(&fs->block_map);
300                 fs->block_map = 0;
301         }
302         if (do_inode) {
303                 ext2fs_free_mem(&fs->inode_map);
304                 fs->inode_map = 0;
305         }
306         if (inode_bitmap)
307                 ext2fs_free_mem(&inode_bitmap);
308         if (block_bitmap)
309                 ext2fs_free_mem(&block_bitmap);
310         if (buf)
311                 ext2fs_free_mem(&buf);
312         return retval;
313 }
314
315 errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs)
316 {
317         return read_bitmaps(fs, 1, 0);
318 }
319
320 errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
321 {
322         return read_bitmaps(fs, 0, 1);
323 }
324
325 errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
326 {
327         return write_bitmaps(fs, 1, 0);
328 }
329
330 errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
331 {
332         return write_bitmaps(fs, 0, 1);
333 }
334
335 errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
336 {
337         if (fs->inode_map && fs->block_map)
338                 return 0;
339
340         return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
341 }
342
343 errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
344 {
345         int do_inode = fs->inode_map && ext2fs_test_ib_dirty(fs);
346         int do_block = fs->block_map && ext2fs_test_bb_dirty(fs);
347
348         if (!do_inode && !do_block)
349                 return 0;
350
351         return write_bitmaps(fs, do_inode, do_block);
352 }