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, |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 33 | void *priv_data) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 34 | { |
| 35 | errcode_t retval; |
| 36 | |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 37 | struct swap_block_struct *sb = (struct swap_block_struct *) priv_data; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 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 | */ |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 78 | static void swap_inode_blocks(e2fsck_t ctx, ino_t ino, char *block_buf, |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 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; |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 86 | sb.dir_buf = block_buf + ctx->fs->blocksize*3; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 87 | sb.errcode = 0; |
| 88 | sb.isdir = 0; |
| 89 | if (LINUX_S_ISDIR(inode->i_mode)) |
| 90 | sb.isdir = 1; |
| 91 | |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 92 | retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf, |
| 93 | swap_block, &sb); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 94 | if (retval) { |
| 95 | com_err("swap_inode_blocks", retval, |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 96 | _("while calling ext2fs_block_iterate")); |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 97 | ctx->flags |= E2F_FLAG_ABORT; |
| 98 | return; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 99 | } |
| 100 | if (sb.errcode) { |
| 101 | com_err("swap_inode_blocks", sb.errcode, |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 102 | _("while calling iterator function")); |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 103 | ctx->flags |= E2F_FLAG_ABORT; |
| 104 | return; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 105 | } |
| 106 | } |
| 107 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 108 | static void swap_inodes(e2fsck_t ctx) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 109 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 110 | ext2_filsys fs = ctx->fs; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 111 | int i, group; |
| 112 | ino_t ino = 1; |
| 113 | char *buf, *block_buf; |
| 114 | errcode_t retval; |
| 115 | struct ext2_inode * inode; |
| 116 | |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 117 | e2fsck_use_inode_shortcuts(ctx, 1); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 118 | |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 119 | retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group, |
| 120 | (void **) &buf); |
| 121 | if (retval) { |
| 122 | com_err("swap_inodes", retval, |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 123 | _("while allocating inode buffer")); |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 124 | ctx->flags |= E2F_FLAG_ABORT; |
| 125 | return; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 126 | } |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 127 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4, |
| 128 | "block interate buffer"); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 129 | for (group = 0; group < fs->group_desc_count; group++) { |
| 130 | retval = io_channel_read_blk(fs->io, |
| 131 | fs->group_desc[group].bg_inode_table, |
| 132 | fs->inode_blocks_per_group, buf); |
| 133 | if (retval) { |
| 134 | com_err("swap_inodes", retval, |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 135 | _("while reading inode table (group %d)"), |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 136 | group); |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 137 | ctx->flags |= E2F_FLAG_ABORT; |
| 138 | return; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 139 | } |
| 140 | inode = (struct ext2_inode *) buf; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 141 | for (i=0; i < fs->super->s_inodes_per_group; |
| 142 | i++, ino++, inode++) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 143 | ctx->stashed_ino = ino; |
| 144 | ctx->stashed_inode = inode; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 145 | |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 146 | if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ) |
| 147 | ext2fs_swap_inode(fs, inode, inode, 0); |
| 148 | |
| 149 | /* |
| 150 | * Skip deleted files. |
| 151 | */ |
| 152 | if (inode->i_links_count == 0) |
| 153 | continue; |
| 154 | |
| 155 | if (LINUX_S_ISDIR(inode->i_mode) || |
| 156 | ((inode->i_block[EXT2_IND_BLOCK] || |
| 157 | inode->i_block[EXT2_DIND_BLOCK] || |
| 158 | inode->i_block[EXT2_TIND_BLOCK]) && |
| 159 | ext2fs_inode_has_valid_blocks(inode))) |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 160 | swap_inode_blocks(ctx, ino, block_buf, inode); |
| 161 | |
Theodore Ts'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 162 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 163 | return; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 164 | |
Theodore Ts'o | 5c57647 | 1997-04-29 15:29:49 +0000 | [diff] [blame] | 165 | if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 166 | ext2fs_swap_inode(fs, inode, inode, 1); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 167 | } |
| 168 | retval = io_channel_write_blk(fs->io, |
| 169 | fs->group_desc[group].bg_inode_table, |
| 170 | fs->inode_blocks_per_group, buf); |
| 171 | if (retval) { |
| 172 | com_err("swap_inodes", retval, |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 173 | _("while writing inode table (group %d)"), |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 174 | group); |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 175 | ctx->flags |= E2F_FLAG_ABORT; |
| 176 | return; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 177 | } |
| 178 | } |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 179 | ext2fs_free_mem((void **) &buf); |
| 180 | ext2fs_free_mem((void **) &block_buf); |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 181 | e2fsck_use_inode_shortcuts(ctx, 0); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 182 | } |
| 183 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 184 | void swap_filesys(e2fsck_t ctx) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 185 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 186 | ext2_filsys fs = ctx->fs; |
Theodore Ts'o | 8bf191e | 1997-10-20 01:38:32 +0000 | [diff] [blame] | 187 | #ifdef RESOURCE_TRACK |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 188 | struct resource_track rtrack; |
| 189 | |
| 190 | init_resource_track(&rtrack); |
Theodore Ts'o | 8bf191e | 1997-10-20 01:38:32 +0000 | [diff] [blame] | 191 | #endif |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 192 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 193 | if (!(ctx->options & E2F_OPT_PREEN)) |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 194 | printf(_("Pass 0: Doing byte-swap of filesystem\n")); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 195 | |
| 196 | #ifdef MTRACE |
| 197 | mtrace_print("Byte swap"); |
| 198 | #endif |
| 199 | |
| 200 | if (fs->super->s_mnt_count) { |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 201 | fprintf(stderr, _("%s: the filesystem must be freshly " |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 202 | "checked using fsck\n" |
| 203 | "and not mounted before trying to " |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 204 | "byte-swap it.\n"), ctx->device_name); |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 205 | ctx->flags |= E2F_FLAG_ABORT; |
| 206 | return; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 207 | } |
Theodore Ts'o | 5c57647 | 1997-04-29 15:29:49 +0000 | [diff] [blame] | 208 | if (fs->flags & EXT2_FLAG_SWAP_BYTES) { |
| 209 | fs->flags &= ~(EXT2_FLAG_SWAP_BYTES| |
| 210 | EXT2_FLAG_SWAP_BYTES_WRITE); |
| 211 | fs->flags |= EXT2_FLAG_SWAP_BYTES_READ; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 212 | } else { |
Theodore Ts'o | 5c57647 | 1997-04-29 15:29:49 +0000 | [diff] [blame] | 213 | fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ; |
| 214 | fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 215 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 216 | swap_inodes(ctx); |
Theodore Ts'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 217 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 218 | return; |
Theodore Ts'o | 5c57647 | 1997-04-29 15:29:49 +0000 | [diff] [blame] | 219 | if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE) |
| 220 | fs->flags |= EXT2_FLAG_SWAP_BYTES; |
| 221 | fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ| |
| 222 | EXT2_FLAG_SWAP_BYTES_WRITE); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 223 | ext2fs_flush(fs); |
| 224 | |
Theodore Ts'o | 8bf191e | 1997-10-20 01:38:32 +0000 | [diff] [blame] | 225 | #ifdef RESOURCE_TRACK |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 226 | if (ctx->options & E2F_OPT_TIME2) |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 227 | print_resource_track(_("Byte swap"), &rtrack); |
Theodore Ts'o | 8bf191e | 1997-10-20 01:38:32 +0000 | [diff] [blame] | 228 | #endif |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 229 | } |
| 230 | |
| 231 | |