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