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