• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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