blob: bcd8aa2fba9aebea4f90ecddf4e70aff7b8535ab [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * pass2.c --- check directory structure
3 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * Copyright (C) 1993, 1994, 1995, 1996, 1997 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%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 *
11 * Pass 2 of e2fsck iterates through all active directory inodes, and
12 * applies to following tests to each directory entry in the directory
13 * blocks in the inodes:
14 *
15 * - The length of the directory entry (rec_len) should be at
16 * least 8 bytes, and no more than the remaining space
17 * left in the directory block.
18 * - The length of the name in the directory entry (name_len)
19 * should be less than (rec_len - 8).
20 * - The inode number in the directory entry should be within
21 * legal bounds.
22 * - The inode number should refer to a in-use inode.
23 * - The first entry should be '.', and its inode should be
24 * the inode of the directory.
25 * - The second entry should be '..'.
26 *
27 * To minimize disk seek time, the directory blocks are processed in
28 * sorted order of block numbers.
29 *
30 * Pass 2 also collects the following information:
31 * - The inode numbers of the subdirectories for each directory.
32 *
33 * Pass 2 relies on the following information from previous passes:
34 * - The directory information collected in pass 1.
35 * - The inode_used_map bitmap
36 * - The inode_bad_map bitmap
37 * - The inode_dir_map bitmap
Theodore Ts'o3839e651997-04-26 13:21:57 +000038 *
39 * Pass 2 frees the following data structures
40 * - The inode_bad_map bitmap
41 */
42
Theodore Ts'o3839e651997-04-26 13:21:57 +000043#include "e2fsck.h"
Theodore Ts'o21c84b71997-04-29 16:15:03 +000044#include "problem.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000045
46/*
47 * Keeps track of how many times an inode is referenced.
48 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000049static void deallocate_inode(e2fsck_t ctx, ino_t ino,
Theodore Ts'o3839e651997-04-26 13:21:57 +000050 char* block_buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000051static int process_bad_inode(e2fsck_t ctx, ino_t dir, ino_t ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +000052static int check_dir_block(ext2_filsys fs,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000053 struct ext2_db_entry *dir_blocks_info,
54 void *private);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000055static int allocate_dir_block(e2fsck_t ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000056 struct ext2_db_entry *dir_blocks_info,
57 char *buf, struct problem_context *pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000058static int update_dir_block(ext2_filsys fs,
59 blk_t *block_nr,
60 int blockcnt,
61 void *private);
Theodore Ts'o3839e651997-04-26 13:21:57 +000062
Theodore Ts'o21c84b71997-04-29 16:15:03 +000063struct check_dir_struct {
64 char *buf;
65 struct problem_context pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000066 e2fsck_t ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000067};
68
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000069void pass2(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +000070{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000071 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +000072 char *buf;
73 struct resource_track rtrack;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000074 struct dir_info *dir;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000075 struct check_dir_struct cd;
76
Theodore Ts'o3839e651997-04-26 13:21:57 +000077 init_resource_track(&rtrack);
78
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000079 clear_problem_context(&cd.pctx);
80
Theodore Ts'o3839e651997-04-26 13:21:57 +000081#ifdef MTRACE
82 mtrace_print("Pass 2");
83#endif
84
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000085 if (!(ctx->options & E2F_OPT_PREEN))
86 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
87
88 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
89 0, ctx->inode_link_info,
90 &ctx->inode_count);
91 if (cd.pctx.errcode) {
92 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +000093 fatal_error(0);
94 }
Theodore Ts'o3839e651997-04-26 13:21:57 +000095 buf = allocate_memory(fs->blocksize, "directory scan buffer");
96
Theodore Ts'o21c84b71997-04-29 16:15:03 +000097 /*
98 * Set up the parent pointer for the root directory, if
99 * present. (If the root directory is not present, we will
100 * create it in pass 3.)
101 */
102 dir = get_dir_info(EXT2_ROOT_INO);
103 if (dir)
104 dir->parent = EXT2_ROOT_INO;
105
106 cd.buf = buf;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000107 cd.ctx = ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000108
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000109 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
110 &cd);
111 if (cd.pctx.errcode) {
112 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
Theodore Ts'o7ac02a51997-06-11 18:32:35 +0000113 fatal_error(0);
114 }
115
Theodore Ts'o3839e651997-04-26 13:21:57 +0000116 free(buf);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000117 ext2fs_free_dblist(fs->dblist);
118
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000119 if (ctx->inode_bad_map) {
120 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
121 ctx->inode_bad_map = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000122 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000123 if (ctx->options & E2F_OPT_TIME2)
124 print_resource_track("Pass 2", &rtrack);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000125}
126
127/*
128 * Make sure the first entry in the directory is '.', and that the
129 * directory entry is sane.
130 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000131static int check_dot(e2fsck_t ctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000132 struct ext2_dir_entry *dirent,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000133 ino_t ino, struct problem_context *pctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000134{
135 struct ext2_dir_entry *nextdir;
136 int status = 0;
137 int created = 0;
138 int new_len;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000139 int problem = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000140
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000141 if (!dirent->inode)
142 problem = PR_2_MISSING_DOT;
143 else if ((dirent->name_len != 1) ||
144 (dirent->name[0] != '.'))
145 problem = PR_2_1ST_NOT_DOT;
146 else if (dirent->name[1] != '\0')
147 problem = PR_2_DOT_NULL_TERM;
148
149 if (problem) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000150 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000151 if (dirent->rec_len < 12)
152 dirent->rec_len = 12;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000153 dirent->inode = ino;
154 dirent->name_len = 1;
155 dirent->name[0] = '.';
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000156 dirent->name[1] = '\0';
Theodore Ts'o3839e651997-04-26 13:21:57 +0000157 status = 1;
158 created = 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000159 }
160 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000161 if (dirent->inode != ino) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000162 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000163 dirent->inode = ino;
164 status = 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000165 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000166 }
167 if (dirent->rec_len > 12) {
168 new_len = dirent->rec_len - 12;
169 if (new_len > 12) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000170 preenhalt(ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000171 if (created ||
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000172 ask(ctx, "Directory entry for '.' is big. Split", 1)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000173 nextdir = (struct ext2_dir_entry *)
174 ((char *) dirent + 12);
175 dirent->rec_len = 12;
176 nextdir->rec_len = new_len;
177 nextdir->inode = 0;
178 nextdir->name_len = 0;
179 status = 1;
180 }
181 }
182 }
183 return status;
184}
185
186/*
187 * Make sure the second entry in the directory is '..', and that the
188 * directory entry is sane. We do not check the inode number of '..'
189 * here; this gets done in pass 3.
190 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000191static int check_dotdot(e2fsck_t ctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000192 struct ext2_dir_entry *dirent,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000193 struct dir_info *dir, struct problem_context *pctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000194{
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000195 int problem = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000196
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000197 if (!dirent->inode)
198 problem = PR_2_MISSING_DOT_DOT;
199 else if ((dirent->name_len != 2) ||
200 (dirent->name[0] != '.') ||
201 (dirent->name[1] != '.'))
202 problem = PR_2_2ND_NOT_DOT_DOT;
203 else if (dirent->name[2] != '\0')
204 problem = PR_2_DOT_DOT_NULL_TERM;
205
206 if (problem) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000207 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000208 if (dirent->rec_len < 12)
209 dirent->rec_len = 12;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000210 /*
211 * Note: we don't have the parent inode just
212 * yet, so we will fill it in with the root
213 * inode. This will get fixed in pass 3.
214 */
215 dirent->inode = EXT2_ROOT_INO;
216 dirent->name_len = 2;
217 dirent->name[0] = '.';
218 dirent->name[1] = '.';
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000219 dirent->name[2] = '\0';
Theodore Ts'o3839e651997-04-26 13:21:57 +0000220 return 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000221 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000222 return 0;
223 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000224 dir->dotdot = dirent->inode;
225 return 0;
226}
227
228/*
229 * Check to make sure a directory entry doesn't contain any illegal
230 * characters.
231 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000232static int check_name(e2fsck_t ctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000233 struct ext2_dir_entry *dirent,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000234 ino_t dir_ino, struct problem_context *pctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000235{
236 int i;
237 int fixup = -1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000238 int ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000239
240 for ( i = 0; i < dirent->name_len; i++) {
241 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
242 if (fixup < 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000243 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000244 }
245 if (fixup) {
246 dirent->name[i] = '.';
247 ret = 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000248 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000249 }
250 }
251 return ret;
252}
253
254static int check_dir_block(ext2_filsys fs,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000255 struct ext2_db_entry *db,
256 void *private)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000257{
258 struct dir_info *subdir, *dir;
259 struct ext2_dir_entry *dirent;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000260 int offset = 0;
261 int dir_modified = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000262 int dot_state;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000263 blk_t block_nr = db->blk;
264 ino_t ino = db->ino;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000265 __u16 links;
266 struct check_dir_struct *cd = private;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000267 char *buf;
268 e2fsck_t ctx;
269 int problem;
270
271 buf = cd->buf;
272 ctx = cd->ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000273
Theodore Ts'o3839e651997-04-26 13:21:57 +0000274 /*
275 * Make sure the inode is still in use (could have been
276 * deleted in the duplicate/bad blocks pass.
277 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000278 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000279 return 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000280
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000281 cd->pctx.ino = ino;
282 cd->pctx.blk = block_nr;
283 cd->pctx.blkcount = db->blockcnt;
284 cd->pctx.ino2 = 0;
285 cd->pctx.dirent = 0;
286 cd->pctx.num = 0;
287
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000288 if (db->blk == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000289 if (allocate_dir_block(ctx, db, buf, &cd->pctx))
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000290 return 0;
291 block_nr = db->blk;
292 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000293
294 if (db->blockcnt)
295 dot_state = 2;
296 else
297 dot_state = 0;
298
299#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000300 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000301 db->blockcnt, ino);
302#endif
303
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000304 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
305 if (cd->pctx.errcode) {
306 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx))
307 fatal_error(0);
308 memset(buf, 0, fs->blocksize);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000309 }
310
311 do {
312 dot_state++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000313 problem = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000314 dirent = (struct ext2_dir_entry *) (buf + offset);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000315 cd->pctx.dirent = dirent;
316 cd->pctx.num = offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000317 if (((offset + dirent->rec_len) > fs->blocksize) ||
318 (dirent->rec_len < 8) ||
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000319 ((dirent->rec_len % 4) != 0) ||
Theodore Ts'o3839e651997-04-26 13:21:57 +0000320 ((dirent->name_len+8) > dirent->rec_len)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000321 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000322 dirent->rec_len = fs->blocksize - offset;
323 dirent->name_len = 0;
324 dirent->inode = 0;
325 dir_modified++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000326 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000327 return DIRENT_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000328 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000329 if (dirent->name_len > EXT2_NAME_LEN) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000330 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000331 dirent->name_len = EXT2_NAME_LEN;
332 dir_modified++;
333 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000334 }
335
Theodore Ts'o3839e651997-04-26 13:21:57 +0000336 if (dot_state == 1) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000337 if (check_dot(ctx, dirent, ino, &cd->pctx))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000338 dir_modified++;
339 } else if (dot_state == 2) {
340 dir = get_dir_info(ino);
341 if (!dir) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000342 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000343 fatal_error(0);
344 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000345 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000346 dir_modified++;
347 } else if (dirent->inode == ino) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000348 problem = PR_2_LINK_DOT;
349 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000350 dirent->inode = 0;
351 dir_modified++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000352 goto next;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000353 }
354 }
355 if (!dirent->inode)
356 goto next;
357
Theodore Ts'o3839e651997-04-26 13:21:57 +0000358 /*
359 * Make sure the inode listed is a legal one.
360 */
361 if (((dirent->inode != EXT2_ROOT_INO) &&
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000362 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
Theodore Ts'o3839e651997-04-26 13:21:57 +0000363 (dirent->inode > fs->super->s_inodes_count)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000364 problem = PR_2_BAD_INO;
365 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000366 dirent->inode))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000367 /*
368 * If the inode is unused, offer to clear it.
369 */
370 problem = PR_2_UNUSED_INODE;
371 } else if (ctx->inode_bb_map &&
372 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
373 dirent->inode))) {
374 /*
375 * If the inode is in a bad block, offer to
376 * clear it.
377 */
378 problem = PR_2_BB_INODE;
379 } else if ((dot_state > 2) &&
380 (dirent->name_len == 1) &&
381 (dirent->name[0] == '.')) {
382 /*
383 * If there's a '.' entry in anything other
384 * than the first directory entry, it's a
385 * duplicate entry that should be removed.
386 */
387 problem = PR_2_DUP_DOT;
388 } else if ((dot_state > 2) &&
389 (dirent->name_len == 2) &&
390 (dirent->name[0] == '.') &&
391 (dirent->name[1] == '.')) {
392 /*
393 * If there's a '..' entry in anything other
394 * than the second directory entry, it's a
395 * duplicate entry that should be removed.
396 */
397 problem = PR_2_DUP_DOT_DOT;
398 } else if ((dot_state > 2) &&
399 (dirent->inode == EXT2_ROOT_INO)) {
400 /*
401 * Don't allow links to the root directory.
402 * We check this specially to make sure we
403 * catch this error case even if the root
404 * directory hasn't been created yet.
405 */
406 problem = PR_2_LINK_ROOT;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000407 }
408
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000409 if (problem) {
410 if (fix_problem(ctx, problem, &cd->pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000411 dirent->inode = 0;
412 dir_modified++;
413 goto next;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000414 } else {
415 ext2fs_unmark_valid(fs);
416 if (problem == PR_2_BAD_INO)
417 goto next;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000418 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000419 }
420
421 /*
422 * If the inode was marked as having bad fields in
423 * pass1, process it and offer to fix/clear it.
424 * (We wait until now so that we can display the
425 * pathname to the user.)
426 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000427 if (ctx->inode_bad_map &&
428 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000429 dirent->inode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000430 if (process_bad_inode(ctx, ino, dirent->inode)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000431 dirent->inode = 0;
432 dir_modified++;
433 goto next;
434 }
435 }
436
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000437 if (check_name(ctx, dirent, ino, &cd->pctx))
438 dir_modified++;
439
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000440 /*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000441 * If this is a directory, then mark its parent in its
442 * dir_info structure. If the parent field is already
443 * filled in, then this directory has more than one
444 * hard link. We assume the first link is correct,
445 * and ask the user if he/she wants to clear this one.
446 */
447 if ((dot_state > 2) &&
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000448 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000449 dirent->inode))) {
450 subdir = get_dir_info(dirent->inode);
451 if (!subdir) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000452 cd->pctx.ino = dirent->inode;
453 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000454 fatal_error(0);
455 }
456 if (subdir->parent) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000457 cd->pctx.ino2 = subdir->parent;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000458 if (fix_problem(ctx, PR_2_LINK_DIR,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000459 &cd->pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000460 dirent->inode = 0;
461 dir_modified++;
462 goto next;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000463 }
464 cd->pctx.ino2 = 0;
465 } else
466 subdir->parent = ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000467 }
468
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000469 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
470 &links);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000471 if (links > 1)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000472 ctx->fs_links_count++;
473 ctx->fs_total_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000474 next:
475 offset += dirent->rec_len;
476 } while (offset < fs->blocksize);
477#if 0
478 printf("\n");
479#endif
480 if (offset != fs->blocksize) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000481 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
482 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
483 dirent->rec_len = cd->pctx.num;
484 dir_modified++;
485 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000486 }
487 if (dir_modified) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000488 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
489 if (cd->pctx.errcode) {
490 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK, &cd->pctx))
491 fatal_error(0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000492 }
493 ext2fs_mark_changed(fs);
494 }
495 return 0;
496}
497
498/*
499 * This function is called to deallocate a block, and is an interator
500 * functioned called by deallocate inode via ext2fs_iterate_block().
501 */
502static int deallocate_inode_block(ext2_filsys fs,
503 blk_t *block_nr,
504 int blockcnt,
505 void *private)
506{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000507 e2fsck_t ctx = (e2fsck_t) private;
508
Theodore Ts'o3839e651997-04-26 13:21:57 +0000509 if (!*block_nr)
510 return 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000511 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000512 ext2fs_unmark_block_bitmap(fs->block_map, *block_nr);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000513 return 0;
514}
515
516/*
517 * This fuction deallocates an inode
518 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000519static void deallocate_inode(e2fsck_t ctx, ino_t ino,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000520 char* block_buf)
521{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000522 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000523 struct ext2_inode inode;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000524 struct problem_context pctx;
525
526 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000527 e2fsck_read_inode(fs, ino, &inode, "deallocate_inode");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000528 inode.i_links_count = 0;
529 inode.i_dtime = time(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000530 e2fsck_write_inode(fs, ino, &inode, "deallocate_inode");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000531 clear_problem_context(&pctx);
532 pctx.ino = ino;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000533
Theodore Ts'o3839e651997-04-26 13:21:57 +0000534 /*
535 * Fix up the bitmaps...
536 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000537 read_bitmaps(ctx);
538 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
539 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
540 if (ctx->inode_bad_map)
541 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000542 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000543 ext2fs_mark_ib_dirty(fs);
544
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000545 if (!ext2fs_inode_has_valid_blocks(&inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000546 return;
547
548 ext2fs_mark_bb_dirty(fs);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000549 pctx.errcode = ext2fs_block_iterate(fs, ino, 0, block_buf,
550 deallocate_inode_block, ctx);
551 if (pctx.errcode) {
552 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
553 fatal_error(0);
554 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000555}
556
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000557static int process_bad_inode(e2fsck_t ctx, ino_t dir, ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000558{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000559 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000560 struct ext2_inode inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000561 int inode_modified = 0;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000562 unsigned char *frag, *fsize;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000563 struct problem_context pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000564
Theodore Ts'of3db3561997-04-26 13:34:30 +0000565 e2fsck_read_inode(fs, ino, &inode, "process_bad_inode");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000566
567 clear_problem_context(&pctx);
568 pctx.ino = ino;
569 pctx.dir = dir;
570 pctx.inode = &inode;
571
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000572 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
573 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
574 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
575 !(LINUX_S_ISSOCK(inode.i_mode))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000576 if (fix_problem(ctx, PR_2_BAD_MODE, &pctx)) {
577 deallocate_inode(ctx, ino, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000578 return 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000579 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000580 }
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000581
582 if (LINUX_S_ISCHR(inode.i_mode)
583 && !e2fsck_pass1_check_device_inode(&inode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000584 if (fix_problem(ctx, PR_2_BAD_CHAR_DEV, &pctx)) {
585 deallocate_inode(ctx, ino, 0);
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000586 return 1;
587 }
588 }
589
590 if (LINUX_S_ISBLK(inode.i_mode)
591 && !e2fsck_pass1_check_device_inode(&inode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000592 if (fix_problem(ctx, PR_2_BAD_BLOCK_DEV, &pctx)) {
593 deallocate_inode(ctx, ino, 0);
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000594 return 1;
595 }
596 }
597
598
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000599 if (inode.i_faddr &&
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000600 fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000601 inode.i_faddr = 0;
602 inode_modified++;
603 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000604
605 switch (fs->super->s_creator_os) {
606 case EXT2_OS_LINUX:
607 frag = &inode.osd2.linux2.l_i_frag;
608 fsize = &inode.osd2.linux2.l_i_fsize;
609 break;
610 case EXT2_OS_HURD:
611 frag = &inode.osd2.hurd2.h_i_frag;
612 fsize = &inode.osd2.hurd2.h_i_fsize;
613 break;
614 case EXT2_OS_MASIX:
615 frag = &inode.osd2.masix2.m_i_frag;
616 fsize = &inode.osd2.masix2.m_i_fsize;
617 break;
618 default:
619 frag = fsize = 0;
620 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000621 if (frag && *frag) {
622 pctx.num = *frag;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000623 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000624 *frag = 0;
625 inode_modified++;
626 }
627 pctx.num = 0;
628 }
629 if (fsize && *fsize) {
630 pctx.num = *fsize;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000631 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000632 *fsize = 0;
633 inode_modified++;
634 }
635 pctx.num = 0;
636 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000637
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000638 if (inode.i_file_acl &&
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000639 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000640 inode.i_file_acl = 0;
641 inode_modified++;
642 }
643 if (inode.i_dir_acl &&
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000644 fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000645 inode.i_dir_acl = 0;
646 inode_modified++;
647 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000648 if (inode_modified)
649 e2fsck_write_inode(fs, ino, &inode, "process_bad_inode");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000650 return 0;
651}
652
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000653
654/*
655 * allocate_dir_block --- this function allocates a new directory
656 * block for a particular inode; this is done if a directory has
657 * a "hole" in it, or if a directory has a illegal block number
658 * that was zeroed out and now needs to be replaced.
659 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000660static int allocate_dir_block(e2fsck_t ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000661 struct ext2_db_entry *db,
662 char *buf, struct problem_context *pctx)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000663{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000664 ext2_filsys fs = ctx->fs;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000665 blk_t blk;
666 char *block;
667 struct ext2_inode inode;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000668
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000669 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000670 return 1;
671
672 /*
673 * Read the inode and block bitmaps in; we'll be messing with
674 * them.
675 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000676 read_bitmaps(ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000677
678 /*
679 * First, find a free block
680 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000681 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
682 if (pctx->errcode) {
683 pctx->str = "ext2fs_new_block";
684 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000685 return 1;
686 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000687 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000688 ext2fs_mark_block_bitmap(fs->block_map, blk);
689 ext2fs_mark_bb_dirty(fs);
690
691 /*
692 * Now let's create the actual data block for the inode
693 */
694 if (db->blockcnt)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000695 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000696 else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000697 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
698 EXT2_ROOT_INO, &block);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000699
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000700 if (pctx->errcode) {
701 pctx->str = "ext2fs_new_dir_block";
702 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000703 return 1;
704 }
705
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000706 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000707 free(block);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000708 if (pctx->errcode) {
709 pctx->str = "ext2fs_write_dir_block";
710 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000711 return 1;
712 }
713
714 /*
715 * Update the inode block count
716 */
717 e2fsck_read_inode(fs, db->ino, &inode, "allocate_dir_block");
718 inode.i_blocks += fs->blocksize / 512;
719 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
720 inode.i_size = (db->blockcnt+1) * fs->blocksize;
721 e2fsck_write_inode(fs, db->ino, &inode, "allocate_dir_block");
722
723 /*
724 * Finally, update the block pointers for the inode
725 */
726 db->blk = blk;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000727 pctx->errcode = ext2fs_block_iterate(fs, db->ino, BLOCK_FLAG_HOLE,
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000728 0, update_dir_block, db);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000729 if (pctx->errcode) {
730 pctx->str = "ext2fs_block_iterate";
731 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000732 return 1;
733 }
734
735 return 0;
736}
737
738/*
739 * This is a helper function for allocate_dir_block().
740 */
741static int update_dir_block(ext2_filsys fs,
742 blk_t *block_nr,
743 int blockcnt,
744 void *private)
745{
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000746 struct ext2_db_entry *db = private;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000747
748 if (db->blockcnt == blockcnt) {
749 *block_nr = db->blk;
750 return BLOCK_CHANGED;
751 }
752 return 0;
753}
754