Home | History | Annotate | Download | only in e2fsck
      1 /*
      2  * swapfs.c --- byte-swap an ext2 filesystem
      3  *
      4  * Copyright 1996, 1997 by 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 
     13 #ifdef HAVE_ERRNO_H
     14 #include <errno.h>
     15 #endif
     16 #include <et/com_err.h>
     17 #include "e2fsck.h"
     18 
     19 #ifdef ENABLE_SWAPFS
     20 
     21 struct swap_block_struct {
     22 	ext2_ino_t	ino;
     23 	int		isdir;
     24 	errcode_t	errcode;
     25 	char		*dir_buf;
     26 	struct ext2_inode *inode;
     27 };
     28 
     29 /*
     30  * This is a helper function for block_iterate.  We mark all of the
     31  * indirect and direct blocks as changed, so that block_iterate will
     32  * write them out.
     33  */
     34 static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
     35 		      void *priv_data)
     36 {
     37 	errcode_t	retval;
     38 
     39 	struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
     40 
     41 	if (sb->isdir && (blockcnt >= 0) && *block_nr) {
     42 		retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
     43 		if (retval) {
     44 			sb->errcode = retval;
     45 			return BLOCK_ABORT;
     46 		}
     47 		retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
     48 		if (retval) {
     49 			sb->errcode = retval;
     50 			return BLOCK_ABORT;
     51 		}
     52 	}
     53 	if (blockcnt >= 0) {
     54 		if (blockcnt < EXT2_NDIR_BLOCKS)
     55 			return 0;
     56 		return BLOCK_CHANGED;
     57 	}
     58 	if (blockcnt == BLOCK_COUNT_IND) {
     59 		if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
     60 			return 0;
     61 		return BLOCK_CHANGED;
     62 	}
     63 	if (blockcnt == BLOCK_COUNT_DIND) {
     64 		if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
     65 			return 0;
     66 		return BLOCK_CHANGED;
     67 	}
     68 	if (blockcnt == BLOCK_COUNT_TIND) {
     69 		if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
     70 			return 0;
     71 		return BLOCK_CHANGED;
     72 	}
     73 	return BLOCK_CHANGED;
     74 }
     75 
     76 /*
     77  * This function is responsible for byte-swapping all of the indirect,
     78  * block pointers.  It is also responsible for byte-swapping directories.
     79  */
     80 static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
     81 			      struct ext2_inode *inode)
     82 {
     83 	errcode_t			retval;
     84 	struct swap_block_struct	sb;
     85 
     86 	sb.ino = ino;
     87 	sb.inode = inode;
     88 	sb.dir_buf = block_buf + ctx->fs->blocksize*3;
     89 	sb.errcode = 0;
     90 	sb.isdir = 0;
     91 	if (LINUX_S_ISDIR(inode->i_mode))
     92 		sb.isdir = 1;
     93 
     94 	retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
     95 				      swap_block, &sb);
     96 	if (retval) {
     97 		com_err("swap_inode_blocks", retval,
     98 			_("while calling ext2fs_block_iterate"));
     99 		ctx->flags |= E2F_FLAG_ABORT;
    100 		return;
    101 	}
    102 	if (sb.errcode) {
    103 		com_err("swap_inode_blocks", sb.errcode,
    104 			_("while calling iterator function"));
    105 		ctx->flags |= E2F_FLAG_ABORT;
    106 		return;
    107 	}
    108 }
    109 
    110 static void swap_inodes(e2fsck_t ctx)
    111 {
    112 	ext2_filsys fs = ctx->fs;
    113 	dgrp_t			group;
    114 	unsigned int		i;
    115 	ext2_ino_t		ino = 1;
    116 	char 			*buf = NULL, *block_buf = NULL;
    117 	errcode_t		retval;
    118 	struct ext2_inode *	inode;
    119 
    120 	e2fsck_use_inode_shortcuts(ctx, 1);
    121 
    122 	retval = ext2fs_get_array(fs->blocksize, fs->inode_blocks_per_group,
    123 				&buf);
    124 	if (retval) {
    125 		com_err("swap_inodes", retval,
    126 			_("while allocating inode buffer"));
    127 		ctx->flags |= E2F_FLAG_ABORT;
    128 		goto errout;
    129 	}
    130 	block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
    131 						    "block interate buffer");
    132 	for (group = 0; group < fs->group_desc_count; group++) {
    133 		retval = io_channel_read_blk(fs->io,
    134 		      fs->group_desc[group].bg_inode_table,
    135 		      fs->inode_blocks_per_group, buf);
    136 		if (retval) {
    137 			com_err("swap_inodes", retval,
    138 				_("while reading inode table (group %d)"),
    139 				group);
    140 			ctx->flags |= E2F_FLAG_ABORT;
    141 			goto errout;
    142 		}
    143 		inode = (struct ext2_inode *) buf;
    144 		for (i=0; i < fs->super->s_inodes_per_group;
    145 		     i++, ino++, inode++) {
    146 			ctx->stashed_ino = ino;
    147 			ctx->stashed_inode = inode;
    148 
    149 			if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
    150 				ext2fs_swap_inode(fs, inode, inode, 0);
    151 
    152 			/*
    153 			 * Skip deleted files.
    154 			 */
    155 			if (inode->i_links_count == 0)
    156 				continue;
    157 
    158 			if (LINUX_S_ISDIR(inode->i_mode) ||
    159 			    ((inode->i_block[EXT2_IND_BLOCK] ||
    160 			      inode->i_block[EXT2_DIND_BLOCK] ||
    161 			      inode->i_block[EXT2_TIND_BLOCK]) &&
    162 			     ext2fs_inode_has_valid_blocks(inode)))
    163 				swap_inode_blocks(ctx, ino, block_buf, inode);
    164 
    165 			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
    166 				goto errout;
    167 
    168 			if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
    169 				ext2fs_swap_inode(fs, inode, inode, 1);
    170 		}
    171 		retval = io_channel_write_blk(fs->io,
    172 		      fs->group_desc[group].bg_inode_table,
    173 		      fs->inode_blocks_per_group, buf);
    174 		if (retval) {
    175 			com_err("swap_inodes", retval,
    176 				_("while writing inode table (group %d)"),
    177 				group);
    178 			ctx->flags |= E2F_FLAG_ABORT;
    179 			goto errout;
    180 		}
    181 	}
    182 errout:
    183 	if (buf)
    184 		ext2fs_free_mem(&buf);
    185 	if (block_buf)
    186 		ext2fs_free_mem(&block_buf);
    187 	e2fsck_use_inode_shortcuts(ctx, 0);
    188 	ext2fs_flush_icache(fs);
    189 }
    190 
    191 #if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
    192 /*
    193  * On the PowerPC, the big-endian variant of the ext2 filesystem
    194  * has its bitmaps stored as 32-bit words with bit 0 as the LSB
    195  * of each word.  Thus a bitmap with only bit 0 set would be, as
    196  * a string of bytes, 00 00 00 01 00 ...
    197  * To cope with this, we byte-reverse each word of a bitmap if
    198  * we have a big-endian filesystem, that is, if we are *not*
    199  * byte-swapping other word-sized numbers.
    200  */
    201 #define EXT2_BIG_ENDIAN_BITMAPS
    202 #endif
    203 
    204 #ifdef EXT2_BIG_ENDIAN_BITMAPS
    205 static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
    206 {
    207 	__u32 *p = (__u32 *) bmap->bitmap;
    208 	int n, nbytes = (bmap->end - bmap->start + 7) / 8;
    209 
    210 	for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
    211 		*p = ext2fs_swab32(*p);
    212 }
    213 #endif
    214 
    215 
    216 void swap_filesys(e2fsck_t ctx)
    217 {
    218 	ext2_filsys fs = ctx->fs;
    219 #ifdef RESOURCE_TRACK
    220 	struct resource_track	rtrack;
    221 
    222 	init_resource_track(&rtrack);
    223 #endif
    224 
    225 	if (!(ctx->options & E2F_OPT_PREEN))
    226 		printf(_("Pass 0: Doing byte-swap of filesystem\n"));
    227 
    228 #ifdef MTRACE
    229 	mtrace_print("Byte swap");
    230 #endif
    231 
    232 	if (fs->super->s_mnt_count) {
    233 		fprintf(stderr, _("%s: the filesystem must be freshly "
    234 			"checked using fsck\n"
    235 			"and not mounted before trying to "
    236 			"byte-swap it.\n"), ctx->device_name);
    237 		ctx->flags |= E2F_FLAG_ABORT;
    238 		return;
    239 	}
    240 	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
    241 		fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
    242 			       EXT2_FLAG_SWAP_BYTES_WRITE);
    243 		fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
    244 	} else {
    245 		fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
    246 		fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
    247 	}
    248 	swap_inodes(ctx);
    249 	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
    250 		return;
    251 	if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
    252 		fs->flags |= EXT2_FLAG_SWAP_BYTES;
    253 	fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
    254 		       EXT2_FLAG_SWAP_BYTES_WRITE);
    255 
    256 #ifdef EXT2_BIG_ENDIAN_BITMAPS
    257 	e2fsck_read_bitmaps(ctx);
    258 	ext2fs_swap_bitmap(fs->inode_map);
    259 	ext2fs_swap_bitmap(fs->block_map);
    260 	fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
    261 #endif
    262 	fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
    263 	ext2fs_flush(fs);
    264 	fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
    265 
    266 #ifdef RESOURCE_TRACK
    267 	if (ctx->options & E2F_OPT_TIME2)
    268 		print_resource_track(_("Byte swap"), &rtrack);
    269 #endif
    270 }
    271 
    272 #endif
    273