Whamcloud - gitweb
Merge branch 'maint' into next
[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 "config.h"
13 #include <stdio.h>
14 #include <string.h>
15 #if HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 #include <fcntl.h>
19 #include <time.h>
20 #ifdef HAVE_SYS_STAT_H
21 #include <sys/stat.h>
22 #endif
23 #ifdef HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif
26
27 #include "ext2_fs.h"
28 #include "ext2fs.h"
29 #include "e2image.h"
30
31 static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
32 {
33         dgrp_t          i;
34         unsigned int    j;
35         int             block_nbytes, inode_nbytes;
36         unsigned int    nbits;
37         errcode_t       retval;
38         char            *block_buf = NULL, *inode_buf = NULL;
39         int             csum_flag;
40         blk64_t         blk;
41         blk64_t         blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
42         ext2_ino_t      ino_itr = 1;
43
44         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
45
46         if (!(fs->flags & EXT2_FLAG_RW))
47                 return EXT2_ET_RO_FILSYS;
48
49         csum_flag = ext2fs_has_group_desc_csum(fs);
50
51         inode_nbytes = block_nbytes = 0;
52         if (do_block) {
53                 block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
54                 retval = io_channel_alloc_buf(fs->io, 0, &block_buf);
55                 if (retval)
56                         goto errout;
57                 memset(block_buf, 0xff, fs->blocksize);
58         }
59         if (do_inode) {
60                 inode_nbytes = (size_t)
61                         ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
62                 retval = io_channel_alloc_buf(fs->io, 0, &inode_buf);
63                 if (retval)
64                         goto errout;
65                 memset(inode_buf, 0xff, fs->blocksize);
66         }
67
68         for (i = 0; i < fs->group_desc_count; i++) {
69                 if (!do_block)
70                         goto skip_block_bitmap;
71
72                 if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT)
73                     )
74                         goto skip_this_block_bitmap;
75
76                 retval = ext2fs_get_block_bitmap_range2(fs->block_map,
77                                 blk_itr, block_nbytes << 3, block_buf);
78                 if (retval)
79                         goto errout;
80
81                 if (i == fs->group_desc_count - 1) {
82                         /* Force bitmap padding for the last group */
83                         nbits = EXT2FS_NUM_B2C(fs,
84                                 ((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
92                 retval = ext2fs_block_bitmap_csum_set(fs, i, block_buf,
93                                                       block_nbytes);
94                 if (retval)
95                         return retval;
96                 ext2fs_group_desc_csum_set(fs, i);
97
98                 blk = ext2fs_block_bitmap_loc(fs, i);
99                 if (blk) {
100                         retval = io_channel_write_blk64(fs->io, blk, 1,
101                                                         block_buf);
102                         if (retval) {
103                                 retval = EXT2_ET_BLOCK_BITMAP_WRITE;
104                                 goto errout;
105                         }
106                 }
107         skip_this_block_bitmap:
108                 blk_itr += block_nbytes << 3;
109         skip_block_bitmap:
110
111                 if (!do_inode)
112                         continue;
113
114                 if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT)
115                     )
116                         goto skip_this_inode_bitmap;
117
118                 retval = ext2fs_get_inode_bitmap_range2(fs->inode_map,
119                                 ino_itr, inode_nbytes << 3, inode_buf);
120                 if (retval)
121                         goto errout;
122
123                 retval = ext2fs_inode_bitmap_csum_set(fs, i, inode_buf,
124                                                       inode_nbytes);
125                 if (retval)
126                         goto errout;
127                 ext2fs_group_desc_csum_set(fs, i);
128
129                 blk = ext2fs_inode_bitmap_loc(fs, i);
130                 if (blk) {
131                         retval = io_channel_write_blk64(fs->io, blk, 1,
132                                                       inode_buf);
133                         if (retval) {
134                                 retval = EXT2_ET_INODE_BITMAP_WRITE;
135                                 goto errout;
136                         }
137                 }
138         skip_this_inode_bitmap:
139                 ino_itr += inode_nbytes << 3;
140
141         }
142         if (do_block) {
143                 fs->flags &= ~EXT2_FLAG_BB_DIRTY;
144                 ext2fs_free_mem(&block_buf);
145         }
146         if (do_inode) {
147                 fs->flags &= ~EXT2_FLAG_IB_DIRTY;
148                 ext2fs_free_mem(&inode_buf);
149         }
150         return 0;
151 errout:
152         if (inode_buf)
153                 ext2fs_free_mem(&inode_buf);
154         if (block_buf)
155                 ext2fs_free_mem(&block_buf);
156         return retval;
157 }
158
159 static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs)
160 {
161         dgrp_t                  i;
162         blk64_t                 blk;
163         ext2fs_block_bitmap     bmap = fs->block_map;
164
165         for (i = 0; i < fs->group_desc_count; i++) {
166                 if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT))
167                         continue;
168
169                 ext2fs_reserve_super_and_bgd(fs, i, bmap);
170
171                 /*
172                  * Mark the blocks used for the inode table
173                  */
174                 blk = ext2fs_inode_table_loc(fs, i);
175                 if (blk)
176                         ext2fs_mark_block_bitmap_range2(bmap, blk,
177                                                 fs->inode_blocks_per_group);
178
179                 /*
180                  * Mark block used for the block bitmap
181                  */
182                 blk = ext2fs_block_bitmap_loc(fs, i);
183                 if (blk)
184                         ext2fs_mark_block_bitmap2(bmap, blk);
185
186                 /*
187                  * Mark block used for the inode bitmap
188                  */
189                 blk = ext2fs_inode_bitmap_loc(fs, i);
190                 if (blk)
191                         ext2fs_mark_block_bitmap2(bmap, blk);
192         }
193         return 0;
194 }
195
196 static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
197 {
198         dgrp_t i;
199         char *block_bitmap = 0, *inode_bitmap = 0;
200         char *buf;
201         errcode_t retval;
202         int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
203         int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
204         int csum_flag;
205         unsigned int    cnt;
206         blk64_t blk;
207         blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
208         blk64_t   blk_cnt;
209         ext2_ino_t ino_itr = 1;
210         ext2_ino_t ino_cnt;
211
212         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
213
214         if ((block_nbytes > (int) fs->blocksize) ||
215             (inode_nbytes > (int) fs->blocksize))
216                 return EXT2_ET_CORRUPT_SUPERBLOCK;
217
218         fs->write_bitmaps = ext2fs_write_bitmaps;
219
220         csum_flag = ext2fs_has_group_desc_csum(fs);
221
222         retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
223         if (retval)
224                 return retval;
225         if (do_block) {
226                 if (fs->block_map)
227                         ext2fs_free_block_bitmap(fs->block_map);
228                 strcpy(buf, "block bitmap for ");
229                 strcat(buf, fs->device_name);
230                 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
231                 if (retval)
232                         goto cleanup;
233                 retval = io_channel_alloc_buf(fs->io, 0, &block_bitmap);
234                 if (retval)
235                         goto cleanup;
236         } else
237                 block_nbytes = 0;
238         if (do_inode) {
239                 if (fs->inode_map)
240                         ext2fs_free_inode_bitmap(fs->inode_map);
241                 strcpy(buf, "inode bitmap for ");
242                 strcat(buf, fs->device_name);
243                 retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
244                 if (retval)
245                         goto cleanup;
246                 retval = io_channel_alloc_buf(fs->io, 0, &inode_bitmap);
247                 if (retval)
248                         goto cleanup;
249         } else
250                 inode_nbytes = 0;
251         ext2fs_free_mem(&buf);
252
253         if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
254                 blk = (fs->image_header->offset_inodemap / fs->blocksize);
255                 ino_cnt = fs->super->s_inodes_count;
256                 while (inode_nbytes > 0) {
257                         retval = io_channel_read_blk64(fs->image_io, blk++,
258                                                      1, inode_bitmap);
259                         if (retval)
260                                 goto cleanup;
261                         cnt = fs->blocksize << 3;
262                         if (cnt > ino_cnt)
263                                 cnt = ino_cnt;
264                         retval = ext2fs_set_inode_bitmap_range2(fs->inode_map,
265                                                ino_itr, cnt, inode_bitmap);
266                         if (retval)
267                                 goto cleanup;
268                         ino_itr += fs->blocksize << 3;
269                         ino_cnt -= fs->blocksize << 3;
270                         inode_nbytes -= fs->blocksize;
271                 }
272                 blk = (fs->image_header->offset_blockmap /
273                        fs->blocksize);
274                 blk_cnt = (blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) *
275                         fs->group_desc_count;
276                 while (block_nbytes > 0) {
277                         retval = io_channel_read_blk64(fs->image_io, blk++,
278                                                      1, block_bitmap);
279                         if (retval)
280                                 goto cleanup;
281                         cnt = fs->blocksize << 3;
282                         if (cnt > blk_cnt)
283                                 cnt = blk_cnt;
284                         retval = ext2fs_set_block_bitmap_range2(fs->block_map,
285                                        blk_itr, cnt, block_bitmap);
286                         if (retval)
287                                 goto cleanup;
288                         blk_itr += fs->blocksize << 3;
289                         blk_cnt -= fs->blocksize << 3;
290                         block_nbytes -= fs->blocksize;
291                 }
292                 goto success_cleanup;
293         }
294
295         for (i = 0; i < fs->group_desc_count; i++) {
296                 if (block_bitmap) {
297                         blk = ext2fs_block_bitmap_loc(fs, i);
298                         if (csum_flag &&
299                             ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) &&
300                             ext2fs_group_desc_csum_verify(fs, i))
301                                 blk = 0;
302                         if (blk) {
303                                 retval = io_channel_read_blk64(fs->io, blk,
304                                                                1, block_bitmap);
305                                 if (retval) {
306                                         retval = EXT2_ET_BLOCK_BITMAP_READ;
307                                         goto cleanup;
308                                 }
309                                 /* verify block bitmap checksum */
310                                 if (!(fs->flags &
311                                       EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
312                                     !ext2fs_block_bitmap_csum_verify(fs, i,
313                                                 block_bitmap, block_nbytes)) {
314                                         retval =
315                                         EXT2_ET_BLOCK_BITMAP_CSUM_INVALID;
316                                         goto cleanup;
317                                 }
318                         } else
319                                 memset(block_bitmap, 0, block_nbytes);
320                         cnt = block_nbytes << 3;
321                         retval = ext2fs_set_block_bitmap_range2(fs->block_map,
322                                                blk_itr, cnt, block_bitmap);
323                         if (retval)
324                                 goto cleanup;
325                         blk_itr += block_nbytes << 3;
326                 }
327                 if (inode_bitmap) {
328                         blk = ext2fs_inode_bitmap_loc(fs, i);
329                         if (csum_flag &&
330                             ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) &&
331                             ext2fs_group_desc_csum_verify(fs, i))
332                                 blk = 0;
333                         if (blk) {
334                                 retval = io_channel_read_blk64(fs->io, blk,
335                                                                1, inode_bitmap);
336                                 if (retval) {
337                                         retval = EXT2_ET_INODE_BITMAP_READ;
338                                         goto cleanup;
339                                 }
340
341                                 /* verify inode bitmap checksum */
342                                 if (!(fs->flags &
343                                       EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
344                                     !ext2fs_inode_bitmap_csum_verify(fs, i,
345                                                 inode_bitmap, inode_nbytes)) {
346                                         retval =
347                                         EXT2_ET_INODE_BITMAP_CSUM_INVALID;
348                                         goto cleanup;
349                                 }
350                         } else
351                                 memset(inode_bitmap, 0, inode_nbytes);
352                         cnt = inode_nbytes << 3;
353                         retval = ext2fs_set_inode_bitmap_range2(fs->inode_map,
354                                                ino_itr, cnt, inode_bitmap);
355                         if (retval)
356                                 goto cleanup;
357                         ino_itr += inode_nbytes << 3;
358                 }
359         }
360
361         /* Mark group blocks for any BLOCK_UNINIT groups */
362         if (do_block) {
363                 retval = mark_uninit_bg_group_blocks(fs);
364                 if (retval)
365                         goto cleanup;
366         }
367
368 success_cleanup:
369         if (inode_bitmap)
370                 ext2fs_free_mem(&inode_bitmap);
371         if (block_bitmap)
372                 ext2fs_free_mem(&block_bitmap);
373         return 0;
374
375 cleanup:
376         if (do_block) {
377                 ext2fs_free_mem(&fs->block_map);
378                 fs->block_map = 0;
379         }
380         if (do_inode) {
381                 ext2fs_free_mem(&fs->inode_map);
382                 fs->inode_map = 0;
383         }
384         if (inode_bitmap)
385                 ext2fs_free_mem(&inode_bitmap);
386         if (block_bitmap)
387                 ext2fs_free_mem(&block_bitmap);
388         if (buf)
389                 ext2fs_free_mem(&buf);
390         return retval;
391 }
392
393 errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs)
394 {
395         return read_bitmaps(fs, 1, 0);
396 }
397
398 errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
399 {
400         return read_bitmaps(fs, 0, 1);
401 }
402
403 errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
404 {
405         return write_bitmaps(fs, 1, 0);
406 }
407
408 errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
409 {
410         return write_bitmaps(fs, 0, 1);
411 }
412
413 errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
414 {
415         if (fs->inode_map && fs->block_map)
416                 return 0;
417
418         return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
419 }
420
421 errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
422 {
423         int do_inode = fs->inode_map && ext2fs_test_ib_dirty(fs);
424         int do_block = fs->block_map && ext2fs_test_bb_dirty(fs);
425
426         if (!do_inode && !do_block)
427                 return 0;
428
429         return write_bitmaps(fs, do_inode, do_block);
430 }