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 */
swap_block(ext2_filsys fs,blk_t * block_nr,int blockcnt,void * priv_data)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 */
swap_inode_blocks(e2fsck_t ctx,ext2_ino_t ino,char * block_buf,struct ext2_inode * inode)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
swap_inodes(e2fsck_t ctx)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
ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)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
swap_filesys(e2fsck_t ctx)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