blob: 4facc601009bd77d3b33828775662b09295ff907 [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'o08b21301997-11-03 19:42:40 +000069void e2fsck_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;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +000073#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +000074 struct resource_track rtrack;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +000075#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +000076 struct dir_info *dir;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000077 struct check_dir_struct cd;
78
Theodore Ts'o8bf191e1997-10-20 01:38:32 +000079#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +000080 init_resource_track(&rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +000081#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000082
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000083 clear_problem_context(&cd.pctx);
84
Theodore Ts'o3839e651997-04-26 13:21:57 +000085#ifdef MTRACE
86 mtrace_print("Pass 2");
87#endif
88
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000089 if (!(ctx->options & E2F_OPT_PREEN))
90 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
91
92 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
93 0, ctx->inode_link_info,
94 &ctx->inode_count);
95 if (cd.pctx.errcode) {
96 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +000097 ctx->flags |= E2F_FLAG_ABORT;
98 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000099 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000100 buf = allocate_memory(fs->blocksize, "directory scan buffer");
101
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000102 /*
103 * Set up the parent pointer for the root directory, if
104 * present. (If the root directory is not present, we will
105 * create it in pass 3.)
106 */
Theodore Ts'o08b21301997-11-03 19:42:40 +0000107 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000108 if (dir)
109 dir->parent = EXT2_ROOT_INO;
110
111 cd.buf = buf;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000112 cd.ctx = ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000113
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000114 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
115 &cd);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000116 if (ctx->flags & E2F_FLAG_ABORT)
117 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000118 if (cd.pctx.errcode) {
119 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000120 ctx->flags |= E2F_FLAG_ABORT;
121 return;
Theodore Ts'o7ac02a51997-06-11 18:32:35 +0000122 }
123
Theodore Ts'o08b21301997-11-03 19:42:40 +0000124 ext2fs_free_mem((void **) &buf);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000125 ext2fs_free_dblist(fs->dblist);
126
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000127 if (ctx->inode_bad_map) {
128 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
129 ctx->inode_bad_map = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000130 }
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000131#ifdef RESOURCE_TRACK
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000132 if (ctx->options & E2F_OPT_TIME2)
133 print_resource_track("Pass 2", &rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000134#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000135}
136
137/*
138 * Make sure the first entry in the directory is '.', and that the
139 * directory entry is sane.
140 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000141static int check_dot(e2fsck_t ctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000142 struct ext2_dir_entry *dirent,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000143 ino_t ino, struct problem_context *pctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000144{
145 struct ext2_dir_entry *nextdir;
146 int status = 0;
147 int created = 0;
148 int new_len;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000149 int problem = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000150
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000151 if (!dirent->inode)
152 problem = PR_2_MISSING_DOT;
153 else if ((dirent->name_len != 1) ||
154 (dirent->name[0] != '.'))
155 problem = PR_2_1ST_NOT_DOT;
156 else if (dirent->name[1] != '\0')
157 problem = PR_2_DOT_NULL_TERM;
158
159 if (problem) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000160 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000161 if (dirent->rec_len < 12)
162 dirent->rec_len = 12;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000163 dirent->inode = ino;
164 dirent->name_len = 1;
165 dirent->name[0] = '.';
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000166 dirent->name[1] = '\0';
Theodore Ts'o3839e651997-04-26 13:21:57 +0000167 status = 1;
168 created = 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000169 }
170 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000171 if (dirent->inode != ino) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000172 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000173 dirent->inode = ino;
174 status = 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000175 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000176 }
177 if (dirent->rec_len > 12) {
178 new_len = dirent->rec_len - 12;
179 if (new_len > 12) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000180 preenhalt(ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000181 if (created ||
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000182 ask(ctx, "Directory entry for '.' is big. Split", 1)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000183 nextdir = (struct ext2_dir_entry *)
184 ((char *) dirent + 12);
185 dirent->rec_len = 12;
186 nextdir->rec_len = new_len;
187 nextdir->inode = 0;
188 nextdir->name_len = 0;
189 status = 1;
190 }
191 }
192 }
193 return status;
194}
195
196/*
197 * Make sure the second entry in the directory is '..', and that the
198 * directory entry is sane. We do not check the inode number of '..'
199 * here; this gets done in pass 3.
200 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000201static int check_dotdot(e2fsck_t ctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000202 struct ext2_dir_entry *dirent,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000203 struct dir_info *dir, struct problem_context *pctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000204{
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000205 int problem = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000206
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000207 if (!dirent->inode)
208 problem = PR_2_MISSING_DOT_DOT;
209 else if ((dirent->name_len != 2) ||
210 (dirent->name[0] != '.') ||
211 (dirent->name[1] != '.'))
212 problem = PR_2_2ND_NOT_DOT_DOT;
213 else if (dirent->name[2] != '\0')
214 problem = PR_2_DOT_DOT_NULL_TERM;
215
216 if (problem) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000217 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000218 if (dirent->rec_len < 12)
219 dirent->rec_len = 12;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000220 /*
221 * Note: we don't have the parent inode just
222 * yet, so we will fill it in with the root
223 * inode. This will get fixed in pass 3.
224 */
225 dirent->inode = EXT2_ROOT_INO;
226 dirent->name_len = 2;
227 dirent->name[0] = '.';
228 dirent->name[1] = '.';
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000229 dirent->name[2] = '\0';
Theodore Ts'o3839e651997-04-26 13:21:57 +0000230 return 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000231 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000232 return 0;
233 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000234 dir->dotdot = dirent->inode;
235 return 0;
236}
237
238/*
239 * Check to make sure a directory entry doesn't contain any illegal
240 * characters.
241 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000242static int check_name(e2fsck_t ctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000243 struct ext2_dir_entry *dirent,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000244 ino_t dir_ino, struct problem_context *pctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000245{
246 int i;
247 int fixup = -1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000248 int ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000249
250 for ( i = 0; i < dirent->name_len; i++) {
251 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
252 if (fixup < 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000253 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000254 }
255 if (fixup) {
256 dirent->name[i] = '.';
257 ret = 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000258 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000259 }
260 }
261 return ret;
262}
263
264static int check_dir_block(ext2_filsys fs,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000265 struct ext2_db_entry *db,
266 void *private)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000267{
268 struct dir_info *subdir, *dir;
269 struct ext2_dir_entry *dirent;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000270 int offset = 0;
271 int dir_modified = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000272 int dot_state;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000273 blk_t block_nr = db->blk;
274 ino_t ino = db->ino;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000275 __u16 links;
276 struct check_dir_struct *cd = private;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000277 char *buf;
278 e2fsck_t ctx;
279 int problem;
280
281 buf = cd->buf;
282 ctx = cd->ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000283
Theodore Ts'o3839e651997-04-26 13:21:57 +0000284 /*
285 * Make sure the inode is still in use (could have been
286 * deleted in the duplicate/bad blocks pass.
287 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000288 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000289 return 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000290
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000291 cd->pctx.ino = ino;
292 cd->pctx.blk = block_nr;
293 cd->pctx.blkcount = db->blockcnt;
294 cd->pctx.ino2 = 0;
295 cd->pctx.dirent = 0;
296 cd->pctx.num = 0;
297
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000298 if (db->blk == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000299 if (allocate_dir_block(ctx, db, buf, &cd->pctx))
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000300 return 0;
301 block_nr = db->blk;
302 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000303
304 if (db->blockcnt)
305 dot_state = 2;
306 else
307 dot_state = 0;
308
309#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000310 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000311 db->blockcnt, ino);
312#endif
313
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000314 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
315 if (cd->pctx.errcode) {
Theodore Ts'o08b21301997-11-03 19:42:40 +0000316 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
317 ctx->flags |= E2F_FLAG_ABORT;
318 return DIRENT_ABORT;
319 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000320 memset(buf, 0, fs->blocksize);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000321 }
322
323 do {
324 dot_state++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000325 problem = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000326 dirent = (struct ext2_dir_entry *) (buf + offset);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000327 cd->pctx.dirent = dirent;
328 cd->pctx.num = offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000329 if (((offset + dirent->rec_len) > fs->blocksize) ||
330 (dirent->rec_len < 8) ||
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000331 ((dirent->rec_len % 4) != 0) ||
Theodore Ts'o3839e651997-04-26 13:21:57 +0000332 ((dirent->name_len+8) > dirent->rec_len)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000333 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000334 dirent->rec_len = fs->blocksize - offset;
335 dirent->name_len = 0;
336 dirent->inode = 0;
337 dir_modified++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000338 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000339 return DIRENT_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000340 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000341 if (dirent->name_len > EXT2_NAME_LEN) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000342 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000343 dirent->name_len = EXT2_NAME_LEN;
344 dir_modified++;
345 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000346 }
347
Theodore Ts'o3839e651997-04-26 13:21:57 +0000348 if (dot_state == 1) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000349 if (check_dot(ctx, dirent, ino, &cd->pctx))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000350 dir_modified++;
351 } else if (dot_state == 2) {
Theodore Ts'o08b21301997-11-03 19:42:40 +0000352 dir = e2fsck_get_dir_info(ctx, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000353 if (!dir) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000354 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000355 ctx->flags |= E2F_FLAG_ABORT;
356 return DIRENT_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000357 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000358 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000359 dir_modified++;
360 } else if (dirent->inode == ino) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000361 problem = PR_2_LINK_DOT;
362 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000363 dirent->inode = 0;
364 dir_modified++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000365 goto next;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000366 }
367 }
368 if (!dirent->inode)
369 goto next;
370
Theodore Ts'o3839e651997-04-26 13:21:57 +0000371 /*
372 * Make sure the inode listed is a legal one.
373 */
374 if (((dirent->inode != EXT2_ROOT_INO) &&
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000375 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
Theodore Ts'o3839e651997-04-26 13:21:57 +0000376 (dirent->inode > fs->super->s_inodes_count)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000377 problem = PR_2_BAD_INO;
378 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000379 dirent->inode))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000380 /*
381 * If the inode is unused, offer to clear it.
382 */
383 problem = PR_2_UNUSED_INODE;
384 } else if (ctx->inode_bb_map &&
385 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
386 dirent->inode))) {
387 /*
388 * If the inode is in a bad block, offer to
389 * clear it.
390 */
391 problem = PR_2_BB_INODE;
392 } else if ((dot_state > 2) &&
393 (dirent->name_len == 1) &&
394 (dirent->name[0] == '.')) {
395 /*
396 * If there's a '.' entry in anything other
397 * than the first directory entry, it's a
398 * duplicate entry that should be removed.
399 */
400 problem = PR_2_DUP_DOT;
401 } else if ((dot_state > 2) &&
402 (dirent->name_len == 2) &&
403 (dirent->name[0] == '.') &&
404 (dirent->name[1] == '.')) {
405 /*
406 * If there's a '..' entry in anything other
407 * than the second directory entry, it's a
408 * duplicate entry that should be removed.
409 */
410 problem = PR_2_DUP_DOT_DOT;
411 } else if ((dot_state > 2) &&
412 (dirent->inode == EXT2_ROOT_INO)) {
413 /*
414 * Don't allow links to the root directory.
415 * We check this specially to make sure we
416 * catch this error case even if the root
417 * directory hasn't been created yet.
418 */
419 problem = PR_2_LINK_ROOT;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000420 }
421
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000422 if (problem) {
423 if (fix_problem(ctx, problem, &cd->pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000424 dirent->inode = 0;
425 dir_modified++;
426 goto next;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000427 } else {
428 ext2fs_unmark_valid(fs);
429 if (problem == PR_2_BAD_INO)
430 goto next;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000431 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000432 }
433
434 /*
435 * If the inode was marked as having bad fields in
436 * pass1, process it and offer to fix/clear it.
437 * (We wait until now so that we can display the
438 * pathname to the user.)
439 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000440 if (ctx->inode_bad_map &&
441 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000442 dirent->inode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000443 if (process_bad_inode(ctx, ino, dirent->inode)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000444 dirent->inode = 0;
445 dir_modified++;
446 goto next;
447 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000448 if (ctx->flags & E2F_FLAG_ABORT)
449 return DIRENT_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000450 }
451
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000452 if (check_name(ctx, dirent, ino, &cd->pctx))
453 dir_modified++;
454
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000455 /*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000456 * If this is a directory, then mark its parent in its
457 * dir_info structure. If the parent field is already
458 * filled in, then this directory has more than one
459 * hard link. We assume the first link is correct,
460 * and ask the user if he/she wants to clear this one.
461 */
462 if ((dot_state > 2) &&
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000463 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000464 dirent->inode))) {
Theodore Ts'o08b21301997-11-03 19:42:40 +0000465 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000466 if (!subdir) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000467 cd->pctx.ino = dirent->inode;
468 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000469 ctx->flags |= E2F_FLAG_ABORT;
470 return DIRENT_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000471 }
472 if (subdir->parent) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000473 cd->pctx.ino2 = subdir->parent;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000474 if (fix_problem(ctx, PR_2_LINK_DIR,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000475 &cd->pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000476 dirent->inode = 0;
477 dir_modified++;
478 goto next;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000479 }
480 cd->pctx.ino2 = 0;
481 } else
482 subdir->parent = ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000483 }
484
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000485 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
486 &links);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000487 if (links > 1)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000488 ctx->fs_links_count++;
489 ctx->fs_total_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000490 next:
491 offset += dirent->rec_len;
492 } while (offset < fs->blocksize);
493#if 0
494 printf("\n");
495#endif
496 if (offset != fs->blocksize) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000497 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
498 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
499 dirent->rec_len = cd->pctx.num;
500 dir_modified++;
501 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000502 }
503 if (dir_modified) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000504 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
505 if (cd->pctx.errcode) {
Theodore Ts'o08b21301997-11-03 19:42:40 +0000506 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
507 &cd->pctx)) {
508 ctx->flags |= E2F_FLAG_ABORT;
509 return DIRENT_ABORT;
510 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000511 }
512 ext2fs_mark_changed(fs);
513 }
514 return 0;
515}
516
517/*
518 * This function is called to deallocate a block, and is an interator
519 * functioned called by deallocate inode via ext2fs_iterate_block().
520 */
521static int deallocate_inode_block(ext2_filsys fs,
522 blk_t *block_nr,
523 int blockcnt,
524 void *private)
525{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000526 e2fsck_t ctx = (e2fsck_t) private;
527
Theodore Ts'o3839e651997-04-26 13:21:57 +0000528 if (!*block_nr)
529 return 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000530 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000531 ext2fs_unmark_block_bitmap(fs->block_map, *block_nr);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000532 return 0;
533}
534
535/*
536 * This fuction deallocates an inode
537 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000538static void deallocate_inode(e2fsck_t ctx, ino_t ino,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000539 char* block_buf)
540{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000541 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000542 struct ext2_inode inode;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000543 struct problem_context pctx;
544
545 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000546 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000547 inode.i_links_count = 0;
548 inode.i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000549 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000550 clear_problem_context(&pctx);
551 pctx.ino = ino;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000552
Theodore Ts'o3839e651997-04-26 13:21:57 +0000553 /*
554 * Fix up the bitmaps...
555 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000556 read_bitmaps(ctx);
557 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
558 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
559 if (ctx->inode_bad_map)
560 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000561 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000562 ext2fs_mark_ib_dirty(fs);
563
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000564 if (!ext2fs_inode_has_valid_blocks(&inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000565 return;
566
567 ext2fs_mark_bb_dirty(fs);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000568 pctx.errcode = ext2fs_block_iterate(fs, ino, 0, block_buf,
569 deallocate_inode_block, ctx);
570 if (pctx.errcode) {
571 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000572 ctx->flags |= E2F_FLAG_ABORT;
573 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000574 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000575}
576
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000577static int process_bad_inode(e2fsck_t ctx, ino_t dir, ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000578{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000579 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000580 struct ext2_inode inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000581 int inode_modified = 0;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000582 unsigned char *frag, *fsize;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000583 struct problem_context pctx;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000584 int problem = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000585
Theodore Ts'o08b21301997-11-03 19:42:40 +0000586 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000587
588 clear_problem_context(&pctx);
589 pctx.ino = ino;
590 pctx.dir = dir;
591 pctx.inode = &inode;
592
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000593 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
594 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
595 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
Theodore Ts'o08b21301997-11-03 19:42:40 +0000596 !(LINUX_S_ISSOCK(inode.i_mode)))
597 problem = PR_2_BAD_MODE;
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000598
599 if (LINUX_S_ISCHR(inode.i_mode)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000600 && !e2fsck_pass1_check_device_inode(&inode))
601 problem = PR_2_BAD_CHAR_DEV;
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000602
603 if (LINUX_S_ISBLK(inode.i_mode)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000604 && !e2fsck_pass1_check_device_inode(&inode))
605 problem = PR_2_BAD_BLOCK_DEV;
606
607 if (problem) {
608 if (fix_problem(ctx, problem, &pctx)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000609 deallocate_inode(ctx, ino, 0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000610 if (ctx->flags & E2F_FLAG_ABORT)
611 return 0;
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000612 return 1;
613 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000614 problem = 0;
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000615 }
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000616
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000617 if (inode.i_faddr &&
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000618 fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000619 inode.i_faddr = 0;
620 inode_modified++;
621 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000622
623 switch (fs->super->s_creator_os) {
624 case EXT2_OS_LINUX:
625 frag = &inode.osd2.linux2.l_i_frag;
626 fsize = &inode.osd2.linux2.l_i_fsize;
627 break;
628 case EXT2_OS_HURD:
629 frag = &inode.osd2.hurd2.h_i_frag;
630 fsize = &inode.osd2.hurd2.h_i_fsize;
631 break;
632 case EXT2_OS_MASIX:
633 frag = &inode.osd2.masix2.m_i_frag;
634 fsize = &inode.osd2.masix2.m_i_fsize;
635 break;
636 default:
637 frag = fsize = 0;
638 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000639 if (frag && *frag) {
640 pctx.num = *frag;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000641 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000642 *frag = 0;
643 inode_modified++;
644 }
645 pctx.num = 0;
646 }
647 if (fsize && *fsize) {
648 pctx.num = *fsize;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000649 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000650 *fsize = 0;
651 inode_modified++;
652 }
653 pctx.num = 0;
654 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000655
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000656 if (inode.i_file_acl &&
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000657 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000658 inode.i_file_acl = 0;
659 inode_modified++;
660 }
661 if (inode.i_dir_acl &&
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000662 fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000663 inode.i_dir_acl = 0;
664 inode_modified++;
665 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000666 if (inode_modified)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000667 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000668 return 0;
669}
670
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000671
672/*
673 * allocate_dir_block --- this function allocates a new directory
674 * block for a particular inode; this is done if a directory has
675 * a "hole" in it, or if a directory has a illegal block number
676 * that was zeroed out and now needs to be replaced.
677 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000678static int allocate_dir_block(e2fsck_t ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000679 struct ext2_db_entry *db,
680 char *buf, struct problem_context *pctx)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000681{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000682 ext2_filsys fs = ctx->fs;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000683 blk_t blk;
684 char *block;
685 struct ext2_inode inode;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000686
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000687 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000688 return 1;
689
690 /*
691 * Read the inode and block bitmaps in; we'll be messing with
692 * them.
693 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000694 read_bitmaps(ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000695
696 /*
697 * First, find a free block
698 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000699 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
700 if (pctx->errcode) {
701 pctx->str = "ext2fs_new_block";
702 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000703 return 1;
704 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000705 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000706 ext2fs_mark_block_bitmap(fs->block_map, blk);
707 ext2fs_mark_bb_dirty(fs);
708
709 /*
710 * Now let's create the actual data block for the inode
711 */
712 if (db->blockcnt)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000713 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000714 else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000715 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
716 EXT2_ROOT_INO, &block);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000717
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000718 if (pctx->errcode) {
719 pctx->str = "ext2fs_new_dir_block";
720 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000721 return 1;
722 }
723
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000724 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000725 ext2fs_free_mem((void **) &block);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000726 if (pctx->errcode) {
727 pctx->str = "ext2fs_write_dir_block";
728 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000729 return 1;
730 }
731
732 /*
733 * Update the inode block count
734 */
Theodore Ts'o08b21301997-11-03 19:42:40 +0000735 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000736 inode.i_blocks += fs->blocksize / 512;
737 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
738 inode.i_size = (db->blockcnt+1) * fs->blocksize;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000739 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000740
741 /*
742 * Finally, update the block pointers for the inode
743 */
744 db->blk = blk;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000745 pctx->errcode = ext2fs_block_iterate(fs, db->ino, BLOCK_FLAG_HOLE,
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000746 0, update_dir_block, db);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000747 if (pctx->errcode) {
748 pctx->str = "ext2fs_block_iterate";
749 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000750 return 1;
751 }
752
753 return 0;
754}
755
756/*
757 * This is a helper function for allocate_dir_block().
758 */
759static int update_dir_block(ext2_filsys fs,
760 blk_t *block_nr,
761 int blockcnt,
762 void *private)
763{
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000764 struct ext2_db_entry *db = private;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000765
766 if (db->blockcnt == blockcnt) {
767 *block_nr = db->blk;
768 return BLOCK_CHANGED;
769 }
770 return 0;
771}
772