Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 1 | /* |
| 2 | * swapfs.c --- byte-swap an ext2 filesystem |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 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 | * |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 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 | struct swap_block_struct { |
| 20 | ino_t ino; |
| 21 | int isdir; |
| 22 | errcode_t errcode; |
| 23 | char *dir_buf; |
| 24 | struct ext2_inode *inode; |
| 25 | }; |
| 26 | |
| 27 | /* |
| 28 | * This is a helper function for block_iterate. We mark all of the |
| 29 | * indirect and direct blocks as changed, so that block_iterate will |
| 30 | * write them out. |
| 31 | */ |
| 32 | static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt, |
| 33 | void *private) |
| 34 | { |
| 35 | errcode_t retval; |
| 36 | |
| 37 | struct swap_block_struct *sb = (struct swap_block_struct *) private; |
| 38 | |
| 39 | if (sb->isdir && (blockcnt >= 0) && *block_nr) { |
| 40 | retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf); |
| 41 | if (retval) { |
| 42 | sb->errcode = retval; |
| 43 | return BLOCK_ABORT; |
| 44 | } |
| 45 | retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf); |
| 46 | if (retval) { |
| 47 | sb->errcode = retval; |
| 48 | return BLOCK_ABORT; |
| 49 | } |
| 50 | } |
| 51 | if (blockcnt >= 0) { |
| 52 | if (blockcnt < EXT2_NDIR_BLOCKS) |
| 53 | return 0; |
| 54 | return BLOCK_CHANGED; |
| 55 | } |
| 56 | if (blockcnt == BLOCK_COUNT_IND) { |
| 57 | if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK]) |
| 58 | return 0; |
| 59 | return BLOCK_CHANGED; |
| 60 | } |
| 61 | if (blockcnt == BLOCK_COUNT_DIND) { |
| 62 | if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK]) |
| 63 | return 0; |
| 64 | return BLOCK_CHANGED; |
| 65 | } |
| 66 | if (blockcnt == BLOCK_COUNT_TIND) { |
| 67 | if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK]) |
| 68 | return 0; |
| 69 | return BLOCK_CHANGED; |
| 70 | } |
| 71 | return BLOCK_CHANGED; |
| 72 | } |
| 73 | |
| 74 | /* |
| 75 | * This function is responsible for byte-swapping all of the indirect, |
| 76 | * block pointers. It is also responsible for byte-swapping directories. |
| 77 | */ |
| 78 | static void swap_inode_blocks(ext2_filsys fs, ino_t ino, char *block_buf, |
| 79 | struct ext2_inode *inode) |
| 80 | { |
| 81 | errcode_t retval; |
| 82 | struct swap_block_struct sb; |
| 83 | |
| 84 | sb.ino = ino; |
| 85 | sb.inode = inode; |
| 86 | sb.dir_buf = block_buf + fs->blocksize*3; |
| 87 | sb.errcode = 0; |
| 88 | sb.isdir = 0; |
| 89 | if (LINUX_S_ISDIR(inode->i_mode)) |
| 90 | sb.isdir = 1; |
| 91 | |
| 92 | retval = ext2fs_block_iterate(fs, ino, 0, block_buf, swap_block, &sb); |
| 93 | if (retval) { |
| 94 | com_err("swap_inode_blocks", retval, |
| 95 | "while calling ext2fs_block_iterate"); |
| 96 | fatal_error(0); |
| 97 | } |
| 98 | if (sb.errcode) { |
| 99 | com_err("swap_inode_blocks", sb.errcode, |
| 100 | "while calling iterator function"); |
| 101 | fatal_error(0); |
| 102 | } |
| 103 | } |
| 104 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 105 | static void swap_inodes(e2fsck_t ctx) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 106 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 107 | ext2_filsys fs = ctx->fs; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 108 | int i, group; |
| 109 | ino_t ino = 1; |
| 110 | char *buf, *block_buf; |
| 111 | errcode_t retval; |
| 112 | struct ext2_inode * inode; |
| 113 | |
| 114 | fs->read_inode = pass1_read_inode; |
| 115 | fs->get_blocks = pass1_get_blocks; |
| 116 | |
| 117 | |
| 118 | buf = malloc(fs->blocksize * fs->inode_blocks_per_group); |
| 119 | if (!buf) { |
| 120 | com_err("swap_inodes", ENOMEM, |
| 121 | "while allocating inode buffer"); |
| 122 | fatal_error(0); |
| 123 | } |
| 124 | block_buf = allocate_memory(fs->blocksize * 4, |
| 125 | "block interate buffer"); |
| 126 | for (group = 0; group < fs->group_desc_count; group++) { |
| 127 | retval = io_channel_read_blk(fs->io, |
| 128 | fs->group_desc[group].bg_inode_table, |
| 129 | fs->inode_blocks_per_group, buf); |
| 130 | if (retval) { |
| 131 | com_err("swap_inodes", retval, |
| 132 | "while reading inode table (group %d)", |
| 133 | group); |
| 134 | fatal_error(0); |
| 135 | } |
| 136 | inode = (struct ext2_inode *) buf; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 137 | for (i=0; i < fs->super->s_inodes_per_group; |
| 138 | i++, ino++, inode++) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 139 | ctx->stashed_ino = ino; |
| 140 | ctx->stashed_inode = inode; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 141 | |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 142 | if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ) |
| 143 | ext2fs_swap_inode(fs, inode, inode, 0); |
| 144 | |
| 145 | /* |
| 146 | * Skip deleted files. |
| 147 | */ |
| 148 | if (inode->i_links_count == 0) |
| 149 | continue; |
| 150 | |
| 151 | if (LINUX_S_ISDIR(inode->i_mode) || |
| 152 | ((inode->i_block[EXT2_IND_BLOCK] || |
| 153 | inode->i_block[EXT2_DIND_BLOCK] || |
| 154 | inode->i_block[EXT2_TIND_BLOCK]) && |
| 155 | ext2fs_inode_has_valid_blocks(inode))) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 156 | swap_inode_blocks(fs, ino, block_buf, inode); |
| 157 | |
Theodore Ts'o | 5c57647 | 1997-04-29 15:29:49 +0000 | [diff] [blame] | 158 | if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 159 | ext2fs_swap_inode(fs, inode, inode, 1); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 160 | } |
| 161 | retval = io_channel_write_blk(fs->io, |
| 162 | fs->group_desc[group].bg_inode_table, |
| 163 | fs->inode_blocks_per_group, buf); |
| 164 | if (retval) { |
| 165 | com_err("swap_inodes", retval, |
| 166 | "while writing inode table (group %d)", |
| 167 | group); |
| 168 | fatal_error(0); |
| 169 | } |
| 170 | } |
| 171 | free(buf); |
| 172 | free(block_buf); |
| 173 | fs->read_inode = 0; |
| 174 | fs->get_blocks = 0; |
| 175 | } |
| 176 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 177 | void swap_filesys(e2fsck_t ctx) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 178 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 179 | ext2_filsys fs = ctx->fs; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 180 | struct resource_track rtrack; |
| 181 | |
| 182 | init_resource_track(&rtrack); |
| 183 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 184 | if (!(ctx->options & E2F_OPT_PREEN)) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 185 | printf("Pass 0: Doing byte-swap of filesystem\n"); |
| 186 | |
| 187 | #ifdef MTRACE |
| 188 | mtrace_print("Byte swap"); |
| 189 | #endif |
| 190 | |
| 191 | if (fs->super->s_mnt_count) { |
| 192 | fprintf(stderr, "%s: the filesystem must be freshly " |
| 193 | "checked using fsck\n" |
| 194 | "and not mounted before trying to " |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 195 | "byte-swap it.\n", ctx->device_name); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 196 | fatal_error(0); |
| 197 | } |
Theodore Ts'o | 5c57647 | 1997-04-29 15:29:49 +0000 | [diff] [blame] | 198 | if (fs->flags & EXT2_FLAG_SWAP_BYTES) { |
| 199 | fs->flags &= ~(EXT2_FLAG_SWAP_BYTES| |
| 200 | EXT2_FLAG_SWAP_BYTES_WRITE); |
| 201 | fs->flags |= EXT2_FLAG_SWAP_BYTES_READ; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 202 | } else { |
Theodore Ts'o | 5c57647 | 1997-04-29 15:29:49 +0000 | [diff] [blame] | 203 | fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ; |
| 204 | fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 205 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 206 | swap_inodes(ctx); |
Theodore Ts'o | 5c57647 | 1997-04-29 15:29:49 +0000 | [diff] [blame] | 207 | if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE) |
| 208 | fs->flags |= EXT2_FLAG_SWAP_BYTES; |
| 209 | fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ| |
| 210 | EXT2_FLAG_SWAP_BYTES_WRITE); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 211 | ext2fs_flush(fs); |
| 212 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame^] | 213 | if (ctx->options & E2F_OPT_TIME2) |
| 214 | print_resource_track("Byte swap", &rtrack); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 215 | } |
| 216 | |
| 217 | |