Whamcloud - gitweb
Many files:
[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 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,
33                       void *priv_data)
34 {
35         errcode_t       retval;
36         
37         struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
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  */
78 static void swap_inode_blocks(e2fsck_t ctx, ino_t ino, char *block_buf,
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;
86         sb.dir_buf = block_buf + ctx->fs->blocksize*3;
87         sb.errcode = 0;
88         sb.isdir = 0;
89         if (LINUX_S_ISDIR(inode->i_mode))
90                 sb.isdir = 1;
91
92         retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
93                                       swap_block, &sb);
94         if (retval) {
95                 com_err("swap_inode_blocks", retval,
96                         _("while calling ext2fs_block_iterate"));
97                 ctx->flags |= E2F_FLAG_ABORT;
98                 return;
99         }
100         if (sb.errcode) {
101                 com_err("swap_inode_blocks", sb.errcode,
102                         _("while calling iterator function"));
103                 ctx->flags |= E2F_FLAG_ABORT;
104                 return;
105         }
106 }
107
108 static void swap_inodes(e2fsck_t ctx)
109 {
110         ext2_filsys fs = ctx->fs;
111         int                     i, group;
112         ino_t                   ino = 1;
113         char                    *buf, *block_buf;
114         errcode_t               retval;
115         struct ext2_inode *     inode;
116
117         e2fsck_use_inode_shortcuts(ctx, 1);
118         
119         retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
120                                 (void **) &buf);
121         if (retval) {
122                 com_err("swap_inodes", retval,
123                         _("while allocating inode buffer"));
124                 ctx->flags |= E2F_FLAG_ABORT;
125                 return;
126         }
127         block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
128                                                     "block interate buffer");
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,
135                                 _("while reading inode table (group %d)"),
136                                 group);
137                         ctx->flags |= E2F_FLAG_ABORT;
138                         return;
139                 }
140                 inode = (struct ext2_inode *) buf;
141                 for (i=0; i < fs->super->s_inodes_per_group;
142                      i++, ino++, inode++) {
143                         ctx->stashed_ino = ino;
144                         ctx->stashed_inode = inode;
145                         
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)))
160                                 swap_inode_blocks(ctx, ino, block_buf, inode);
161
162                         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
163                                 return;
164                         
165                         if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
166                                 ext2fs_swap_inode(fs, inode, inode, 1);
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,
173                                 _("while writing inode table (group %d)"),
174                                 group);
175                         ctx->flags |= E2F_FLAG_ABORT;
176                         return;
177                 }
178         }
179         ext2fs_free_mem((void **) &buf);
180         ext2fs_free_mem((void **) &block_buf);
181         e2fsck_use_inode_shortcuts(ctx, 0);
182 }
183
184 void swap_filesys(e2fsck_t ctx)
185 {
186         ext2_filsys fs = ctx->fs;
187 #ifdef RESOURCE_TRACK
188         struct resource_track   rtrack;
189
190         init_resource_track(&rtrack);
191 #endif
192
193         if (!(ctx->options & E2F_OPT_PREEN))
194                 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
195         
196 #ifdef MTRACE
197         mtrace_print("Byte swap");
198 #endif
199
200         if (fs->super->s_mnt_count) {
201                 fprintf(stderr, _("%s: the filesystem must be freshly "
202                         "checked using fsck\n"
203                         "and not mounted before trying to "
204                         "byte-swap it.\n"), ctx->device_name);
205                 ctx->flags |= E2F_FLAG_ABORT;
206                 return;
207         }
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;
212         } else {
213                 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
214                 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
215         }
216         swap_inodes(ctx);
217         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
218                 return;
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);
223         ext2fs_flush(fs);
224         
225 #ifdef RESOURCE_TRACK
226         if (ctx->options & E2F_OPT_TIME2)
227                 print_resource_track(_("Byte swap"), &rtrack);
228 #endif
229 }
230
231