Whamcloud - gitweb
Fix gcc -Wall issues in e2fsck sources
[tools/e2fsprogs.git] / e2fsck / swapfs.c
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  */
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  */
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
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_mem(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
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
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