blob: b251e9e742dcb27cd087e3ec5254577aa6460c8d [file] [log] [blame]
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001/*
2 * swapfs.c --- byte-swap an ext2 filesystem
Theodore Ts'o21c84b71997-04-29 16:15:03 +00003 *
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'o1e3472c1997-04-29 14:53:37 +000011 */
12
13#ifdef HAVE_ERRNO_H
14#include <errno.h>
15#endif
16#include <et/com_err.h>
17#include "e2fsck.h"
18
19struct 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 */
32static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000033 void *priv_data)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000034{
35 errcode_t retval;
36
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000037 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000038
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'of8188ff1997-11-14 05:23:04 +000078static void swap_inode_blocks(e2fsck_t ctx, ino_t ino, char *block_buf,
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000079 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'of8188ff1997-11-14 05:23:04 +000086 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000087 sb.errcode = 0;
88 sb.isdir = 0;
89 if (LINUX_S_ISDIR(inode->i_mode))
90 sb.isdir = 1;
91
Theodore Ts'of8188ff1997-11-14 05:23:04 +000092 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
93 swap_block, &sb);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000094 if (retval) {
95 com_err("swap_inode_blocks", retval,
Theodore Ts'o0c4a0722000-02-07 03:11:03 +000096 _("while calling ext2fs_block_iterate"));
Theodore Ts'of8188ff1997-11-14 05:23:04 +000097 ctx->flags |= E2F_FLAG_ABORT;
98 return;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000099 }
100 if (sb.errcode) {
101 com_err("swap_inode_blocks", sb.errcode,
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000102 _("while calling iterator function"));
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000103 ctx->flags |= E2F_FLAG_ABORT;
104 return;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000105 }
106}
107
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000108static void swap_inodes(e2fsck_t ctx)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000109{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000110 ext2_filsys fs = ctx->fs;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000111 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'oe72a9ba1999-06-25 15:40:18 +0000117 e2fsck_use_inode_shortcuts(ctx, 1);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000118
Theodore Ts'o08b21301997-11-03 19:42:40 +0000119 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'o0c4a0722000-02-07 03:11:03 +0000123 _("while allocating inode buffer"));
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000124 ctx->flags |= E2F_FLAG_ABORT;
125 return;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000126 }
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000127 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
128 "block interate buffer");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000129 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'o0c4a0722000-02-07 03:11:03 +0000135 _("while reading inode table (group %d)"),
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000136 group);
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000137 ctx->flags |= E2F_FLAG_ABORT;
138 return;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000139 }
140 inode = (struct ext2_inode *) buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000141 for (i=0; i < fs->super->s_inodes_per_group;
142 i++, ino++, inode++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000143 ctx->stashed_ino = ino;
144 ctx->stashed_inode = inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000145
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000146 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'of8188ff1997-11-14 05:23:04 +0000160 swap_inode_blocks(ctx, ino, block_buf, inode);
161
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000162 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000163 return;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000164
Theodore Ts'o5c576471997-04-29 15:29:49 +0000165 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000166 ext2fs_swap_inode(fs, inode, inode, 1);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000167 }
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'o0c4a0722000-02-07 03:11:03 +0000173 _("while writing inode table (group %d)"),
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000174 group);
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000175 ctx->flags |= E2F_FLAG_ABORT;
176 return;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000177 }
178 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000179 ext2fs_free_mem((void **) &buf);
180 ext2fs_free_mem((void **) &block_buf);
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +0000181 e2fsck_use_inode_shortcuts(ctx, 0);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000182}
183
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000184void swap_filesys(e2fsck_t ctx)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000185{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000186 ext2_filsys fs = ctx->fs;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000187#ifdef RESOURCE_TRACK
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000188 struct resource_track rtrack;
189
190 init_resource_track(&rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000191#endif
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000192
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000193 if (!(ctx->options & E2F_OPT_PREEN))
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000194 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000195
196#ifdef MTRACE
197 mtrace_print("Byte swap");
198#endif
199
200 if (fs->super->s_mnt_count) {
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000201 fprintf(stderr, _("%s: the filesystem must be freshly "
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000202 "checked using fsck\n"
203 "and not mounted before trying to "
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000204 "byte-swap it.\n"), ctx->device_name);
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000205 ctx->flags |= E2F_FLAG_ABORT;
206 return;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000207 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000208 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'o1e3472c1997-04-29 14:53:37 +0000212 } else {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000213 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
214 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000215 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000216 swap_inodes(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000217 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000218 return;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000219 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'o1e3472c1997-04-29 14:53:37 +0000223 ext2fs_flush(fs);
224
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000225#ifdef RESOURCE_TRACK
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000226 if (ctx->options & E2F_OPT_TIME2)
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000227 print_resource_track(_("Byte swap"), &rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000228#endif
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000229}
230
231