Home | History | Annotate | Download | only in ext2fs
      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 	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 
     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 && fs->group_desc[i].bg_flags &
     74 		    EXT2_BG_BLOCK_UNINIT)
     75 			goto skip_this_block_bitmap;
     76 
     77 		retval = ext2fs_get_block_bitmap_range(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 = ((fs->super->s_blocks_count
     85 				  - fs->super->s_first_data_block)
     86 				 % 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_blk(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 && fs->group_desc[i].bg_flags &
    106 		    EXT2_BG_INODE_UNINIT)
    107 			goto skip_this_inode_bitmap;
    108 
    109 		retval = ext2fs_get_inode_bitmap_range(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_blk(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 	blk_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_blk(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_range(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 = EXT2_BLOCKS_PER_GROUP(fs->super) *
    216 			fs->group_desc_count;
    217 		while (block_nbytes > 0) {
    218 			retval = io_channel_read_blk(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_range(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 && fs->group_desc[i].bg_flags &
    240 			    EXT2_BG_BLOCK_UNINIT &&
    241 			    ext2fs_group_desc_csum_verify(fs, i))
    242 				blk = 0;
    243 			if (blk) {
    244 				retval = io_channel_read_blk(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_range(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 && fs->group_desc[i].bg_flags &
    262 			    EXT2_BG_INODE_UNINIT &&
    263 			    ext2fs_group_desc_csum_verify(fs, i))
    264 				blk = 0;
    265 			if (blk) {
    266 				retval = io_channel_read_blk(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_range(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 }
    345